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

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 time
import traceback
import pprint
import pathlib
import flask
import nkf
import tjaf
from functools import wraps
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)
sess = Session()
sess.init_app(app)
csrf = CSRFProtect(app)
#csrf = CSRFProtect(app)
db = client[take_config('MONGO', required=True)['database']]
db.users.create_index('username', unique=True)
@ -741,19 +747,81 @@ def cache_wrap(res_from, secs):
@app.route(basedir + "src/<path: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>")
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>")
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")
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__':
import argparse

View File

@ -203,16 +203,18 @@ class SongSelect{
})
// カスタムメニュー
this.songs.push({
title: "ソースコード",
skin: this.songSkin.sourceCode,
action: "sourceCode",
});
this.songs.push({
title: "曲を投稿",
skin: this.songSkin.upload,
action: "upload",
});
// this.songs.push({
// title: "ソースコード",
// skin: this.songSkin.sourceCode,
// action: "sourceCode",
// });
for (let i = 0; i < 10; i++) {
this.songs.push({
title: "曲を投稿!",
skin: this.songSkin.upload,
action: "upload",
});
}
this.songs.push({
title: strings.back,
@ -842,8 +844,8 @@ class SongSelect{
} else if (currentSong.action === "upload") {
this.playSound("se_don");
setTimeout(() => {
open("https://upload.taikoapp.uk/","_blank");
}, 500);
window.location.href = "/upload/";
}, 20);
}
}
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
Werkzeug==3.0.1
jinja2==3.1.3
git+https://github.com/nurse/nkf.git#egg=nkf&subdirectory=NKF.python3
tjaf==1.0.6