2 Commits

Author SHA1 Message Date
taiko-web
6d7be5c45c initial import 2026-01-01 21:31:54 +08:00
92c1261f6f feat: 中文曲名优先显示 TITLEZH,其次 TITLEJA;版本号改为 vLightNova 1.0.0 2025-12-14 12:49:20 +08:00
5 changed files with 31 additions and 22 deletions

View File

@@ -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
View File

@@ -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

View File

@@ -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

View File

@@ -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");
@@ -3113,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]

View File

@@ -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>