Compare commits
5 Commits
sorted
...
6d7be5c45c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d7be5c45c | ||
| 92c1261f6f | |||
| 9a2a7dbee6 | |||
| f91e3c9089 | |||
| 84a0c2b7e0 |
@@ -0,0 +1,9 @@
|
|||||||
|
I will implement the requested changes to remove the delete functionality and redirect the upload interface while keeping the upload API intact.
|
||||||
|
|
||||||
|
### 1. Frontend: Song Selection Menu (`public/src/js/songselect.js`)
|
||||||
|
* **Remove Delete Button**: I will remove the "Delete" (削除) button configuration from the `difficultyMenu` buttons array (around lines 313-319). This removes the option from the UI.
|
||||||
|
* **Redirect Upload Action**: I will modify the handler for the "upload" action (around lines 954-958). Instead of redirecting to the local `/upload/` page, it will redirect to `https://zizhipu.taiko.asia`.
|
||||||
|
|
||||||
|
### 2. Backend: API Security (`app.py`)
|
||||||
|
* **Disable Delete API**: I will modify the `/api/delete` route to return a 403 Forbidden error (or simply pass), ensuring that songs cannot be deleted even if someone calls the API directly.
|
||||||
|
* **Keep Upload API**: The `/api/upload` route will remain unchanged, preserving the ability to upload songs via API as requested.
|
||||||
13
app.py
13
app.py
@@ -911,19 +911,8 @@ def upload_file():
|
|||||||
return flask.jsonify({'success': True})
|
return flask.jsonify({'success': True})
|
||||||
|
|
||||||
@app.route("/api/delete", methods=["POST"])
|
@app.route("/api/delete", methods=["POST"])
|
||||||
@limiter.limit("1 per day")
|
|
||||||
def delete():
|
def delete():
|
||||||
id = flask.request.get_json().get('id')
|
return flask.jsonify({ "success": False, "reason": "Deletion is disabled" }), 403
|
||||||
client["taiko"]["songs"].delete_one({ "id": id })
|
|
||||||
|
|
||||||
parent_dir = pathlib.Path(os.getenv("TAIKO_WEB_SONGS_DIR", "public/songs"))
|
|
||||||
target_dir = parent_dir / id
|
|
||||||
if not (target_dir.resolve().parents and parent_dir.resolve() in target_dir.resolve().parents):
|
|
||||||
return flask.jsonify({ "success": False, "reason": "PARENT IS NOT ALLOWED" })
|
|
||||||
|
|
||||||
shutil.rmtree(target_dir)
|
|
||||||
|
|
||||||
return "成功しました。"
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import argparse
|
import argparse
|
||||||
|
|||||||
BIN
flask_session/2029240f6d1128be89ddc32729463129
Normal file
BIN
flask_session/2029240f6d1128be89ddc32729463129
Normal file
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
class ImportSongs{
|
class ImportSongs{
|
||||||
constructor(...args){
|
constructor(...args){
|
||||||
this.init(...args)
|
this.init(...args)
|
||||||
}
|
}
|
||||||
@@ -322,6 +322,10 @@
|
|||||||
songTitle = songTitle.slice(0, uraPos)
|
songTitle = songTitle.slice(0, uraPos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(id === "cn" && !meta["titlecn"] && meta.titlezh){
|
||||||
|
titleLang.cn = meta.titlezh
|
||||||
|
titleLangAdded = true
|
||||||
|
}
|
||||||
if(meta["title" + id]){
|
if(meta["title" + id]){
|
||||||
titleLang[id] = meta["title" + id]
|
titleLang[id] = meta["title" + id]
|
||||||
titleLangAdded = true
|
titleLangAdded = true
|
||||||
@@ -329,6 +333,10 @@
|
|||||||
titleLang[id] = this.songTitle[songTitle][id] + ura
|
titleLang[id] = this.songTitle[songTitle][id] + ura
|
||||||
titleLangAdded = true
|
titleLangAdded = true
|
||||||
}
|
}
|
||||||
|
if(id === "cn" && !meta["subtitlecn"] && meta.subtitlezh){
|
||||||
|
subtitleLang.cn = meta.subtitlezh
|
||||||
|
subtitleLangAdded = true
|
||||||
|
}
|
||||||
if(meta["subtitle" + id]){
|
if(meta["subtitle" + id]){
|
||||||
subtitleLang[id] = meta["subtitle" + id]
|
subtitleLang[id] = meta["subtitle" + id]
|
||||||
subtitleLangAdded = true
|
subtitleLangAdded = true
|
||||||
|
|||||||
@@ -310,12 +310,6 @@ class SongSelect{
|
|||||||
iconName: "download",
|
iconName: "download",
|
||||||
iconFill: "#e7cbe1",
|
iconFill: "#e7cbe1",
|
||||||
letterSpacing: 4
|
letterSpacing: 4
|
||||||
}, {
|
|
||||||
text: "削除",
|
|
||||||
fill: "silver",
|
|
||||||
iconName: "trash",
|
|
||||||
iconFill: "#111111",
|
|
||||||
letterSpacing: 4
|
|
||||||
}]
|
}]
|
||||||
this.optionsList = [strings.none, strings.auto, strings.netplay]
|
this.optionsList = [strings.none, strings.auto, strings.netplay]
|
||||||
|
|
||||||
@@ -954,7 +948,7 @@ class SongSelect{
|
|||||||
} else if (currentSong.action === "upload") {
|
} else if (currentSong.action === "upload") {
|
||||||
this.playSound("se_don");
|
this.playSound("se_don");
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.href = "/upload/";
|
window.location.href = "https://zizhipu.taiko.asia";
|
||||||
}, 100);
|
}, 100);
|
||||||
} else if (currentSong.action === "keijiban") {
|
} else if (currentSong.action === "keijiban") {
|
||||||
this.playSound("se_don");
|
this.playSound("se_don");
|
||||||
@@ -2965,6 +2959,12 @@ class SongSelect{
|
|||||||
var categoryName = song.category
|
var categoryName = song.category
|
||||||
var originalCategory = song.category
|
var originalCategory = song.category
|
||||||
}
|
}
|
||||||
|
if(!categoryName){
|
||||||
|
if(song.song_type){
|
||||||
|
categoryName = song.song_type
|
||||||
|
originalCategory = song.song_type
|
||||||
|
}
|
||||||
|
}
|
||||||
var addedSong = {
|
var addedSong = {
|
||||||
title: title,
|
title: title,
|
||||||
originalTitle: song.title,
|
originalTitle: song.title,
|
||||||
@@ -3107,6 +3107,15 @@ class SongSelect{
|
|||||||
|
|
||||||
getLocalTitle(title, titleLang){
|
getLocalTitle(title, titleLang){
|
||||||
if(titleLang){
|
if(titleLang){
|
||||||
|
if(strings.id === "cn"){
|
||||||
|
if(titleLang.cn){
|
||||||
|
return titleLang.cn
|
||||||
|
}
|
||||||
|
if(titleLang.ja){
|
||||||
|
return titleLang.ja
|
||||||
|
}
|
||||||
|
return title
|
||||||
|
}
|
||||||
for(var id in titleLang){
|
for(var id in titleLang){
|
||||||
if(id === "en" && strings.preferEn && !(strings.id in titleLang) && titleLang.en || id === strings.id && titleLang[id]){
|
if(id === "en" && strings.preferEn && !(strings.id in titleLang) && titleLang.en || id === strings.id && titleLang[id]){
|
||||||
return titleLang[id]
|
return titleLang[id]
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
<div id="screen" class="pattern-bg"></div>
|
<div id="screen" class="pattern-bg"></div>
|
||||||
<div data-nosnippet id="version">
|
<div data-nosnippet id="version">
|
||||||
{% if version.version and version.commit_short and version.commit %}
|
{% if version.version and version.commit_short and version.commit %}
|
||||||
<a href="{{version.url}}commit/{{version.commit}}" target="_blank" rel="noopener" id="version-link" class="stroke-sub" alt="taiko-web ver.{{version.version}} ({{version.commit_short}})">taiko-web ver.{{version.version}} ({{version.commit_short}})</a>
|
<a href="{{version.url}}commit/{{version.commit}}" target="_blank" rel="noopener" id="version-link" class="stroke-sub" alt="vLightNova 1.0.0">vLightNova 1.0.0</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a target="_blank" rel="noopener" id="version-link" class="stroke-sub" alt="taiko-web vRAINBOW-BETA4">taiko-web vRAINBOW-BETA4</a>
|
<a target="_blank" rel="noopener" id="version-link" class="stroke-sub" alt="vLightNova 1.0.0">vLightNova 1.0.0</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<script src="src/js/browsersupport.js?{{version.commit_short}}"></script>
|
<script src="src/js/browsersupport.js?{{version.commit_short}}"></script>
|
||||||
|
|||||||
22
tjaf.py
22
tjaf.py
@@ -7,6 +7,8 @@ class Tja:
|
|||||||
self.text = text
|
self.text = text
|
||||||
self.title: Optional[str] = None
|
self.title: Optional[str] = None
|
||||||
self.subtitle: Optional[str] = None
|
self.subtitle: Optional[str] = None
|
||||||
|
self.title_ja: Optional[str] = None
|
||||||
|
self.subtitle_ja: Optional[str] = None
|
||||||
self.wave: Optional[str] = None
|
self.wave: Optional[str] = None
|
||||||
self.offset: Optional[float] = None
|
self.offset: Optional[float] = None
|
||||||
self.courses: Dict[str, Dict[str, Optional[int]]] = {}
|
self.courses: Dict[str, Dict[str, Optional[int]]] = {}
|
||||||
@@ -25,8 +27,12 @@ class Tja:
|
|||||||
val = v.strip()
|
val = v.strip()
|
||||||
if key == "TITLE":
|
if key == "TITLE":
|
||||||
self.title = val or None
|
self.title = val or None
|
||||||
|
elif key == "TITLEJA":
|
||||||
|
self.title_ja = val or None
|
||||||
elif key == "SUBTITLE":
|
elif key == "SUBTITLE":
|
||||||
self.subtitle = val or None
|
self.subtitle = val or None
|
||||||
|
elif key == "SUBTITLEJA":
|
||||||
|
self.subtitle_ja = val or None
|
||||||
elif key == "WAVE":
|
elif key == "WAVE":
|
||||||
self.wave = val or None
|
self.wave = val or None
|
||||||
elif key == "OFFSET":
|
elif key == "OFFSET":
|
||||||
@@ -73,8 +79,20 @@ class Tja:
|
|||||||
"type": "tja",
|
"type": "tja",
|
||||||
"title": self.title,
|
"title": self.title,
|
||||||
"subtitle": self.subtitle,
|
"subtitle": self.subtitle,
|
||||||
"title_lang": {"ja": self.title, "en": None, "cn": None, "tw": None, "ko": None},
|
"title_lang": {
|
||||||
"subtitle_lang": {"ja": self.subtitle, "en": None, "cn": None, "tw": None, "ko": None},
|
"ja": self.title_ja or self.title,
|
||||||
|
"en": None,
|
||||||
|
"cn": self.title_ja or None,
|
||||||
|
"tw": None,
|
||||||
|
"ko": None,
|
||||||
|
},
|
||||||
|
"subtitle_lang": {
|
||||||
|
"ja": self.subtitle_ja or self.subtitle,
|
||||||
|
"en": None,
|
||||||
|
"cn": self.subtitle_ja or None,
|
||||||
|
"tw": None,
|
||||||
|
"ko": None,
|
||||||
|
},
|
||||||
"courses": courses_out,
|
"courses": courses_out,
|
||||||
"enabled": False,
|
"enabled": False,
|
||||||
"category_id": None,
|
"category_id": None,
|
||||||
|
|||||||
40
update.sh
Normal file
40
update.sh
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
if [ "${EUID}" -ne 0 ]; then echo "需要 root 权限"; exit 1; fi
|
||||||
|
|
||||||
|
SRC_DIR=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
DEST_DIR=/srv/taiko-web
|
||||||
|
SONGS_DIR="$DEST_DIR/public/songs"
|
||||||
|
BACKUP_DIR="$DEST_DIR/.backup_songs_$(date +%Y%m%d_%H%M%S)"
|
||||||
|
|
||||||
|
systemctl stop taiko-web || true
|
||||||
|
|
||||||
|
if [ -d "$SONGS_DIR" ]; then
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
rsync -a "$SONGS_DIR/" "$BACKUP_DIR/" || cp -a "$SONGS_DIR/." "$BACKUP_DIR/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$DEST_DIR"
|
||||||
|
rsync -a --delete \
|
||||||
|
--exclude '.git' \
|
||||||
|
--exclude '.venv' \
|
||||||
|
--exclude 'public/songs' \
|
||||||
|
"$SRC_DIR/" "$DEST_DIR/"
|
||||||
|
|
||||||
|
if [ -x "$DEST_DIR/.venv/bin/pip" ]; then
|
||||||
|
"$DEST_DIR/.venv/bin/pip" install -U pip
|
||||||
|
"$DEST_DIR/.venv/bin/pip" install -r "$DEST_DIR/requirements.txt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
chown -R www-data:www-data "$DEST_DIR"
|
||||||
|
|
||||||
|
if [ -d "$BACKUP_DIR" ]; then
|
||||||
|
mkdir -p "$SONGS_DIR"
|
||||||
|
rsync -a "$BACKUP_DIR/" "$SONGS_DIR/" || cp -a "$BACKUP_DIR/." "$SONGS_DIR/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
systemctl daemon-reload || true
|
||||||
|
systemctl restart taiko-web || systemctl start taiko-web || true
|
||||||
|
|
||||||
|
systemctl is-active --quiet taiko-web
|
||||||
Reference in New Issue
Block a user