曲を投稿できるようにする

This commit is contained in:
yuuki 2024-02-13 11:58:04 +09:00
parent a318a177ea
commit 1b03e5d0e7
6 changed files with 146 additions and 17 deletions

78
app.py
View File

@ -14,7 +14,13 @@ import schema
import os import os
import time import time
import traceback
import pprint
import pathlib
import flask import flask
import nkf
import tjaf
from functools import wraps from functools import wraps
from flask import Flask, g, jsonify, render_template, request, abort, redirect, session, flash, make_response, send_from_directory from flask import Flask, g, jsonify, render_template, request, abort, redirect, session, flash, make_response, send_from_directory
@ -50,7 +56,7 @@ app.config['SESSION_REDIS'] = Redis(
app.cache = Cache(app, config=redis_config) app.cache = Cache(app, config=redis_config)
sess = Session() sess = Session()
sess.init_app(app) sess.init_app(app)
csrf = CSRFProtect(app) #csrf = CSRFProtect(app)
db = client[take_config('MONGO', required=True)['database']] db = client[take_config('MONGO', required=True)['database']]
db.users.create_index('username', unique=True) db.users.create_index('username', unique=True)
@ -741,19 +747,81 @@ def cache_wrap(res_from, secs):
@app.route(basedir + "src/<path:ref>") @app.route(basedir + "src/<path:ref>")
def send_src(ref): def send_src(ref):
return cache_wrap(send_from_directory("public/src", ref), 3600) return cache_wrap(flask.send_from_directory("public/src", ref), 3600)
@app.route(basedir + "assets/<path:ref>") @app.route(basedir + "assets/<path:ref>")
def send_assets(ref): def send_assets(ref):
return cache_wrap(send_from_directory("public/assets", ref), 3600) return cache_wrap(flask.send_from_directory("public/assets", ref), 3600)
@app.route(basedir + "songs/<path:ref>") @app.route(basedir + "songs/<path:ref>")
def send_songs(ref): def send_songs(ref):
return cache_wrap(send_from_directory("public/songs", ref), 604800) return cache_wrap(flask.send_from_directory("public/songs", ref), 604800)
@app.route(basedir + "manifest.json") @app.route(basedir + "manifest.json")
def send_manifest(): def send_manifest():
return cache_wrap(send_from_directory("public", "manifest.json"), 3600) return cache_wrap(flask.send_from_directory("public", "manifest.json"), 3600)
@app.route("/upload/")
def send_upload():
return cache_wrap(flask.send_from_directory("public/upload", "index.html"), 3600)
@app.route("/upload/<path:ref>")
def send_upload_sub(ref):
return cache_wrap(flask.send_from_directory("public/upload", ref), 3600)
@app.route("/upload", methods=["POST"])
def upload_file():
try:
# POSTリクエストにファイルの部分がない場合
if 'file_tja' not in flask.request.files or 'file_music' not in flask.request.files:
return flask.jsonify({'error': 'リクエストにファイルの部分がありません'})
file_tja = flask.request.files['file_tja']
file_music = flask.request.files['file_music']
# ファイルが選択されておらず空のファイルを受け取った場合
if file_tja.filename == '' or file_music.filename == '':
return flask.jsonify({'error': 'ファイルが選択されていません'})
# TJAファイルをテキストUTF-8/LFに変換
tja_data = nkf.nkf('-wd', file_tja.read())
tja_text = tja_data.decode("utf-8")
print("TJAのサイズ:",len(tja_text))
# TJAファイルの内容を解析
tja = tjaf.Tja(tja_text)
# TJAファイルのハッシュ値を生成
msg = hashlib.sha256()
msg.update(tja_data)
tja_hash = msg.hexdigest()
print("TJA:",tja_hash)
# 音楽ファイルのハッシュ値を生成
music_data = file_music.read()
msg2 = hashlib.sha256()
msg2.update(music_data)
music_hash = msg2.hexdigest()
print("音楽:",music_hash)
# IDを生成
generated_id = f"{tja_hash}-{music_hash}"
# MongoDBのデータも作成
db_entry = tja.to_mongo(generated_id, time.time_ns())
pprint.pprint(db_entry)
# mongoDBにデータをぶち込む
client['taiko']["songs"].insert_one(db_entry)
# ディレクトリを作成
target_dir = pathlib.Path(os.getenv("TAIKO_WEB_SONGS_DIR", "public/songs")) / generated_id
target_dir.mkdir(parents=True,exist_ok=True)
# TJAを保存
(target_dir / "main.tja").write_bytes(tja_data)
# 曲ファイルも保存
(target_dir / f"main.{db_entry['music_type']}").write_bytes(music_data)
except Exception as e:
error_str = ''.join(traceback.TracebackException.from_exception(e).format())
return flask.jsonify({'error': error_str})
return flask.jsonify({'success': True})
if __name__ == '__main__': if __name__ == '__main__':
import argparse import argparse

View File

@ -203,16 +203,18 @@ class SongSelect{
}) })
// カスタムメニュー // カスタムメニュー
this.songs.push({ // this.songs.push({
title: "ソースコード", // title: "ソースコード",
skin: this.songSkin.sourceCode, // skin: this.songSkin.sourceCode,
action: "sourceCode", // action: "sourceCode",
}); // });
this.songs.push({ for (let i = 0; i < 10; i++) {
title: "曲を投稿", this.songs.push({
skin: this.songSkin.upload, title: "曲を投稿!",
action: "upload", skin: this.songSkin.upload,
}); action: "upload",
});
}
this.songs.push({ this.songs.push({
title: strings.back, title: strings.back,
@ -842,8 +844,8 @@ class SongSelect{
} else if (currentSong.action === "upload") { } else if (currentSong.action === "upload") {
this.playSound("se_don"); this.playSound("se_don");
setTimeout(() => { setTimeout(() => {
open("https://upload.taikoapp.uk/","_blank"); window.location.href = "/upload/";
}, 500); }, 20);
} }
} }
this.pointer(false) this.pointer(false)

27
public/upload/index.html Normal file
View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>太鼓ウェブあっぷろーだー</title>
<link rel="stylesheet" href="./style.css">
<script src="./upload.js"></script>
</head>
<body>
<h1>太鼓ウェブあっぷろーだー</h1>
<form id="upload-form" enctype="multipart/form-data">
<label for="file_tja">TJA ファイル:</label>
<input type="file" name="file_tja" accept=".tja" required><br>
<label for="file_music">音楽ファイル:</label>
<input type="file" name="file_music" accept=".ogg,.mp3,.wav" required><br>
<br>
<button type="button" onclick="uploadFiles()">今すぐ投稿! (30秒ほどかかる場合があります)</button>
</form>
<br>
<div id="error-view"></div>
</body>
</html>

3
public/upload/style.css Normal file
View File

@ -0,0 +1,3 @@
#error-view {
white-space: pre-line;
}

27
public/upload/upload.js Normal file
View File

@ -0,0 +1,27 @@
function uploadFiles() {
const form = document.getElementById('upload-form');
const formData = new FormData(form);
fetch('/upload', {
method: 'POST',
body: formData,
})
.then(res => {
if (res.ok) {
return res.json();
} else {
throw new Error(res.url + " で " + res.status.toString() + " が発生しました。");
}
})
.then(data => {
if (data.success) {
alert("おめでとう!ファイルの投稿に成功しました!");
} else {
throw new Error(data.error);
}
})
.catch(error => {
console.error('エラー:', error);
document.getElementById("error-view").textContent = error;
});
}

View File

@ -12,3 +12,5 @@ requests==2.31.0
websockets==12.0 websockets==12.0
Werkzeug==3.0.1 Werkzeug==3.0.1
jinja2==3.1.3 jinja2==3.1.3
git+https://github.com/nurse/nkf.git#egg=nkf&subdirectory=NKF.python3
tjaf==1.0.6