mirror of
https://github.com/yuukiwww/taiko-web.git
synced 2024-09-29 12:49:13 +02:00
曲を投稿できるようにする
This commit is contained in:
parent
a318a177ea
commit
1b03e5d0e7
78
app.py
78
app.py
@ -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
|
||||||
|
@ -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
27
public/upload/index.html
Normal 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
3
public/upload/style.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#error-view {
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
27
public/upload/upload.js
Normal file
27
public/upload/upload.js
Normal 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;
|
||||||
|
});
|
||||||
|
}
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user