from starlette.responses import Response, FileResponse, HTMLResponse
from starlette.requests import Request
from starlette.routing import Route
import os
import json
import math
from sqlalchemy import select, update
import xml.etree.ElementTree as ET
from config import START_COIN, AUTHORIZATION_NEEDED, STAGE_PRICE, START_COIN, AVATAR_PRICE, ITEM_PRICE, FMAX_PRICE, EX_PRICE
from api.crypt import decrypt_fields
from api.misc import inform_page, parse_res, FMAX_VER, FMAX_RES
from api.database import database, daily_reward, check_blacklist, check_whitelist
from api.templates import START_AVATARS, START_STAGES, EXCLUDE_STAGE_EXP, SONG_LIST, AVATAR_LIST, ITEM_LIST
async def web_shop(request: Request):
decrypted_fields, _ = await decrypt_fields(request)
if not decrypted_fields:
return HTMLResponse("""
Invalid request data
""", status_code=400)
should_serve = True
if AUTHORIZATION_NEEDED:
should_serve = await check_whitelist(decrypted_fields) and not await check_blacklist(decrypted_fields)
if should_serve:
cnt_type = decrypted_fields[b'cnt_type'][0].decode()
device_id = decrypted_fields[b'vid'][0].decode()
if (decrypted_fields.get(b'page')):
page = int(decrypted_fields.get(b'page')[0].decode())
else:
page = 0
inc = 0
fmax_inc = 0
buttons_html = ""
spawn_prev_page = False
spawn_next_page = False
query = select(daily_reward.c.my_stage, daily_reward.c.my_avatar, daily_reward.c.coin).where(daily_reward.c.device_id == device_id)
result = await database.fetch_one(query)
my_stage = set(json.loads(result["my_stage"])) if result and result["my_stage"] else START_STAGES
my_avatar = set(json.loads(result["my_avatar"])) if result and result["my_avatar"] else START_AVATARS
coin = result["coin"] if result and result["coin"] else START_COIN
if cnt_type == "1":
low_range = 100
up_range = 615
if page < 0 or page > math.ceil(up_range - low_range) / 80:
return HTMLResponse("""
Invalid page number
""", status_code=400)
if page > 0:
spawn_prev_page = True
if page < math.ceil(up_range - low_range) / 80 - 1:
spawn_next_page = True
low_range = low_range + page * 80
up_range = min(up_range, low_range + 80)
if 700 not in my_stage and os.path.isfile('./files/dlc_4max.html') and not spawn_prev_page:
buttons_html += """
"""
fmax_inc = 1
elif 700 in my_stage and os.path.isfile('./files/dlc_4max.html') and not spawn_prev_page:
buttons_html += """
"""
if 980 not in my_stage and os.path.isfile('./files/dlc_extra.html') and not spawn_prev_page:
buttons_html += """
"""
fmax_inc = 1
elif 980 in my_stage and os.path.isfile('./files/dlc_4max.html') and not spawn_prev_page:
buttons_html += """
"""
for i in range(low_range, up_range):
if i not in my_stage and i not in EXCLUDE_STAGE_EXP:
buttons_html += f"""
"""
inc += 1
if inc % 4 == 0:
buttons_html += " "
if spawn_prev_page:
buttons_html += """
""".format(page - 1)
if spawn_next_page:
buttons_html += """
""".format(page + 1)
elif cnt_type == "2":
low_range = 15
up_range = 173 if FMAX_VER == 0 else 267
if page < 0 or page > math.ceil(up_range - low_range) / 80:
return HTMLResponse("""
Invalid page number
""", status_code=400)
if page > 0:
spawn_prev_page = True
if page < math.ceil(up_range - low_range) / 80 - 1:
spawn_next_page = True
low_range = low_range + page * 80
up_range = min(up_range, low_range + 80)
for i in range(low_range, up_range):
if i not in my_avatar and i not in EXCLUDE_STAGE_EXP:
buttons_html += f"""
"""
inc += 1
if inc % 4 == 0:
buttons_html += " "
if spawn_prev_page:
buttons_html += """
""".format(page - 1)
if spawn_next_page:
buttons_html += """
""".format(page + 1)
elif cnt_type == "3":
for i in range(1, 11):
buttons_html += f"""
"""
if i % 4 == 0:
buttons_html += " "
if inc == 0 and fmax_inc == 0 and cnt_type != "3":
buttons_html += """
Everything has been purchased!
"""
html_path = f"files/web_shop_{cnt_type}.html"
try:
with open(html_path, "r", encoding="utf-8") as file:
html_content = file.read().format(text=buttons_html, coin=coin)
except FileNotFoundError:
return HTMLResponse("""
Please report bugs/missing tracks to Discord: #AnTcfgss, or QQ 3421587952.
This server has version {FMAX_VER}.
Update log:
{log}
"""
elif cnt_id == -4:
html = f"""
You have unlocked the EXTRA Challenge!
Please report bugs/missing tracks to Discord: #AnTcfgss, or QQ 3421587952.
"""
elif cnt_id == -2:
html = f"""
Are you looking for a bad time?
If so, this is the Ultimate - Extra - Challenge.
180+ Arcade Extra difficulty charts await you.
You have been warned.
"""
elif cnt_id == -1:
html = f"""
Experience the arcade with the GC4MAX expansion! This DLC unlocks 320+ exclusive songs for your 2OS experience.
Note that these songs don't have mobile difficulties. A short placeholder is used, and GCoin reward is not available for playing them. You must clear the Normal difficulty to unlock AC content.
Due to technical limitations, Extra level charts cannot be ported as of now. After purchasing, you will have access to support information and update logs.
"""
elif cnt_type == "2":
avatar = next((item for item in AVATAR_LIST if item.get("id") == cnt_id), None)
if avatar:
html = f"""
Would you like to purchase this avatar?
{avatar.get("name")}
Effect: {avatar.get("effect")}
{AVATAR_PRICE}
"""
else:
html = "
Avatar not found.
"
elif cnt_type == "3":
item = next((item for item in ITEM_LIST if item.get("id") == cnt_id), None)
if item:
html = f"""
Would you like to purchase this item?
{item.get("name")}
Effect: {item.get("effect")}
{ITEM_PRICE}
"""
else:
html = "
Item not found.
"
if cnt_type == "1" and (cnt_id == -1 or cnt_id == -3):
source_html = f"files/dlc_4max.html"
elif cnt_type == "1" and (cnt_id == -2 or cnt_id == -4):
source_html = f"files/dlc_extra.html"
else:
source_html = f"files/web_shop_detail.html"
html += f"""