mirror of
https://github.com/qwerfd2/Groove_Coaster_2_Server.git
synced 2026-02-23 01:42:41 +00:00
fixes
This commit is contained in:
3
7002.py
3
7002.py
@@ -13,6 +13,7 @@ from api.misc import get_4max_version_string
|
||||
from api.user import routes as user_routes
|
||||
from api.ranking import routes as rank_routes
|
||||
from api.shop import routes as shop_routes
|
||||
from api.play import routes as play_routes
|
||||
|
||||
from config import HOST, PORT, DEBUG, SSL_CERT, SSL_KEY, ROOT_FOLDER, ACTUAL_HOST, ACTUAL_PORT
|
||||
|
||||
@@ -33,7 +34,7 @@ async def serve_file(request):
|
||||
|
||||
routes = []
|
||||
|
||||
routes = routes + user_routes + rank_routes + shop_routes
|
||||
routes = routes + user_routes + rank_routes + shop_routes + play_routes
|
||||
|
||||
routes.append(Route("/{path:path}", serve_file))
|
||||
|
||||
|
||||
@@ -53,20 +53,19 @@ result = Table(
|
||||
Column("rid", Integer, primary_key=True, autoincrement=True),
|
||||
Column("vid", String(512), nullable=False),
|
||||
Column("tid", String(512), nullable=False),
|
||||
Column("sid", String(512), nullable=False),
|
||||
Column("sid", Integer, nullable=False),
|
||||
Column("stts", String(64)),
|
||||
Column("id", String(8)),
|
||||
Column("mode", String(4)),
|
||||
Column("avatar", String(4)),
|
||||
Column("score", String(16)),
|
||||
Column("id", Integer),
|
||||
Column("mode", Integer),
|
||||
Column("avatar", Integer),
|
||||
Column("score", Integer),
|
||||
Column("high_score", String(128)),
|
||||
Column("play_rslt", String(128)),
|
||||
Column("item", String(16)),
|
||||
Column("item", Integer),
|
||||
Column("os", String(16)),
|
||||
Column("os_ver", String(16)),
|
||||
Column("ver", String(16)),
|
||||
Column("mike", String(8)),
|
||||
|
||||
Column("mike", Integer),
|
||||
)
|
||||
|
||||
whitelist = Table(
|
||||
@@ -93,6 +92,7 @@ async def init_db():
|
||||
|
||||
await engine.dispose()
|
||||
print("[DB] Database initialized successfully.")
|
||||
await ensure_user_columns()
|
||||
|
||||
async def get_user_data(uid, data_field):
|
||||
query = select(user.c[data_field]).where(user.c.device_id == uid[b'vid'][0].decode())
|
||||
@@ -125,4 +125,22 @@ async def check_blacklist(uid):
|
||||
)
|
||||
async with database.transaction():
|
||||
result = await database.fetch_one(query)
|
||||
return result is None
|
||||
return result is None
|
||||
|
||||
async def ensure_user_columns():
|
||||
import aiosqlite
|
||||
|
||||
async with aiosqlite.connect(DB_PATH) as db:
|
||||
async with db.execute("PRAGMA table_info(user);") as cursor:
|
||||
columns = [row[1] async for row in cursor]
|
||||
|
||||
alter_needed = False
|
||||
if "save_id" not in columns:
|
||||
await db.execute("ALTER TABLE user ADD COLUMN save_id TEXT;")
|
||||
alter_needed = True
|
||||
if "coin_mp" not in columns:
|
||||
await db.execute("ALTER TABLE user ADD COLUMN coin_mp INTEGER DEFAULT 1;")
|
||||
alter_needed = True
|
||||
if alter_needed:
|
||||
await db.commit()
|
||||
print("[DB] Added missing columns to user table.")
|
||||
|
||||
170
api/play.py
Normal file
170
api/play.py
Normal file
@@ -0,0 +1,170 @@
|
||||
from starlette.responses import Response
|
||||
from starlette.requests import Request
|
||||
from starlette.routing import Route
|
||||
import os
|
||||
import json
|
||||
from sqlalchemy import select, update, insert
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from config import ROOT_FOLDER, START_COIN, COIN_REWARD, AUTHORIZATION_NEEDED
|
||||
|
||||
from api.database import database, user, daily_reward, result, result, check_blacklist, check_whitelist
|
||||
from api.crypt import decrypt_fields
|
||||
from api.templates import START_STAGES, EXP_UNLOCKED_SONGS
|
||||
|
||||
async def result_request(request: Request):
|
||||
decrypted_fields, _ = await decrypt_fields(request)
|
||||
if not decrypted_fields:
|
||||
return Response("""<response><code>10</code><message>Invalid request data.</message></response>""", media_type="application/xml")
|
||||
|
||||
should_serve = True
|
||||
if AUTHORIZATION_NEEDED:
|
||||
should_serve = await check_whitelist(decrypted_fields) and not await check_blacklist(decrypted_fields)
|
||||
|
||||
if not should_serve:
|
||||
return Response("""<response><code>403</code><message>Access denied.</message></response>""", media_type="application/xml")
|
||||
|
||||
device_id = decrypted_fields[b'vid'][0].decode()
|
||||
file_path = os.path.join(ROOT_FOLDER, "files/result.xml")
|
||||
try:
|
||||
tree = ET.parse(file_path)
|
||||
root = tree.getroot()
|
||||
except Exception as e:
|
||||
return Response(f"""<response><code>500</code><message>Error parsing XML: {str(e)}</message></response>""", media_type="application/xml")
|
||||
|
||||
vid = decrypted_fields[b'vid'][0].decode()
|
||||
stts = decrypted_fields[b'stts'][0].decode()
|
||||
track_id = decrypted_fields[b'id'][0].decode()
|
||||
mode = decrypted_fields[b'mode'][0].decode()
|
||||
avatar = decrypted_fields[b'avatar'][0].decode()
|
||||
score = int(decrypted_fields[b'score'][0].decode())
|
||||
high_score = decrypted_fields[b'high_score'][0].decode()
|
||||
play_rslt = decrypted_fields[b'play_rslt'][0].decode()
|
||||
item = decrypted_fields[b'item'][0].decode()
|
||||
device_os = decrypted_fields[b'os'][0].decode()
|
||||
os_ver = decrypted_fields[b'os_ver'][0].decode()
|
||||
tid = decrypted_fields[b'tid'][0].decode()
|
||||
ver = decrypted_fields[b'ver'][0].decode()
|
||||
mike = decrypted_fields[b'mike'][0].decode()
|
||||
|
||||
if int(track_id) not in range(616, 1024) or int(mode) not in range(0, 4):
|
||||
query = select(daily_reward.c.coin).where(daily_reward.c.device_id == device_id)
|
||||
row = await database.fetch_one(query)
|
||||
query = select(user.c.coin_mp).where(user.c.device_id == device_id)
|
||||
coin_mp_row = await database.fetch_one(query)
|
||||
if coin_mp_row is None:
|
||||
coin_mp_row = {"coin_mp": 1}
|
||||
current_coin = row["coin"] if row and row["coin"] else START_COIN
|
||||
updated_coin = current_coin + COIN_REWARD * coin_mp_row["coin_mp"]
|
||||
|
||||
update_query = (
|
||||
update(daily_reward)
|
||||
.where(daily_reward.c.device_id == device_id)
|
||||
.values(coin=updated_coin)
|
||||
)
|
||||
await database.execute(update_query)
|
||||
|
||||
query = select(user.c.id).where(user.c.device_id == vid)
|
||||
user_row = await database.fetch_one(query)
|
||||
sid = user_row["id"] if user_row else ""
|
||||
|
||||
do_insert = False
|
||||
do_update_sid = False
|
||||
do_update_vid = False
|
||||
last_row_id = 0
|
||||
|
||||
if sid:
|
||||
query = select(result.c.rid, result.c.score).where(
|
||||
(result.c.id == track_id) &
|
||||
(result.c.mode == mode) &
|
||||
(result.c.sid == sid)
|
||||
).order_by(result.c.score.desc())
|
||||
records = await database.fetch_all(query)
|
||||
if records:
|
||||
last_row_id = records[0]["rid"]
|
||||
if score > int(records[0]["score"]):
|
||||
do_update_sid = True
|
||||
else:
|
||||
do_insert = True
|
||||
else:
|
||||
query = select(result.c.rid, result.c.score).where(
|
||||
(result.c.id == track_id) &
|
||||
(result.c.mode == mode) &
|
||||
(result.c.sid == "") &
|
||||
(result.c.vid == vid)
|
||||
).order_by(result.c.score.desc())
|
||||
records = await database.fetch_all(query)
|
||||
if records:
|
||||
last_row_id = records[0]["rid"]
|
||||
if score > records[0]["score"]:
|
||||
do_update_vid = True
|
||||
else:
|
||||
do_insert = True
|
||||
|
||||
if do_insert:
|
||||
insert_query = insert(result).values(
|
||||
vid=vid, stts=stts, id=track_id, mode=mode, avatar=avatar,
|
||||
score=score, high_score=high_score, play_rslt=play_rslt, item=item,
|
||||
os=device_os, os_ver=os_ver, tid=tid, sid=sid, ver=ver, mike=mike
|
||||
)
|
||||
result_obj = await database.execute(insert_query)
|
||||
last_row_id = result_obj
|
||||
elif do_update_sid:
|
||||
update_query = (
|
||||
update(result)
|
||||
.where((result.c.sid == sid) & (result.c.id == track_id) & (result.c.mode == mode))
|
||||
.values(
|
||||
stts=stts, avatar=avatar, score=score, high_score=high_score,
|
||||
play_rslt=play_rslt, item=item, os=device_os, os_ver=os_ver,
|
||||
tid=tid, ver=ver, mike=mike, vid=vid
|
||||
)
|
||||
)
|
||||
await database.execute(update_query)
|
||||
elif do_update_vid:
|
||||
update_query = (
|
||||
update(result)
|
||||
.where((result.c.vid == vid) & (result.c.id == track_id) & (result.c.mode == mode))
|
||||
.values(
|
||||
stts=stts, avatar=avatar, score=score, high_score=high_score,
|
||||
play_rslt=play_rslt, item=item, os=device_os, os_ver=os_ver,
|
||||
sid=sid, ver=ver, mike=mike
|
||||
)
|
||||
)
|
||||
await database.execute(update_query)
|
||||
|
||||
query = select(daily_reward.c.my_stage).where(daily_reward.c.device_id == device_id)
|
||||
row = await database.fetch_one(query)
|
||||
my_stage = set(json.loads(row["my_stage"])) if row and row["my_stage"] else set(START_STAGES)
|
||||
|
||||
current_exp = int(stts.split(",")[0])
|
||||
for song in EXP_UNLOCKED_SONGS:
|
||||
if song["lvl"] <= current_exp:
|
||||
my_stage.add(song["id"])
|
||||
|
||||
my_stage = sorted(my_stage)
|
||||
update_query = (
|
||||
update(daily_reward)
|
||||
.where(daily_reward.c.device_id == device_id)
|
||||
.values(lvl=current_exp, avatar=int(avatar), my_stage=json.dumps(my_stage))
|
||||
)
|
||||
await database.execute(update_query)
|
||||
|
||||
query = select(result.c.rid, result.c.score).where(
|
||||
(result.c.id == track_id) & (result.c.mode == mode)
|
||||
).order_by(result.c.score.desc())
|
||||
records = await database.fetch_all(query)
|
||||
|
||||
rank = None
|
||||
for idx, record in enumerate(records, start=1):
|
||||
if record["rid"] == last_row_id:
|
||||
rank = idx
|
||||
break
|
||||
|
||||
after_element = root.find('.//after')
|
||||
after_element.text = str(rank)
|
||||
xml_response = ET.tostring(tree.getroot(), encoding='unicode')
|
||||
return Response(xml_response, media_type="application/xml")
|
||||
|
||||
routes = [
|
||||
Route('/result.php', result_request, methods=['GET'])
|
||||
]
|
||||
@@ -81,7 +81,6 @@ async def ranking_detail(request: Request):
|
||||
html = f"""<div style="text-align: center; font-size: 36px; margin-bottom: 20px;">{song_name}</div>"""
|
||||
|
||||
button_modes = [1, 2, 3]
|
||||
print(len(difficulty_levels))
|
||||
|
||||
if (len(difficulty_levels) == 6):
|
||||
button_labels.extend(["AC-Easy", "AC-Normal", "AC-Hard"])
|
||||
@@ -215,10 +214,9 @@ async def ranking_detail(request: Request):
|
||||
"""
|
||||
|
||||
else:
|
||||
query = select(result).where(
|
||||
(result.c.id == song_id) & (result.c.mode == mode)
|
||||
).order_by(result.c.score.desc())
|
||||
query = select(result).where((result.c.id == song_id) & (result.c.mode == mode))
|
||||
play_results = await database.fetch_all(query)
|
||||
play_results = sorted(play_results, key=lambda x: int(x[8]), reverse=True)
|
||||
|
||||
query = select(user).where(user.c.device_id == device_id)
|
||||
user_result = await database.fetch_one(query)
|
||||
|
||||
163
api/user.py
163
api/user.py
@@ -8,12 +8,12 @@ import secrets
|
||||
from sqlalchemy import select, update, insert
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from config import ROOT_FOLDER, START_COIN, COIN_REWARD, AUTHORIZATION_NEEDED, HOST, PORT
|
||||
from config import ROOT_FOLDER, START_COIN, AUTHORIZATION_NEEDED, HOST, PORT
|
||||
|
||||
from api.misc import is_alphanumeric, inform_page, verify_password, hash_password, crc32_decimal, get_model_pak, get_tune_pak, get_skin_pak, get_m4a_path, get_stage_path, get_stage_zero
|
||||
from api.database import database, user, daily_reward, result, get_user_data, set_user_data, check_blacklist, check_whitelist
|
||||
from api.database import database, user, daily_reward, get_user_data, set_user_data, check_blacklist, check_whitelist
|
||||
from api.crypt import decrypt_fields
|
||||
from api.templates import START_AVATARS, START_STAGES, EXP_UNLOCKED_SONGS
|
||||
from api.templates import START_AVATARS, START_STAGES
|
||||
|
||||
async def info(request: Request):
|
||||
file_path = os.path.join(ROOT_FOLDER, "files/history.html")
|
||||
@@ -652,160 +652,6 @@ async def bonus(request: Request):
|
||||
|
||||
return Response(xml_response, media_type="application/xml")
|
||||
|
||||
async def result_request(request: Request):
|
||||
decrypted_fields, _ = await decrypt_fields(request)
|
||||
if not decrypted_fields:
|
||||
return Response("""<response><code>10</code><message>Invalid request data.</message></response>""", media_type="application/xml")
|
||||
|
||||
should_serve = True
|
||||
if AUTHORIZATION_NEEDED:
|
||||
should_serve = await check_whitelist(decrypted_fields) and not await check_blacklist(decrypted_fields)
|
||||
|
||||
if not should_serve:
|
||||
return Response("""<response><code>403</code><message>Access denied.</message></response>""", media_type="application/xml")
|
||||
|
||||
device_id = decrypted_fields[b'vid'][0].decode()
|
||||
file_path = os.path.join(ROOT_FOLDER, "files/result.xml")
|
||||
try:
|
||||
tree = ET.parse(file_path)
|
||||
root = tree.getroot()
|
||||
except Exception as e:
|
||||
return Response(f"""<response><code>500</code><message>Error parsing XML: {str(e)}</message></response>""", media_type="application/xml")
|
||||
|
||||
vid = decrypted_fields[b'vid'][0].decode()
|
||||
stts = decrypted_fields[b'stts'][0].decode()
|
||||
track_id = decrypted_fields[b'id'][0].decode()
|
||||
mode = decrypted_fields[b'mode'][0].decode()
|
||||
avatar = decrypted_fields[b'avatar'][0].decode()
|
||||
score = int(decrypted_fields[b'score'][0].decode())
|
||||
high_score = decrypted_fields[b'high_score'][0].decode()
|
||||
play_rslt = decrypted_fields[b'play_rslt'][0].decode()
|
||||
item = decrypted_fields[b'item'][0].decode()
|
||||
device_os = decrypted_fields[b'os'][0].decode()
|
||||
os_ver = decrypted_fields[b'os_ver'][0].decode()
|
||||
tid = decrypted_fields[b'tid'][0].decode()
|
||||
ver = decrypted_fields[b'ver'][0].decode()
|
||||
mike = decrypted_fields[b'mike'][0].decode()
|
||||
|
||||
if int(track_id) not in range(616, 1024) or int(mode) not in range(0, 4):
|
||||
query = select(daily_reward.c.coin).where(daily_reward.c.device_id == device_id)
|
||||
row = await database.fetch_one(query)
|
||||
query = select(user.c.coin_mp).where(user.c.device_id == device_id)
|
||||
coin_mp_row = await database.fetch_one(query)
|
||||
if coin_mp_row is None:
|
||||
coin_mp_row = {"coin_mp": 1}
|
||||
current_coin = row["coin"] if row and row["coin"] else START_COIN
|
||||
updated_coin = current_coin + COIN_REWARD * coin_mp_row["coin_mp"]
|
||||
|
||||
update_query = (
|
||||
update(daily_reward)
|
||||
.where(daily_reward.c.device_id == device_id)
|
||||
.values(coin=updated_coin)
|
||||
)
|
||||
await database.execute(update_query)
|
||||
|
||||
query = select(user.c.id).where(user.c.device_id == vid)
|
||||
user_row = await database.fetch_one(query)
|
||||
sid = user_row["id"] if user_row else ""
|
||||
|
||||
do_insert = False
|
||||
do_update_sid = False
|
||||
do_update_vid = False
|
||||
last_row_id = 0
|
||||
|
||||
if sid:
|
||||
query = select(result.c.rid, result.c.score).where(
|
||||
(result.c.id == track_id) &
|
||||
(result.c.mode == mode) &
|
||||
(result.c.sid == sid)
|
||||
).order_by(result.c.score.desc())
|
||||
records = await database.fetch_all(query)
|
||||
if records:
|
||||
last_row_id = records[0]["rid"]
|
||||
if score > int(records[0]["score"]):
|
||||
do_update_sid = True
|
||||
else:
|
||||
do_insert = True
|
||||
else:
|
||||
query = select(result.c.rid, result.c.score).where(
|
||||
(result.c.id == track_id) &
|
||||
(result.c.mode == mode) &
|
||||
(result.c.sid == "") &
|
||||
(result.c.vid == vid)
|
||||
).order_by(result.c.score.desc())
|
||||
records = await database.fetch_all(query)
|
||||
if records:
|
||||
last_row_id = records[0]["rid"]
|
||||
if score > records[0]["score"]:
|
||||
do_update_vid = True
|
||||
else:
|
||||
do_insert = True
|
||||
|
||||
if do_insert:
|
||||
insert_query = insert(result).values(
|
||||
vid=vid, stts=stts, id=track_id, mode=mode, avatar=avatar,
|
||||
score=score, high_score=high_score, play_rslt=play_rslt, item=item,
|
||||
os=device_os, os_ver=os_ver, tid=tid, sid=sid, ver=ver, mike=mike
|
||||
)
|
||||
result_obj = await database.execute(insert_query)
|
||||
last_row_id = result_obj
|
||||
elif do_update_sid:
|
||||
update_query = (
|
||||
update(result)
|
||||
.where((result.c.sid == sid) & (result.c.id == track_id) & (result.c.mode == mode))
|
||||
.values(
|
||||
stts=stts, avatar=avatar, score=score, high_score=high_score,
|
||||
play_rslt=play_rslt, item=item, os=device_os, os_ver=os_ver,
|
||||
tid=tid, ver=ver, mike=mike, vid=vid
|
||||
)
|
||||
)
|
||||
await database.execute(update_query)
|
||||
elif do_update_vid:
|
||||
update_query = (
|
||||
update(result)
|
||||
.where((result.c.vid == vid) & (result.c.id == track_id) & (result.c.mode == mode))
|
||||
.values(
|
||||
stts=stts, avatar=avatar, score=score, high_score=high_score,
|
||||
play_rslt=play_rslt, item=item, os=device_os, os_ver=os_ver,
|
||||
sid=sid, ver=ver, mike=mike
|
||||
)
|
||||
)
|
||||
await database.execute(update_query)
|
||||
|
||||
query = select(daily_reward.c.my_stage).where(daily_reward.c.device_id == device_id)
|
||||
row = await database.fetch_one(query)
|
||||
my_stage = set(json.loads(row["my_stage"])) if row and row["my_stage"] else set(START_STAGES)
|
||||
|
||||
current_exp = int(stts.split(",")[0])
|
||||
for song in EXP_UNLOCKED_SONGS:
|
||||
if song["lvl"] <= current_exp:
|
||||
my_stage.add(song["id"])
|
||||
|
||||
my_stage = sorted(my_stage)
|
||||
update_query = (
|
||||
update(daily_reward)
|
||||
.where(daily_reward.c.device_id == device_id)
|
||||
.values(lvl=current_exp, avatar=int(avatar), my_stage=json.dumps(my_stage))
|
||||
)
|
||||
await database.execute(update_query)
|
||||
|
||||
query = select(result.c.rid, result.c.score).where(
|
||||
(result.c.id == track_id) & (result.c.mode == mode)
|
||||
).order_by(result.c.score.desc())
|
||||
records = await database.fetch_all(query)
|
||||
|
||||
rank = None
|
||||
for idx, record in enumerate(records, start=1):
|
||||
if record["rid"] == last_row_id:
|
||||
rank = idx
|
||||
break
|
||||
|
||||
after_element = root.find('.//after')
|
||||
after_element.text = str(rank)
|
||||
xml_response = ET.tostring(tree.getroot(), encoding='unicode')
|
||||
return Response(xml_response, media_type="application/xml")
|
||||
|
||||
|
||||
routes = [
|
||||
Route('/info.php', info, methods=['GET']),
|
||||
Route('/history.php', history, methods=['GET']),
|
||||
@@ -824,6 +670,5 @@ routes = [
|
||||
Route('/start.php', start, methods=['GET']),
|
||||
Route('/sync.php', sync, methods=['GET', 'POST']),
|
||||
Route('/ttag.php', ttag, methods=['GET']),
|
||||
Route('/login_bonus.php', bonus, methods=['GET']),
|
||||
Route('/result.php', result_request, methods=['GET']),
|
||||
Route('/login_bonus.php', bonus, methods=['GET'])
|
||||
]
|
||||
@@ -1,4 +1,8 @@
|
||||
cryptography
|
||||
databases
|
||||
multipart
|
||||
requests
|
||||
sqlalchemy
|
||||
starlette
|
||||
bcrypt
|
||||
pycryptodome
|
||||
requests
|
||||
urllib
|
||||
uvicorn
|
||||
Reference in New Issue
Block a user