mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2026-02-09 09:17:26 +08:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a90380df4c | ||
|
|
4f66f492fc | ||
|
|
df181f104e | ||
|
|
a890a9af4a | ||
|
|
c6bb4c9afb | ||
|
|
98358ad216 | ||
|
|
e0e6128826 | ||
|
|
08872399cc | ||
|
|
29a6cfaac1 | ||
|
|
f25bd4130e | ||
|
|
68c757f9d7 | ||
|
|
26216bf84a | ||
|
|
5771d0c669 | ||
|
|
80122d749e | ||
|
|
5c02ecdf37 | ||
|
|
dfcbb6f9c0 | ||
|
|
30690b2fbf | ||
|
|
56ae7047fc | ||
|
|
f5d2589971 | ||
|
|
8bb5c28663 | ||
|
|
123554e24d | ||
|
|
bb7ba249e9 | ||
|
|
3ecefcb802 | ||
|
|
798a838ca4 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.log
|
||||||
97
README.md
97
README.md
@@ -2,56 +2,81 @@
|
|||||||
一个微型的Arcaea本地服务器 A small local server for Arcaea
|
一个微型的Arcaea本地服务器 A small local server for Arcaea
|
||||||
|
|
||||||
## 简介 Introduction
|
## 简介 Introduction
|
||||||
这是基于Python以及Flask的微型本地Arcaea服务器,可以模拟游戏的主要功能,一时兴起在五天之内糊了出来。这可能是我第一次写这种大程序,若有不妥之处,敬请谅解。
|
这是基于Python以及Flask的微型本地Arcaea服务器,可以模拟游戏的主要功能。这可能是我第一次写这种大程序,若有不妥之处,敬请谅解。
|
||||||
This is a small local Arcaea server based on Python and Flask, which can simulate the main functions of the game. I completed it on the spur of the moment in five days. This may be the first time I have written such a large program. Please understand if there is something wrong with it.
|
|
||||||
|
本程序主要用于学习研究,不得用于任何商业行为,否则后果自负,这不是强制要求,只是一个提醒与警告。
|
||||||
|
|
||||||
|
This is a small local Arcaea server based on Python and Flask, which can simulate the main functions of the game. This may be the first time I have written such a large program. Please understand if there is something wrong with it.
|
||||||
|
|
||||||
|
This procedure is mainly used for study and research, and shall not be used for any commercial activities, otherwise the consequences will be borne by oneself. This is not a mandatory requirement, just a reminder and warning.
|
||||||
|
|
||||||
> 虽然看起来很蠢,但是可以用!
|
> 虽然看起来很蠢,但是可以用!
|
||||||
> It looks stupid, but it works!
|
> It looks stupid, but it works!
|
||||||
|
|
||||||
|
## 特性 Features
|
||||||
|
有以下 We have:
|
||||||
|
- 登录、注册 Login and registration
|
||||||
|
- 多设备登录 Multi device login
|
||||||
|
- 成绩上传 Score upload
|
||||||
|
- PTT
|
||||||
|
- 排名 Rank
|
||||||
|
- 好友系统 Friends
|
||||||
|
- 数据同步 Data synchronization
|
||||||
|
- 爬梯 Climbing steps
|
||||||
|
- 自定义世界模式 Customizable World Mode
|
||||||
|
- 自定义歌曲下载 Customizable songs download
|
||||||
|
- 单曲和曲包购买(没啥用) Single songs and song packs purchase(useless)
|
||||||
|
- 奖励系统 Present system
|
||||||
|
- 兑换码系统 Redeem code system
|
||||||
|
- 全角色立绘 All character drawings
|
||||||
|
- 角色技能 Character skills
|
||||||
|
- 自定义角色属性 Customizable characters attributes
|
||||||
|
- 全剧情解锁 Unlock all the stories
|
||||||
|
- 后台查询 Background search
|
||||||
|
- 后台自定义信息 Customize some things in the background
|
||||||
|
- 成绩校验 Score check
|
||||||
|
- 下载校验 Download check
|
||||||
|
- 服务器日志 Server log
|
||||||
|
|
||||||
|
没有以下 We don't have:
|
||||||
|
- 角色数值 Character characteristic value
|
||||||
|
- 服务器安全性保证 Server security assurance
|
||||||
|
|
||||||
|
可能有问题 There may be problems:
|
||||||
|
- Recent 30
|
||||||
|
- 一些歌曲的解锁 Some songs' unlocking
|
||||||
|
- 同设备多共存登录 Multiple app logins on the same device
|
||||||
|
|
||||||
## 说明 Statement
|
## 说明 Statement
|
||||||
只是很有趣,用处探索中。
|
只是很有趣,用处探索中。
|
||||||
It is just so interesting. What it can do is under exploration.
|
It is just so interesting. What it can do is under exploration.
|
||||||
|
|
||||||
|
|
||||||
|
## 下载 Download
|
||||||
|
[这里 Here](https://github.com/Lost-MSth/Arcaea-server/releases)
|
||||||
|
|
||||||
|
[Arcaea](https://konmai.cn/#arcaea)
|
||||||
|
|
||||||
## 更新日志 Update log
|
## 更新日志 Update log
|
||||||
### Version 1.3
|
只保留最新版本 Only keep the latest version.
|
||||||
- 适用于Arcaea 3.2.1版本 For Arcaea 3.2.1
|
|
||||||
- 新增了可自定义的世界模式 Add customizable World Mode.
|
|
||||||
- 对于官方版本,解锁几乎所有歌曲 For the official version, unlock almost all songs.
|
|
||||||
|
|
||||||
> 更新说明:本次更新无法从旧版本同步数据,请使用游戏内数据同步功能上传best_score数据
|
> 提醒:更新时请注意保留原先的数据库,以防数据丢失
|
||||||
|
>
|
||||||
|
> Tips: When updating, please keep the original database in case of data loss.
|
||||||
|
|
||||||
> Update note: In this update you cannot synchronize data from an older version. Please use the data synchronization function in game to upload best_score data.
|
### Version 2.3
|
||||||
|
- 适用于Arcaea 3.5.2版本 For Arcaea 3.5.2
|
||||||
### Version 1.2
|
|
||||||
- 仍然适用于Arcaea 3.2.0版本 Still for Arcaea 3.2.0
|
|
||||||
- 新增了网页管理页面,可以通过 http:// HOST IP : PORT /web 进行访问 Add a new management webpage, you can visit http:// HOST IP : PORT /web to use it.
|
|
||||||
- 修改了character表结构,这将方便以后的角色更新 The character table structure has been modified, which will facilitate the character update in the future.
|
|
||||||
- 修复了best_score表的时间记录,应该是精确到秒的Unix时间戳 Fix the time record of best_score table. It should be a UNIX timestamp accurate to seconds.
|
|
||||||
- 修复了一个bug,recent30现在会考虑同一首歌的不同难度 Fix a bug. Now recent30 will consider different difficulties of one song.
|
|
||||||
> 更新说明:现在你可以使用web管理页面来迁移旧数据了,后台固定账号admin,密码admin
|
|
||||||
> 如果使用数据迁移,那么请先清空recent30表数据,或者在迁移后打30首歌手动清除recent30,这次更新后web页面读取原来的recent30表将会报错
|
|
||||||
|
|
||||||
> Update note: Now you can use the web management page to migrate old data. Background account is fixed. Username is admin, and password is admin.
|
|
||||||
> If you use data migration, please clear the data in the recent30 table first, or manually clear recent30 by playing 30 songs after the migration. After this update, an error will be reported when the web page reads the past recent30 table.
|
|
||||||
|
|
||||||
### Version 1.1
|
|
||||||
- 适用于Arcaea 3.2.0版本 For Arcaea 3.2.0
|
|
||||||
- 更新了歌曲数据库 Update the song database.
|
- 更新了歌曲数据库 Update the song database.
|
||||||
- 角色**梦**可以看到觉醒立绘了 The drawing of uncapped character **Yume** can be seen.
|
- 新增服务器日志 Add server log.
|
||||||
- 修复了一个Bug,现在剧情可以全部解锁了 Fix a bug. Now the plot can be unlocked.
|
- 优化了代码结构 Optimize the code structure.
|
||||||
> 更新说明:您若需要做数据迁移,请使用原来的数据库文件**arcaea_database.db**,并使用数据库操作软件打开数据库修改角色数据,SQL命令为
|
- 修复了一些Bug,提升服务器安全性 Fix some bugs and improve server security.
|
||||||
> `Update user_char set is_uncapped=1, is_uncapped_override=1 where character_id=21;`
|
|
||||||
|
|
||||||
> Update note: If you need to do data migration, please use the original database file **arcaea_ database.db**, and use the database operation software to open the database to modify the character data. The SQL command is
|
|
||||||
> `Update user_char set is_uncapped=1, is_uncapped_override=1 where character_id=21;`
|
|
||||||
|
|
||||||
### Version 1.0
|
|
||||||
- 适用于Arcaea 3.1.2版本 For Arcaea 3.1.2
|
|
||||||
|
|
||||||
## 运行环境与依赖 Running environment and requirements
|
## 运行环境与依赖 Running environment and requirements
|
||||||
- Windows操作系统 Windows operating system
|
- Windows/Linux/Mac OS/Android
|
||||||
- Python 3
|
- Python 3
|
||||||
- Flask模块 Flask module
|
- Flask module
|
||||||
- Charles
|
- Charles (optional)
|
||||||
|
|
||||||
## 环境搭建 Environment construction
|
## 环境搭建 Environment construction
|
||||||
[中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA)
|
[中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA)
|
||||||
@@ -69,6 +94,8 @@ It is just so interesting. What it can do is under exploration.
|
|||||||
歌曲数据库来自 Using song database from
|
歌曲数据库来自 Using song database from
|
||||||
[BotArcAPI releases](https://github.com/TheSnowfield/BotArcAPI/releases)
|
[BotArcAPI releases](https://github.com/TheSnowfield/BotArcAPI/releases)
|
||||||
|
|
||||||
|
网站图标来自 Using favicon from [black fate - てんてん - pixiv](https://www.pixiv.net/artworks/82374369)
|
||||||
|
|
||||||
## 联系方式 Contact
|
## 联系方式 Contact
|
||||||
如有必要,可以联系本人 Contact me if necessary
|
如有必要,可以联系本人 Contact me if necessary
|
||||||
邮箱 Email:th84292@foxmail.com
|
邮箱 Email:th84292@foxmail.com
|
||||||
|
|||||||
BIN
latest version/database/arcaea_database.db
Normal file
BIN
latest version/database/arcaea_database.db
Normal file
Binary file not shown.
BIN
latest version/database/arcsong.db
Normal file
BIN
latest version/database/arcsong.db
Normal file
Binary file not shown.
356
latest version/database/database_initialize.py
Normal file
356
latest version/database/database_initialize.py
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
import sqlite3
|
||||||
|
import hashlib
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
|
||||||
|
# 数据库初始化文件,删掉arcaea_database.db文件后运行即可,谨慎使用
|
||||||
|
|
||||||
|
conn = sqlite3.connect('arcaea_database.db')
|
||||||
|
c = conn.cursor()
|
||||||
|
c.execute('''create table if not exists user(user_id int primary key,
|
||||||
|
name text unique,
|
||||||
|
password text not null,
|
||||||
|
join_date char(20),
|
||||||
|
user_code char(10),
|
||||||
|
rating_ptt int,
|
||||||
|
character_id int,
|
||||||
|
is_skill_sealed int,
|
||||||
|
is_char_uncapped int,
|
||||||
|
is_char_uncapped_override int,
|
||||||
|
is_hide_rating int,
|
||||||
|
song_id text,
|
||||||
|
difficulty int,
|
||||||
|
score int,
|
||||||
|
shiny_perfect_count int,
|
||||||
|
perfect_count int,
|
||||||
|
near_count int,
|
||||||
|
miss_count int,
|
||||||
|
health int,
|
||||||
|
modifier int,
|
||||||
|
time_played int,
|
||||||
|
clear_type int,
|
||||||
|
rating real,
|
||||||
|
favorite_character int,
|
||||||
|
max_stamina_notification_enabled int,
|
||||||
|
current_map text,
|
||||||
|
ticket int,
|
||||||
|
prog_boost int
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists login(access_token text,
|
||||||
|
user_id int,
|
||||||
|
login_time int,
|
||||||
|
login_ip text,
|
||||||
|
login_device text,
|
||||||
|
primary key(access_token, user_id)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists friend(user_id_me int,
|
||||||
|
user_id_other int,
|
||||||
|
primary key (user_id_me, user_id_other)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists best_score(user_id int,
|
||||||
|
song_id text,
|
||||||
|
difficulty int,
|
||||||
|
score int,
|
||||||
|
shiny_perfect_count int,
|
||||||
|
perfect_count int,
|
||||||
|
near_count int,
|
||||||
|
miss_count int,
|
||||||
|
health int,
|
||||||
|
modifier int,
|
||||||
|
time_played int,
|
||||||
|
best_clear_type int,
|
||||||
|
clear_type int,
|
||||||
|
rating real,
|
||||||
|
primary key(user_id, song_id, difficulty)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists user_char(user_id int,
|
||||||
|
character_id int,
|
||||||
|
level int,
|
||||||
|
exp real,
|
||||||
|
level_exp real,
|
||||||
|
frag real,
|
||||||
|
prog real,
|
||||||
|
overdrive real,
|
||||||
|
skill_id text,
|
||||||
|
skill_unlock_level int,
|
||||||
|
skill_requires_uncap int,
|
||||||
|
skill_id_uncap text,
|
||||||
|
char_type int,
|
||||||
|
is_uncapped int,
|
||||||
|
is_uncapped_override int,
|
||||||
|
primary key(user_id, character_id)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists character(character_id int primary key,
|
||||||
|
name text,
|
||||||
|
level int,
|
||||||
|
exp real,
|
||||||
|
level_exp real,
|
||||||
|
frag real,
|
||||||
|
prog real,
|
||||||
|
overdrive real,
|
||||||
|
skill_id text,
|
||||||
|
skill_unlock_level int,
|
||||||
|
skill_requires_uncap int,
|
||||||
|
skill_id_uncap text,
|
||||||
|
char_type int,
|
||||||
|
uncap_cores text,
|
||||||
|
is_uncapped int,
|
||||||
|
is_uncapped_override int
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists recent30(user_id int primary key,
|
||||||
|
r0 real,
|
||||||
|
song_id0 text,
|
||||||
|
r1 real,
|
||||||
|
song_id1 text,
|
||||||
|
r2 real,
|
||||||
|
song_id2 text,
|
||||||
|
r3 real,
|
||||||
|
song_id3 text,
|
||||||
|
r4 real,
|
||||||
|
song_id4 text,
|
||||||
|
r5 real,
|
||||||
|
song_id5 text,
|
||||||
|
r6 real,
|
||||||
|
song_id6 text,
|
||||||
|
r7 real,
|
||||||
|
song_id7 text,
|
||||||
|
r8 real,
|
||||||
|
song_id8 text,
|
||||||
|
r9 real,
|
||||||
|
song_id9 text,
|
||||||
|
r10 real,
|
||||||
|
song_id10 text,
|
||||||
|
r11 real,
|
||||||
|
song_id11 text,
|
||||||
|
r12 real,
|
||||||
|
song_id12 text,
|
||||||
|
r13 real,
|
||||||
|
song_id13 text,
|
||||||
|
r14 real,
|
||||||
|
song_id14 text,
|
||||||
|
r15 real,
|
||||||
|
song_id15 text,
|
||||||
|
r16 real,
|
||||||
|
song_id16 text,
|
||||||
|
r17 real,
|
||||||
|
song_id17 text,
|
||||||
|
r18 real,
|
||||||
|
song_id18 text,
|
||||||
|
r19 real,
|
||||||
|
song_id19 text,
|
||||||
|
r20 real,
|
||||||
|
song_id20 text,
|
||||||
|
r21 real,
|
||||||
|
song_id21 text,
|
||||||
|
r22 real,
|
||||||
|
song_id22 text,
|
||||||
|
r23 real,
|
||||||
|
song_id23 text,
|
||||||
|
r24 real,
|
||||||
|
song_id24 text,
|
||||||
|
r25 real,
|
||||||
|
song_id25 text,
|
||||||
|
r26 real,
|
||||||
|
song_id26 text,
|
||||||
|
r27 real,
|
||||||
|
song_id27 text,
|
||||||
|
r28 real,
|
||||||
|
song_id28 text,
|
||||||
|
r29 real,
|
||||||
|
song_id29 text
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists user_world(user_id int,
|
||||||
|
map_id text,
|
||||||
|
curr_position int,
|
||||||
|
curr_capture real,
|
||||||
|
is_locked int,
|
||||||
|
primary key(user_id, map_id)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists world_songplay(user_id int,
|
||||||
|
song_id text,
|
||||||
|
difficulty int,
|
||||||
|
stamina_multiply int,
|
||||||
|
fragment_multiply int,
|
||||||
|
prog_boost_multiply int,
|
||||||
|
primary key(user_id, song_id, difficulty)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists download_token(user_id int,
|
||||||
|
song_id text,
|
||||||
|
file_name text,
|
||||||
|
token text,
|
||||||
|
time int,
|
||||||
|
primary key(user_id, song_id, file_name)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists user_download(user_id int,
|
||||||
|
token text,
|
||||||
|
time int,
|
||||||
|
primary key(user_id, token, time)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists item(item_id text,
|
||||||
|
type text,
|
||||||
|
is_available int,
|
||||||
|
price int,
|
||||||
|
orig_price int,
|
||||||
|
discount_from int,
|
||||||
|
discount_to int,
|
||||||
|
_id text,
|
||||||
|
primary key(item_id, type)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists user_item(user_id int,
|
||||||
|
item_id text,
|
||||||
|
type text,
|
||||||
|
primary key(user_id, item_id, type)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists user_save(user_id int primary key,
|
||||||
|
scores_data text,
|
||||||
|
clearlamps_data text,
|
||||||
|
clearedsongs_data text,
|
||||||
|
unlocklist_data text,
|
||||||
|
installid_data text,
|
||||||
|
devicemodelname_data text,
|
||||||
|
story_data text,
|
||||||
|
createdAt int
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists present(present_id text primary key,
|
||||||
|
expire_ts int,
|
||||||
|
items text,
|
||||||
|
description text
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists user_present(user_id int,
|
||||||
|
present_id text,
|
||||||
|
primary key(user_id, present_id)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists songfile(song_id text,
|
||||||
|
file_type int,
|
||||||
|
md5 text,
|
||||||
|
primary key(song_id, file_type)
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists redeem(code text primary key,
|
||||||
|
items text,
|
||||||
|
type int
|
||||||
|
);''')
|
||||||
|
c.execute('''create table if not exists user_redeem(user_id int,
|
||||||
|
code text,
|
||||||
|
primary key(user_id, code)
|
||||||
|
);''')
|
||||||
|
|
||||||
|
|
||||||
|
char = ['Hikari', 'Tairitsu', 'Kou', 'Sapphire', 'Lethe', '', 'Tairitsu(Axium)', 'Tairitsu(Grievous Lady)', 'Stella', 'Hikari & Fisica', 'Ilith', 'Eto', 'Luna', 'Shirabe', 'Hikari(Zero)', 'Hikari(Fracture)', 'Hikari(Summer)', 'Tairitsu(Summer)', 'Tairitsu & Trin',
|
||||||
|
'Ayu', 'Eto & Luna', 'Yume', 'Seine & Hikari', 'Saya', 'Tairitsu & Chuni Penguin', 'Chuni Penguin', 'Haruna', 'Nono', 'MTA-XXX', 'MDA-21', 'Kanae', 'Hikari(Fantasia)', 'Tairitsu(Sonata)', 'Sia', 'DORO*C', 'Tairitsu(Tempest)', 'Brillante', 'Ilith(Summer)', 'Etude', 'Alice & Tenniel', 'Luna & Mia', 'Areus', 'Seele', 'Isabelle', 'Mir']
|
||||||
|
|
||||||
|
skill_id = ['gauge_easy', '', '', '', 'note_mirror', '', '', 'gauge_hard', 'frag_plus_10_pack_stellights', 'gauge_easy|frag_plus_15_pst&prs', 'gauge_hard|fail_frag_minus_100', 'frag_plus_5_side_light', 'visual_hide_hp', 'frag_plus_5_side_conflict', 'challenge_fullcombo_0gauge', 'gauge_overflow', 'gauge_easy|note_mirror', 'note_mirror', 'visual_tomato_pack_tonesphere',
|
||||||
|
'frag_rng_ayu', 'gaugestart_30|gaugegain_70', 'combo_100-frag_1', 'audio_gcemptyhit_pack_groovecoaster', 'gauge_saya', 'gauge_chuni', 'kantandeshou', 'gauge_haruna', 'frags_nono', 'gauge_pandora', 'gauge_regulus', 'omatsuri_daynight', '', '', 'sometimes(note_mirror|frag_plus_5)', 'scoreclear_aa|visual_scoregauge', 'gauge_tempest', 'gauge_hard', 'gauge_ilith_summer', '', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle', 'gauge_exhaustion']
|
||||||
|
|
||||||
|
skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', '', '', 'shirabe_entry_fee',
|
||||||
|
'', '', '', '', '', '', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
|
||||||
|
|
||||||
|
for i in range(0, 45):
|
||||||
|
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21, 42, 43]:
|
||||||
|
sql = 'insert into character values('+str(
|
||||||
|
i)+',"'+char[i]+'''",30,25000,25000,90,90,90,"'''+skill_id[i]+'''",0,0,"'''+skill_id_uncap[i]+'''",0,'',1,1)'''
|
||||||
|
c.execute(sql)
|
||||||
|
else:
|
||||||
|
if i != 5:
|
||||||
|
sql = 'insert into character values('+str(
|
||||||
|
i)+',"'+char[i]+'''",30,25000,25000,90,90,90,"'''+skill_id[i]+'''",0,0,"'''+skill_id_uncap[i]+'''",0,'',0,0)'''
|
||||||
|
c.execute(sql)
|
||||||
|
|
||||||
|
|
||||||
|
def b2int(x):
|
||||||
|
# int与布尔值转换
|
||||||
|
if x:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def insert_items(c, items):
|
||||||
|
# 物品数据导入
|
||||||
|
for i in items:
|
||||||
|
if 'discount_from' not in i:
|
||||||
|
discount_from = -1
|
||||||
|
else:
|
||||||
|
discount_from = i['discount_from']
|
||||||
|
if 'discount_to' not in i:
|
||||||
|
discount_to = -1
|
||||||
|
else:
|
||||||
|
discount_to = i['discount_to']
|
||||||
|
for j in i['items']:
|
||||||
|
if "_id" not in j:
|
||||||
|
_id = ''
|
||||||
|
else:
|
||||||
|
_id = j['_id']
|
||||||
|
if j['type'] != 'character':
|
||||||
|
c.execute('''insert into item(item_id, type, is_available, price, orig_price, discount_from, discount_to, _id) values(:a,:b,:c,:d,:e,:f,:g,:h)''', {
|
||||||
|
'a': j['id'], 'b': j['type'], 'c': b2int(j['is_available']), 'd': i['price'], 'e': i['orig_price'], 'f': discount_from, 'g': discount_to, 'h': _id})
|
||||||
|
|
||||||
|
|
||||||
|
f = open('singles.json', 'r')
|
||||||
|
singles = json.load(f)
|
||||||
|
f.close()
|
||||||
|
insert_items(c, singles)
|
||||||
|
|
||||||
|
f = open('packs.json', 'r')
|
||||||
|
packs = json.load(f)
|
||||||
|
f.close()
|
||||||
|
insert_items(c, packs)
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def arc_register(name: str, password: str):
|
||||||
|
def build_user_code(c):
|
||||||
|
return '123456789'
|
||||||
|
|
||||||
|
def build_user_id(c):
|
||||||
|
return 2000000
|
||||||
|
|
||||||
|
# def insert_user_char(c, user_id):
|
||||||
|
# for i in range(0, 38):
|
||||||
|
# if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]:
|
||||||
|
# sql = 'insert into user_char values('+str(user_id)+','+str(
|
||||||
|
# i)+''',30,25000,25000,90,90,90,'',0,0,'',0,1,1)'''
|
||||||
|
# c.execute(sql)
|
||||||
|
# else:
|
||||||
|
# if i != 5:
|
||||||
|
# sql = 'insert into user_char values('+str(user_id)+','+str(
|
||||||
|
# i)+''',30,25000,25000,90,90,90,'',0,0,'',0,0,0)'''
|
||||||
|
# c.execute(sql)
|
||||||
|
def insert_user_char(c, user_id):
|
||||||
|
# 为用户添加所有可用角色
|
||||||
|
c.execute('''select * from character''')
|
||||||
|
x = c.fetchall()
|
||||||
|
if x != []:
|
||||||
|
for i in x:
|
||||||
|
c.execute('''insert into user_char values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o)''', {
|
||||||
|
'a': user_id, 'b': i[0], 'c': i[2], 'd': i[3], 'e': i[4], 'f': i[5], 'g': i[6], 'h': i[7], 'i': i[8], 'j': i[9], 'k': i[10], 'l': i[11], 'm': i[12], 'n': i[14], 'o': i[15]})
|
||||||
|
|
||||||
|
conn = sqlite3.connect('arcaea_database.db')
|
||||||
|
c = conn.cursor()
|
||||||
|
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
||||||
|
c.execute(
|
||||||
|
'''select exists(select * from user where name = :name)''', {'name': name})
|
||||||
|
if c.fetchone() == (0,):
|
||||||
|
user_code = build_user_code(c)
|
||||||
|
user_id = build_user_id(c)
|
||||||
|
now = int(time.time() * 1000)
|
||||||
|
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
||||||
|
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled, current_map, ticket)
|
||||||
|
values(:user_id, :name, :password, :join_date, :user_code, 1250, 1, 0, 1, 0, 0, -1, 0, '', 114514)
|
||||||
|
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
|
||||||
|
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
||||||
|
'user_id': user_id})
|
||||||
|
c.execute(
|
||||||
|
'''insert into best_score values(2000000,'vexaria',3,10000000,100,0,0,0,100,0,1599667200,3,3,10.8)''')
|
||||||
|
insert_user_char(c, user_id)
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
arc_register('admin', 'admin123')
|
||||||
70
latest version/database/map/byd_lumia.json
Normal file
70
latest version/database/map/byd_lumia.json
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"map_id": "byd_lumia",
|
||||||
|
"is_legacy": false,
|
||||||
|
"chapter": 1001,
|
||||||
|
"available_from": -1,
|
||||||
|
"available_to": 9999999999999,
|
||||||
|
"is_repeatable": false,
|
||||||
|
"require_id": "lumia2",
|
||||||
|
"require_type": "chart_unlock",
|
||||||
|
"coordinate": "650,-650",
|
||||||
|
"is_beyond": true,
|
||||||
|
"stamina_cost": 3,
|
||||||
|
"beyond_health": 150,
|
||||||
|
"character_affinity": [0, 15, 14, 16],
|
||||||
|
"affinity_multiplier": [2.4, 1.9, 2.4, 2.9],
|
||||||
|
"step_count": 6,
|
||||||
|
"custom_bg": "",
|
||||||
|
"curr_position": 0,
|
||||||
|
"curr_capture": 0,
|
||||||
|
"is_locked": false,
|
||||||
|
"steps": [{
|
||||||
|
"map_id": "byd_lumia",
|
||||||
|
"position": 0,
|
||||||
|
"capture": 10,
|
||||||
|
"restrict_id": "core",
|
||||||
|
"restrict_type": "pack_id"
|
||||||
|
}, {
|
||||||
|
"map_id": "byd_lumia",
|
||||||
|
"position": 1,
|
||||||
|
"capture": 20,
|
||||||
|
"items": [{
|
||||||
|
"type": "fragment",
|
||||||
|
"amount": 200
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"map_id": "byd_lumia",
|
||||||
|
"position": 2,
|
||||||
|
"capture": 30,
|
||||||
|
"items": [{
|
||||||
|
"type": "core",
|
||||||
|
"id": "core_generic",
|
||||||
|
"amount": 1
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"map_id": "byd_lumia",
|
||||||
|
"position": 3,
|
||||||
|
"capture": 40,
|
||||||
|
"items": [{
|
||||||
|
"type": "fragment",
|
||||||
|
"amount": 250
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"map_id": "byd_lumia",
|
||||||
|
"position": 4,
|
||||||
|
"capture": 50,
|
||||||
|
"items": [{
|
||||||
|
"type": "core",
|
||||||
|
"id": "core_generic",
|
||||||
|
"amount": 1
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"map_id": "byd_lumia",
|
||||||
|
"position": 5,
|
||||||
|
"capture": 0,
|
||||||
|
"items": [{
|
||||||
|
"id": "lumia3",
|
||||||
|
"type": "world_song"
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
256
latest version/database/packs.json
Normal file
256
latest version/database/packs.json
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
[{
|
||||||
|
"name": "core",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "core",
|
||||||
|
"_id": "6046bab736651a07ebc537db",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 400,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "shiawase",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "shiawase",
|
||||||
|
"_id": "6046bab736651a07ebc53823",
|
||||||
|
"is_available": true
|
||||||
|
}, {
|
||||||
|
"type": "character",
|
||||||
|
"id": "kou",
|
||||||
|
"_id": "6046bab736651a07ebc53822",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 250,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "dynamix",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "dynamix",
|
||||||
|
"_id": "6046bab736651a07ebc53827",
|
||||||
|
"is_available": true
|
||||||
|
}, {
|
||||||
|
"type": "character",
|
||||||
|
"id": "sapphire",
|
||||||
|
"_id": "6046bab736651a07ebc53826",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 250,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "mirai",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "mirai",
|
||||||
|
"_id": "6046bab736651a07ebc5381d",
|
||||||
|
"is_available": true
|
||||||
|
}, {
|
||||||
|
"type": "character",
|
||||||
|
"id": "lethe",
|
||||||
|
"_id": "6046bab736651a07ebc5381c",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 250,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "yugamu",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "yugamu",
|
||||||
|
"_id": "6046bab736651a07ebc537dc",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 400,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "lanota",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "lanota",
|
||||||
|
"_id": "6046bab736651a07ebc537e8",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 250,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "nijuusei",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "nijuusei",
|
||||||
|
"_id": "6046bab736651a07ebc537dd",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 250,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "rei",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "rei",
|
||||||
|
"_id": "6046bab736651a07ebc537f6",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 400,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "tonesphere",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "tonesphere",
|
||||||
|
"_id": "6046bab736651a07ebc537ea",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 250,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "groovecoaster",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "groovecoaster",
|
||||||
|
"_id": "6046bab736651a07ebc53812",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 250,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "zettai",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "zettai",
|
||||||
|
"_id": "6046bab736651a07ebc537f8",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 250,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "chunithm",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "chunithm",
|
||||||
|
"_id": "6046bab736651a07ebc53806",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 300,
|
||||||
|
"orig_price": 300
|
||||||
|
}, {
|
||||||
|
"name": "prelude",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "prelude",
|
||||||
|
"_id": "6046bab736651a07ebc53813",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 250,
|
||||||
|
"orig_price": 400,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "omatsuri",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "omatsuri",
|
||||||
|
"_id": "6046bab736651a07ebc537f9",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 250,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "vs",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "vs",
|
||||||
|
"_id": "6046bab736651a07ebc53809",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 400,
|
||||||
|
"orig_price": 500,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "extend",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "extend",
|
||||||
|
"_id": "6046bab736651a07ebc53816",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 500,
|
||||||
|
"orig_price": 700,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "alice",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "alice",
|
||||||
|
"_id": "6046bab736651a07ebc537fe",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"orig_price": 500,
|
||||||
|
"price": 500
|
||||||
|
}, {
|
||||||
|
"name": "alice_append_1",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "alice_append_1",
|
||||||
|
"_id": "6046bab736651a07ebc537e6",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"orig_price": 300,
|
||||||
|
"price": 300
|
||||||
|
}, {
|
||||||
|
"name": "ongeki",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "ongeki",
|
||||||
|
"_id": "6046bab736651a07ebc5380c",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"orig_price": 400,
|
||||||
|
"price": 400
|
||||||
|
}, {
|
||||||
|
"name": "maimai",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "maimai",
|
||||||
|
"_id": "6046bab736651a07ebc53819",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"orig_price": 400,
|
||||||
|
"price": 400
|
||||||
|
}, {
|
||||||
|
"name": "chunithm_append_1",
|
||||||
|
"items": [{
|
||||||
|
"type": "pack",
|
||||||
|
"id": "chunithm_append_1",
|
||||||
|
"_id": "6046bab736651a07ebc537f2",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"orig_price": 300,
|
||||||
|
"price": 300
|
||||||
|
}]
|
||||||
510
latest version/database/singles.json
Normal file
510
latest version/database/singles.json
Normal file
@@ -0,0 +1,510 @@
|
|||||||
|
[{
|
||||||
|
"name": "testsingle",
|
||||||
|
"items": [{
|
||||||
|
"id": "testsingle",
|
||||||
|
"type": "single",
|
||||||
|
"is_available": false
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "dataerror",
|
||||||
|
"items": [{
|
||||||
|
"id": "dataerror",
|
||||||
|
"type": "single",
|
||||||
|
"_id": "6046bab736651a07ebc537f3",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "yourvoiceso",
|
||||||
|
"items": [{
|
||||||
|
"id": "yourvoiceso",
|
||||||
|
"type": "single",
|
||||||
|
"_id": "6046bab736651a07ebc53800",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "crosssoul",
|
||||||
|
"items": [{
|
||||||
|
"id": "crosssoul",
|
||||||
|
"type": "single",
|
||||||
|
"_id": "6046bab736651a07ebc5380d",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "impurebird",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "impurebird",
|
||||||
|
"_id": "6046bab736651a07ebc53801",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "auxesia",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "auxesia",
|
||||||
|
"_id": "6046bab736651a07ebc5380e",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1520413239000,
|
||||||
|
"discount_to": 1521072000000
|
||||||
|
}, {
|
||||||
|
"name": "modelista",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "modelista",
|
||||||
|
"_id": "6046bab736651a07ebc537f4",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "yozakurafubuki",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "yozakurafubuki",
|
||||||
|
"_id": "6046bab736651a07ebc53802",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "surrender",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "surrender",
|
||||||
|
"_id": "6046bab736651a07ebc5380f",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "metallicpunisher",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "metallicpunisher",
|
||||||
|
"_id": "6046bab736651a07ebc537f5",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "carminescythe",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "carminescythe",
|
||||||
|
"_id": "6046bab736651a07ebc53803",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "bethere",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "bethere",
|
||||||
|
"_id": "6046bab736651a07ebc53810",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "callmyname",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "callmyname",
|
||||||
|
"_id": "6046bab736651a07ebc537e9",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "fallensquare",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "fallensquare",
|
||||||
|
"_id": "6046bab736651a07ebc537de",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "dropdead",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "dropdead",
|
||||||
|
"_id": "6046bab736651a07ebc53804",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "alexandrite",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "alexandrite",
|
||||||
|
"_id": "6046bab736651a07ebc53811",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "astraltale",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "astraltale",
|
||||||
|
"_id": "6046bab736651a07ebc537f7",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "phantasia",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "phantasia",
|
||||||
|
"_id": "6046bab736651a07ebc537df",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "empireofwinter",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "empireofwinter",
|
||||||
|
"_id": "6046bab736651a07ebc53805",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "libertas",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "libertas",
|
||||||
|
"_id": "6046bab736651a07ebc537eb",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "dottodot",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "dottodot",
|
||||||
|
"_id": "6046bab736651a07ebc537e0",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "dreadnought",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "dreadnought",
|
||||||
|
"_id": "6046bab736651a07ebc537ec",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "mirzam",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "mirzam",
|
||||||
|
"_id": "6046bab736651a07ebc537e1",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "heavenlycaress",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "heavenlycaress",
|
||||||
|
"_id": "6046bab736651a07ebc53807",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "filament",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "filament",
|
||||||
|
"_id": "6046bab736651a07ebc53814",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "avantraze",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "avantraze",
|
||||||
|
"_id": "6046bab736651a07ebc537ed",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "battlenoone",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "battlenoone",
|
||||||
|
"_id": "6046bab736651a07ebc537fa",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "saikyostronger",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "saikyostronger",
|
||||||
|
"_id": "6046bab736651a07ebc537e2",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "izana",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "izana",
|
||||||
|
"_id": "6046bab736651a07ebc53808",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "einherjar",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "einherjar",
|
||||||
|
"_id": "6046bab736651a07ebc53815",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "laqryma",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "laqryma",
|
||||||
|
"_id": "6046bab736651a07ebc537ee",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "amygdata",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "amygdata",
|
||||||
|
"_id": "6046bab736651a07ebc537fb",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "altale",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "altale",
|
||||||
|
"_id": "6046bab736651a07ebc537e3",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "feelssoright",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "feelssoright",
|
||||||
|
"_id": "6046bab736651a07ebc537ef",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "scarletcage",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "scarletcage",
|
||||||
|
"_id": "6046bab736651a07ebc537fc",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "teriqma",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "teriqma",
|
||||||
|
"_id": "6046bab736651a07ebc537e4",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "mahoroba",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "mahoroba",
|
||||||
|
"_id": "6046bab736651a07ebc5380a",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "badtek",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "badtek",
|
||||||
|
"_id": "6046bab736651a07ebc537f0",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "maliciousmischance",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "maliciousmischance",
|
||||||
|
"_id": "6046bab736651a07ebc53817",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "buchigireberserker",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "buchigireberserker",
|
||||||
|
"_id": "6046bab736651a07ebc537e5",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "galaxyfriends",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "galaxyfriends",
|
||||||
|
"_id": "6046bab736651a07ebc5380b",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 50,
|
||||||
|
"orig_price": 100,
|
||||||
|
"discount_from": 1615248000000,
|
||||||
|
"discount_to": 1615852799000
|
||||||
|
}, {
|
||||||
|
"name": "xeraphinite",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "xeraphinite",
|
||||||
|
"_id": "6046bab736651a07ebc53818",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"orig_price": 100,
|
||||||
|
"price": 100
|
||||||
|
}, {
|
||||||
|
"name": "xanatos",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "xanatos",
|
||||||
|
"_id": "6046bab736651a07ebc537f1",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"price": 100,
|
||||||
|
"orig_price": 100
|
||||||
|
}, {
|
||||||
|
"name": "attraqtia",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "attraqtia",
|
||||||
|
"_id": "6046bab736651a07ebc537ff",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"orig_price": 100,
|
||||||
|
"price": 100
|
||||||
|
}, {
|
||||||
|
"name": "gimmedablood",
|
||||||
|
"items": [{
|
||||||
|
"type": "single",
|
||||||
|
"id": "gimmedablood",
|
||||||
|
"_id": "6046bab736651a07ebc537e7",
|
||||||
|
"is_available": true
|
||||||
|
}],
|
||||||
|
"orig_price": 100,
|
||||||
|
"price": 100
|
||||||
|
}]
|
||||||
22
latest version/database/songs/dement/3.aff
Normal file
22
latest version/database/songs/dement/3.aff
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
AudioOffset:408
|
||||||
|
-
|
||||||
|
timing(0,210.00,4.00);
|
||||||
|
(1142,4);
|
||||||
|
flick(1142,0.50,0.50,0.00,1.00);
|
||||||
|
(1571,2);
|
||||||
|
(2857,1);
|
||||||
|
(3142,2);
|
||||||
|
(3428,3);
|
||||||
|
(3857,4);
|
||||||
|
(4142,3);
|
||||||
|
(4571,2);
|
||||||
|
(5000,1);
|
||||||
|
(5428,3);
|
||||||
|
arc(5714,6857,0.00,0.50,s,1.00,1.00,0,none,false);
|
||||||
|
arc(6857,8000,0.50,0.00,s,1.00,1.00,0,none,false);
|
||||||
|
arc(8000,9142,0.00,0.50,s,1.00,1.00,0,none,false);
|
||||||
|
arc(9142,10285,0.50,0.00,s,1.00,1.00,0,none,false);
|
||||||
|
arc(10285,11428,1.00,0.50,s,1.00,1.00,1,none,false);
|
||||||
|
arc(11428,12571,0.50,1.00,s,1.00,1.00,1,none,false);
|
||||||
|
arc(12571,13714,1.00,0.50,s,1.00,1.00,1,none,false);
|
||||||
|
arc(13714,14571,0.50,1.00,s,1.00,1.00,1,none,false);
|
||||||
1
latest version/log/error.log
Normal file
1
latest version/log/error.log
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
580
latest version/main.py
Normal file
580
latest version/main.py
Normal file
@@ -0,0 +1,580 @@
|
|||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
from flask import Flask, request, jsonify, make_response, send_from_directory
|
||||||
|
from logging.config import dictConfig
|
||||||
|
from setting import Config
|
||||||
|
import base64
|
||||||
|
import server.auth
|
||||||
|
import server.info
|
||||||
|
import server.setme
|
||||||
|
import server.arcscore
|
||||||
|
import web.login
|
||||||
|
import web.index
|
||||||
|
import server.arcworld
|
||||||
|
import server.arcdownload
|
||||||
|
import server.arcpurchase
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
wsgi_app = app.wsgi_app
|
||||||
|
|
||||||
|
|
||||||
|
def error_return(error_code): # 错误返回
|
||||||
|
# -7 处理交易时发生了错误
|
||||||
|
# -5 所有的曲目都已经下载完毕
|
||||||
|
# -4 您的账号已在别处登录
|
||||||
|
# -3 无法连接至服务器
|
||||||
|
# 2 Arcaea服务器正在维护
|
||||||
|
# 5 请更新Arcaea到最新版本
|
||||||
|
# 100 无法在此ip地址下登录游戏
|
||||||
|
# 101 用户名占用
|
||||||
|
# 102 电子邮箱已注册
|
||||||
|
# 103 已有一个账号由此设备创建
|
||||||
|
# 104 用户名密码错误
|
||||||
|
# 105 24小时内登入两台设备
|
||||||
|
# 106 账户冻结
|
||||||
|
# 107 你没有足够的体力
|
||||||
|
# 113 活动已结束
|
||||||
|
# 114 该活动已结束,您的成绩不会提交
|
||||||
|
# 120 封号警告
|
||||||
|
# 121 账户冻结
|
||||||
|
# 122 账户暂时冻结
|
||||||
|
# 123 账户被限制
|
||||||
|
# 124 你今天不能再使用这个IP地址创建新的账号
|
||||||
|
# 150 非常抱歉您已被限制使用此功能
|
||||||
|
# 151 目前无法使用此功能
|
||||||
|
# 401 用户不存在
|
||||||
|
# 403 无法连接至服务器
|
||||||
|
# 501 502 -6 此物品目前无法获取
|
||||||
|
# 504 无效的序列码
|
||||||
|
# 505 此序列码已被使用
|
||||||
|
# 506 你已拥有了此物品
|
||||||
|
# 601 好友列表已满
|
||||||
|
# 602 此用户已是好友
|
||||||
|
# 604 你不能加自己为好友
|
||||||
|
# 903 下载量超过了限制,请24小时后重试
|
||||||
|
# 905 请在再次使用此功能前等待24小时
|
||||||
|
# 1001 设备数量达到上限
|
||||||
|
# 1002 此设备已使用过此功能
|
||||||
|
# 9801 下载歌曲时发生问题,请再试一次
|
||||||
|
# 9802 保存歌曲时发生问题,请检查设备空间容量
|
||||||
|
# 9905 没有在云端发现任何数据
|
||||||
|
# 9907 更新数据时发生了问题
|
||||||
|
# 9908 服务器只支持最新的版本,请更新Arcaea
|
||||||
|
# 其它 发生未知错误
|
||||||
|
return jsonify({
|
||||||
|
"success": False,
|
||||||
|
"error_code": error_code
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def hello():
|
||||||
|
return "Hello World!"
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/favicon.ico', methods=['GET']) # 图标
|
||||||
|
def favicon():
|
||||||
|
# Pixiv ID: 82374369
|
||||||
|
# 我觉得这张图虽然并不是那么精细,但很有感觉,色彩的强烈对比下给人带来一种惊艳
|
||||||
|
# 然后在压缩之下什么也看不清了:(
|
||||||
|
|
||||||
|
return app.send_static_file('favicon.ico')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/auth/login', methods=['POST']) # 登录接口
|
||||||
|
def login():
|
||||||
|
headers = request.headers
|
||||||
|
id_pwd = headers['Authorization']
|
||||||
|
id_pwd = base64.b64decode(id_pwd[6:]).decode()
|
||||||
|
name, password = id_pwd.split(':', 1)
|
||||||
|
device_id = headers['DeviceId']
|
||||||
|
token, error_code = server.auth.arc_login(name, password, device_id)
|
||||||
|
if not error_code:
|
||||||
|
r = {"success": True, "token_type": "Bearer"}
|
||||||
|
r['access_token'] = token
|
||||||
|
return jsonify(r)
|
||||||
|
else:
|
||||||
|
return error_return(error_code)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/user/', methods=['POST']) # 注册接口
|
||||||
|
def register():
|
||||||
|
name = request.form['name']
|
||||||
|
password = request.form['password']
|
||||||
|
device_id = request.form['device_id']
|
||||||
|
user_id, token, error_code = server.auth.arc_register(
|
||||||
|
name, password, device_id)
|
||||||
|
if user_id is not None:
|
||||||
|
r = {"success": True, "value": {
|
||||||
|
'user_id': user_id, 'access_token': token}}
|
||||||
|
return jsonify(r)
|
||||||
|
else:
|
||||||
|
return error_return(error_code) # 应该是101,用户名被占用,毕竟电子邮箱没记录
|
||||||
|
|
||||||
|
|
||||||
|
# 集成式请求,没想到什么好办法处理,就先这样写着
|
||||||
|
@app.route('/latte/13/compose/aggregate', methods=['GET'])
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def aggregate(user_id):
|
||||||
|
calls = request.args.get('calls')
|
||||||
|
if calls == '[{ "endpoint": "/user/me", "id": 0 }]': # 极其沙雕的判断,我猜get的参数就两种
|
||||||
|
r = server.info.arc_aggregate_small(user_id)
|
||||||
|
else:
|
||||||
|
r = server.info.arc_aggregate_big(user_id)
|
||||||
|
return jsonify(r)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/user/me/character', methods=['POST']) # 角色切换
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def character_change(user_id):
|
||||||
|
character_id = request.form['character']
|
||||||
|
skill_sealed = request.form['skill_sealed']
|
||||||
|
|
||||||
|
flag = server.setme.change_char(user_id, character_id, skill_sealed)
|
||||||
|
if flag:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {
|
||||||
|
"user_id": user_id,
|
||||||
|
"character": character_id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return error_return(108)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/<path:path>/toggle_uncap', methods=['POST']) # 角色觉醒切换
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def character_uncap(user_id, path):
|
||||||
|
while '//' in path:
|
||||||
|
path = path.replace('//', '/')
|
||||||
|
character_id = int(path[21:])
|
||||||
|
r = server.setme.change_char_uncap(user_id, character_id)
|
||||||
|
if r is not None:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {
|
||||||
|
"user_id": user_id,
|
||||||
|
"character": [r]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return error_return(108)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/friend/me/add', methods=['POST']) # 加好友
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def add_friend(user_id):
|
||||||
|
friend_code = request.form['friend_code']
|
||||||
|
friend_id = server.auth.code_get_id(friend_code)
|
||||||
|
if friend_id is not None:
|
||||||
|
r = server.setme.arc_add_friend(user_id, friend_id)
|
||||||
|
if r is not None and r != 602 and r != 604:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {
|
||||||
|
"user_id": user_id,
|
||||||
|
"updatedAt": "2020-09-07T07:32:12.740Z",
|
||||||
|
"createdAt": "2020-09-06T10:05:18.471Z",
|
||||||
|
"friends": r
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
if r is not None:
|
||||||
|
return error_return(r)
|
||||||
|
else:
|
||||||
|
return error_return(108)
|
||||||
|
else:
|
||||||
|
return error_return(401)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/friend/me/delete', methods=['POST']) # 删好友
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def delete_friend(user_id):
|
||||||
|
friend_id = int(request.form['friend_id'])
|
||||||
|
if friend_id is not None:
|
||||||
|
r = server.setme.arc_delete_friend(user_id, friend_id)
|
||||||
|
if r is not None:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {
|
||||||
|
"user_id": user_id,
|
||||||
|
"updatedAt": "2020-09-07T07:32:12.740Z",
|
||||||
|
"createdAt": "2020-09-06T10:05:18.471Z",
|
||||||
|
"friends": r
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return error_return(108)
|
||||||
|
else:
|
||||||
|
return error_return(401)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/score/song/friend', methods=['GET']) # 好友排名,默认最多50
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def song_score_friend(user_id):
|
||||||
|
song_id = request.args.get('song_id')
|
||||||
|
difficulty = request.args.get('difficulty')
|
||||||
|
r = server.arcscore.arc_score_friend(user_id, song_id, difficulty)
|
||||||
|
if r is not None:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": r
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return error_return(108)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/score/song/me', methods=['GET']) # 我的排名,默认最多20
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def song_score_me(user_id):
|
||||||
|
song_id = request.args.get('song_id')
|
||||||
|
difficulty = request.args.get('difficulty')
|
||||||
|
r = server.arcscore.arc_score_me(user_id, song_id, difficulty)
|
||||||
|
if r is not None:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": r
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return error_return(108)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/score/song', methods=['GET']) # TOP20
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def song_score_top(user_id):
|
||||||
|
song_id = request.args.get('song_id')
|
||||||
|
difficulty = request.args.get('difficulty')
|
||||||
|
r = server.arcscore.arc_score_top(song_id, difficulty)
|
||||||
|
if r is not None:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": r
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return error_return(108)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/score/song', methods=['POST']) # 成绩上传
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def song_score_post(user_id):
|
||||||
|
song_token = request.form['song_token']
|
||||||
|
song_hash = request.form['song_hash']
|
||||||
|
song_id = request.form['song_id']
|
||||||
|
difficulty = int(request.form['difficulty'])
|
||||||
|
score = int(request.form['score'])
|
||||||
|
shiny_perfect_count = int(request.form['shiny_perfect_count'])
|
||||||
|
perfect_count = int(request.form['perfect_count'])
|
||||||
|
near_count = int(request.form['near_count'])
|
||||||
|
miss_count = int(request.form['miss_count'])
|
||||||
|
health = int(request.form['health'])
|
||||||
|
modifier = int(request.form['modifier'])
|
||||||
|
beyond_gauge = int(request.form['beyond_gauge'])
|
||||||
|
clear_type = int(request.form['clear_type'])
|
||||||
|
submission_hash = request.form['submission_hash']
|
||||||
|
|
||||||
|
# 增加成绩校验
|
||||||
|
if not server.arcscore.arc_score_check(user_id, song_id, difficulty, score, shiny_perfect_count, perfect_count, near_count, miss_count, health, modifier, beyond_gauge, clear_type, song_token, song_hash, submission_hash):
|
||||||
|
return error_return(107)
|
||||||
|
|
||||||
|
r, re = server.arcscore.arc_score_post(user_id, song_id, difficulty, score, shiny_perfect_count,
|
||||||
|
perfect_count, near_count, miss_count, health, modifier, beyond_gauge, clear_type)
|
||||||
|
if r is not None:
|
||||||
|
if re:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": re
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {"user_rating": r}
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return error_return(108)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/score/token', methods=['GET']) # 成绩上传所需的token,显然我不想验证
|
||||||
|
def score_token():
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {
|
||||||
|
"token": "1145141919810"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
# 世界模式成绩上传所需的token,无验证
|
||||||
|
@app.route('/latte/13/score/token/world', methods=['GET'])
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def score_token_world(user_id):
|
||||||
|
args = request.args
|
||||||
|
server.arcworld.play_world_song(user_id, args)
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {
|
||||||
|
"stamina": 12,
|
||||||
|
"max_stamina_ts": 1599547603825,
|
||||||
|
"token": "13145201919810"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/user/me/save', methods=['GET']) # 从云端同步
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def cloud_get(user_id):
|
||||||
|
r = server.arcscore.arc_all_get(user_id)
|
||||||
|
if r is not None:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": r
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return error_return(108)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/user/me/save', methods=['POST']) # 向云端同步
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def cloud_post(user_id):
|
||||||
|
scores_data = request.form['scores_data']
|
||||||
|
clearlamps_data = request.form['clearlamps_data']
|
||||||
|
clearedsongs_data = request.form['clearedsongs_data']
|
||||||
|
unlocklist_data = request.form['unlocklist_data']
|
||||||
|
installid_data = request.form['installid_data']
|
||||||
|
devicemodelname_data = request.form['devicemodelname_data']
|
||||||
|
story_data = request.form['story_data']
|
||||||
|
|
||||||
|
server.arcscore.arc_all_post(user_id, scores_data, clearlamps_data, clearedsongs_data,
|
||||||
|
unlocklist_data, installid_data, devicemodelname_data, story_data)
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {
|
||||||
|
"user_id": user_id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/purchase/me/redeem', methods=['POST']) # 兑换码
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def redeem(user_id):
|
||||||
|
code = request.form['code']
|
||||||
|
fragment, error_code = server.arcpurchase.claim_user_redeem(
|
||||||
|
user_id, code)
|
||||||
|
if not error_code:
|
||||||
|
if fragment > 0:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {"coupon": "fragment"+str(fragment)}
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {"coupon": ""}
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return error_return(error_code)
|
||||||
|
|
||||||
|
|
||||||
|
# 礼物确认
|
||||||
|
@app.route('/latte/13/present/me/claim/<present_id>', methods=['POST'])
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def claim_present(user_id, present_id):
|
||||||
|
flag = server.arcpurchase.claim_user_present(user_id, present_id)
|
||||||
|
if flag:
|
||||||
|
return jsonify({
|
||||||
|
"success": True
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return error_return(108)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/purchase/me/item', methods=['POST']) # 购买,world模式boost
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def prog_boost(user_id):
|
||||||
|
re = {"success": False}
|
||||||
|
if 'item_id' in request.form:
|
||||||
|
if request.form['item_id'] == 'prog_boost_300':
|
||||||
|
ticket, error_code = server.arcpurchase.get_prog_boost(user_id)
|
||||||
|
if error_code:
|
||||||
|
return error_return(error_code)
|
||||||
|
|
||||||
|
re = {
|
||||||
|
"success": True,
|
||||||
|
"value": {'ticket': ticket}
|
||||||
|
}
|
||||||
|
return jsonify(re)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/purchase/me/pack', methods=['POST']) # 曲包和单曲购买
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def pack(user_id):
|
||||||
|
if 'pack_id' in request.form:
|
||||||
|
return jsonify(server.arcpurchase.buy_pack(user_id, request.form['pack_id']))
|
||||||
|
if 'single_id' in request.form:
|
||||||
|
return jsonify(server.arcpurchase.buy_single(user_id, request.form['single_id']))
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/purchase/bundle/single', methods=['GET']) # 单曲购买信息获取
|
||||||
|
def single():
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": server.arcpurchase.get_single_purchase()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/world/map/me', methods=['GET']) # 获得世界模式信息,所有地图
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def world_all(user_id):
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {
|
||||||
|
"current_map": server.arcworld.get_current_map(user_id),
|
||||||
|
"user_id": user_id,
|
||||||
|
"maps": server.arcworld.get_world_all(user_id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/world/map/me/', methods=['POST']) # 进入地图
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def world_in(user_id):
|
||||||
|
map_id = request.form['map_id']
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": server.arcworld.get_user_world(user_id, map_id)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/world/map/me/<map_id>', methods=['GET']) # 获得单个地图完整信息
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def world_one(user_id, map_id):
|
||||||
|
server.arcworld.change_user_current_map(user_id, map_id)
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": {
|
||||||
|
"user_id": user_id,
|
||||||
|
"current_map": map_id,
|
||||||
|
"maps": [server.arcworld.get_user_world_info(user_id, map_id)]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/13/serve/download/me/song', methods=['GET']) # 歌曲下载
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def download_song(user_id):
|
||||||
|
song_ids = request.args.getlist('sid')
|
||||||
|
if server.arcdownload.is_able_download(user_id):
|
||||||
|
re = {}
|
||||||
|
if not song_ids:
|
||||||
|
re = server.arcdownload.get_all_songs(user_id)
|
||||||
|
else:
|
||||||
|
re = server.arcdownload.get_some_songs(user_id, song_ids)
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"value": re
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return error_return(903)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/download/<path:file_path>', methods=['GET']) # 下载
|
||||||
|
def download(file_path):
|
||||||
|
try:
|
||||||
|
t = request.args.get('t')
|
||||||
|
message = server.arcdownload.is_token_able_download(t)
|
||||||
|
if message == 0:
|
||||||
|
path = os.path.join('./database/songs', file_path)
|
||||||
|
if os.path.isfile(path) and not('../' in path or '..\\' in path):
|
||||||
|
return send_from_directory('./database/songs', file_path, as_attachment=True)
|
||||||
|
else:
|
||||||
|
return error_return(109)
|
||||||
|
else:
|
||||||
|
return error_return(message)
|
||||||
|
except:
|
||||||
|
return error_return(108)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/latte/<path:path>', methods=['POST']) # 三个设置,写在最后降低优先级
|
||||||
|
@server.auth.auth_required(request)
|
||||||
|
def sys_set(user_id, path):
|
||||||
|
set_arg = path[10:]
|
||||||
|
value = request.form['value']
|
||||||
|
server.setme.arc_sys_set(user_id, value, set_arg)
|
||||||
|
r = server.info.arc_aggregate_small(user_id)
|
||||||
|
r['value'] = r['value'][0]['value']
|
||||||
|
return jsonify(r)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app.config.from_mapping(SECRET_KEY=Config.SECRET_KEY)
|
||||||
|
app.config['SESSION_TYPE'] = 'filesystem'
|
||||||
|
app.register_blueprint(web.login.bp)
|
||||||
|
app.register_blueprint(web.index.bp)
|
||||||
|
|
||||||
|
log_dict = {
|
||||||
|
'version': 1,
|
||||||
|
'root': {
|
||||||
|
'level': 'INFO',
|
||||||
|
'handlers': ['wsgi', 'error_file']
|
||||||
|
},
|
||||||
|
'handlers': {
|
||||||
|
'wsgi': {
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
'stream': 'ext://flask.logging.wsgi_errors_stream',
|
||||||
|
'formatter': 'default'
|
||||||
|
},
|
||||||
|
"error_file": {
|
||||||
|
"class": "logging.handlers.RotatingFileHandler",
|
||||||
|
"maxBytes": 1024 * 1024,
|
||||||
|
"backupCount": 1,
|
||||||
|
"encoding": "utf-8",
|
||||||
|
"level": "ERROR",
|
||||||
|
"formatter": "default",
|
||||||
|
"filename": "./log/error.log"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'formatters': {
|
||||||
|
'default': {
|
||||||
|
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if Config.ALLOW_LOG_INFO:
|
||||||
|
log_dict['root']['handlers'] = ['wsgi', 'info_file', 'error_file']
|
||||||
|
log_dict['handlers']['info_file'] = {
|
||||||
|
"class": "logging.handlers.RotatingFileHandler",
|
||||||
|
"maxBytes": 1024 * 1024,
|
||||||
|
"backupCount": 1,
|
||||||
|
"encoding": "utf-8",
|
||||||
|
"level": "INFO",
|
||||||
|
"formatter": "default",
|
||||||
|
"filename": "./log/info.log"
|
||||||
|
}
|
||||||
|
|
||||||
|
dictConfig(log_dict)
|
||||||
|
|
||||||
|
app.logger.info("Start to initialize data in 'songfile' table...")
|
||||||
|
try:
|
||||||
|
error = server.arcdownload.initialize_songfile()
|
||||||
|
except:
|
||||||
|
error = 'Something wrong.'
|
||||||
|
if error:
|
||||||
|
app.logger.warning(error)
|
||||||
|
else:
|
||||||
|
app.logger.info('Complete!')
|
||||||
|
|
||||||
|
app.run(Config.HOST, Config.PORT)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
# Made By Lost 2020.9.11
|
||||||
1
latest version/run.bat
Normal file
1
latest version/run.bat
Normal file
@@ -0,0 +1 @@
|
|||||||
|
python -B main.py
|
||||||
175
latest version/server/arcdownload.py
Normal file
175
latest version/server/arcdownload.py
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
import os
|
||||||
|
import hashlib
|
||||||
|
from flask import url_for
|
||||||
|
import sqlite3
|
||||||
|
from server.sql import Connect
|
||||||
|
import time
|
||||||
|
from setting import Config
|
||||||
|
|
||||||
|
time_limit = Config.DOWNLOAD_TIMES_LIMIT # 每个玩家24小时下载次数限制
|
||||||
|
time_gap_limit = Config.DOWNLOAD_TIME_GAP_LIMIT # 下载链接有效秒数
|
||||||
|
|
||||||
|
|
||||||
|
def get_file_md5(file_path):
|
||||||
|
# 计算文件MD5
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
return None
|
||||||
|
myhash = hashlib.md5()
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
while True:
|
||||||
|
b = f.read(8096)
|
||||||
|
if not b:
|
||||||
|
break
|
||||||
|
myhash.update(b)
|
||||||
|
|
||||||
|
return myhash.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def get_one_song(c, user_id, song_id, file_dir='./database/songs'):
|
||||||
|
# 获取一首歌的下载链接,返回字典
|
||||||
|
dir_list = os.listdir(os.path.join(file_dir, song_id))
|
||||||
|
re = {}
|
||||||
|
now = int(time.time())
|
||||||
|
c.execute('''delete from download_token where user_id=:a and song_id=:b''', {
|
||||||
|
'a': user_id, 'b': song_id})
|
||||||
|
|
||||||
|
for i in dir_list:
|
||||||
|
if os.path.isfile(os.path.join(file_dir, song_id, i)) and i in ['0.aff', '1.aff', '2.aff', '3.aff', 'base.ogg']:
|
||||||
|
token = hashlib.md5(
|
||||||
|
(str(user_id) + song_id + i + str(now)).encode(encoding='UTF-8')).hexdigest()
|
||||||
|
token = token[:8]
|
||||||
|
|
||||||
|
if i == 'base.ogg':
|
||||||
|
c.execute(
|
||||||
|
'''select md5 from songfile where song_id=:a and file_type=-1''', {'a': song_id})
|
||||||
|
x = c.fetchone()
|
||||||
|
if x:
|
||||||
|
checksum = x[0]
|
||||||
|
else:
|
||||||
|
checksum = get_file_md5(os.path.join(
|
||||||
|
file_dir, song_id, 'base.ogg'))
|
||||||
|
re['audio'] = {"checksum": checksum,
|
||||||
|
"url": url_for('download', file_path=song_id+'/base.ogg', t=token, _external=True)}
|
||||||
|
else:
|
||||||
|
if 'chart' not in re:
|
||||||
|
re['chart'] = {}
|
||||||
|
c.execute(
|
||||||
|
'''select md5 from songfile where song_id=:a and file_type=:b''', {'a': song_id, 'b': int(i[0])})
|
||||||
|
x = c.fetchone()
|
||||||
|
if x:
|
||||||
|
checksum = x[0]
|
||||||
|
else:
|
||||||
|
checksum = get_file_md5(os.path.join(file_dir, song_id, i))
|
||||||
|
re['chart'][i[0]] = {"checksum": checksum,
|
||||||
|
"url": url_for('download', file_path=song_id+'/'+i, t=token, _external=True)}
|
||||||
|
|
||||||
|
c.execute('''insert into download_token values(:a,:b,:c,:d,:e)''', {
|
||||||
|
'a': user_id, 'b': song_id, 'c': i, 'd': token, 'e': now})
|
||||||
|
|
||||||
|
return {song_id: re}
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_songs(user_id, file_dir='./database/songs'):
|
||||||
|
# 获取所有歌的下载链接,返回字典
|
||||||
|
dir_list = os.listdir(file_dir)
|
||||||
|
re = {}
|
||||||
|
with Connect() as c:
|
||||||
|
for i in dir_list:
|
||||||
|
if os.path.isdir(os.path.join(file_dir, i)):
|
||||||
|
re.update(get_one_song(c, user_id, i, file_dir))
|
||||||
|
|
||||||
|
return re
|
||||||
|
|
||||||
|
|
||||||
|
def get_some_songs(user_id, song_ids):
|
||||||
|
# 获取一些歌的下载链接,返回字典
|
||||||
|
re = {}
|
||||||
|
with Connect() as c:
|
||||||
|
for song_id in song_ids:
|
||||||
|
re.update(get_one_song(c, user_id, song_id))
|
||||||
|
|
||||||
|
return re
|
||||||
|
|
||||||
|
|
||||||
|
def is_token_able_download(t):
|
||||||
|
# token是否可以下载,返回错误码,0即可以
|
||||||
|
errorcode = 108
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute('''select * from download_token where token = :t limit 1''',
|
||||||
|
{'t': t})
|
||||||
|
x = c.fetchone()
|
||||||
|
now = int(time.time())
|
||||||
|
if x and now - x[4] <= time_gap_limit:
|
||||||
|
c.execute(
|
||||||
|
'''select count(*) from user_download where user_id = :a''', {'a': x[0]})
|
||||||
|
y = c.fetchone()
|
||||||
|
if y and y[0] <= time_limit:
|
||||||
|
c.execute('''insert into user_download values(:a,:b,:c)''', {
|
||||||
|
'a': x[0], 'b': x[3], 'c': now})
|
||||||
|
errorcode = 0
|
||||||
|
else:
|
||||||
|
errorcode = 903
|
||||||
|
else:
|
||||||
|
errorcode = 108
|
||||||
|
|
||||||
|
return errorcode
|
||||||
|
|
||||||
|
|
||||||
|
def is_able_download(user_id):
|
||||||
|
# 是否可以下载,返回布尔值
|
||||||
|
f = False
|
||||||
|
with Connect() as c:
|
||||||
|
now = int(time.time())
|
||||||
|
c.execute(
|
||||||
|
'''delete from user_download where user_id = :a and time <= :b''', {'a': user_id, 'b': now - 24*3600})
|
||||||
|
c.execute(
|
||||||
|
'''select count(*) from user_download where user_id = :a''', {'a': user_id})
|
||||||
|
y = c.fetchone()
|
||||||
|
if y and y[0] <= time_limit:
|
||||||
|
f = True
|
||||||
|
else:
|
||||||
|
f = False
|
||||||
|
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_one_songfile(c, song_id, file_dir='./database/songs'):
|
||||||
|
# 计算并添加歌曲md5到表中,无返回
|
||||||
|
dir_list = os.listdir(os.path.join(file_dir, song_id))
|
||||||
|
for i in dir_list:
|
||||||
|
if os.path.isfile(os.path.join(file_dir, song_id, i)) and i in ['0.aff', '1.aff', '2.aff', '3.aff', 'base.ogg']:
|
||||||
|
if i == 'base.ogg':
|
||||||
|
c.execute('''insert into songfile values(:a,-1,:c)''', {
|
||||||
|
'a': song_id, 'c': get_file_md5(os.path.join(file_dir, song_id, 'base.ogg'))})
|
||||||
|
else:
|
||||||
|
c.execute('''insert into songfile values(:a,:b,:c)''', {
|
||||||
|
'a': song_id, 'b': int(i[0]), 'c': get_file_md5(os.path.join(file_dir, song_id, i))})
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_songfile(file_dir='./database/songs'):
|
||||||
|
# 初始化歌曲数据的md5表,返回错误信息
|
||||||
|
error = None
|
||||||
|
try:
|
||||||
|
dir_list = os.listdir(file_dir)
|
||||||
|
except:
|
||||||
|
error = 'OS error!'
|
||||||
|
return error
|
||||||
|
try:
|
||||||
|
conn = sqlite3.connect('./database/arcaea_database.db')
|
||||||
|
c = conn.cursor()
|
||||||
|
except:
|
||||||
|
error = 'Database error!'
|
||||||
|
return error
|
||||||
|
try:
|
||||||
|
c.execute('''delete from songfile''')
|
||||||
|
for i in dir_list:
|
||||||
|
if os.path.isdir(os.path.join(file_dir, i)):
|
||||||
|
initialize_one_songfile(c, i, file_dir)
|
||||||
|
except:
|
||||||
|
error = 'Initialization error!'
|
||||||
|
finally:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return error
|
||||||
219
latest version/server/arcpurchase.py
Normal file
219
latest version/server/arcpurchase.py
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
from server.sql import Connect
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def int2b(x):
|
||||||
|
# int与布尔值转换
|
||||||
|
if x is None or x == 0:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_item(c, type='pack'):
|
||||||
|
# 读取packs内容,返回字典列表
|
||||||
|
c.execute('''select * from item where type = :a''', {'a': type})
|
||||||
|
x = c.fetchall()
|
||||||
|
if not x:
|
||||||
|
return []
|
||||||
|
|
||||||
|
re = []
|
||||||
|
for i in x:
|
||||||
|
r = {"name": i[0],
|
||||||
|
"items": [{
|
||||||
|
"type": i[1],
|
||||||
|
"id": i[0],
|
||||||
|
"is_available": int2b(i[2])
|
||||||
|
}],
|
||||||
|
"price": i[3],
|
||||||
|
"orig_price": i[4]}
|
||||||
|
|
||||||
|
if i[5] > 0:
|
||||||
|
r['discount_from'] = i[5]
|
||||||
|
if i[6] > 0:
|
||||||
|
r['discount_to'] = i[6]
|
||||||
|
|
||||||
|
re.append(r)
|
||||||
|
|
||||||
|
return re
|
||||||
|
|
||||||
|
|
||||||
|
def get_single_purchase():
|
||||||
|
# main里面没开数据库,这里写一下代替
|
||||||
|
re = []
|
||||||
|
with Connect() as c:
|
||||||
|
re = get_item(c, type='single')
|
||||||
|
|
||||||
|
return re
|
||||||
|
|
||||||
|
|
||||||
|
def buy_item(c, user_id, price):
|
||||||
|
# 购买接口,返回成功与否标识符和剩余源点数
|
||||||
|
c.execute('''select ticket from user where user_id = :a''',
|
||||||
|
{'a': user_id})
|
||||||
|
ticket = c.fetchone()
|
||||||
|
if ticket:
|
||||||
|
ticket = ticket[0]
|
||||||
|
else:
|
||||||
|
ticket = 0
|
||||||
|
|
||||||
|
if ticket < price:
|
||||||
|
return False, ticket
|
||||||
|
|
||||||
|
c.execute('''update user set ticket = :b where user_id = :a''',
|
||||||
|
{'a': user_id, 'b': ticket-price})
|
||||||
|
|
||||||
|
return True, ticket - price
|
||||||
|
|
||||||
|
|
||||||
|
def buy_pack(user_id, pack_id):
|
||||||
|
# 曲包购买,返回字典
|
||||||
|
re = {"success": False}
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute('''select price from item where item_id = :a''',
|
||||||
|
{'a': pack_id})
|
||||||
|
price = c.fetchone()
|
||||||
|
if price:
|
||||||
|
price = price[0]
|
||||||
|
else:
|
||||||
|
price = 0
|
||||||
|
|
||||||
|
flag, ticket = buy_item(c, user_id, price)
|
||||||
|
|
||||||
|
if flag:
|
||||||
|
c.execute('''insert into user_item values(:a,:b,'pack')''',
|
||||||
|
{'a': user_id, 'b': pack_id})
|
||||||
|
|
||||||
|
re = {"success": True}
|
||||||
|
|
||||||
|
return re
|
||||||
|
|
||||||
|
|
||||||
|
def buy_single(user_id, single_id):
|
||||||
|
# 单曲购买,返回字典
|
||||||
|
re = {"success": False}
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute('''select price from item where item_id = :a''',
|
||||||
|
{'a': single_id})
|
||||||
|
price = c.fetchone()
|
||||||
|
if price:
|
||||||
|
price = price[0]
|
||||||
|
else:
|
||||||
|
price = 0
|
||||||
|
|
||||||
|
flag, ticket = buy_item(c, user_id, price)
|
||||||
|
|
||||||
|
if flag:
|
||||||
|
c.execute('''insert into user_item values(:a,:b,'single')''',
|
||||||
|
{'a': user_id, 'b': single_id})
|
||||||
|
re = {"success": True}
|
||||||
|
|
||||||
|
return re
|
||||||
|
|
||||||
|
|
||||||
|
def get_prog_boost(user_id):
|
||||||
|
# 世界模式源韵强化,扣50源点,返回剩余源点数
|
||||||
|
|
||||||
|
ticket = -1
|
||||||
|
with Connect() as c:
|
||||||
|
flag, ticket = buy_item(c, user_id, 50)
|
||||||
|
|
||||||
|
if flag:
|
||||||
|
c.execute('''update user set prog_boost = 1 where user_id = :a''', {
|
||||||
|
'a': user_id})
|
||||||
|
if ticket >= 0:
|
||||||
|
return ticket, None
|
||||||
|
else:
|
||||||
|
return 0, 108
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_present(c, user_id):
|
||||||
|
# 获取用户奖励,返回字典列表
|
||||||
|
c.execute(
|
||||||
|
'''select * from present where present_id in (select present_id from user_present where user_id=:a)''', {'a': user_id})
|
||||||
|
x = c.fetchall()
|
||||||
|
re = []
|
||||||
|
now = int(time.time() * 1000)
|
||||||
|
if x:
|
||||||
|
for i in x:
|
||||||
|
if now <= int(i[1]):
|
||||||
|
re.append({'expire_ts': i[1],
|
||||||
|
'description': i[3],
|
||||||
|
'present_id': i[0],
|
||||||
|
'items': json.loads(i[2])
|
||||||
|
})
|
||||||
|
|
||||||
|
return re
|
||||||
|
|
||||||
|
|
||||||
|
def claim_user_present(user_id, present_id):
|
||||||
|
# 确认并删除用户奖励,返回成功与否的布尔值
|
||||||
|
flag = False
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute('''select exists(select * from user_present where user_id=:a and present_id=:b)''',
|
||||||
|
{'a': user_id, 'b': present_id})
|
||||||
|
if c.fetchone() == (1,):
|
||||||
|
c.execute('''delete from user_present where user_id=:a and present_id=:b''',
|
||||||
|
{'a': user_id, 'b': present_id})
|
||||||
|
c.execute('''select * from present where present_id=:b''',
|
||||||
|
{'b': present_id})
|
||||||
|
x = c.fetchone()
|
||||||
|
now = int(time.time() * 1000)
|
||||||
|
if now <= int(x[1]):
|
||||||
|
# 处理memory
|
||||||
|
items = json.loads(x[2])
|
||||||
|
for i in items:
|
||||||
|
if i['id'] == 'memory':
|
||||||
|
c.execute('''select ticket from user where user_id=:a''', {
|
||||||
|
'a': user_id})
|
||||||
|
ticket = int(c.fetchone()[0])
|
||||||
|
ticket += int(i['amount'])
|
||||||
|
c.execute('''update user set ticket=:b where user_id=:a''', {
|
||||||
|
'a': user_id, 'b': ticket})
|
||||||
|
flag = True
|
||||||
|
else:
|
||||||
|
# 过期
|
||||||
|
flag = False
|
||||||
|
|
||||||
|
return flag
|
||||||
|
|
||||||
|
|
||||||
|
def claim_user_redeem(user_id, code):
|
||||||
|
# 处理兑换码,返回碎片数量和错误码
|
||||||
|
fragment = 0
|
||||||
|
error_code = 108
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute('''select * from redeem where code=:a''', {'a': code})
|
||||||
|
x = c.fetchone()
|
||||||
|
if not x:
|
||||||
|
return 0, 504
|
||||||
|
|
||||||
|
if x[2] == 0: # 一次性
|
||||||
|
c.execute(
|
||||||
|
'''select exists(select * from user_redeem where code=:a)''', {'a': code})
|
||||||
|
if c.fetchone() == (1,):
|
||||||
|
return 0, 505
|
||||||
|
elif x[2] == 1: # 每个玩家一次
|
||||||
|
c.execute('''select exists(select * from user_redeem where code=:a and user_id=:b)''',
|
||||||
|
{'a': code, 'b': user_id})
|
||||||
|
if c.fetchone() == (1,):
|
||||||
|
return 0, 506
|
||||||
|
|
||||||
|
c.execute('''insert into user_redeem values(:b,:a)''',
|
||||||
|
{'a': code, 'b': user_id})
|
||||||
|
|
||||||
|
items = json.loads(x[1])
|
||||||
|
for i in items:
|
||||||
|
if i['type'] == 'fragment':
|
||||||
|
fragment = i['amount']
|
||||||
|
if i['type'] == 'memory':
|
||||||
|
c.execute('''select ticket from user where user_id=:a''', {
|
||||||
|
'a': user_id})
|
||||||
|
ticket = int(c.fetchone()[0])
|
||||||
|
ticket += int(i['amount'])
|
||||||
|
c.execute('''update user set ticket=:b where user_id=:a''', {
|
||||||
|
'a': user_id, 'b': ticket})
|
||||||
|
error_code = None
|
||||||
|
|
||||||
|
return fragment, error_code
|
||||||
1525
latest version/server/arcscore.py
Normal file
1525
latest version/server/arcscore.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
import sqlite3
|
from server.sql import Connect
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
@@ -23,17 +23,17 @@ def get_world_name(file_dir='./database/map'):
|
|||||||
|
|
||||||
def get_world_info(map_id):
|
def get_world_info(map_id):
|
||||||
# 读取json文件内容,返回字典
|
# 读取json文件内容,返回字典
|
||||||
f = open('./database/map/'+map_id+'.json', 'r')
|
world_info = {}
|
||||||
|
with open('./database/map/'+map_id+'.json', 'r') as f:
|
||||||
world_info = json.load(f)
|
world_info = json.load(f)
|
||||||
f.close()
|
|
||||||
return world_info
|
return world_info
|
||||||
|
|
||||||
|
|
||||||
def get_user_world_info(user_id, map_id):
|
def get_user_world_info(user_id, map_id):
|
||||||
# 读取json文件内容,加上用户信息,返回字典
|
# 读取json文件内容,加上用户信息,返回字典
|
||||||
info = get_world_info(map_id)
|
info = get_world_info(map_id)
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
with Connect() as c:
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select * from user_world where map_id = :a and user_id = :b''',
|
c.execute('''select * from user_world where map_id = :a and user_id = :b''',
|
||||||
{'a': map_id, 'b': user_id})
|
{'a': map_id, 'b': user_id})
|
||||||
x = c.fetchone()
|
x = c.fetchone()
|
||||||
@@ -44,33 +44,28 @@ def get_user_world_info(user_id, map_id):
|
|||||||
else:
|
else:
|
||||||
c.execute('''insert into user_world values(:a,:b,0,0,0)''', {
|
c.execute('''insert into user_world values(:a,:b,0,0,0)''', {
|
||||||
'a': user_id, 'b': map_id})
|
'a': user_id, 'b': map_id})
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
def get_current_map(user_id):
|
def get_current_map(user_id):
|
||||||
# 得到user的当前图,返回字符串
|
# 得到user的当前图,返回字符串
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
re = ''
|
||||||
c = conn.cursor()
|
with Connect() as c:
|
||||||
c.execute('''select current_map from user where user_id = :a''',
|
c.execute('''select current_map from user where user_id = :a''',
|
||||||
{'a': user_id})
|
{'a': user_id})
|
||||||
x = c.fetchone()
|
x = c.fetchone()
|
||||||
re = ''
|
|
||||||
if x:
|
if x:
|
||||||
re = x[0]
|
re = x[0]
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return re
|
return re
|
||||||
|
|
||||||
|
|
||||||
def get_world_all(user_id):
|
def get_world_all(user_id):
|
||||||
# 读取所有地图信息并处理,返回字典列表
|
# 读取所有地图信息并处理,返回字典列表
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
worlds = get_world_name()
|
|
||||||
re = []
|
re = []
|
||||||
|
with Connect() as c:
|
||||||
|
worlds = get_world_name()
|
||||||
for map_id in worlds:
|
for map_id in worlds:
|
||||||
info = get_world_info(map_id)
|
info = get_world_info(map_id)
|
||||||
steps = info['steps']
|
steps = info['steps']
|
||||||
@@ -94,15 +89,13 @@ def get_world_all(user_id):
|
|||||||
|
|
||||||
re.append(info)
|
re.append(info)
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return re
|
return re
|
||||||
|
|
||||||
|
|
||||||
def get_user_world(user_id, map_id):
|
def get_user_world(user_id, map_id):
|
||||||
# 获取用户图信息,返回字典
|
# 获取用户图信息,返回字典
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
re = {}
|
||||||
c = conn.cursor()
|
with Connect() as c:
|
||||||
c.execute('''select * from user_world where map_id = :a and user_id = :b''',
|
c.execute('''select * from user_world where map_id = :a and user_id = :b''',
|
||||||
{'a': map_id, 'b': user_id})
|
{'a': map_id, 'b': user_id})
|
||||||
x = c.fetchone()
|
x = c.fetchone()
|
||||||
@@ -121,27 +114,20 @@ def get_user_world(user_id, map_id):
|
|||||||
c.execute('''insert into user_world values(:a,:b,0,0,0)''', {
|
c.execute('''insert into user_world values(:a,:b,0,0,0)''', {
|
||||||
'a': user_id, 'b': map_id})
|
'a': user_id, 'b': map_id})
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return re
|
return re
|
||||||
|
|
||||||
|
|
||||||
def change_user_current_map(user_id, map_id):
|
def change_user_current_map(user_id, map_id):
|
||||||
# 改变用户当前图
|
# 改变用户当前图
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
with Connect() as c:
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''update user set current_map = :a where user_id=:b''', {
|
c.execute('''update user set current_map = :a where user_id=:b''', {
|
||||||
'a': map_id, 'b': user_id})
|
'a': map_id, 'b': user_id})
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def play_world_song(user_id, args):
|
def play_world_song(user_id, args):
|
||||||
# 声明是世界模式的打歌,并且记录加成信息
|
# 声明是世界模式的打歌,并且记录加成信息
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
with Connect() as c:
|
||||||
c = conn.cursor()
|
|
||||||
|
|
||||||
stamina_multiply = 1
|
stamina_multiply = 1
|
||||||
fragment_multiply = 100
|
fragment_multiply = 100
|
||||||
prog_boost_multiply = 0
|
prog_boost_multiply = 0
|
||||||
@@ -150,15 +136,17 @@ def play_world_song(user_id, args):
|
|||||||
if 'fragment_multiply' in args:
|
if 'fragment_multiply' in args:
|
||||||
fragment_multiply = int(args['fragment_multiply'])
|
fragment_multiply = int(args['fragment_multiply'])
|
||||||
if 'prog_boost_multiply' in args:
|
if 'prog_boost_multiply' in args:
|
||||||
prog_boost_multiply = int(args['prog_boost_multiply'])
|
c.execute('''select prog_boost from user where user_id=:a''', {
|
||||||
|
'a': user_id})
|
||||||
|
x = c.fetchone()
|
||||||
|
if x and x[0] == 1:
|
||||||
|
prog_boost_multiply = 300
|
||||||
|
|
||||||
c.execute('''delete from world_songplay where user_id=:a and song_id=:b and difficulty=:c''', {
|
c.execute('''delete from world_songplay where user_id=:a and song_id=:b and difficulty=:c''', {
|
||||||
'a': user_id, 'b': args['song_id'], 'c': args['difficulty']})
|
'a': user_id, 'b': args['song_id'], 'c': args['difficulty']})
|
||||||
c.execute('''insert into world_songplay values(:a,:b,:c,:d,:e,:f)''', {
|
c.execute('''insert into world_songplay values(:a,:b,:c,:d,:e,:f)''', {
|
||||||
'a': user_id, 'b': args['song_id'], 'c': args['difficulty'], 'd': stamina_multiply, 'e': fragment_multiply, 'f': prog_boost_multiply})
|
'a': user_id, 'b': args['song_id'], 'c': args['difficulty'], 'd': stamina_multiply, 'e': fragment_multiply, 'f': prog_boost_multiply})
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
181
latest version/server/auth.py
Normal file
181
latest version/server/auth.py
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
import hashlib
|
||||||
|
import time
|
||||||
|
import server.arcworld
|
||||||
|
from server.sql import Connect
|
||||||
|
import functools
|
||||||
|
from setting import Config
|
||||||
|
|
||||||
|
|
||||||
|
def arc_login(name: str, password: str, device_id: str): # 登录判断
|
||||||
|
# 查询数据库中的user表,验证账号密码,返回并记录token,多返回个error code
|
||||||
|
# token采用user_id和时间戳连接后hash生成(真的是瞎想的,没用bear)
|
||||||
|
# 密码和token的加密方式为 SHA-256
|
||||||
|
|
||||||
|
error_code = 108
|
||||||
|
token = None
|
||||||
|
with Connect() as c:
|
||||||
|
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
||||||
|
c.execute('''select user_id, password from user where name = :name''', {
|
||||||
|
'name': name})
|
||||||
|
x = c.fetchone()
|
||||||
|
if x is not None:
|
||||||
|
if x[1] == '':
|
||||||
|
# 账号封禁
|
||||||
|
error_code = 106
|
||||||
|
elif x[1] == hash_pwd:
|
||||||
|
user_id = str(x[0])
|
||||||
|
now = int(time.time() * 1000)
|
||||||
|
token = hashlib.sha256(
|
||||||
|
(user_id + str(now)).encode("utf8")).hexdigest()
|
||||||
|
c.execute(
|
||||||
|
'''select login_device from login where user_id = :user_id''', {"user_id": user_id})
|
||||||
|
y = c.fetchall()
|
||||||
|
if y:
|
||||||
|
device_list = []
|
||||||
|
for i in y:
|
||||||
|
if i[0]:
|
||||||
|
device_list.append(i[0])
|
||||||
|
else:
|
||||||
|
device_list.append('')
|
||||||
|
|
||||||
|
should_delete_num = len(
|
||||||
|
device_list) + 1 - Config.LOGIN_DEVICE_NUMBER_LIMIT
|
||||||
|
|
||||||
|
if not Config.ALLOW_LOGIN_SAME_DEVICE:
|
||||||
|
if device_id in device_list: # 对相同设备进行删除
|
||||||
|
c.execute('''delete from login where login_device=:a''', {
|
||||||
|
'a': device_id})
|
||||||
|
should_delete_num = len(
|
||||||
|
device_list) + 1 - device_list.count(device_id) - Config.LOGIN_DEVICE_NUMBER_LIMIT
|
||||||
|
|
||||||
|
if should_delete_num >= 1: # 删掉多余token
|
||||||
|
c.execute('''delete from login where rowid in (select rowid from login where user_id=:user_id limit :a);''',
|
||||||
|
{'user_id': user_id, 'a': int(should_delete_num)})
|
||||||
|
|
||||||
|
c.execute('''insert into login(access_token, user_id, login_device) values(:access_token, :user_id, :device_id)''', {
|
||||||
|
'user_id': user_id, 'access_token': token, 'device_id': device_id})
|
||||||
|
error_code = None
|
||||||
|
else:
|
||||||
|
# 密码错误
|
||||||
|
error_code = 104
|
||||||
|
else:
|
||||||
|
# 用户名错误
|
||||||
|
error_code = 104
|
||||||
|
|
||||||
|
return token, error_code
|
||||||
|
|
||||||
|
|
||||||
|
def arc_register(name: str, password: str, device_id: str): # 注册
|
||||||
|
# 账号注册,只记录hash密码和用户名,生成user_id和user_code,自动登录返回token
|
||||||
|
# token和密码的处理同登录部分
|
||||||
|
|
||||||
|
def build_user_code(c):
|
||||||
|
# 生成9位的user_code,用的自然是随机
|
||||||
|
import random
|
||||||
|
flag = True
|
||||||
|
while flag:
|
||||||
|
user_code = ''.join([str(random.randint(0, 9)) for i in range(9)])
|
||||||
|
c.execute('''select exists(select * from user where user_code = :user_code)''',
|
||||||
|
{'user_code': user_code})
|
||||||
|
if c.fetchone() == (0,):
|
||||||
|
flag = False
|
||||||
|
return user_code
|
||||||
|
|
||||||
|
def build_user_id(c):
|
||||||
|
# 生成user_id,往后加1
|
||||||
|
c.execute('''select max(user_id) from user''')
|
||||||
|
x = c.fetchone()
|
||||||
|
if x[0] is not None:
|
||||||
|
return x[0] + 1
|
||||||
|
else:
|
||||||
|
return 2000001
|
||||||
|
|
||||||
|
def insert_user_char(c, user_id):
|
||||||
|
# 为用户添加所有可用角色
|
||||||
|
c.execute('''select * from character''')
|
||||||
|
x = c.fetchall()
|
||||||
|
if x != []:
|
||||||
|
for i in x:
|
||||||
|
c.execute('''insert into user_char values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o)''', {
|
||||||
|
'a': user_id, 'b': i[0], 'c': i[2], 'd': i[3], 'e': i[4], 'f': i[5], 'g': i[6], 'h': i[7], 'i': i[8], 'j': i[9], 'k': i[10], 'l': i[11], 'm': i[12], 'n': i[14], 'o': i[15]})
|
||||||
|
|
||||||
|
user_id = None
|
||||||
|
token = None
|
||||||
|
error_code = 108
|
||||||
|
with Connect() as c:
|
||||||
|
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
||||||
|
c.execute(
|
||||||
|
'''select exists(select * from user where name = :name)''', {'name': name})
|
||||||
|
if c.fetchone() == (0,):
|
||||||
|
user_code = build_user_code(c)
|
||||||
|
user_id = build_user_id(c)
|
||||||
|
now = int(time.time() * 1000)
|
||||||
|
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
||||||
|
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled, current_map, ticket)
|
||||||
|
values(:user_id, :name, :password, :join_date, :user_code, 0, 0, 0, 0, 0, 0, -1, 0, '', 0)
|
||||||
|
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
|
||||||
|
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
||||||
|
'user_id': user_id})
|
||||||
|
|
||||||
|
token = hashlib.sha256(
|
||||||
|
(str(user_id) + str(now)).encode("utf8")).hexdigest()
|
||||||
|
c.execute('''insert into login(access_token, user_id, login_device) values(:access_token, :user_id, :device_id)''', {
|
||||||
|
'user_id': user_id, 'access_token': token, 'device_id': device_id})
|
||||||
|
|
||||||
|
insert_user_char(c, user_id)
|
||||||
|
error_code = 0
|
||||||
|
else:
|
||||||
|
error_code = 101
|
||||||
|
|
||||||
|
return user_id, token, error_code
|
||||||
|
|
||||||
|
|
||||||
|
def token_get_id(token: str):
|
||||||
|
# 用token获取id,没有考虑不同用户token相同情况,说不定会有bug
|
||||||
|
|
||||||
|
user_id = None
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute('''select user_id from login where access_token = :token''', {
|
||||||
|
'token': token})
|
||||||
|
x = c.fetchone()
|
||||||
|
if x is not None:
|
||||||
|
user_id = x[0]
|
||||||
|
|
||||||
|
return user_id
|
||||||
|
|
||||||
|
|
||||||
|
def code_get_id(user_code):
|
||||||
|
# 用user_code获取id
|
||||||
|
|
||||||
|
user_id = None
|
||||||
|
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute('''select user_id from user where user_code = :a''',
|
||||||
|
{'a': user_code})
|
||||||
|
x = c.fetchone()
|
||||||
|
if x is not None:
|
||||||
|
user_id = x[0]
|
||||||
|
|
||||||
|
return user_id
|
||||||
|
|
||||||
|
|
||||||
|
def auth_required(request):
|
||||||
|
# arcaea登录验证,写成了修饰器
|
||||||
|
def decorator(view):
|
||||||
|
@functools.wraps(view)
|
||||||
|
def wrapped_view(*args, **kwargs):
|
||||||
|
|
||||||
|
user_id = None
|
||||||
|
with Connect() as c:
|
||||||
|
headers = request.headers
|
||||||
|
token = headers['Authorization']
|
||||||
|
token = token[7:]
|
||||||
|
user_id = token_get_id(token)
|
||||||
|
|
||||||
|
if user_id is not None:
|
||||||
|
return view(user_id, *args, **kwargs)
|
||||||
|
else:
|
||||||
|
return '''{"success":false,"error_code":108}'''
|
||||||
|
|
||||||
|
return wrapped_view
|
||||||
|
return decorator
|
||||||
355
latest version/server/info.py
Normal file
355
latest version/server/info.py
Normal file
@@ -0,0 +1,355 @@
|
|||||||
|
from server.sql import Connect
|
||||||
|
import server.arcworld
|
||||||
|
import server.arcpurchase
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def int2b(x):
|
||||||
|
# int与布尔值转换
|
||||||
|
if x is None or x == 0:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_recent_score(c, user_id):
|
||||||
|
# 得到用户最近一次的成绩,返回列表
|
||||||
|
c.execute('''select * from user where user_id = :x''', {'x': user_id})
|
||||||
|
x = c.fetchone()
|
||||||
|
if x is not None:
|
||||||
|
if x[11] is not None:
|
||||||
|
c.execute('''select best_clear_type from best_score where user_id=:u and song_id=:s and difficulty=:d''', {
|
||||||
|
'u': user_id, 's': x[11], 'd': x[12]})
|
||||||
|
y = c.fetchone()
|
||||||
|
if y is not None:
|
||||||
|
best_clear_type = y[0]
|
||||||
|
else:
|
||||||
|
best_clear_type = x[21]
|
||||||
|
|
||||||
|
return [{
|
||||||
|
"rating": x[22],
|
||||||
|
"modifier": x[19],
|
||||||
|
"time_played": x[20],
|
||||||
|
"health": x[18],
|
||||||
|
"best_clear_type": best_clear_type,
|
||||||
|
"clear_type": x[21],
|
||||||
|
"miss_count": x[17],
|
||||||
|
"near_count": x[16],
|
||||||
|
"perfect_count": x[15],
|
||||||
|
"shiny_perfect_count": x[14],
|
||||||
|
"score": x[13],
|
||||||
|
"difficulty": x[12],
|
||||||
|
"song_id": x[11]
|
||||||
|
}]
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_character(c, user_id):
|
||||||
|
# 得到用户拥有的角色列表,返回列表
|
||||||
|
c.execute('''select * from user_char where user_id = :user_id''',
|
||||||
|
{'user_id': user_id})
|
||||||
|
x = c.fetchall()
|
||||||
|
if x != []:
|
||||||
|
s = []
|
||||||
|
for i in x:
|
||||||
|
char_name = ''
|
||||||
|
c.execute(
|
||||||
|
'''select name from character where character_id = :x''', {'x': i[1]})
|
||||||
|
y = c.fetchone()
|
||||||
|
if y is not None:
|
||||||
|
char_name = y[0]
|
||||||
|
char = {
|
||||||
|
"is_uncapped_override": int2b(i[14]),
|
||||||
|
"is_uncapped": int2b(i[13]),
|
||||||
|
"uncap_cores": [],
|
||||||
|
"char_type": i[12],
|
||||||
|
"skill_id_uncap": i[11],
|
||||||
|
"skill_requires_uncap": int2b(i[10]),
|
||||||
|
"skill_unlock_level": i[9],
|
||||||
|
"skill_id": i[8],
|
||||||
|
"overdrive": i[7],
|
||||||
|
"prog": i[6],
|
||||||
|
"frag": i[5],
|
||||||
|
"level_exp": i[4],
|
||||||
|
"exp": i[3],
|
||||||
|
"level": i[2],
|
||||||
|
"name": char_name,
|
||||||
|
"character_id": i[1]
|
||||||
|
}
|
||||||
|
if i[1] == 21:
|
||||||
|
char["voice"] = [0, 1, 2, 3, 100, 1000, 1001]
|
||||||
|
s.append(char)
|
||||||
|
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_friend(c, user_id):
|
||||||
|
# 得到用户的朋友列表,返回列表
|
||||||
|
c.execute('''select user_id_other from friend where user_id_me = :user_id''', {
|
||||||
|
'user_id': user_id})
|
||||||
|
x = c.fetchall()
|
||||||
|
s = []
|
||||||
|
if x != [] and x[0][0] is not None:
|
||||||
|
|
||||||
|
for i in x:
|
||||||
|
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
||||||
|
{'x': i[0], 'y': user_id})
|
||||||
|
if c.fetchone() == (1,):
|
||||||
|
is_mutual = True
|
||||||
|
else:
|
||||||
|
is_mutual = False
|
||||||
|
|
||||||
|
c.execute('''select * from user where user_id = :x''', {'x': i[0]})
|
||||||
|
y = c.fetchone()
|
||||||
|
if y is not None:
|
||||||
|
character = y[6]
|
||||||
|
is_char_uncapped = int2b(y[8])
|
||||||
|
is_char_uncapped_override = int2b(y[9])
|
||||||
|
if y[23] != -1:
|
||||||
|
character = y[23]
|
||||||
|
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id=:a and character_id=:b''', {
|
||||||
|
'a': i[0], 'b': character})
|
||||||
|
z = c.fetchone()
|
||||||
|
if z:
|
||||||
|
is_char_uncapped = int2b(z[0])
|
||||||
|
is_char_uncapped_override = int2b(z[1])
|
||||||
|
|
||||||
|
s.append({
|
||||||
|
"is_mutual": is_mutual,
|
||||||
|
"is_char_uncapped_override": is_char_uncapped_override,
|
||||||
|
"is_char_uncapped": is_char_uncapped,
|
||||||
|
"is_skill_sealed": int2b(y[7]),
|
||||||
|
"rating": y[5],
|
||||||
|
"join_date": int(y[3]),
|
||||||
|
"character": character,
|
||||||
|
"recent_score": get_recent_score(c, i[0]),
|
||||||
|
"name": y[1],
|
||||||
|
"user_id": i[0]
|
||||||
|
})
|
||||||
|
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_singles(c, user_id):
|
||||||
|
# 得到用户的单曲,返回列表
|
||||||
|
c.execute('''select * from user_item where user_id = :user_id and type = "single"''',
|
||||||
|
{'user_id': user_id})
|
||||||
|
x = c.fetchall()
|
||||||
|
if not x:
|
||||||
|
return []
|
||||||
|
|
||||||
|
re = []
|
||||||
|
for i in x:
|
||||||
|
re.append(i[1])
|
||||||
|
return re
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_packs(c, user_id):
|
||||||
|
# 得到用户的曲包,返回列表
|
||||||
|
c.execute('''select * from user_item where user_id = :user_id and type = "pack"''',
|
||||||
|
{'user_id': user_id})
|
||||||
|
x = c.fetchall()
|
||||||
|
if not x:
|
||||||
|
return []
|
||||||
|
|
||||||
|
re = []
|
||||||
|
for i in x:
|
||||||
|
re.append(i[1])
|
||||||
|
return re
|
||||||
|
|
||||||
|
|
||||||
|
def get_value_0(c, user_id):
|
||||||
|
# 构造value id=0的数据,返回字典
|
||||||
|
c.execute('''select * from user where user_id = :x''', {'x': user_id})
|
||||||
|
x = c.fetchone()
|
||||||
|
r = {}
|
||||||
|
if x is not None:
|
||||||
|
user_character = get_user_character(c, user_id)
|
||||||
|
characters = []
|
||||||
|
for i in user_character:
|
||||||
|
characters.append(i['character_id'])
|
||||||
|
prog_boost = 0
|
||||||
|
if x[27] and x[27] != 0:
|
||||||
|
prog_boost = 300
|
||||||
|
|
||||||
|
r = {"is_aprilfools": False,
|
||||||
|
"curr_available_maps": [],
|
||||||
|
"character_stats": user_character,
|
||||||
|
"friends": get_user_friend(c, user_id),
|
||||||
|
"settings": {
|
||||||
|
"favorite_character": x[23],
|
||||||
|
"is_hide_rating": int2b(x[10]),
|
||||||
|
"max_stamina_notification_enabled": int2b(x[24])
|
||||||
|
},
|
||||||
|
"user_id": user_id,
|
||||||
|
"name": x[1],
|
||||||
|
"user_code": x[4],
|
||||||
|
"display_name": x[1],
|
||||||
|
"ticket": x[26],
|
||||||
|
"character": x[6],
|
||||||
|
"is_locked_name_duplicate": False,
|
||||||
|
"is_skill_sealed": int2b(x[7]),
|
||||||
|
"current_map": x[25],
|
||||||
|
"prog_boost": prog_boost,
|
||||||
|
"next_fragstam_ts": -1,
|
||||||
|
"max_stamina_ts": 1586274871917,
|
||||||
|
"stamina": 12,
|
||||||
|
"world_unlocks": ["scenery_chap1", "scenery_chap2", "scenery_chap3", "scenery_chap4", "scenery_chap5"],
|
||||||
|
"world_songs": ["babaroque", "shadesoflight", "kanagawa", "lucifer", "anokumene", "ignotus", "rabbitintheblackroom", "qualia", "redandblue", "bookmaker", "darakunosono", "espebranch", "blacklotus", "givemeanightmare", "vividtheory", "onefr", "gekka", "vexaria3", "infinityheaven3", "fairytale3", "goodtek3", "suomi", "rugie", "faintlight", "harutopia", "goodtek", "dreaminattraction", "syro", "diode", "freefall", "grimheart", "blaster", "cyberneciacatharsis", "monochromeprincess", "revixy", "vector", "supernova", "nhelv", "purgatorium3", "dement3", "crossover", "guardina", "axiumcrisis", "worldvanquisher", "sheriruth", "pragmatism", "gloryroad", "etherstrike", "corpssansorganes", "lostdesire", "blrink", "essenceoftwilight", "lapis", "solitarydream", "lumia3", "purpleverse", "moonheart3", "glow", "enchantedlove", "take"],
|
||||||
|
"singles": get_user_singles(c, user_id),
|
||||||
|
"packs": get_user_packs(c, user_id),
|
||||||
|
"characters": characters,
|
||||||
|
"cores": [],
|
||||||
|
"recent_score": get_recent_score(c, user_id),
|
||||||
|
"max_friend": 50,
|
||||||
|
"rating": x[5],
|
||||||
|
"join_date": int(x[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def arc_aggregate_small(user_id):
|
||||||
|
# 返回用户数据
|
||||||
|
r = {"success": False}
|
||||||
|
with Connect() as c:
|
||||||
|
r = {"success": True,
|
||||||
|
"value": [{
|
||||||
|
"id": 0,
|
||||||
|
"value": get_value_0(c, user_id)
|
||||||
|
}]}
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def arc_aggregate_big(user_id):
|
||||||
|
# 返回用户数据和地图歌曲信息
|
||||||
|
r = {"success": False}
|
||||||
|
with Connect() as c:
|
||||||
|
r = {"success": True,
|
||||||
|
"value": [{
|
||||||
|
"id": 0,
|
||||||
|
"value": get_value_0(c, user_id)
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"value": server.arcpurchase.get_item(c, 'pack')
|
||||||
|
}, {
|
||||||
|
"id": 2,
|
||||||
|
"value": {}
|
||||||
|
}, {
|
||||||
|
"id": 3,
|
||||||
|
"value": {
|
||||||
|
"max_stamina": 12,
|
||||||
|
"stamina_recover_tick": 1800000,
|
||||||
|
"core_exp": 250,
|
||||||
|
"curr_ts": int(time.time())*1000,
|
||||||
|
"level_steps": [{
|
||||||
|
"level": 1,
|
||||||
|
"level_exp": 0
|
||||||
|
}, {
|
||||||
|
"level": 2,
|
||||||
|
"level_exp": 50
|
||||||
|
}, {
|
||||||
|
"level": 3,
|
||||||
|
"level_exp": 100
|
||||||
|
}, {
|
||||||
|
"level": 4,
|
||||||
|
"level_exp": 150
|
||||||
|
}, {
|
||||||
|
"level": 5,
|
||||||
|
"level_exp": 200
|
||||||
|
}, {
|
||||||
|
"level": 6,
|
||||||
|
"level_exp": 300
|
||||||
|
}, {
|
||||||
|
"level": 7,
|
||||||
|
"level_exp": 450
|
||||||
|
}, {
|
||||||
|
"level": 8,
|
||||||
|
"level_exp": 650
|
||||||
|
}, {
|
||||||
|
"level": 9,
|
||||||
|
"level_exp": 900
|
||||||
|
}, {
|
||||||
|
"level": 10,
|
||||||
|
"level_exp": 1200
|
||||||
|
}, {
|
||||||
|
"level": 11,
|
||||||
|
"level_exp": 1600
|
||||||
|
}, {
|
||||||
|
"level": 12,
|
||||||
|
"level_exp": 2100
|
||||||
|
}, {
|
||||||
|
"level": 13,
|
||||||
|
"level_exp": 2700
|
||||||
|
}, {
|
||||||
|
"level": 14,
|
||||||
|
"level_exp": 3400
|
||||||
|
}, {
|
||||||
|
"level": 15,
|
||||||
|
"level_exp": 4200
|
||||||
|
}, {
|
||||||
|
"level": 16,
|
||||||
|
"level_exp": 5100
|
||||||
|
}, {
|
||||||
|
"level": 17,
|
||||||
|
"level_exp": 6100
|
||||||
|
}, {
|
||||||
|
"level": 18,
|
||||||
|
"level_exp": 7200
|
||||||
|
}, {
|
||||||
|
"level": 19,
|
||||||
|
"level_exp": 8500
|
||||||
|
}, {
|
||||||
|
"level": 20,
|
||||||
|
"level_exp": 10000
|
||||||
|
}, {
|
||||||
|
"level": 21,
|
||||||
|
"level_exp": 11500
|
||||||
|
}, {
|
||||||
|
"level": 22,
|
||||||
|
"level_exp": 13000
|
||||||
|
}, {
|
||||||
|
"level": 23,
|
||||||
|
"level_exp": 14500
|
||||||
|
}, {
|
||||||
|
"level": 24,
|
||||||
|
"level_exp": 16000
|
||||||
|
}, {
|
||||||
|
"level": 25,
|
||||||
|
"level_exp": 17500
|
||||||
|
}, {
|
||||||
|
"level": 26,
|
||||||
|
"level_exp": 19000
|
||||||
|
}, {
|
||||||
|
"level": 27,
|
||||||
|
"level_exp": 20500
|
||||||
|
}, {
|
||||||
|
"level": 28,
|
||||||
|
"level_exp": 22000
|
||||||
|
}, {
|
||||||
|
"level": 29,
|
||||||
|
"level_exp": 23500
|
||||||
|
}, {
|
||||||
|
"level": 30,
|
||||||
|
"level_exp": 25000
|
||||||
|
}],
|
||||||
|
"world_ranking_enabled": False,
|
||||||
|
"is_byd_chapter_unlocked": True
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"id": 4,
|
||||||
|
"value": server.arcpurchase.get_user_present(c, user_id)
|
||||||
|
}, {
|
||||||
|
"id": 5,
|
||||||
|
"value": {
|
||||||
|
"current_map": server.arcworld.get_current_map(user_id),
|
||||||
|
"user_id": user_id,
|
||||||
|
"maps": server.arcworld.get_world_all(user_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
|
||||||
|
return r
|
||||||
142
latest version/server/setme.py
Normal file
142
latest version/server/setme.py
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
from server.sql import Connect
|
||||||
|
import server.info
|
||||||
|
|
||||||
|
|
||||||
|
def b2int(x):
|
||||||
|
# int与布尔值转换
|
||||||
|
if x:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def int2b(x):
|
||||||
|
# int与布尔值转换
|
||||||
|
if x is None or x == 0:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def change_char(user_id, character_id, skill_sealed):
|
||||||
|
# 角色改变,包括技能封印的改变,返回成功与否的布尔值
|
||||||
|
re = False
|
||||||
|
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
||||||
|
{'a': user_id, 'b': character_id})
|
||||||
|
x = c.fetchone()
|
||||||
|
if x is not None:
|
||||||
|
if skill_sealed == 'false':
|
||||||
|
skill_sealed = False
|
||||||
|
else:
|
||||||
|
skill_sealed = True
|
||||||
|
c.execute('''update user set is_skill_sealed = :a, character_id = :b, is_char_uncapped = :c, is_char_uncapped_override = :d where user_id = :e''', {
|
||||||
|
'a': b2int(skill_sealed), 'b': character_id, 'c': x[0], 'd': x[1], 'e': user_id})
|
||||||
|
|
||||||
|
re = True
|
||||||
|
|
||||||
|
return re
|
||||||
|
|
||||||
|
|
||||||
|
def change_char_uncap(user_id, character_id):
|
||||||
|
# 角色觉醒改变,返回字典
|
||||||
|
r = None
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
||||||
|
{'a': user_id, 'b': character_id})
|
||||||
|
x = c.fetchone()
|
||||||
|
|
||||||
|
if x is not None and x[0] == 1:
|
||||||
|
c.execute('''update user set is_char_uncapped_override = :a where user_id = :b''', {
|
||||||
|
'a': b2int(x[1] == 0), 'b': user_id})
|
||||||
|
c.execute('''update user_char set is_uncapped_override = :a where user_id = :b and character_id = :c''', {
|
||||||
|
'a': b2int(x[1] == 0), 'b': user_id, 'c': character_id})
|
||||||
|
c.execute('''select * from user_char where user_id = :a and character_id = :b''',
|
||||||
|
{'a': user_id, 'b': character_id})
|
||||||
|
y = c.fetchone()
|
||||||
|
c.execute(
|
||||||
|
'''select name from character where character_id = :x''', {'x': y[1]})
|
||||||
|
z = c.fetchone()
|
||||||
|
if z is not None:
|
||||||
|
char_name = z[0]
|
||||||
|
if y is not None:
|
||||||
|
r = {
|
||||||
|
"is_uncapped_override": int2b(y[14]),
|
||||||
|
"is_uncapped": int2b(y[13]),
|
||||||
|
"uncap_cores": [],
|
||||||
|
"char_type": y[12],
|
||||||
|
"skill_id_uncap": y[11],
|
||||||
|
"skill_requires_uncap": int2b(y[10]),
|
||||||
|
"skill_unlock_level": y[9],
|
||||||
|
"skill_id": y[8],
|
||||||
|
"overdrive": y[7],
|
||||||
|
"prog": y[6],
|
||||||
|
"frag": y[5],
|
||||||
|
"level_exp": y[4],
|
||||||
|
"exp": y[3],
|
||||||
|
"level": y[2],
|
||||||
|
"name": char_name,
|
||||||
|
"character_id": y[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def arc_sys_set(user_id, value, set_arg):
|
||||||
|
# 三个设置,PTT隐藏、体力满通知、最爱角色,无返回
|
||||||
|
with Connect() as c:
|
||||||
|
if 'favorite_character' in set_arg:
|
||||||
|
value = int(value)
|
||||||
|
c.execute('''update user set favorite_character = :a where user_id = :b''', {
|
||||||
|
'a': value, 'b': user_id})
|
||||||
|
|
||||||
|
else:
|
||||||
|
if value == 'false':
|
||||||
|
value = False
|
||||||
|
else:
|
||||||
|
value = True
|
||||||
|
|
||||||
|
if 'is_hide_rating' in set_arg:
|
||||||
|
c.execute('''update user set is_hide_rating = :a where user_id = :b''', {
|
||||||
|
'a': b2int(value), 'b': user_id})
|
||||||
|
if 'max_stamina_notification_enabled' in set_arg:
|
||||||
|
c.execute('''update user set max_stamina_notification_enabled = :a where user_id = :b''', {
|
||||||
|
'a': b2int(value), 'b': user_id})
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def arc_add_friend(user_id, friend_id):
|
||||||
|
# 加好友,返回好友列表,或者是错误码602、604
|
||||||
|
if user_id == friend_id:
|
||||||
|
return 604
|
||||||
|
|
||||||
|
r = None
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
||||||
|
{'x': user_id, 'y': friend_id})
|
||||||
|
if c.fetchone() == (0,):
|
||||||
|
c.execute('''insert into friend values(:a, :b)''',
|
||||||
|
{'a': user_id, 'b': friend_id})
|
||||||
|
r = server.info.get_user_friend(c, user_id)
|
||||||
|
else:
|
||||||
|
r = 602
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def arc_delete_friend(user_id, friend_id):
|
||||||
|
# 删好友,返回好友列表
|
||||||
|
r = None
|
||||||
|
with Connect() as c:
|
||||||
|
|
||||||
|
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
||||||
|
{'x': user_id, 'y': friend_id})
|
||||||
|
if c.fetchone() == (1,):
|
||||||
|
c.execute('''delete from friend where user_id_me = :x and user_id_other = :y''',
|
||||||
|
{'x': user_id, 'y': friend_id})
|
||||||
|
|
||||||
|
r = server.info.get_user_friend(c, user_id)
|
||||||
|
|
||||||
|
return r
|
||||||
31
latest version/server/sql.py
Normal file
31
latest version/server/sql.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import sqlite3
|
||||||
|
from flask import current_app
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
|
class Connect():
|
||||||
|
# 数据库连接类,上下文管理
|
||||||
|
|
||||||
|
def __init__(self, file_path='./database/arcaea_database.db'):
|
||||||
|
"""
|
||||||
|
数据库连接,默认连接arcaea_database.db
|
||||||
|
接受:文件路径
|
||||||
|
返回:sqlite3连接操作对象
|
||||||
|
"""
|
||||||
|
self.file_path = file_path
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.conn = sqlite3.connect(self.file_path)
|
||||||
|
self.c = self.conn.cursor()
|
||||||
|
return self.c
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
if self.conn:
|
||||||
|
self.conn.commit()
|
||||||
|
self.conn.close()
|
||||||
|
|
||||||
|
if exc_type is not None:
|
||||||
|
current_app.logger.error(
|
||||||
|
traceback.format_exception(exc_type, exc_val, exc_tb))
|
||||||
|
|
||||||
|
return True
|
||||||
77
latest version/setting.py
Normal file
77
latest version/setting.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
class Config():
|
||||||
|
'''
|
||||||
|
This is the setting file. You can change some parameters here.
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
主机的地址和端口号
|
||||||
|
Host and port of your server
|
||||||
|
'''
|
||||||
|
HOST = '192.168.1.105'
|
||||||
|
PORT = '80'
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
Web后台管理页面的用户名和密码
|
||||||
|
Username and password of web background management page
|
||||||
|
'''
|
||||||
|
USERNAME = 'admin'
|
||||||
|
PASSWORD = 'admin'
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
Web后台管理页面的session秘钥,如果不知道是什么,请不要修改
|
||||||
|
Session key of web background management page
|
||||||
|
If you don't know what it is, please don't modify it.
|
||||||
|
'''
|
||||||
|
SECRET_KEY = '1145141919810'
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
玩家歌曲下载的24小时次数限制,每个文件算一次
|
||||||
|
Player's song download limit times in 24 hours, once per file
|
||||||
|
'''
|
||||||
|
DOWNLOAD_TIMES_LIMIT = 3000
|
||||||
|
'''
|
||||||
|
歌曲下载链接的有效时长,单位:秒
|
||||||
|
Effective duration of song download link, unit: seconds
|
||||||
|
'''
|
||||||
|
DOWNLOAD_TIME_GAP_LIMIT = 1000
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
Arcaea登录的最大允许设备数量,最小值为1
|
||||||
|
The maximum number of devices allowed to log in Arcaea, minimum: 1
|
||||||
|
'''
|
||||||
|
LOGIN_DEVICE_NUMBER_LIMIT = 1
|
||||||
|
'''
|
||||||
|
是否允许同设备多应用共存登录
|
||||||
|
If logging in from multiple applications on the same device is allowed
|
||||||
|
'''
|
||||||
|
ALLOW_LOGIN_SAME_DEVICE = False
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
是否记录详细的服务器日志
|
||||||
|
If recording detailed server logs is enabled
|
||||||
|
'''
|
||||||
|
ALLOW_LOG_INFO = False
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
'''
|
||||||
BIN
latest version/static/favicon.ico
Normal file
BIN
latest version/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -210,8 +210,28 @@ input[type=submit] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer{
|
.footer {
|
||||||
font-size: 0.5em;
|
font-size: 0.5em;
|
||||||
color: grey;
|
color: grey;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.char-item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.char-name {
|
||||||
|
font-size: 1.3em;
|
||||||
|
font-weight: bold;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.char-id {
|
||||||
|
font-size: 1em;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.char-num {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
59
latest version/templates/web/allchar.html
Normal file
59
latest version/templates/web/allchar.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}All characters{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% if posts %}<br />
|
||||||
|
{% for char in posts %}
|
||||||
|
|
||||||
|
<div class="char-item">
|
||||||
|
<span>Id: </span>
|
||||||
|
<span class="char-id">{{char['character_id']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Name: </span>
|
||||||
|
<span class="char-name">{{char['name']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Level: </span>
|
||||||
|
<span class="char-num">{{char['level']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Frag: </span>
|
||||||
|
<span class="char-num">{{char['frag']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Prog: </span>
|
||||||
|
<span class="char-num">{{char['prog']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Overdrive: </span>
|
||||||
|
<span class="char-num">{{char['overdrive']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Skill id: </span>
|
||||||
|
<span class="char-num">{{char['skill_id']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Uncapped skill id: </span>
|
||||||
|
<span class="char-num">{{char['skill_id_uncap']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Is uncapped: </span>
|
||||||
|
<span class="char-num">{{char['is_uncapped']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% if not loop.last %}
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<br />
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
51
latest version/templates/web/allitem.html
Normal file
51
latest version/templates/web/allitem.html
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}All items{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% if posts %}<br />
|
||||||
|
{% for item in posts %}
|
||||||
|
|
||||||
|
<div class="char-item">
|
||||||
|
<span>Id: </span>
|
||||||
|
<span class="name">{{item['item_id']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Type: </span>
|
||||||
|
<span class="char-num">{{item['type']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Is available: </span>
|
||||||
|
<span class="char-num">{{item['is_available']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Price: </span>
|
||||||
|
<span class="char-num">{{item['price']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Original price: </span>
|
||||||
|
<span class="char-num">{{item['orig_price']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Discount from: </span>
|
||||||
|
<span class="char-num">{{item['discount_from']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Discount to: </span>
|
||||||
|
<span class="char-num">{{item['discount_to']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% if not loop.last %}
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<br />
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
@@ -11,9 +11,13 @@
|
|||||||
<div class="name">{{user['name']}}
|
<div class="name">{{user['name']}}
|
||||||
<span class="rank">UID: {{user['user_id']}}</span>
|
<span class="rank">UID: {{user['user_id']}}</span>
|
||||||
<span class="rank">User code: {{user['user_code']}}</span>
|
<span class="rank">User code: {{user['user_code']}}</span>
|
||||||
|
{% if user['ban_flag'] %}
|
||||||
|
<span class="rank">Banned</span>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="join-date">注册于 Registered in: {{user['join_date']}}</div>
|
<div class="join-date">注册于 Registered in: {{user['join_date']}}</div>
|
||||||
<div class="ptt">PTT: {{user['rating_ptt']//100 ~ '.' ~ user['rating_ptt']%100}}</div>
|
<div class="ptt">PTT: {{'%0.2f'|format(user['rating_ptt']/100|float)}}</div>
|
||||||
|
<div class="ptt">Memories: {{user['ticket']}}</div>
|
||||||
<div>
|
<div>
|
||||||
<div>Recent plays: </div>
|
<div>Recent plays: </div>
|
||||||
<div>
|
<div>
|
||||||
37
latest version/templates/web/allpresent.html
Normal file
37
latest version/templates/web/allpresent.html
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}All presents{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% if posts %}<br />
|
||||||
|
{% for present in posts %}
|
||||||
|
|
||||||
|
<div class="char-present">
|
||||||
|
<span>Id: </span>
|
||||||
|
<span class="name">{{present['present_id']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Expire time: </span>
|
||||||
|
<span class="char-num">{{present['expire_ts']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Description: </span>
|
||||||
|
<span class="char-num">{{present['description']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Items: </span>
|
||||||
|
<span class="char-num" style='white-space:pre'>{{present['items']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% if not loop.last %}
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<br />
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
39
latest version/templates/web/allredeem.html
Normal file
39
latest version/templates/web/allredeem.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}All redeem codes{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% if posts %}<br />
|
||||||
|
{% for redeem in posts %}
|
||||||
|
|
||||||
|
<div class="char-redeem">
|
||||||
|
<span>Code: </span>
|
||||||
|
<span class="name">{{redeem['code']}}</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Type: </span>
|
||||||
|
<span class="char-num">
|
||||||
|
{% if redeem['type'] == 0 %}
|
||||||
|
仅可使用一次 It can only be used once.
|
||||||
|
{% elif redeem['type'] == 1 %}
|
||||||
|
每个用户仅可以使用一次 Each user can only use it once.
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span>Items: </span>
|
||||||
|
<span class="char-num" style='white-space:pre'>{{redeem['items']}}</span>
|
||||||
|
<br />
|
||||||
|
<div><a href="/web/redeem/{{redeem['code']}}">使用者 Players who have used it.</a></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% if not loop.last %}
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<br />
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
37
latest version/templates/web/banuser.html
Normal file
37
latest version/templates/web/banuser.html
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Ban the user{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="/web/banuser" method="post">
|
||||||
|
<div class="title">Ban the user</div>
|
||||||
|
<label for="name">Arcaea Username</label>
|
||||||
|
<input name="name" id="name">
|
||||||
|
or<br />
|
||||||
|
<label for="user_code">Arcaea User Code</label>
|
||||||
|
<input name="user_code" id="user_code">
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<div class="content">提示:重设用户密码即可解封账号</div>
|
||||||
|
<div class="content">Tip: Reset the user password to unseal the account.</div>
|
||||||
|
<br />
|
||||||
|
<input type="submit" value="Execute">
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<form action="/web/banuser/deleteuserscore" method="post">
|
||||||
|
<div class="title">Delete all of the user's scores</div>
|
||||||
|
<label for="name">Arcaea Username</label>
|
||||||
|
<input name="name" id="name">
|
||||||
|
or<br />
|
||||||
|
<label for="user_code">Arcaea User Code</label>
|
||||||
|
<input name="user_code" id="user_code">
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<div class="content">警告!这个操作具有破坏性,且不可恢复。</div>
|
||||||
|
<div class="content">Warning! This operation is destructive and unrecoverable.</div>
|
||||||
|
<br />
|
||||||
|
<input type="submit" value="Execute">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
55
latest version/templates/web/changechar.html
Normal file
55
latest version/templates/web/changechar.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Change the characters{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="/web/changesong/editchar" method="post">
|
||||||
|
<div class="title">Edit the character</div>
|
||||||
|
<label for="id">ID of the character</label>
|
||||||
|
<input name="id" id="sid" required>
|
||||||
|
|
||||||
|
<label for="level">Level</label>
|
||||||
|
<input name="level" id="level">
|
||||||
|
|
||||||
|
<label for="frag">Frag</label>
|
||||||
|
<input name="frag" id="frag">
|
||||||
|
|
||||||
|
<label for="prog">Prog</label>
|
||||||
|
<input name="prog" id="prog">
|
||||||
|
|
||||||
|
<label for="overdrive">Overdrive</label>
|
||||||
|
<input name="overdrive" id="overdrive">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<select name="skill_id">
|
||||||
|
<option value="">Skill id</option>
|
||||||
|
{% for skill_id in skill_ids %}
|
||||||
|
<option value={{ skill_id }}>{{ skill_id }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<select name="skill_id_uncap">
|
||||||
|
<option value="">Uncapped skill id</option>
|
||||||
|
{% for skill_id in skill_ids %}
|
||||||
|
<option value={{ skill_id }}>{{ skill_id }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div class="content">如果某些不需要修改,留空即可</div>
|
||||||
|
<div class="content">If some things do not need to be modified, leave it blank.</div>
|
||||||
|
<div class="content">更新时角色数据表不会同步</div>
|
||||||
|
<div class="content">The character table will not be synchronized when updated.</div>
|
||||||
|
<input type="submit" value="Edit">
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<form action="/web/changesong/updatechar" method="post">
|
||||||
|
<div class="title">Update the character</div>
|
||||||
|
<div class="content">更新所有用户拥有的角色</div>
|
||||||
|
<div class="content">Update all users' characters.</div>
|
||||||
|
<input type="submit" value="Update">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
41
latest version/templates/web/changeitem.html
Normal file
41
latest version/templates/web/changeitem.html
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Change the items{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="/web/changeitem" method="post">
|
||||||
|
<div class="title">Change the item</div>
|
||||||
|
<label for="item_id">ID of the item</label>
|
||||||
|
<input name="item_id" id="item_id" required>
|
||||||
|
<label for="type">Type</label>
|
||||||
|
<div>
|
||||||
|
<select name="type">
|
||||||
|
<option value='single'>Single</option>
|
||||||
|
<option value='pack'>Pack</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div class="content">可修改项 Modifiable items:</div>
|
||||||
|
<div><label for="is_available">是否可用 Is available:</label>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<label><input type="radio" name="is_available" value=1>True</label>
|
||||||
|
<br />
|
||||||
|
<label><input type="radio" name="is_available" value=0>False</label>
|
||||||
|
</div>
|
||||||
|
<label for="price">Price</label>
|
||||||
|
<input name="price" id="price">
|
||||||
|
<label for="orig_price">Original price</label>
|
||||||
|
<input name="orig_price" id="orig_price">
|
||||||
|
<label for="discount_from">Discount from</label>
|
||||||
|
<input type="datetime-local" name="discount_from" id="discount_from">
|
||||||
|
<label for="discount_to">Discount to</label>
|
||||||
|
<input type="datetime-local" name="discount_to" id="discount_to">
|
||||||
|
<div class="content">如果某些不需要修改,留空即可</div>
|
||||||
|
<div class="content">If some things do not need to be modified, leave it blank.</div>
|
||||||
|
<div class="content">时间填写是一个HTML5控件</div>
|
||||||
|
<div class="content">Time filling is an HTML5 control.</div>
|
||||||
|
<input type="submit" value="Edit">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
39
latest version/templates/web/changepresent.html
Normal file
39
latest version/templates/web/changepresent.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Change the presents{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="/web/changepresent/addpresent" method="post">
|
||||||
|
<div class="title">Add the present</div>
|
||||||
|
<label for="present_id">ID of the present</label>
|
||||||
|
<input name="present_id" id="present_id" required>
|
||||||
|
<label for="description">Description of the present</label>
|
||||||
|
<input name="description" id="description" required>
|
||||||
|
|
||||||
|
<label for="expire_ts">Expire time</label>
|
||||||
|
<input type="datetime-local" name="expire_ts" id="expire_ts" required>
|
||||||
|
<br />
|
||||||
|
<div>Items:</div>
|
||||||
|
<label for="fragment">Fragments</label>
|
||||||
|
<input name="fragment" id="fragment">
|
||||||
|
<label for="ticket">Memories</label>
|
||||||
|
<input name="ticket" id="ticket">
|
||||||
|
|
||||||
|
<div class="content">两种奖励只能有一个,另一个请留空。如果都填写,以记忆源点优先。</div>
|
||||||
|
<div class="content">There can only be one of the two kinds of present. Please leave the other one blank. If you
|
||||||
|
fill both, the memories will be given priority.</div>
|
||||||
|
<div class="content">时间填写是一个HTML5控件</div>
|
||||||
|
<div class="content">Time filling is an HTML5 control.</div>
|
||||||
|
<input type="submit" value="Add">
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<form action="/web/changepresent/deletepresent" method="post">
|
||||||
|
<div class="title">Delete the present</div>
|
||||||
|
<label for="present_id">ID of the present</label>
|
||||||
|
<input name="present_id" id="present_id" required>
|
||||||
|
|
||||||
|
<input type="submit" value="Delete">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
50
latest version/templates/web/changeredeem.html
Normal file
50
latest version/templates/web/changeredeem.html
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Change the redeem codes{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="/web/changeredeem/addredeem" method="post">
|
||||||
|
<div class="title">Add the redeem</div>
|
||||||
|
<div>指定生成 Specify generation</div>
|
||||||
|
<label for="code">The redeem code</label>
|
||||||
|
<input name="code" id="code">
|
||||||
|
<div>Or</div>
|
||||||
|
<div>随机批量生成 Batch generation at random</div>
|
||||||
|
<label for="amount">Amount</label>
|
||||||
|
<input name="amount" id="amount">
|
||||||
|
<br />
|
||||||
|
<div>Type:
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<label><input type="radio" name="type" value="0" checked>仅可使用一次 It can only be used once.</label>
|
||||||
|
<br />
|
||||||
|
<label><input type="radio" name="type" value="1">每个用户仅可以使用一次 Each user can only use it once.</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<div>Items:</div>
|
||||||
|
<label for="fragment">Fragments</label>
|
||||||
|
<input name="fragment" id="fragment">
|
||||||
|
<label for="ticket">Memories</label>
|
||||||
|
<input name="ticket" id="ticket">
|
||||||
|
|
||||||
|
<div class="content">两种奖励可以都有,不需要请留空。</div>
|
||||||
|
<div class="content">You can have both kinds of items. Please leave it blank if you don't need it.</div>
|
||||||
|
<div class="content">兑换码长度为10~20。</div>
|
||||||
|
<div class="content">The length of redeem code is 10 ~ 20.</div>
|
||||||
|
<div class="content">随机生成数量不得超过1000。</div>
|
||||||
|
<div class="content">The amount of batch generation should not be more than 1000.</div>
|
||||||
|
<input type="submit" value="Add">
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<form action="/web/changeredeem/deleteredeem" method="post">
|
||||||
|
<div class="title">Delete the redeem</div>
|
||||||
|
<label for="code">The redeem code</label>
|
||||||
|
<input name="code" id="code" required>
|
||||||
|
|
||||||
|
<input type="submit" value="Delete">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
37
latest version/templates/web/changeuser.html
Normal file
37
latest version/templates/web/changeuser.html
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Change user information{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="/web/changeuser/edituser" method="post">
|
||||||
|
<div class="title">Edit the user</div>
|
||||||
|
<label for="name">Arcaea Username</label>
|
||||||
|
<input name="name" id="name">
|
||||||
|
or<br />
|
||||||
|
<label for="user_code">Arcaea User Code</label>
|
||||||
|
<input name="user_code" id="user_code">
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<label for="ticket">Memories</label>
|
||||||
|
<input name="ticket" id="ticket">
|
||||||
|
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<div class="content">如果某些不需要修改,留空即可</div>
|
||||||
|
<div class="content">If some things do not need to be modified, leave it blank.</div>
|
||||||
|
<div class="content">目前只支持修改记忆源点</div>
|
||||||
|
<div class="content">At present, only memories can be modified.</div>
|
||||||
|
<input type="submit" value="Edit">
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<form action="/web/changeuser/edituser" method="post">
|
||||||
|
<div class="title">Edit all the users</div>
|
||||||
|
<label for="ticket">Memories</label>
|
||||||
|
<input name="ticket" id="ticket">
|
||||||
|
|
||||||
|
<input type="submit" value="Edit all">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
44
latest version/templates/web/changeuserpurchase.html
Normal file
44
latest version/templates/web/changeuserpurchase.html
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Change user purchase information{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="/web/changeuserpurchase/edituser" method="post">
|
||||||
|
<div class="title">Edit the user</div>
|
||||||
|
<label for="name">Arcaea Username</label>
|
||||||
|
<input name="name" id="name">
|
||||||
|
or<br />
|
||||||
|
<label for="user_code">Arcaea User Code</label>
|
||||||
|
<input name="user_code" id="user_code">
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<div>对所有单曲和曲包的操作 Operation to all singles and packs:
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<label><input type="radio" name="method" value="0">解锁 Unlock</label>
|
||||||
|
<br />
|
||||||
|
<label><input type="radio" name="method" value="1">封绝 Lock</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<input type="submit" value="Execute">
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<form action="/web/changeuserpurchase/edituser" method="post">
|
||||||
|
<div class="title">Edit all the users</div>
|
||||||
|
<br />
|
||||||
|
<div>对所有单曲和曲包的操作 Operation to all singles and packs:
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<label><input type="radio" name="method" value="0">解锁 Unlock</label>
|
||||||
|
<br />
|
||||||
|
<label><input type="radio" name="method" value="1">封绝 Lock</label>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<input type="submit" value="Execute">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
24
latest version/templates/web/changeuserpwd.html
Normal file
24
latest version/templates/web/changeuserpwd.html
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Change user password{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="/web/changeuserpwd" method="post">
|
||||||
|
<div class="title">Edit the user's password</div>
|
||||||
|
<label for="name">Arcaea Username</label>
|
||||||
|
<input name="name" id="name">
|
||||||
|
or<br />
|
||||||
|
<label for="user_code">Arcaea User Code</label>
|
||||||
|
<input name="user_code" id="user_code">
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<label for="pwd">Password</label>
|
||||||
|
<input type="password" name="pwd" id="pwd" required>
|
||||||
|
<label for="pwd2">Enter again</label>
|
||||||
|
<input type="password" name="pwd2" id="pwd2" required>
|
||||||
|
|
||||||
|
<input type="submit" value="Edit">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
32
latest version/templates/web/deliverpresent.html
Normal file
32
latest version/templates/web/deliverpresent.html
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Deliver presents{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="/web/deliverpresent" method="post">
|
||||||
|
<div class="title">Deliver to the user</div>
|
||||||
|
<label for="name">Arcaea Username</label>
|
||||||
|
<input name="name" id="name">
|
||||||
|
or<br />
|
||||||
|
<label for="user_code">Arcaea User Code</label>
|
||||||
|
<input name="user_code" id="user_code">
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<label for="present_id">ID of the present</label>
|
||||||
|
<input name="present_id" id="present_id" required>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<input type="submit" value="Edit">
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<form action="/web/deliverpresent" method="post">
|
||||||
|
<div class="title">Deliver to all the users</div>
|
||||||
|
<label for="present_id">ID of the present</label>
|
||||||
|
<input name="present_id" id="present_id" required>
|
||||||
|
|
||||||
|
<input type="submit" value="Edit all">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
39
latest version/templates/web/index.html
Normal file
39
latest version/templates/web/index.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Index{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>说明 Statement</h1>
|
||||||
|
<p>这是Arcaea Server的后台管理协助系统,可以进行一些简单的操作</br>
|
||||||
|
This is the background management assistance system of Arcaea Server, which can be used to do some simple
|
||||||
|
operations.
|
||||||
|
</p>
|
||||||
|
<h1>游戏方面 Game</h1>
|
||||||
|
<a href="{{ url_for('index.single_player_score') }}">单个玩家成绩查询 Single player score</a></br></br>
|
||||||
|
<a href="{{ url_for('index.single_player_ptt') }}">单个玩家PTT详情查询 Single player ptt</a></br></br>
|
||||||
|
<a href="{{ url_for('index.all_player') }}">所有玩家信息查询 All players</a></br></br>
|
||||||
|
<a href="{{ url_for('index.all_song') }}">铺面信息查询 All songs</a></br></br>
|
||||||
|
<a href="{{ url_for('index.all_character') }}">角色信息查询 All characters</a></br></br>
|
||||||
|
<a href="{{ url_for('index.all_item') }}">购买信息查询 All items</a></br></br>
|
||||||
|
<a href="{{ url_for('index.all_present') }}">奖励信息查询 All presents</a></br></br>
|
||||||
|
<a href="{{ url_for('index.all_redeem') }}">兑换码信息查询 All redeem codes</a></br></br>
|
||||||
|
<a href="{{ url_for('index.single_chart_top') }}">单个铺面排行榜查询 Single song chart tops</a>
|
||||||
|
<hr>
|
||||||
|
<h1>系统方面 System</h1>
|
||||||
|
<a href="{{ url_for('index.update_database') }}">数据库更新 Update databases</a></br></br>
|
||||||
|
<a href="{{ url_for('index.edit_userpwd') }}">用户密码修改 Change user password</a></br></br>
|
||||||
|
<a href="{{ url_for('index.ban_user') }}">封禁用户 Ban the user</a></br></br>
|
||||||
|
<a href="{{ url_for('index.update_user_save') }}">用户存档更新 Update user saves</a></br></br>
|
||||||
|
<a href="{{ url_for('index.change_song') }}">歌曲修改 Change the songs</a></br></br>
|
||||||
|
<a href="{{ url_for('index.change_character') }}">角色修改 Change the characters</a></br></br>
|
||||||
|
<a href="{{ url_for('index.change_item') }}">购买信息修改 Change the items</a></br></br>
|
||||||
|
<a href="{{ url_for('index.change_user') }}">用户信息修改 Change user information</a></br></br>
|
||||||
|
<a href="{{ url_for('index.change_user_purchase') }}">用户购买信息修改 Change user purchase information</a></br></br>
|
||||||
|
<a href="{{ url_for('index.change_present') }}">奖励修改 Change the presents</a></br></br>
|
||||||
|
<a href="{{ url_for('index.deliver_present') }}">奖励分发 Deliver the presents</a></br></br>
|
||||||
|
<a href="{{ url_for('index.change_redeem') }}">兑换码修改 Change the redeem codes</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
24
latest version/templates/web/redeem.html
Normal file
24
latest version/templates/web/redeem.html
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Redeem - {{code}}{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% if posts %}
|
||||||
|
{% for user in posts %}
|
||||||
|
|
||||||
|
<div id="user-info">
|
||||||
|
<div class="name">{{user['name']}}
|
||||||
|
<span class="rank">UID: {{user['user_id']}}</span>
|
||||||
|
<span class="rank">User code: {{user['user_code']}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if not loop.last %}
|
||||||
|
<br />
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
<br />
|
||||||
|
<a href="{{ url_for('index.all_redeem') }}">Back</a>
|
||||||
|
{% endblock %}
|
||||||
@@ -22,9 +22,13 @@
|
|||||||
<div class="name">{{user['name']}}
|
<div class="name">{{user['name']}}
|
||||||
<span class="rank">UID: {{user['user_id']}}</span>
|
<span class="rank">UID: {{user['user_id']}}</span>
|
||||||
<span class="rank">User code: {{user['user_code']}}</span>
|
<span class="rank">User code: {{user['user_code']}}</span>
|
||||||
|
{% if user['ban_flag'] %}
|
||||||
|
<span class="rank">Banned</span>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="join-date">注册于 Registered in: {{user['join_date']}}</div>
|
<div class="join-date">注册于 Registered in: {{user['join_date']}}</div>
|
||||||
<div class="ptt">PTT: {{user['rating_ptt']//100 ~ '.' ~ user['rating_ptt']%100}}</div>
|
<div class="ptt">Memories: {{user['ticket']}}</div>
|
||||||
|
<div class="ptt">PTT: {{'%0.2f'|format(user['rating_ptt']/100|float)}}</div>
|
||||||
<div class="ptt">Best 30 PTT: {{bestptt}}</div>
|
<div class="ptt">Best 30 PTT: {{bestptt}}</div>
|
||||||
<div class="ptt">Recent 10 PTT: {{recentptt}}</div>
|
<div class="ptt">Recent 10 PTT: {{recentptt}}</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -12,10 +12,10 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
这里可以将旧版本的数据库同步到新版本的数据库,并刷新用户拥有的角色列表。<br />
|
这里可以将旧版本的数据库同步到新版本的数据库,并刷新用户拥有的角色列表。<br />
|
||||||
可上传文件: arcaea_database.db和arcsong.db<br />
|
可上传文件: arcaea_database.db和arcsong.db<br />
|
||||||
新数据库不存在的数据会被添加,存在的数据将不会被改变。<br /><br />
|
新数据库不存在的数据会被添加,存在的重复数据也会被改变。<br /><br />
|
||||||
Here you can synchronize the old version of the database to the new version of the database and refresh the list of
|
Here you can synchronize the old version of the database to the new version of the database and refresh the list of
|
||||||
characters owned by players.<br />
|
characters owned by players.<br />
|
||||||
Uploadable files: arcaea_database.db & arcsong.db<br />
|
Uploadable files: arcaea_database.db & arcsong.db<br />
|
||||||
Data that does not exist in the new database will be added and the existing data will not be changed.
|
Data that does not exist in the new database will be added and the existing duplicate data will also be changed.
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
30
latest version/templates/web/updateusersave.html
Normal file
30
latest version/templates/web/updateusersave.html
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<h1>{% block title %}Update users' saves{% endblock %}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="/web/updateusersave" method="post">
|
||||||
|
<div class="title">Update one user's saves to the database</div>
|
||||||
|
<label for="name">Arcaea Username</label>
|
||||||
|
<input name="name" id="name">
|
||||||
|
or<br />
|
||||||
|
<label for="user_code">Arcaea User Code</label>
|
||||||
|
<input name="user_code" id="user_code">
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<input type="submit" value="Update">
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<form action="/web/updateusersave" method="post">
|
||||||
|
<div class="title">Update all users' saves to the database</div>
|
||||||
|
<br />
|
||||||
|
<input type="submit" value="Update all">
|
||||||
|
|
||||||
|
<div class="content">这里会将用户上传的存档覆盖到best_score表中,请注意是覆盖,不会进行分数比较。</div>
|
||||||
|
<div class="content">Here you can overlay the saves uploaded by users to best_score table. Please remember that it
|
||||||
|
is an overlay action, so scores will not be compared.</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
1205
latest version/web/index.py
Normal file
1205
latest version/web/index.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,8 @@
|
|||||||
from flask import (Blueprint, flash, g, redirect,
|
from flask import (Blueprint, flash, g, redirect,
|
||||||
render_template, request, session, url_for)
|
render_template, request, session, url_for)
|
||||||
import functools
|
import functools
|
||||||
|
from setting import Config
|
||||||
|
import hashlib
|
||||||
|
|
||||||
bp = Blueprint('login', __name__, url_prefix='/web')
|
bp = Blueprint('login', __name__, url_prefix='/web')
|
||||||
|
|
||||||
@@ -14,12 +16,16 @@ def login():
|
|||||||
password = request.form['password']
|
password = request.form['password']
|
||||||
error = None
|
error = None
|
||||||
|
|
||||||
if username != 'admin' and password != 'admin':
|
if username != Config.USERNAME or password != Config.PASSWORD:
|
||||||
error = '错误的用户名或密码 Incorrect username or password.'
|
error = '错误的用户名或密码 Incorrect username or password.'
|
||||||
|
|
||||||
if error is None:
|
if error is None:
|
||||||
session.clear()
|
session.clear()
|
||||||
session['user_id'] = 'admin'
|
hash_session = username + \
|
||||||
|
hashlib.sha256(password.encode("utf8")).hexdigest()
|
||||||
|
hash_session = hashlib.sha256(
|
||||||
|
hash_session.encode("utf8")).hexdigest()
|
||||||
|
session['user_id'] = hash_session
|
||||||
return redirect(url_for('index.index'))
|
return redirect(url_for('index.index'))
|
||||||
|
|
||||||
flash(error)
|
flash(error)
|
||||||
@@ -40,11 +46,15 @@ def login_required(view):
|
|||||||
@functools.wraps(view)
|
@functools.wraps(view)
|
||||||
def wrapped_view(**kwargs):
|
def wrapped_view(**kwargs):
|
||||||
x = session.get('user_id')
|
x = session.get('user_id')
|
||||||
# 少用户存在验证
|
|
||||||
if x is None:
|
hash_session = Config.USERNAME + \
|
||||||
|
hashlib.sha256(Config.PASSWORD.encode("utf8")).hexdigest()
|
||||||
|
hash_session = hashlib.sha256(hash_session.encode("utf8")).hexdigest()
|
||||||
|
|
||||||
|
if x != hash_session:
|
||||||
return redirect(url_for('login.login'))
|
return redirect(url_for('login.login'))
|
||||||
|
|
||||||
g.user = {'user_id': x, 'username': 'admin'}
|
g.user = {'user_id': x, 'username': Config.USERNAME}
|
||||||
return view(**kwargs)
|
return view(**kwargs)
|
||||||
|
|
||||||
return wrapped_view
|
return wrapped_view
|
||||||
478
latest version/web/system.py
Normal file
478
latest version/web/system.py
Normal file
@@ -0,0 +1,478 @@
|
|||||||
|
import os
|
||||||
|
from server.sql import Connect
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
import server.arcscore
|
||||||
|
import hashlib
|
||||||
|
from random import Random
|
||||||
|
|
||||||
|
|
||||||
|
def int2b(x):
|
||||||
|
# int与布尔值转换
|
||||||
|
if x is None or x == 0:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def random_str(randomlength=10):
|
||||||
|
# 随机生成字符串
|
||||||
|
s = ''
|
||||||
|
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
|
||||||
|
length = len(chars) - 1
|
||||||
|
random = Random()
|
||||||
|
for i in range(randomlength):
|
||||||
|
s += chars[random.randint(0, length)]
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def get_table_info(c, table_name):
|
||||||
|
# 得到表结构,返回主键列表和字段名列表
|
||||||
|
pk = []
|
||||||
|
name = []
|
||||||
|
|
||||||
|
c.execute('''pragma table_info ("'''+table_name+'''")''')
|
||||||
|
x = c.fetchall()
|
||||||
|
if x:
|
||||||
|
for i in x:
|
||||||
|
name.append(i[1])
|
||||||
|
if i[5] != 0:
|
||||||
|
pk.append(i[1])
|
||||||
|
|
||||||
|
return pk, name
|
||||||
|
|
||||||
|
|
||||||
|
def get_sql_select_table(table_name, get_field, where_field=[], where_value=[]):
|
||||||
|
# sql语句拼接,select ... from ... where ...
|
||||||
|
sql = 'select '
|
||||||
|
sql_dict = {}
|
||||||
|
if len(get_field) >= 2:
|
||||||
|
sql += get_field[0]
|
||||||
|
for i in range(1, len(get_field)):
|
||||||
|
sql += ',' + get_field[i]
|
||||||
|
sql += ' from ' + table_name
|
||||||
|
elif len(get_field) == 1:
|
||||||
|
sql += get_field[0] + ' from ' + table_name
|
||||||
|
else:
|
||||||
|
sql += '* from ' + table_name
|
||||||
|
|
||||||
|
if where_field and where_value:
|
||||||
|
sql += ' where '
|
||||||
|
sql += where_field[0] + '=:' + where_field[0]
|
||||||
|
sql_dict[where_field[0]] = where_value[0]
|
||||||
|
if len(where_field) >= 1:
|
||||||
|
for i in range(1, len(where_field)):
|
||||||
|
sql_dict[where_field[i]] = where_value[i]
|
||||||
|
sql += ' and ' + where_field[i] + '=:' + where_field[i]
|
||||||
|
|
||||||
|
sql += ' order by rowid'
|
||||||
|
return sql, sql_dict
|
||||||
|
|
||||||
|
|
||||||
|
def get_sql_insert_table(table_name, field, value):
|
||||||
|
# sql语句拼接,insert into ...(...) values(...)
|
||||||
|
sql = 'insert into ' + table_name + '('
|
||||||
|
sql_dict = {}
|
||||||
|
sql2 = ''
|
||||||
|
if len(field) >= 2:
|
||||||
|
sql += field[0]
|
||||||
|
sql2 += ':' + field[0]
|
||||||
|
sql_dict[field[0]] = value[0]
|
||||||
|
for i in range(1, len(field)):
|
||||||
|
sql += ',' + field[i]
|
||||||
|
sql2 += ', :' + field[i]
|
||||||
|
sql_dict[field[i]] = value[i]
|
||||||
|
|
||||||
|
sql += ') values('
|
||||||
|
|
||||||
|
elif len(field) == 1:
|
||||||
|
sql += field[0] + ') values('
|
||||||
|
sql2 += ':' + field[0]
|
||||||
|
sql_dict[field[0]] = value[0]
|
||||||
|
|
||||||
|
else:
|
||||||
|
return 'error', {}
|
||||||
|
|
||||||
|
sql += sql2 + ')'
|
||||||
|
|
||||||
|
return sql, sql_dict
|
||||||
|
|
||||||
|
|
||||||
|
def get_sql_delete_table(table_name, where_field=[], where_value=[]):
|
||||||
|
# sql语句拼接,delete from ... where ...
|
||||||
|
sql = 'delete from ' + table_name
|
||||||
|
sql_dict = {}
|
||||||
|
|
||||||
|
if where_field and where_value:
|
||||||
|
sql += ' where '
|
||||||
|
sql += where_field[0] + '=:' + where_field[0]
|
||||||
|
sql_dict[where_field[0]] = where_value[0]
|
||||||
|
if len(where_field) >= 1:
|
||||||
|
for i in range(1, len(where_field)):
|
||||||
|
sql_dict[where_field[i]] = where_value[i]
|
||||||
|
sql += ' and ' + where_field[i] + '=:' + where_field[i]
|
||||||
|
|
||||||
|
return sql, sql_dict
|
||||||
|
|
||||||
|
|
||||||
|
def update_one_table(c1, c2, table_name):
|
||||||
|
# 从c1向c2更新数据表,c1中存在的信息不变
|
||||||
|
c1.execute(
|
||||||
|
'''select * from sqlite_master where type = 'table' and name = :a''', {'a': table_name})
|
||||||
|
c2.execute(
|
||||||
|
'''select * from sqlite_master where type = 'table' and name = :a''', {'a': table_name})
|
||||||
|
if not c1.fetchone() or not c2.fetchone():
|
||||||
|
return 'error'
|
||||||
|
|
||||||
|
db1_pk, db1_name = get_table_info(c1, table_name)
|
||||||
|
db2_pk, db2_name = get_table_info(c2, table_name)
|
||||||
|
if db1_pk != db2_pk:
|
||||||
|
return 'error'
|
||||||
|
|
||||||
|
field = []
|
||||||
|
for i in db1_name:
|
||||||
|
if i in db2_name:
|
||||||
|
field.append(i)
|
||||||
|
|
||||||
|
sql, sql_dict = get_sql_select_table(table_name, db1_pk)
|
||||||
|
c1.execute(sql)
|
||||||
|
x = c1.fetchall()
|
||||||
|
sql, sql_dict = get_sql_select_table(table_name, field)
|
||||||
|
c1.execute(sql)
|
||||||
|
y = c1.fetchall()
|
||||||
|
if x:
|
||||||
|
for i in range(0, len(x)):
|
||||||
|
sql, sql_dict = get_sql_select_table(
|
||||||
|
table_name, [], db1_pk, list(x[i]))
|
||||||
|
sql = 'select exists(' + sql + ')'
|
||||||
|
c2.execute(sql, sql_dict)
|
||||||
|
|
||||||
|
if c2.fetchone() == (1,): # 如果c2里存在,先删除
|
||||||
|
sql, sql_dict = get_sql_delete_table(
|
||||||
|
table_name, db1_pk, list(x[i]))
|
||||||
|
c2.execute(sql, sql_dict)
|
||||||
|
|
||||||
|
sql, sql_dict = get_sql_insert_table(
|
||||||
|
table_name, field, list(y[i]))
|
||||||
|
c2.execute(sql, sql_dict)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def update_user_char(c):
|
||||||
|
# 用character数据更新user_char
|
||||||
|
c.execute('''select * from character''')
|
||||||
|
x = c.fetchall()
|
||||||
|
c.execute('''select user_id from user''')
|
||||||
|
y = c.fetchall()
|
||||||
|
if x and y:
|
||||||
|
for j in y:
|
||||||
|
for i in x:
|
||||||
|
c.execute('''delete from user_char where user_id=:a and character_id=:b''', {
|
||||||
|
'a': j[0], 'b': i[0]})
|
||||||
|
c.execute('''insert into user_char values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o)''', {
|
||||||
|
'a': j[0], 'b': i[0], 'c': i[2], 'd': i[3], 'e': i[4], 'f': i[5], 'g': i[6], 'h': i[7], 'i': i[8], 'j': i[9], 'k': i[10], 'l': i[11], 'm': i[12], 'n': i[14], 'o': i[15]})
|
||||||
|
|
||||||
|
|
||||||
|
def update_database():
|
||||||
|
# 将old数据库不存在数据加入到新数据库上,并删除old数据库
|
||||||
|
# 对于arcaea_datebase.db,更新一些表,并用character数据更新user_char
|
||||||
|
# 对于arcsong.db,更新songs
|
||||||
|
if os.path.isfile("database/old_arcaea_database.db") and os.path.isfile("database/arcaea_database.db"):
|
||||||
|
with Connect('./database/old_arcaea_database.db') as c1:
|
||||||
|
with Connect() as c2:
|
||||||
|
|
||||||
|
update_one_table(c1, c2, 'user')
|
||||||
|
update_one_table(c1, c2, 'friend')
|
||||||
|
update_one_table(c1, c2, 'best_score')
|
||||||
|
update_one_table(c1, c2, 'recent30')
|
||||||
|
update_one_table(c1, c2, 'user_world')
|
||||||
|
update_one_table(c1, c2, 'item')
|
||||||
|
update_one_table(c1, c2, 'user_item')
|
||||||
|
update_one_table(c1, c2, 'user_save')
|
||||||
|
update_one_table(c1, c2, 'login')
|
||||||
|
update_one_table(c1, c2, 'present')
|
||||||
|
update_one_table(c1, c2, 'user_present')
|
||||||
|
update_one_table(c1, c2, 'redeem')
|
||||||
|
update_one_table(c1, c2, 'user_redeem')
|
||||||
|
|
||||||
|
update_user_char(c2)
|
||||||
|
|
||||||
|
os.remove('database/old_arcaea_database.db')
|
||||||
|
|
||||||
|
# songs
|
||||||
|
if os.path.isfile("database/old_arcsong.db") and os.path.isfile("database/arcsong.db"):
|
||||||
|
with Connect('./database/old_arcsong.db') as c1:
|
||||||
|
with Connect('./database/arcsong.db') as c2:
|
||||||
|
|
||||||
|
update_one_table(c1, c2, 'songs')
|
||||||
|
|
||||||
|
os.remove('database/old_arcsong.db')
|
||||||
|
|
||||||
|
|
||||||
|
def unlock_all_user_item(c):
|
||||||
|
# 解锁所有用户购买
|
||||||
|
|
||||||
|
c.execute('''select user_id from user''')
|
||||||
|
x = c.fetchall()
|
||||||
|
c.execute('''select item_id, type from item''')
|
||||||
|
y = c.fetchall()
|
||||||
|
c.execute('''delete from user_item''')
|
||||||
|
if x and y:
|
||||||
|
for i in x:
|
||||||
|
for j in y:
|
||||||
|
c.execute('''insert into user_item values(:a,:b,:c)''', {
|
||||||
|
'a': i[0], 'b': j[0], 'c': j[1]})
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def unlock_user_item(c, user_id):
|
||||||
|
# 解锁用户购买
|
||||||
|
|
||||||
|
c.execute('''select item_id, type from item''')
|
||||||
|
y = c.fetchall()
|
||||||
|
|
||||||
|
for j in y:
|
||||||
|
c.execute('''select exists(select * from user_item where user_id=:a and item_id=:b and type=:c)''', {
|
||||||
|
'a': user_id, 'b': j[0], 'c': j[1]})
|
||||||
|
if c.fetchone() == (0,):
|
||||||
|
c.execute('''insert into user_item values(:a,:b,:c)''', {
|
||||||
|
'a': user_id, 'b': j[0], 'c': j[1]})
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_item():
|
||||||
|
# 所有购买数据查询
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute('''select * from item''')
|
||||||
|
x = c.fetchall()
|
||||||
|
re = []
|
||||||
|
if x:
|
||||||
|
for i in x:
|
||||||
|
discount_from = None
|
||||||
|
discount_to = None
|
||||||
|
|
||||||
|
if i[5] and i[5] >= 0:
|
||||||
|
discount_from = time.strftime(
|
||||||
|
"%Y-%m-%d %H:%M:%S", time.localtime(int(i[5])/1000))
|
||||||
|
if i[6] and i[6] >= 0:
|
||||||
|
discount_to = time.strftime(
|
||||||
|
"%Y-%m-%d %H:%M:%S", time.localtime(int(i[6])//1000))
|
||||||
|
|
||||||
|
re.append({'item_id': i[0],
|
||||||
|
'type': i[1],
|
||||||
|
'is_available': int2b(i[2]),
|
||||||
|
'price': i[3],
|
||||||
|
'orig_price': i[4],
|
||||||
|
'discount_from': discount_from,
|
||||||
|
'discount_to': discount_to
|
||||||
|
})
|
||||||
|
|
||||||
|
return re
|
||||||
|
|
||||||
|
|
||||||
|
def update_one_save(c, user_id):
|
||||||
|
# 同步指定用户存档
|
||||||
|
# 注意,best_score表不比较,直接覆盖
|
||||||
|
|
||||||
|
c.execute('''select scores_data, clearlamps_data from user_save where user_id=:a''', {
|
||||||
|
'a': user_id})
|
||||||
|
x = c.fetchone()
|
||||||
|
if x:
|
||||||
|
scores = json.loads(x[0])[""]
|
||||||
|
clearlamps = json.loads(x[1])[""]
|
||||||
|
clear_song_id_difficulty = []
|
||||||
|
clear_state = []
|
||||||
|
for i in clearlamps:
|
||||||
|
clear_song_id_difficulty.append(i['song_id']+str(i['difficulty']))
|
||||||
|
clear_state.append(i['clear_type'])
|
||||||
|
|
||||||
|
for i in scores:
|
||||||
|
rating = server.arcscore.get_one_ptt(
|
||||||
|
i['song_id'], i['difficulty'], i['score'])
|
||||||
|
if rating < 0:
|
||||||
|
rating = 0
|
||||||
|
try:
|
||||||
|
index = clear_song_id_difficulty.index(
|
||||||
|
i['song_id'] + str(i['difficulty']))
|
||||||
|
except:
|
||||||
|
index = -1
|
||||||
|
if index != -1:
|
||||||
|
clear_type = clear_state[index]
|
||||||
|
else:
|
||||||
|
clear_type = 0
|
||||||
|
c.execute('''delete from best_score where user_id=:a and song_id=:b and difficulty=:c''', {
|
||||||
|
'a': user_id, 'b': i['song_id'], 'c': i['difficulty']})
|
||||||
|
c.execute('''insert into best_score values(:a, :b, :c, :d, :e, :f, :g, :h, :i, :j, :k, :l, :m, :n)''', {
|
||||||
|
'a': user_id, 'b': i['song_id'], 'c': i['difficulty'], 'd': i['score'], 'e': i['shiny_perfect_count'], 'f': i['perfect_count'], 'g': i['near_count'], 'h': i['miss_count'], 'i': i['health'], 'j': i['modifier'], 'k': i['time_played'], 'l': clear_type, 'm': clear_type, 'n': rating})
|
||||||
|
|
||||||
|
ptt = server.arcscore.get_user_ptt(c, user_id) # 更新PTT
|
||||||
|
c.execute('''update user set rating_ptt=:a where user_id=:b''', {
|
||||||
|
'a': ptt, 'b': user_id})
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def update_all_save(c):
|
||||||
|
# 同步所有用户存档
|
||||||
|
|
||||||
|
c.execute('''select user_id from user_save''')
|
||||||
|
x = c.fetchall()
|
||||||
|
if x:
|
||||||
|
for i in x:
|
||||||
|
update_one_save(c, i[0])
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def add_one_present(present_id, expire_ts, description, items):
|
||||||
|
# 添加一个奖励
|
||||||
|
|
||||||
|
message = None
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute(
|
||||||
|
'''select exists(select * from present where present_id=:a)''', {'a': present_id})
|
||||||
|
if c.fetchone() == (0,):
|
||||||
|
c.execute('''insert into present values(:a,:b,:c,:d)''', {
|
||||||
|
'a': present_id, 'b': expire_ts, 'c': items, 'd': description})
|
||||||
|
message = '添加成功 Successfully add it.'
|
||||||
|
else:
|
||||||
|
message = '奖励已存在 The present exists.'
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def delete_one_present(present_id):
|
||||||
|
# 删除一个奖励
|
||||||
|
|
||||||
|
message = None
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute(
|
||||||
|
'''select exists(select * from present where present_id=:a)''', {'a': present_id})
|
||||||
|
if c.fetchone() == (1,):
|
||||||
|
c.execute('''delete from present where present_id = :a''',
|
||||||
|
{'a': present_id})
|
||||||
|
c.execute('''delete from user_present where present_id =:a''', {
|
||||||
|
'a': present_id})
|
||||||
|
message = '删除成功 Successfully delete it.'
|
||||||
|
else:
|
||||||
|
message = '奖励不存在 The present does not exist.'
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def is_present_available(c, present_id):
|
||||||
|
# 判断present_id是否有效
|
||||||
|
c.execute(
|
||||||
|
'''select exists(select * from present where present_id = :a)''', {'a': present_id})
|
||||||
|
|
||||||
|
if c.fetchone() == (1,):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def deliver_one_user_present(c, present_id, user_id):
|
||||||
|
# 为指定玩家添加奖励,重复添加不会提示
|
||||||
|
c.execute('''select exists(select * from user_present where user_id=:a and present_id=:b)''',
|
||||||
|
{'a': user_id, 'b': present_id})
|
||||||
|
if c.fetchone() == (0,):
|
||||||
|
c.execute('''insert into user_present values(:a,:b)''',
|
||||||
|
{'a': user_id, 'b': present_id})
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def deliver_all_user_present(c, present_id):
|
||||||
|
# 为所有玩家添加奖励
|
||||||
|
c.execute('''select user_id from user''')
|
||||||
|
x = c.fetchall()
|
||||||
|
if x:
|
||||||
|
c.execute('''delete from user_present where present_id=:b''',
|
||||||
|
{'b': present_id})
|
||||||
|
for i in x:
|
||||||
|
c.execute('''insert into user_present values(:a,:b)''',
|
||||||
|
{'a': i[0], 'b': present_id})
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def add_one_redeem(code, redeem_type, items):
|
||||||
|
# 添加一个兑换码
|
||||||
|
|
||||||
|
message = None
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute(
|
||||||
|
'''select exists(select * from redeem where code=:a)''', {'a': code})
|
||||||
|
if c.fetchone() == (0,):
|
||||||
|
c.execute('''insert into redeem values(:a,:b,:c)''', {
|
||||||
|
'a': code, 'b': items, 'c': redeem_type})
|
||||||
|
message = '添加成功 Successfully add it.'
|
||||||
|
else:
|
||||||
|
message = '兑换码已存在 The redeem code exists.'
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def add_some_random_redeem(amount, redeem_type, items):
|
||||||
|
# 随机生成一堆10位的兑换码
|
||||||
|
|
||||||
|
message = None
|
||||||
|
with Connect() as c:
|
||||||
|
i = 1
|
||||||
|
while i <= amount:
|
||||||
|
code = random_str()
|
||||||
|
c.execute(
|
||||||
|
'''select exists(select * from redeem where code=:a)''', {'a': code})
|
||||||
|
if c.fetchone() == (0,):
|
||||||
|
c.execute('''insert into redeem values(:a,:b,:c)''',
|
||||||
|
{'a': code, 'b': items, 'c': redeem_type})
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
message = '添加成功 Successfully add it.'
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def delete_one_redeem(code):
|
||||||
|
# 删除一个兑换码
|
||||||
|
|
||||||
|
message = None
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute(
|
||||||
|
'''select exists(select * from redeem where code=:a)''', {'a': code})
|
||||||
|
if c.fetchone() == (1,):
|
||||||
|
c.execute('''delete from redeem where code = :a''', {'a': code})
|
||||||
|
c.execute(
|
||||||
|
'''delete from user_redeem where code =:a''', {'a': code})
|
||||||
|
message = '删除成功 Successfully delete it.'
|
||||||
|
else:
|
||||||
|
message = '兑换码不存在 The redeem code does not exist.'
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def change_userpwd(c, user_id, password):
|
||||||
|
# 修改用户密码
|
||||||
|
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
||||||
|
c.execute('''update user set password =:a where user_id=:b''',
|
||||||
|
{'a': hash_pwd, 'b': user_id})
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def ban_one_user(c, user_id):
|
||||||
|
# 封禁用户
|
||||||
|
c.execute('''update user set password = '' where user_id=:a''',
|
||||||
|
{'a': user_id})
|
||||||
|
c.execute('''delete from login where user_id=:a''', {'a': user_id})
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def clear_user_score(c, user_id):
|
||||||
|
# 清除用户所有成绩,包括best_score和recent30,以及recent数据,但不包括云端存档
|
||||||
|
c.execute('''update user set rating_ptt=0, song_id='', difficulty=0, score=0, shiny_perfect_count=0, perfect_count=0, near_count=0, miss_count=0, health=0, time_played=0, rating=0 where user_id=:a''',
|
||||||
|
{'a': user_id})
|
||||||
|
c.execute('''delete from best_score where user_id=:a''', {'a': user_id})
|
||||||
|
c.execute('''delete from recent30 where user_id=:a''', {'a': user_id})
|
||||||
|
return
|
||||||
@@ -49,6 +49,10 @@ def get_user(c, user_id):
|
|||||||
if x[20]:
|
if x[20]:
|
||||||
time_played = time.strftime('%Y-%m-%d %H:%M:%S',
|
time_played = time.strftime('%Y-%m-%d %H:%M:%S',
|
||||||
time.localtime(int(x[20])//1000))
|
time.localtime(int(x[20])//1000))
|
||||||
|
if x[2] == '':
|
||||||
|
ban_flag = True
|
||||||
|
else:
|
||||||
|
ban_flag = False
|
||||||
|
|
||||||
r = {'name': x[1],
|
r = {'name': x[1],
|
||||||
'user_id': user_id,
|
'user_id': user_id,
|
||||||
@@ -64,7 +68,9 @@ def get_user(c, user_id):
|
|||||||
'miss_count': x[17],
|
'miss_count': x[17],
|
||||||
'time_played': time_played,
|
'time_played': time_played,
|
||||||
'clear_type': x[21],
|
'clear_type': x[21],
|
||||||
'rating': x[22]
|
'rating': x[22],
|
||||||
|
'ticket': x[26],
|
||||||
|
'ban_flag': ban_flag
|
||||||
}
|
}
|
||||||
|
|
||||||
return r
|
return r
|
||||||
1242
v1.0/arcscore.py
1242
v1.0/arcscore.py
File diff suppressed because it is too large
Load Diff
141
v1.0/auth.py
141
v1.0/auth.py
@@ -1,141 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import hashlib
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
def arc_login(name: str, password: str) -> str: # 登录判断
|
|
||||||
# 查询数据库中的user表,验证账号密码,返回并记录token
|
|
||||||
# token采用user_id和时间戳连接后hash生成(真的是瞎想的,没用bear)
|
|
||||||
# 密码和token的加密方式为 SHA-256
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
|
||||||
c.execute('''select user_id from user where name = :name and password = :password''', {
|
|
||||||
'name': name, 'password': hash_pwd})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
user_id = str(x[0])
|
|
||||||
now = int(time.time() * 1000)
|
|
||||||
token = hashlib.sha256((user_id + str(now)).encode("utf8")).hexdigest()
|
|
||||||
c.execute(
|
|
||||||
'''select exists(select * from login where user_id = :user_id)''', {"user_id": user_id})
|
|
||||||
|
|
||||||
if c.fetchone() == (1,): # 删掉多余token
|
|
||||||
c.execute('''delete from login where user_id = :user_id''',
|
|
||||||
{'user_id': user_id})
|
|
||||||
|
|
||||||
c.execute('''insert into login(access_token, user_id) values(:access_token, :user_id)''', {
|
|
||||||
'user_id': user_id, 'access_token': token})
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return token
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def arc_register(name: str, password: str): # 注册
|
|
||||||
# 账号注册,只记录hash密码和用户名,生成user_id和user_code,自动登录返回token
|
|
||||||
# token和密码的处理同登录部分
|
|
||||||
|
|
||||||
def build_user_code(c):
|
|
||||||
# 生成9位的user_code,用的自然是随机
|
|
||||||
import random
|
|
||||||
flag = True
|
|
||||||
while flag:
|
|
||||||
user_code = ''.join([str(random.randint(0, 9)) for i in range(9)])
|
|
||||||
c.execute('''select exists(select * from user where user_code = :user_code)''',
|
|
||||||
{'user_code': user_code})
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
flag = False
|
|
||||||
return user_code
|
|
||||||
|
|
||||||
def build_user_id(c):
|
|
||||||
# 生成user_id,往后加1
|
|
||||||
c.execute('''select max(user_id) from user''')
|
|
||||||
x = c.fetchone()
|
|
||||||
if x[0] is not None:
|
|
||||||
return x[0] + 1
|
|
||||||
else:
|
|
||||||
return 2000001
|
|
||||||
|
|
||||||
def insert_user_char(c, user_id):
|
|
||||||
# 为用户添加所有可用角色
|
|
||||||
for i in range(0, 38):
|
|
||||||
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36]:
|
|
||||||
sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
i)+''',30,25000,25000,90,90,90,'',0,0,'',0,1,1)'''
|
|
||||||
c.execute(sql)
|
|
||||||
else:
|
|
||||||
if i != 5:
|
|
||||||
sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
i)+''',30,25000,25000,90,90,90,'',0,0,'',0,0,0)'''
|
|
||||||
c.execute(sql)
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
|
||||||
c.execute(
|
|
||||||
'''select exists(select * from user where name = :name)''', {'name': name})
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
user_code = build_user_code(c)
|
|
||||||
user_id = build_user_id(c)
|
|
||||||
now = int(time.time() * 1000)
|
|
||||||
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
|
||||||
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled)
|
|
||||||
values(:user_id, :name, :password, :join_date, :user_code, 0, 0, 0, 0, 0, 0, -1, 0)
|
|
||||||
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
|
|
||||||
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
|
||||||
'user_id': user_id})
|
|
||||||
|
|
||||||
token = hashlib.sha256(
|
|
||||||
(str(user_id) + str(now)).encode("utf8")).hexdigest()
|
|
||||||
c.execute('''insert into login(access_token, user_id) values(:access_token, :user_id)''', {
|
|
||||||
'user_id': user_id, 'access_token': token})
|
|
||||||
|
|
||||||
insert_user_char(c, user_id)
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return user_id, token, 0
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None, None, 101
|
|
||||||
|
|
||||||
|
|
||||||
def token_get_id(token: str):
|
|
||||||
# 用token获取id,没有考虑不同用户token相同情况,说不定会有bug
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select user_id from login where access_token = :token''', {
|
|
||||||
'token': token})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return x[0]
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def code_get_id(user_code):
|
|
||||||
# 用user_code获取id
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select user_id from user where user_code = :a''',
|
|
||||||
{'a': user_code})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return x[0]
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,204 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import hashlib
|
|
||||||
import time
|
|
||||||
# 数据库初始化文件,删掉arcaea_database.db文件后运行即可,谨慎使用
|
|
||||||
|
|
||||||
conn = sqlite3.connect('arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''create table if not exists user(user_id int primary key,
|
|
||||||
name text unique,
|
|
||||||
password text not null,
|
|
||||||
join_date char(20),
|
|
||||||
user_code char(10),
|
|
||||||
rating_ptt int,
|
|
||||||
character_id int,
|
|
||||||
is_skill_sealed int,
|
|
||||||
is_char_uncapped int,
|
|
||||||
is_char_uncapped_override int,
|
|
||||||
is_hide_rating int,
|
|
||||||
song_id text,
|
|
||||||
difficulty int,
|
|
||||||
score int,
|
|
||||||
shiny_perfect_count int,
|
|
||||||
perfect_count int,
|
|
||||||
near_count int,
|
|
||||||
miss_count int,
|
|
||||||
health int,
|
|
||||||
modifier int,
|
|
||||||
time_played int,
|
|
||||||
clear_type int,
|
|
||||||
rating real,
|
|
||||||
favorite_character int,
|
|
||||||
max_stamina_notification_enabled int
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists login(access_token text,
|
|
||||||
user_id int,
|
|
||||||
last_login_time int,
|
|
||||||
last_login_ip text,
|
|
||||||
last_login_device text
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists friend(user_id_me int,
|
|
||||||
user_id_other int,
|
|
||||||
primary key (user_id_me, user_id_other)
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists best_score(user_id int,
|
|
||||||
song_id text,
|
|
||||||
difficulty int,
|
|
||||||
score int,
|
|
||||||
shiny_perfect_count int,
|
|
||||||
perfect_count int,
|
|
||||||
near_count int,
|
|
||||||
miss_count int,
|
|
||||||
health int,
|
|
||||||
modifier int,
|
|
||||||
time_played int,
|
|
||||||
best_clear_type int,
|
|
||||||
clear_type int,
|
|
||||||
rating real,
|
|
||||||
primary key(user_id, song_id, difficulty)
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists user_char(user_id int,
|
|
||||||
character_id int,
|
|
||||||
level int,
|
|
||||||
exp real,
|
|
||||||
level_exp real,
|
|
||||||
frag int,
|
|
||||||
prog int,
|
|
||||||
overdrive int,
|
|
||||||
skill_id text,
|
|
||||||
skill_unlock_level int,
|
|
||||||
skill_requires_uncap int,
|
|
||||||
skill_id_uncap text,
|
|
||||||
char_type int,
|
|
||||||
is_uncapped int,
|
|
||||||
is_uncapped_override int,
|
|
||||||
primary key(user_id, character_id)
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists character(character_id int primary key,
|
|
||||||
name text
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists recent30(user_id int primary key,
|
|
||||||
r0 real,
|
|
||||||
song_id0 text,
|
|
||||||
r1 real,
|
|
||||||
song_id1 text,
|
|
||||||
r2 real,
|
|
||||||
song_id2 text,
|
|
||||||
r3 real,
|
|
||||||
song_id3 text,
|
|
||||||
r4 real,
|
|
||||||
song_id4 text,
|
|
||||||
r5 real,
|
|
||||||
song_id5 text,
|
|
||||||
r6 real,
|
|
||||||
song_id6 text,
|
|
||||||
r7 real,
|
|
||||||
song_id7 text,
|
|
||||||
r8 real,
|
|
||||||
song_id8 text,
|
|
||||||
r9 real,
|
|
||||||
song_id9 text,
|
|
||||||
r10 real,
|
|
||||||
song_id10 text,
|
|
||||||
r11 real,
|
|
||||||
song_id11 text,
|
|
||||||
r12 real,
|
|
||||||
song_id12 text,
|
|
||||||
r13 real,
|
|
||||||
song_id13 text,
|
|
||||||
r14 real,
|
|
||||||
song_id14 text,
|
|
||||||
r15 real,
|
|
||||||
song_id15 text,
|
|
||||||
r16 real,
|
|
||||||
song_id16 text,
|
|
||||||
r17 real,
|
|
||||||
song_id17 text,
|
|
||||||
r18 real,
|
|
||||||
song_id18 text,
|
|
||||||
r19 real,
|
|
||||||
song_id19 text,
|
|
||||||
r20 real,
|
|
||||||
song_id20 text,
|
|
||||||
r21 real,
|
|
||||||
song_id21 text,
|
|
||||||
r22 real,
|
|
||||||
song_id22 text,
|
|
||||||
r23 real,
|
|
||||||
song_id23 text,
|
|
||||||
r24 real,
|
|
||||||
song_id24 text,
|
|
||||||
r25 real,
|
|
||||||
song_id25 text,
|
|
||||||
r26 real,
|
|
||||||
song_id26 text,
|
|
||||||
r27 real,
|
|
||||||
song_id27 text,
|
|
||||||
r28 real,
|
|
||||||
song_id28 text,
|
|
||||||
r29 real,
|
|
||||||
song_id29 text
|
|
||||||
);''')
|
|
||||||
|
|
||||||
char = ['Hikari','Tairitsu','Kou','Sapphire','Lethe','','Tairitsu(Axium)'
|
|
||||||
,'Tairitsu(Grievous Lady)','Stella','Hikari & Fisica','Ilith','Eto','Luna'
|
|
||||||
,'Shirabe','Hikari(Zero)','Hikari(Fracture)','Hikari(Summer)','Tairitsu(Summer)'
|
|
||||||
,'Tairitsu&Trin','Ayu','Eto&Luna','Yume','Seine & Hikari','Saya','Tairitsu & Chuni Penguin'
|
|
||||||
,'Chuni Penguin','Haruna','Nono','MTA-XXX','MDA-21','Kanae','Hikari(Fantasia)','Tairitsu(Sonata)','Sia','DORO*C'
|
|
||||||
,'Tairitsu(Tempest)','Brillante','Ilith(Summer)']
|
|
||||||
|
|
||||||
for i in range(0, 38):
|
|
||||||
c.execute("insert into character values("+str(i)+",'"+char[i]+"');")
|
|
||||||
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def arc_register(name: str, password: str):
|
|
||||||
def build_user_code(c):
|
|
||||||
return '123456789'
|
|
||||||
|
|
||||||
def build_user_id(c):
|
|
||||||
return 2000000
|
|
||||||
|
|
||||||
def insert_user_char(c, user_id):
|
|
||||||
for i in range(0, 38):
|
|
||||||
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36]:
|
|
||||||
sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
i)+''',30,25000,25000,90,90,90,'',0,0,'',0,1,1)'''
|
|
||||||
c.execute(sql)
|
|
||||||
else:
|
|
||||||
if i != 5:
|
|
||||||
sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
i)+''',30,25000,25000,90,90,90,'',0,0,'',0,0,0)'''
|
|
||||||
c.execute(sql)
|
|
||||||
|
|
||||||
conn = sqlite3.connect('arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
|
||||||
c.execute(
|
|
||||||
'''select exists(select * from user where name = :name)''', {'name': name})
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
user_code = build_user_code(c)
|
|
||||||
user_id = build_user_id(c)
|
|
||||||
now = int(time.time() * 1000)
|
|
||||||
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
|
||||||
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled)
|
|
||||||
values(:user_id, :name, :password, :join_date, :user_code, 1250, 1, 0, 1, 0, 0, -1, 0)
|
|
||||||
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
|
|
||||||
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
|
||||||
'user_id': user_id})
|
|
||||||
c.execute('''insert into best_score values(2000000,'vexaria',3,10000000,100,0,0,0,100,0,1599667200000,3,3,10.8)''')
|
|
||||||
insert_user_char(c, user_id)
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
arc_register('admin', 'admin123')
|
|
||||||
4060
v1.0/info.py
4060
v1.0/info.py
File diff suppressed because it is too large
Load Diff
418
v1.0/main.py
418
v1.0/main.py
@@ -1,418 +0,0 @@
|
|||||||
from flask import Flask, request, jsonify, make_response
|
|
||||||
import configparser
|
|
||||||
import base64
|
|
||||||
import auth
|
|
||||||
import info
|
|
||||||
import setme
|
|
||||||
import arcscore
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
wsgi_app = app.wsgi_app
|
|
||||||
|
|
||||||
|
|
||||||
def error_return(error_code): # 错误返回
|
|
||||||
# 100 无法在此ip地址下登录游戏
|
|
||||||
# 101 用户名占用
|
|
||||||
# 102 电子邮箱已注册
|
|
||||||
# 103 已有一个账号由此设备创建
|
|
||||||
# 104 用户名密码错误
|
|
||||||
# 105 24小时内登入两台设备
|
|
||||||
# 106 账户冻结
|
|
||||||
# 107 你没有足够的体力
|
|
||||||
# 401 用户不存在
|
|
||||||
# 403 无法连接至服务器
|
|
||||||
# 501 502 此物品目前无法获取
|
|
||||||
# 504 无效的序列码
|
|
||||||
# 505 此序列码已被使用
|
|
||||||
# 506 你已拥有了此物品
|
|
||||||
# 601 好友列表已满
|
|
||||||
# 602 此用户已是好友
|
|
||||||
# 604 你不能加自己为好友
|
|
||||||
# 其它 发生未知错误
|
|
||||||
return jsonify({
|
|
||||||
"success": False,
|
|
||||||
"error_code": error_code
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
def hello():
|
|
||||||
return "Hello World!"
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/auth/login', methods=['POST']) # 登录接口
|
|
||||||
def login():
|
|
||||||
headers = request.headers
|
|
||||||
id_pwd = headers['Authorization']
|
|
||||||
id_pwd = base64.b64decode(id_pwd[6:]).decode()
|
|
||||||
name, password = id_pwd.split(':', 1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
token = auth.arc_login(name, password)
|
|
||||||
if token is not None:
|
|
||||||
r = {"success": True, "token_type": "Bearer"}
|
|
||||||
r['access_token'] = token
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(104) # 用户名或密码错误
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/', methods=['POST']) # 注册接口
|
|
||||||
def register():
|
|
||||||
name = request.form['name']
|
|
||||||
password = request.form['password']
|
|
||||||
try:
|
|
||||||
user_id, token, error_code = auth.arc_register(name, password)
|
|
||||||
if user_id is not None:
|
|
||||||
r = {"success": True, "value": {
|
|
||||||
'user_id': user_id, 'access_token': token}}
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(error_code) # 应该是101,用户名被占用,毕竟电子邮箱、设备号没记录
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/compose/aggregate', methods=['GET']) # 用户信息获取
|
|
||||||
def aggregate():
|
|
||||||
calls = request.args.get('calls')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
if calls == '[{ "endpoint": "/user/me", "id": 0 }]': # 极其沙雕的判断,我猜get的参数就两种
|
|
||||||
r = info.arc_aggregate_small(user_id)
|
|
||||||
else:
|
|
||||||
r = info.arc_aggregate_big(user_id)
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/me/character', methods=['POST']) # 角色切换
|
|
||||||
def character_change():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
character_id = request.form['character']
|
|
||||||
skill_sealed = request.form['skill_sealed']
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
flag = setme.change_char(user_id, character_id, skill_sealed)
|
|
||||||
if flag:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"character": character_id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/<path:path>/toggle_uncap', methods=['POST']) # 角色觉醒切换
|
|
||||||
def character_uncap(path):
|
|
||||||
character_id = int(path[22:])
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = setme.change_char_uncap(user_id, character_id)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"character": [r]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/friend/me/add', methods=['POST']) # 加好友
|
|
||||||
def add_friend():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
friend_code = request.form['friend_code']
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
friend_id = auth.code_get_id(friend_code)
|
|
||||||
if user_id is not None and friend_id is not None:
|
|
||||||
r = setme.arc_add_friend(user_id, friend_id)
|
|
||||||
if r is not None and r != 602 and r != 604:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"updatedAt": "2020-09-07T07:32:12.740Z",
|
|
||||||
"createdAt": "2020-09-06T10:05:18.471Z",
|
|
||||||
"friends": r
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
if r is not None:
|
|
||||||
return error_return(r)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
if friend_id is None:
|
|
||||||
return error_return(401)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/friend/me/delete', methods=['POST']) # 删好友
|
|
||||||
def delete_friend():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
friend_id = int(request.form['friend_id'])
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None and friend_id is not None:
|
|
||||||
r = setme.arc_delete_friend(user_id, friend_id)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"updatedAt": "2020-09-07T07:32:12.740Z",
|
|
||||||
"createdAt": "2020-09-06T10:05:18.471Z",
|
|
||||||
"friends": r
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
if friend_id is None:
|
|
||||||
return error_return(401)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song/friend', methods=['GET']) # 好友排名,默认最多50
|
|
||||||
def song_score_friend():
|
|
||||||
song_id = request.args.get('song_id')
|
|
||||||
difficulty = request.args.get('difficulty')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = arcscore.arc_score_friend(user_id, song_id, difficulty)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song/me', methods=['GET']) # 我的排名,默认最多20
|
|
||||||
def song_score_me():
|
|
||||||
song_id = request.args.get('song_id')
|
|
||||||
difficulty = request.args.get('difficulty')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = arcscore.arc_score_me(user_id, song_id, difficulty)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song', methods=['GET']) # TOP20
|
|
||||||
def song_score_top():
|
|
||||||
song_id = request.args.get('song_id')
|
|
||||||
difficulty = request.args.get('difficulty')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = arcscore.arc_score_top(song_id, difficulty)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song', methods=['POST']) # 成绩上传
|
|
||||||
def song_score_post():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
song_id = request.form['song_id']
|
|
||||||
difficulty = int(request.form['difficulty'])
|
|
||||||
score = int(request.form['score'])
|
|
||||||
shiny_perfect_count = int(request.form['shiny_perfect_count'])
|
|
||||||
perfect_count = int(request.form['perfect_count'])
|
|
||||||
near_count = int(request.form['near_count'])
|
|
||||||
miss_count = int(request.form['miss_count'])
|
|
||||||
health = int(request.form['health'])
|
|
||||||
modifier = int(request.form['modifier'])
|
|
||||||
beyond_gauge = int(request.form['beyond_gauge'])
|
|
||||||
clear_type = int(request.form['clear_type'])
|
|
||||||
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = arcscore.arc_score_post(user_id, song_id, difficulty, score, shiny_perfect_count,
|
|
||||||
perfect_count, near_count, miss_count, health, modifier, beyond_gauge, clear_type)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {"user_rating": r}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/token', methods=['GET']) # 成绩上传所需的token,显然我不想验证
|
|
||||||
def score_token():
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"token": "1145141919810"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/me/save', methods=['GET']) # 从云端同步
|
|
||||||
def cloud_get():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = arcscore.arc_all_get(user_id)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/me/save', methods=['POST']) # 向云端同步
|
|
||||||
def cloud_post():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
scores_data = request.form['scores_data']
|
|
||||||
clearlamps_data = request.form['clearlamps_data']
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
arcscore.arc_all_post(user_id, scores_data, clearlamps_data)
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/purchase/me/redeem', methods=['POST']) # 兑换码,自然没有用
|
|
||||||
def redeem():
|
|
||||||
return error_return(504)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/<path:path>', methods=['POST']) # 三个设置,写在最后降低优先级
|
|
||||||
def sys_set(path):
|
|
||||||
set_arg = path[10:]
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
value = request.form['value']
|
|
||||||
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
setme.arc_sys_set(user_id, value, set_arg)
|
|
||||||
r = info.arc_aggregate_small(user_id)
|
|
||||||
r['value'] = r['value'][0]['value']
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
path = r'setting.ini'
|
|
||||||
config.read(path, encoding="utf-8")
|
|
||||||
HOST = config.get('CONFIG','HOST')
|
|
||||||
PORT = config.get('CONFIG','PORT')
|
|
||||||
app.run(HOST, PORT)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
|
||||||
|
|
||||||
## Made By Lost 2020.9.11
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
python main.py
|
|
||||||
155
v1.0/setme.py
155
v1.0/setme.py
@@ -1,155 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import info
|
|
||||||
|
|
||||||
|
|
||||||
def b2int(x):
|
|
||||||
# int与布尔值转换
|
|
||||||
if x:
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def int2b(x):
|
|
||||||
# int与布尔值转换
|
|
||||||
if x is None or x == 0:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def change_char(user_id, character_id, skill_sealed):
|
|
||||||
# 角色改变,包括技能封印的改变,返回成功与否的布尔值
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
|
||||||
{'a': user_id, 'b': character_id})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
if skill_sealed == 'false':
|
|
||||||
skill_sealed = False
|
|
||||||
else:
|
|
||||||
skill_sealed = True
|
|
||||||
c.execute('''update user set is_skill_sealed = :a, character_id = :b, is_char_uncapped = :c, is_char_uncapped_override = :d where user_id = :e''', {
|
|
||||||
'a': b2int(skill_sealed), 'b': character_id, 'c': x[0], 'd': x[1], 'e': user_id})
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return True
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def change_char_uncap(user_id, character_id):
|
|
||||||
# 角色觉醒改变,返回字典
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
|
||||||
{'a': user_id, 'b': character_id})
|
|
||||||
x = c.fetchone()
|
|
||||||
r = None
|
|
||||||
if x is not None and x[0] == 1:
|
|
||||||
c.execute('''update user set is_char_uncapped_override = :a where user_id = :b''', {
|
|
||||||
'a': b2int(x[1] == 0), 'b': user_id})
|
|
||||||
c.execute('''update user_char set is_uncapped_override = :a where user_id = :b and character_id = :c''', {
|
|
||||||
'a': b2int(x[1] == 0), 'b': user_id, 'c': character_id})
|
|
||||||
c.execute('''select * from user_char where user_id = :a and character_id = :b''',
|
|
||||||
{'a': user_id, 'b': character_id})
|
|
||||||
y = c.fetchone()
|
|
||||||
c.execute(
|
|
||||||
'''select name from character where character_id = :x''', {'x': y[1]})
|
|
||||||
z = c.fetchone()
|
|
||||||
if z is not None:
|
|
||||||
char_name = z[0]
|
|
||||||
if y is not None:
|
|
||||||
r = {
|
|
||||||
"is_uncapped_override": int2b(y[14]),
|
|
||||||
"is_uncapped": int2b(y[13]),
|
|
||||||
"uncap_cores": [],
|
|
||||||
"char_type": y[12],
|
|
||||||
"skill_id_uncap": y[11],
|
|
||||||
"skill_requires_uncap": int2b(y[10]),
|
|
||||||
"skill_unlock_level": y[9],
|
|
||||||
"skill_id": y[8],
|
|
||||||
"overdrive": y[7],
|
|
||||||
"prog": y[6],
|
|
||||||
"frag": y[5],
|
|
||||||
"level_exp": y[4],
|
|
||||||
"exp": y[3],
|
|
||||||
"level": y[2],
|
|
||||||
"name": char_name,
|
|
||||||
"character_id": y[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def arc_sys_set(user_id, value, set_arg):
|
|
||||||
# 三个设置,PTT隐藏、体力满通知、最爱角色,无返回
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
if 'favorite_character' in set_arg:
|
|
||||||
value = int(value)
|
|
||||||
c.execute('''update user set favorite_character = :a where user_id = :b''', {
|
|
||||||
'a': value, 'b': user_id})
|
|
||||||
|
|
||||||
else:
|
|
||||||
if value == 'false':
|
|
||||||
value = False
|
|
||||||
else:
|
|
||||||
value = True
|
|
||||||
|
|
||||||
if 'is_hide_rating' in set_arg:
|
|
||||||
c.execute('''update user set is_hide_rating = :a where user_id = :b''', {
|
|
||||||
'a': b2int(value), 'b': user_id})
|
|
||||||
if 'max_stamina_notification_enabled' in set_arg:
|
|
||||||
c.execute('''update user set max_stamina_notification_enabled = :a where user_id = :b''', {
|
|
||||||
'a': b2int(value), 'b': user_id})
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def arc_add_friend(user_id, friend_id):
|
|
||||||
# 加好友,返回好友列表,或者是错误码602、604
|
|
||||||
if user_id == friend_id:
|
|
||||||
return 604
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
|
||||||
{'x': user_id, 'y': friend_id})
|
|
||||||
r = None
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
c.execute('''insert into friend values(:a, :b)''',
|
|
||||||
{'a': user_id, 'b': friend_id})
|
|
||||||
r = info.get_user_friend(c, user_id)
|
|
||||||
|
|
||||||
else:
|
|
||||||
return 602
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def arc_delete_friend(user_id, friend_id):
|
|
||||||
# 删好友,返回好友列表
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
|
||||||
{'x': user_id, 'y': friend_id})
|
|
||||||
r = None
|
|
||||||
if c.fetchone() == (1,):
|
|
||||||
c.execute('''delete from friend where user_id_me = :x and user_id_other = :y''',
|
|
||||||
{'x': user_id, 'y': friend_id})
|
|
||||||
|
|
||||||
r = info.get_user_friend(c, user_id)
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return r
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
[CONFIG]
|
|
||||||
HOST = 192.168.1.112
|
|
||||||
PORT = 80
|
|
||||||
1242
v1.1/arcscore.py
1242
v1.1/arcscore.py
File diff suppressed because it is too large
Load Diff
141
v1.1/auth.py
141
v1.1/auth.py
@@ -1,141 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import hashlib
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
def arc_login(name: str, password: str) -> str: # 登录判断
|
|
||||||
# 查询数据库中的user表,验证账号密码,返回并记录token
|
|
||||||
# token采用user_id和时间戳连接后hash生成(真的是瞎想的,没用bear)
|
|
||||||
# 密码和token的加密方式为 SHA-256
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
|
||||||
c.execute('''select user_id from user where name = :name and password = :password''', {
|
|
||||||
'name': name, 'password': hash_pwd})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
user_id = str(x[0])
|
|
||||||
now = int(time.time() * 1000)
|
|
||||||
token = hashlib.sha256((user_id + str(now)).encode("utf8")).hexdigest()
|
|
||||||
c.execute(
|
|
||||||
'''select exists(select * from login where user_id = :user_id)''', {"user_id": user_id})
|
|
||||||
|
|
||||||
if c.fetchone() == (1,): # 删掉多余token
|
|
||||||
c.execute('''delete from login where user_id = :user_id''',
|
|
||||||
{'user_id': user_id})
|
|
||||||
|
|
||||||
c.execute('''insert into login(access_token, user_id) values(:access_token, :user_id)''', {
|
|
||||||
'user_id': user_id, 'access_token': token})
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return token
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def arc_register(name: str, password: str): # 注册
|
|
||||||
# 账号注册,只记录hash密码和用户名,生成user_id和user_code,自动登录返回token
|
|
||||||
# token和密码的处理同登录部分
|
|
||||||
|
|
||||||
def build_user_code(c):
|
|
||||||
# 生成9位的user_code,用的自然是随机
|
|
||||||
import random
|
|
||||||
flag = True
|
|
||||||
while flag:
|
|
||||||
user_code = ''.join([str(random.randint(0, 9)) for i in range(9)])
|
|
||||||
c.execute('''select exists(select * from user where user_code = :user_code)''',
|
|
||||||
{'user_code': user_code})
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
flag = False
|
|
||||||
return user_code
|
|
||||||
|
|
||||||
def build_user_id(c):
|
|
||||||
# 生成user_id,往后加1
|
|
||||||
c.execute('''select max(user_id) from user''')
|
|
||||||
x = c.fetchone()
|
|
||||||
if x[0] is not None:
|
|
||||||
return x[0] + 1
|
|
||||||
else:
|
|
||||||
return 2000001
|
|
||||||
|
|
||||||
def insert_user_char(c, user_id):
|
|
||||||
# 为用户添加所有可用角色
|
|
||||||
for i in range(0, 38):
|
|
||||||
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]:
|
|
||||||
sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
i)+''',30,25000,25000,90,90,90,'',0,0,'',0,1,1)'''
|
|
||||||
c.execute(sql)
|
|
||||||
else:
|
|
||||||
if i != 5:
|
|
||||||
sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
i)+''',30,25000,25000,90,90,90,'',0,0,'',0,0,0)'''
|
|
||||||
c.execute(sql)
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
|
||||||
c.execute(
|
|
||||||
'''select exists(select * from user where name = :name)''', {'name': name})
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
user_code = build_user_code(c)
|
|
||||||
user_id = build_user_id(c)
|
|
||||||
now = int(time.time() * 1000)
|
|
||||||
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
|
||||||
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled)
|
|
||||||
values(:user_id, :name, :password, :join_date, :user_code, 0, 0, 0, 0, 0, 0, -1, 0)
|
|
||||||
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
|
|
||||||
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
|
||||||
'user_id': user_id})
|
|
||||||
|
|
||||||
token = hashlib.sha256(
|
|
||||||
(str(user_id) + str(now)).encode("utf8")).hexdigest()
|
|
||||||
c.execute('''insert into login(access_token, user_id) values(:access_token, :user_id)''', {
|
|
||||||
'user_id': user_id, 'access_token': token})
|
|
||||||
|
|
||||||
insert_user_char(c, user_id)
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return user_id, token, 0
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None, None, 101
|
|
||||||
|
|
||||||
|
|
||||||
def token_get_id(token: str):
|
|
||||||
# 用token获取id,没有考虑不同用户token相同情况,说不定会有bug
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select user_id from login where access_token = :token''', {
|
|
||||||
'token': token})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return x[0]
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def code_get_id(user_code):
|
|
||||||
# 用user_code获取id
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select user_id from user where user_code = :a''',
|
|
||||||
{'a': user_code})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return x[0]
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,204 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import hashlib
|
|
||||||
import time
|
|
||||||
# 数据库初始化文件,删掉arcaea_database.db文件后运行即可,谨慎使用
|
|
||||||
|
|
||||||
conn = sqlite3.connect('arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''create table if not exists user(user_id int primary key,
|
|
||||||
name text unique,
|
|
||||||
password text not null,
|
|
||||||
join_date char(20),
|
|
||||||
user_code char(10),
|
|
||||||
rating_ptt int,
|
|
||||||
character_id int,
|
|
||||||
is_skill_sealed int,
|
|
||||||
is_char_uncapped int,
|
|
||||||
is_char_uncapped_override int,
|
|
||||||
is_hide_rating int,
|
|
||||||
song_id text,
|
|
||||||
difficulty int,
|
|
||||||
score int,
|
|
||||||
shiny_perfect_count int,
|
|
||||||
perfect_count int,
|
|
||||||
near_count int,
|
|
||||||
miss_count int,
|
|
||||||
health int,
|
|
||||||
modifier int,
|
|
||||||
time_played int,
|
|
||||||
clear_type int,
|
|
||||||
rating real,
|
|
||||||
favorite_character int,
|
|
||||||
max_stamina_notification_enabled int
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists login(access_token text,
|
|
||||||
user_id int,
|
|
||||||
last_login_time int,
|
|
||||||
last_login_ip text,
|
|
||||||
last_login_device text
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists friend(user_id_me int,
|
|
||||||
user_id_other int,
|
|
||||||
primary key (user_id_me, user_id_other)
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists best_score(user_id int,
|
|
||||||
song_id text,
|
|
||||||
difficulty int,
|
|
||||||
score int,
|
|
||||||
shiny_perfect_count int,
|
|
||||||
perfect_count int,
|
|
||||||
near_count int,
|
|
||||||
miss_count int,
|
|
||||||
health int,
|
|
||||||
modifier int,
|
|
||||||
time_played int,
|
|
||||||
best_clear_type int,
|
|
||||||
clear_type int,
|
|
||||||
rating real,
|
|
||||||
primary key(user_id, song_id, difficulty)
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists user_char(user_id int,
|
|
||||||
character_id int,
|
|
||||||
level int,
|
|
||||||
exp real,
|
|
||||||
level_exp real,
|
|
||||||
frag int,
|
|
||||||
prog int,
|
|
||||||
overdrive int,
|
|
||||||
skill_id text,
|
|
||||||
skill_unlock_level int,
|
|
||||||
skill_requires_uncap int,
|
|
||||||
skill_id_uncap text,
|
|
||||||
char_type int,
|
|
||||||
is_uncapped int,
|
|
||||||
is_uncapped_override int,
|
|
||||||
primary key(user_id, character_id)
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists character(character_id int primary key,
|
|
||||||
name text
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists recent30(user_id int primary key,
|
|
||||||
r0 real,
|
|
||||||
song_id0 text,
|
|
||||||
r1 real,
|
|
||||||
song_id1 text,
|
|
||||||
r2 real,
|
|
||||||
song_id2 text,
|
|
||||||
r3 real,
|
|
||||||
song_id3 text,
|
|
||||||
r4 real,
|
|
||||||
song_id4 text,
|
|
||||||
r5 real,
|
|
||||||
song_id5 text,
|
|
||||||
r6 real,
|
|
||||||
song_id6 text,
|
|
||||||
r7 real,
|
|
||||||
song_id7 text,
|
|
||||||
r8 real,
|
|
||||||
song_id8 text,
|
|
||||||
r9 real,
|
|
||||||
song_id9 text,
|
|
||||||
r10 real,
|
|
||||||
song_id10 text,
|
|
||||||
r11 real,
|
|
||||||
song_id11 text,
|
|
||||||
r12 real,
|
|
||||||
song_id12 text,
|
|
||||||
r13 real,
|
|
||||||
song_id13 text,
|
|
||||||
r14 real,
|
|
||||||
song_id14 text,
|
|
||||||
r15 real,
|
|
||||||
song_id15 text,
|
|
||||||
r16 real,
|
|
||||||
song_id16 text,
|
|
||||||
r17 real,
|
|
||||||
song_id17 text,
|
|
||||||
r18 real,
|
|
||||||
song_id18 text,
|
|
||||||
r19 real,
|
|
||||||
song_id19 text,
|
|
||||||
r20 real,
|
|
||||||
song_id20 text,
|
|
||||||
r21 real,
|
|
||||||
song_id21 text,
|
|
||||||
r22 real,
|
|
||||||
song_id22 text,
|
|
||||||
r23 real,
|
|
||||||
song_id23 text,
|
|
||||||
r24 real,
|
|
||||||
song_id24 text,
|
|
||||||
r25 real,
|
|
||||||
song_id25 text,
|
|
||||||
r26 real,
|
|
||||||
song_id26 text,
|
|
||||||
r27 real,
|
|
||||||
song_id27 text,
|
|
||||||
r28 real,
|
|
||||||
song_id28 text,
|
|
||||||
r29 real,
|
|
||||||
song_id29 text
|
|
||||||
);''')
|
|
||||||
|
|
||||||
char = ['Hikari','Tairitsu','Kou','Sapphire','Lethe','','Tairitsu(Axium)'
|
|
||||||
,'Tairitsu(Grievous Lady)','Stella','Hikari & Fisica','Ilith','Eto','Luna'
|
|
||||||
,'Shirabe','Hikari(Zero)','Hikari(Fracture)','Hikari(Summer)','Tairitsu(Summer)'
|
|
||||||
,'Tairitsu&Trin','Ayu','Eto&Luna','Yume','Seine & Hikari','Saya','Tairitsu & Chuni Penguin'
|
|
||||||
,'Chuni Penguin','Haruna','Nono','MTA-XXX','MDA-21','Kanae','Hikari(Fantasia)','Tairitsu(Sonata)','Sia','DORO*C'
|
|
||||||
,'Tairitsu(Tempest)','Brillante','Ilith(Summer)']
|
|
||||||
|
|
||||||
for i in range(0, 38):
|
|
||||||
c.execute("insert into character values("+str(i)+",'"+char[i]+"');")
|
|
||||||
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def arc_register(name: str, password: str):
|
|
||||||
def build_user_code(c):
|
|
||||||
return '123456789'
|
|
||||||
|
|
||||||
def build_user_id(c):
|
|
||||||
return 2000000
|
|
||||||
|
|
||||||
def insert_user_char(c, user_id):
|
|
||||||
for i in range(0, 38):
|
|
||||||
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]:
|
|
||||||
sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
i)+''',30,25000,25000,90,90,90,'',0,0,'',0,1,1)'''
|
|
||||||
c.execute(sql)
|
|
||||||
else:
|
|
||||||
if i != 5:
|
|
||||||
sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
i)+''',30,25000,25000,90,90,90,'',0,0,'',0,0,0)'''
|
|
||||||
c.execute(sql)
|
|
||||||
|
|
||||||
conn = sqlite3.connect('arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
|
||||||
c.execute(
|
|
||||||
'''select exists(select * from user where name = :name)''', {'name': name})
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
user_code = build_user_code(c)
|
|
||||||
user_id = build_user_id(c)
|
|
||||||
now = int(time.time() * 1000)
|
|
||||||
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
|
||||||
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled)
|
|
||||||
values(:user_id, :name, :password, :join_date, :user_code, 1250, 1, 0, 1, 0, 0, -1, 0)
|
|
||||||
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
|
|
||||||
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
|
||||||
'user_id': user_id})
|
|
||||||
c.execute('''insert into best_score values(2000000,'vexaria',3,10000000,100,0,0,0,100,0,1599667200000,3,3,10.8)''')
|
|
||||||
insert_user_char(c, user_id)
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
arc_register('admin', 'admin123')
|
|
||||||
4060
v1.1/info.py
4060
v1.1/info.py
File diff suppressed because it is too large
Load Diff
418
v1.1/main.py
418
v1.1/main.py
@@ -1,418 +0,0 @@
|
|||||||
from flask import Flask, request, jsonify, make_response
|
|
||||||
import configparser
|
|
||||||
import base64
|
|
||||||
import auth
|
|
||||||
import info
|
|
||||||
import setme
|
|
||||||
import arcscore
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
wsgi_app = app.wsgi_app
|
|
||||||
|
|
||||||
|
|
||||||
def error_return(error_code): # 错误返回
|
|
||||||
# 100 无法在此ip地址下登录游戏
|
|
||||||
# 101 用户名占用
|
|
||||||
# 102 电子邮箱已注册
|
|
||||||
# 103 已有一个账号由此设备创建
|
|
||||||
# 104 用户名密码错误
|
|
||||||
# 105 24小时内登入两台设备
|
|
||||||
# 106 账户冻结
|
|
||||||
# 107 你没有足够的体力
|
|
||||||
# 401 用户不存在
|
|
||||||
# 403 无法连接至服务器
|
|
||||||
# 501 502 此物品目前无法获取
|
|
||||||
# 504 无效的序列码
|
|
||||||
# 505 此序列码已被使用
|
|
||||||
# 506 你已拥有了此物品
|
|
||||||
# 601 好友列表已满
|
|
||||||
# 602 此用户已是好友
|
|
||||||
# 604 你不能加自己为好友
|
|
||||||
# 其它 发生未知错误
|
|
||||||
return jsonify({
|
|
||||||
"success": False,
|
|
||||||
"error_code": error_code
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
def hello():
|
|
||||||
return "Hello World!"
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/auth/login', methods=['POST']) # 登录接口
|
|
||||||
def login():
|
|
||||||
headers = request.headers
|
|
||||||
id_pwd = headers['Authorization']
|
|
||||||
id_pwd = base64.b64decode(id_pwd[6:]).decode()
|
|
||||||
name, password = id_pwd.split(':', 1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
token = auth.arc_login(name, password)
|
|
||||||
if token is not None:
|
|
||||||
r = {"success": True, "token_type": "Bearer"}
|
|
||||||
r['access_token'] = token
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(104) # 用户名或密码错误
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/', methods=['POST']) # 注册接口
|
|
||||||
def register():
|
|
||||||
name = request.form['name']
|
|
||||||
password = request.form['password']
|
|
||||||
try:
|
|
||||||
user_id, token, error_code = auth.arc_register(name, password)
|
|
||||||
if user_id is not None:
|
|
||||||
r = {"success": True, "value": {
|
|
||||||
'user_id': user_id, 'access_token': token}}
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(error_code) # 应该是101,用户名被占用,毕竟电子邮箱、设备号没记录
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/compose/aggregate', methods=['GET']) # 用户信息获取
|
|
||||||
def aggregate():
|
|
||||||
calls = request.args.get('calls')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
if calls == '[{ "endpoint": "/user/me", "id": 0 }]': # 极其沙雕的判断,我猜get的参数就两种
|
|
||||||
r = info.arc_aggregate_small(user_id)
|
|
||||||
else:
|
|
||||||
r = info.arc_aggregate_big(user_id)
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/me/character', methods=['POST']) # 角色切换
|
|
||||||
def character_change():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
character_id = request.form['character']
|
|
||||||
skill_sealed = request.form['skill_sealed']
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
flag = setme.change_char(user_id, character_id, skill_sealed)
|
|
||||||
if flag:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"character": character_id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/<path:path>/toggle_uncap', methods=['POST']) # 角色觉醒切换
|
|
||||||
def character_uncap(path):
|
|
||||||
character_id = int(path[22:])
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = setme.change_char_uncap(user_id, character_id)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"character": [r]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/friend/me/add', methods=['POST']) # 加好友
|
|
||||||
def add_friend():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
friend_code = request.form['friend_code']
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
friend_id = auth.code_get_id(friend_code)
|
|
||||||
if user_id is not None and friend_id is not None:
|
|
||||||
r = setme.arc_add_friend(user_id, friend_id)
|
|
||||||
if r is not None and r != 602 and r != 604:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"updatedAt": "2020-09-07T07:32:12.740Z",
|
|
||||||
"createdAt": "2020-09-06T10:05:18.471Z",
|
|
||||||
"friends": r
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
if r is not None:
|
|
||||||
return error_return(r)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
if friend_id is None:
|
|
||||||
return error_return(401)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/friend/me/delete', methods=['POST']) # 删好友
|
|
||||||
def delete_friend():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
friend_id = int(request.form['friend_id'])
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None and friend_id is not None:
|
|
||||||
r = setme.arc_delete_friend(user_id, friend_id)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"updatedAt": "2020-09-07T07:32:12.740Z",
|
|
||||||
"createdAt": "2020-09-06T10:05:18.471Z",
|
|
||||||
"friends": r
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
if friend_id is None:
|
|
||||||
return error_return(401)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song/friend', methods=['GET']) # 好友排名,默认最多50
|
|
||||||
def song_score_friend():
|
|
||||||
song_id = request.args.get('song_id')
|
|
||||||
difficulty = request.args.get('difficulty')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = arcscore.arc_score_friend(user_id, song_id, difficulty)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song/me', methods=['GET']) # 我的排名,默认最多20
|
|
||||||
def song_score_me():
|
|
||||||
song_id = request.args.get('song_id')
|
|
||||||
difficulty = request.args.get('difficulty')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = arcscore.arc_score_me(user_id, song_id, difficulty)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song', methods=['GET']) # TOP20
|
|
||||||
def song_score_top():
|
|
||||||
song_id = request.args.get('song_id')
|
|
||||||
difficulty = request.args.get('difficulty')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = arcscore.arc_score_top(song_id, difficulty)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song', methods=['POST']) # 成绩上传
|
|
||||||
def song_score_post():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
song_id = request.form['song_id']
|
|
||||||
difficulty = int(request.form['difficulty'])
|
|
||||||
score = int(request.form['score'])
|
|
||||||
shiny_perfect_count = int(request.form['shiny_perfect_count'])
|
|
||||||
perfect_count = int(request.form['perfect_count'])
|
|
||||||
near_count = int(request.form['near_count'])
|
|
||||||
miss_count = int(request.form['miss_count'])
|
|
||||||
health = int(request.form['health'])
|
|
||||||
modifier = int(request.form['modifier'])
|
|
||||||
beyond_gauge = int(request.form['beyond_gauge'])
|
|
||||||
clear_type = int(request.form['clear_type'])
|
|
||||||
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = arcscore.arc_score_post(user_id, song_id, difficulty, score, shiny_perfect_count,
|
|
||||||
perfect_count, near_count, miss_count, health, modifier, beyond_gauge, clear_type)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {"user_rating": r}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/token', methods=['GET']) # 成绩上传所需的token,显然我不想验证
|
|
||||||
def score_token():
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"token": "1145141919810"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/me/save', methods=['GET']) # 从云端同步
|
|
||||||
def cloud_get():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = arcscore.arc_all_get(user_id)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/me/save', methods=['POST']) # 向云端同步
|
|
||||||
def cloud_post():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
scores_data = request.form['scores_data']
|
|
||||||
clearlamps_data = request.form['clearlamps_data']
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
arcscore.arc_all_post(user_id, scores_data, clearlamps_data)
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/purchase/me/redeem', methods=['POST']) # 兑换码,自然没有用
|
|
||||||
def redeem():
|
|
||||||
return error_return(504)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/<path:path>', methods=['POST']) # 三个设置,写在最后降低优先级
|
|
||||||
def sys_set(path):
|
|
||||||
set_arg = path[10:]
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
value = request.form['value']
|
|
||||||
|
|
||||||
try:
|
|
||||||
user_id = auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
setme.arc_sys_set(user_id, value, set_arg)
|
|
||||||
r = info.arc_aggregate_small(user_id)
|
|
||||||
r['value'] = r['value'][0]['value']
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
path = r'setting.ini'
|
|
||||||
config.read(path, encoding="utf-8")
|
|
||||||
HOST = config.get('CONFIG','HOST')
|
|
||||||
PORT = config.get('CONFIG','PORT')
|
|
||||||
app.run(HOST, PORT)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
|
||||||
|
|
||||||
## Made By Lost 2020.9.11
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
python main.py
|
|
||||||
155
v1.1/setme.py
155
v1.1/setme.py
@@ -1,155 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import info
|
|
||||||
|
|
||||||
|
|
||||||
def b2int(x):
|
|
||||||
# int与布尔值转换
|
|
||||||
if x:
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def int2b(x):
|
|
||||||
# int与布尔值转换
|
|
||||||
if x is None or x == 0:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def change_char(user_id, character_id, skill_sealed):
|
|
||||||
# 角色改变,包括技能封印的改变,返回成功与否的布尔值
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
|
||||||
{'a': user_id, 'b': character_id})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
if skill_sealed == 'false':
|
|
||||||
skill_sealed = False
|
|
||||||
else:
|
|
||||||
skill_sealed = True
|
|
||||||
c.execute('''update user set is_skill_sealed = :a, character_id = :b, is_char_uncapped = :c, is_char_uncapped_override = :d where user_id = :e''', {
|
|
||||||
'a': b2int(skill_sealed), 'b': character_id, 'c': x[0], 'd': x[1], 'e': user_id})
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return True
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def change_char_uncap(user_id, character_id):
|
|
||||||
# 角色觉醒改变,返回字典
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
|
||||||
{'a': user_id, 'b': character_id})
|
|
||||||
x = c.fetchone()
|
|
||||||
r = None
|
|
||||||
if x is not None and x[0] == 1:
|
|
||||||
c.execute('''update user set is_char_uncapped_override = :a where user_id = :b''', {
|
|
||||||
'a': b2int(x[1] == 0), 'b': user_id})
|
|
||||||
c.execute('''update user_char set is_uncapped_override = :a where user_id = :b and character_id = :c''', {
|
|
||||||
'a': b2int(x[1] == 0), 'b': user_id, 'c': character_id})
|
|
||||||
c.execute('''select * from user_char where user_id = :a and character_id = :b''',
|
|
||||||
{'a': user_id, 'b': character_id})
|
|
||||||
y = c.fetchone()
|
|
||||||
c.execute(
|
|
||||||
'''select name from character where character_id = :x''', {'x': y[1]})
|
|
||||||
z = c.fetchone()
|
|
||||||
if z is not None:
|
|
||||||
char_name = z[0]
|
|
||||||
if y is not None:
|
|
||||||
r = {
|
|
||||||
"is_uncapped_override": int2b(y[14]),
|
|
||||||
"is_uncapped": int2b(y[13]),
|
|
||||||
"uncap_cores": [],
|
|
||||||
"char_type": y[12],
|
|
||||||
"skill_id_uncap": y[11],
|
|
||||||
"skill_requires_uncap": int2b(y[10]),
|
|
||||||
"skill_unlock_level": y[9],
|
|
||||||
"skill_id": y[8],
|
|
||||||
"overdrive": y[7],
|
|
||||||
"prog": y[6],
|
|
||||||
"frag": y[5],
|
|
||||||
"level_exp": y[4],
|
|
||||||
"exp": y[3],
|
|
||||||
"level": y[2],
|
|
||||||
"name": char_name,
|
|
||||||
"character_id": y[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def arc_sys_set(user_id, value, set_arg):
|
|
||||||
# 三个设置,PTT隐藏、体力满通知、最爱角色,无返回
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
if 'favorite_character' in set_arg:
|
|
||||||
value = int(value)
|
|
||||||
c.execute('''update user set favorite_character = :a where user_id = :b''', {
|
|
||||||
'a': value, 'b': user_id})
|
|
||||||
|
|
||||||
else:
|
|
||||||
if value == 'false':
|
|
||||||
value = False
|
|
||||||
else:
|
|
||||||
value = True
|
|
||||||
|
|
||||||
if 'is_hide_rating' in set_arg:
|
|
||||||
c.execute('''update user set is_hide_rating = :a where user_id = :b''', {
|
|
||||||
'a': b2int(value), 'b': user_id})
|
|
||||||
if 'max_stamina_notification_enabled' in set_arg:
|
|
||||||
c.execute('''update user set max_stamina_notification_enabled = :a where user_id = :b''', {
|
|
||||||
'a': b2int(value), 'b': user_id})
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def arc_add_friend(user_id, friend_id):
|
|
||||||
# 加好友,返回好友列表,或者是错误码602、604
|
|
||||||
if user_id == friend_id:
|
|
||||||
return 604
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
|
||||||
{'x': user_id, 'y': friend_id})
|
|
||||||
r = None
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
c.execute('''insert into friend values(:a, :b)''',
|
|
||||||
{'a': user_id, 'b': friend_id})
|
|
||||||
r = info.get_user_friend(c, user_id)
|
|
||||||
|
|
||||||
else:
|
|
||||||
return 602
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def arc_delete_friend(user_id, friend_id):
|
|
||||||
# 删好友,返回好友列表
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
|
||||||
{'x': user_id, 'y': friend_id})
|
|
||||||
r = None
|
|
||||||
if c.fetchone() == (1,):
|
|
||||||
c.execute('''delete from friend where user_id_me = :x and user_id_other = :y''',
|
|
||||||
{'x': user_id, 'y': friend_id})
|
|
||||||
|
|
||||||
r = info.get_user_friend(c, user_id)
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return r
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
[CONFIG]
|
|
||||||
HOST = 192.168.1.113
|
|
||||||
PORT = 80
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,233 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import hashlib
|
|
||||||
import time
|
|
||||||
# 数据库初始化文件,删掉arcaea_database.db文件后运行即可,谨慎使用
|
|
||||||
|
|
||||||
conn = sqlite3.connect('arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''create table if not exists user(user_id int primary key,
|
|
||||||
name text unique,
|
|
||||||
password text not null,
|
|
||||||
join_date char(20),
|
|
||||||
user_code char(10),
|
|
||||||
rating_ptt int,
|
|
||||||
character_id int,
|
|
||||||
is_skill_sealed int,
|
|
||||||
is_char_uncapped int,
|
|
||||||
is_char_uncapped_override int,
|
|
||||||
is_hide_rating int,
|
|
||||||
song_id text,
|
|
||||||
difficulty int,
|
|
||||||
score int,
|
|
||||||
shiny_perfect_count int,
|
|
||||||
perfect_count int,
|
|
||||||
near_count int,
|
|
||||||
miss_count int,
|
|
||||||
health int,
|
|
||||||
modifier int,
|
|
||||||
time_played int,
|
|
||||||
clear_type int,
|
|
||||||
rating real,
|
|
||||||
favorite_character int,
|
|
||||||
max_stamina_notification_enabled int
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists login(access_token text,
|
|
||||||
user_id int,
|
|
||||||
last_login_time int,
|
|
||||||
last_login_ip text,
|
|
||||||
last_login_device text
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists friend(user_id_me int,
|
|
||||||
user_id_other int,
|
|
||||||
primary key (user_id_me, user_id_other)
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists best_score(user_id int,
|
|
||||||
song_id text,
|
|
||||||
difficulty int,
|
|
||||||
score int,
|
|
||||||
shiny_perfect_count int,
|
|
||||||
perfect_count int,
|
|
||||||
near_count int,
|
|
||||||
miss_count int,
|
|
||||||
health int,
|
|
||||||
modifier int,
|
|
||||||
time_played int,
|
|
||||||
best_clear_type int,
|
|
||||||
clear_type int,
|
|
||||||
rating real,
|
|
||||||
primary key(user_id, song_id, difficulty)
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists user_char(user_id int,
|
|
||||||
character_id int,
|
|
||||||
level int,
|
|
||||||
exp real,
|
|
||||||
level_exp real,
|
|
||||||
frag int,
|
|
||||||
prog int,
|
|
||||||
overdrive int,
|
|
||||||
skill_id text,
|
|
||||||
skill_unlock_level int,
|
|
||||||
skill_requires_uncap int,
|
|
||||||
skill_id_uncap text,
|
|
||||||
char_type int,
|
|
||||||
is_uncapped int,
|
|
||||||
is_uncapped_override int,
|
|
||||||
primary key(user_id, character_id)
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists character(character_id int primary key,
|
|
||||||
name text,
|
|
||||||
level int,
|
|
||||||
exp real,
|
|
||||||
level_exp real,
|
|
||||||
frag int,
|
|
||||||
prog int,
|
|
||||||
overdrive int,
|
|
||||||
skill_id text,
|
|
||||||
skill_unlock_level int,
|
|
||||||
skill_requires_uncap int,
|
|
||||||
skill_id_uncap text,
|
|
||||||
char_type int,
|
|
||||||
uncap_cores text,
|
|
||||||
is_uncapped int,
|
|
||||||
is_uncapped_override int
|
|
||||||
);''')
|
|
||||||
c.execute('''create table if not exists recent30(user_id int primary key,
|
|
||||||
r0 real,
|
|
||||||
song_id0 text,
|
|
||||||
r1 real,
|
|
||||||
song_id1 text,
|
|
||||||
r2 real,
|
|
||||||
song_id2 text,
|
|
||||||
r3 real,
|
|
||||||
song_id3 text,
|
|
||||||
r4 real,
|
|
||||||
song_id4 text,
|
|
||||||
r5 real,
|
|
||||||
song_id5 text,
|
|
||||||
r6 real,
|
|
||||||
song_id6 text,
|
|
||||||
r7 real,
|
|
||||||
song_id7 text,
|
|
||||||
r8 real,
|
|
||||||
song_id8 text,
|
|
||||||
r9 real,
|
|
||||||
song_id9 text,
|
|
||||||
r10 real,
|
|
||||||
song_id10 text,
|
|
||||||
r11 real,
|
|
||||||
song_id11 text,
|
|
||||||
r12 real,
|
|
||||||
song_id12 text,
|
|
||||||
r13 real,
|
|
||||||
song_id13 text,
|
|
||||||
r14 real,
|
|
||||||
song_id14 text,
|
|
||||||
r15 real,
|
|
||||||
song_id15 text,
|
|
||||||
r16 real,
|
|
||||||
song_id16 text,
|
|
||||||
r17 real,
|
|
||||||
song_id17 text,
|
|
||||||
r18 real,
|
|
||||||
song_id18 text,
|
|
||||||
r19 real,
|
|
||||||
song_id19 text,
|
|
||||||
r20 real,
|
|
||||||
song_id20 text,
|
|
||||||
r21 real,
|
|
||||||
song_id21 text,
|
|
||||||
r22 real,
|
|
||||||
song_id22 text,
|
|
||||||
r23 real,
|
|
||||||
song_id23 text,
|
|
||||||
r24 real,
|
|
||||||
song_id24 text,
|
|
||||||
r25 real,
|
|
||||||
song_id25 text,
|
|
||||||
r26 real,
|
|
||||||
song_id26 text,
|
|
||||||
r27 real,
|
|
||||||
song_id27 text,
|
|
||||||
r28 real,
|
|
||||||
song_id28 text,
|
|
||||||
r29 real,
|
|
||||||
song_id29 text
|
|
||||||
);''')
|
|
||||||
|
|
||||||
char = ['Hikari','Tairitsu','Kou','Sapphire','Lethe','','Tairitsu(Axium)'
|
|
||||||
,'Tairitsu(Grievous Lady)','Stella','Hikari & Fisica','Ilith','Eto','Luna'
|
|
||||||
,'Shirabe','Hikari(Zero)','Hikari(Fracture)','Hikari(Summer)','Tairitsu(Summer)'
|
|
||||||
,'Tairitsu&Trin','Ayu','Eto&Luna','Yume','Seine & Hikari','Saya','Tairitsu & Chuni Penguin'
|
|
||||||
,'Chuni Penguin','Haruna','Nono','MTA-XXX','MDA-21','Kanae','Hikari(Fantasia)','Tairitsu(Sonata)','Sia','DORO*C'
|
|
||||||
,'Tairitsu(Tempest)','Brillante','Ilith(Summer)']
|
|
||||||
|
|
||||||
for i in range(0, 38):
|
|
||||||
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]:
|
|
||||||
sql = 'insert into character values('+str(i)+',"'+char[i]+'''",30,25000,25000,90,90,90,'',0,0,'',0,'',1,1)'''
|
|
||||||
c.execute(sql)
|
|
||||||
else:
|
|
||||||
if i != 5:
|
|
||||||
sql = 'insert into character values('+str(i)+',"'+char[i]+'''",30,25000,25000,90,90,90,'',0,0,'',0,'',0,0)'''
|
|
||||||
c.execute(sql)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def arc_register(name: str, password: str):
|
|
||||||
def build_user_code(c):
|
|
||||||
return '123456789'
|
|
||||||
|
|
||||||
def build_user_id(c):
|
|
||||||
return 2000000
|
|
||||||
|
|
||||||
## def insert_user_char(c, user_id):
|
|
||||||
## for i in range(0, 38):
|
|
||||||
## if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]:
|
|
||||||
## sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
## i)+''',30,25000,25000,90,90,90,'',0,0,'',0,1,1)'''
|
|
||||||
## c.execute(sql)
|
|
||||||
## else:
|
|
||||||
## if i != 5:
|
|
||||||
## sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
## i)+''',30,25000,25000,90,90,90,'',0,0,'',0,0,0)'''
|
|
||||||
## c.execute(sql)
|
|
||||||
def insert_user_char(c, user_id):
|
|
||||||
# 为用户添加所有可用角色
|
|
||||||
c.execute('''select * from character''')
|
|
||||||
x = c.fetchall()
|
|
||||||
if x != []:
|
|
||||||
for i in x:
|
|
||||||
c.execute('''insert into user_char values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o)''', {
|
|
||||||
'a': user_id, 'b': i[0], 'c': i[2], 'd': i[3], 'e': i[4], 'f': i[5], 'g': i[6], 'h': i[7], 'i': i[8], 'j': i[9], 'k': i[10], 'l': i[11], 'm': i[12], 'n': i[14], 'o': i[15]})
|
|
||||||
|
|
||||||
conn = sqlite3.connect('arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
|
||||||
c.execute(
|
|
||||||
'''select exists(select * from user where name = :name)''', {'name': name})
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
user_code = build_user_code(c)
|
|
||||||
user_id = build_user_id(c)
|
|
||||||
now = int(time.time() * 1000)
|
|
||||||
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
|
||||||
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled)
|
|
||||||
values(:user_id, :name, :password, :join_date, :user_code, 1250, 1, 0, 1, 0, 0, -1, 0)
|
|
||||||
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
|
|
||||||
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
|
||||||
'user_id': user_id})
|
|
||||||
c.execute('''insert into best_score values(2000000,'vexaria',3,10000000,100,0,0,0,100,0,1599667200,3,3,10.8)''')
|
|
||||||
insert_user_char(c, user_id)
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
arc_register('admin', 'admin123')
|
|
||||||
425
v1.2/main.py
425
v1.2/main.py
@@ -1,425 +0,0 @@
|
|||||||
from flask import Flask, request, jsonify, make_response
|
|
||||||
import configparser
|
|
||||||
import base64
|
|
||||||
import server.auth
|
|
||||||
import server.info
|
|
||||||
import server.setme
|
|
||||||
import server.arcscore
|
|
||||||
import web.login
|
|
||||||
import web.index
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
wsgi_app = app.wsgi_app
|
|
||||||
|
|
||||||
|
|
||||||
def error_return(error_code): # 错误返回
|
|
||||||
# 100 无法在此ip地址下登录游戏
|
|
||||||
# 101 用户名占用
|
|
||||||
# 102 电子邮箱已注册
|
|
||||||
# 103 已有一个账号由此设备创建
|
|
||||||
# 104 用户名密码错误
|
|
||||||
# 105 24小时内登入两台设备
|
|
||||||
# 106 账户冻结
|
|
||||||
# 107 你没有足够的体力
|
|
||||||
# 401 用户不存在
|
|
||||||
# 403 无法连接至服务器
|
|
||||||
# 501 502 此物品目前无法获取
|
|
||||||
# 504 无效的序列码
|
|
||||||
# 505 此序列码已被使用
|
|
||||||
# 506 你已拥有了此物品
|
|
||||||
# 601 好友列表已满
|
|
||||||
# 602 此用户已是好友
|
|
||||||
# 604 你不能加自己为好友
|
|
||||||
# 其它 发生未知错误
|
|
||||||
return jsonify({
|
|
||||||
"success": False,
|
|
||||||
"error_code": error_code
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
def hello():
|
|
||||||
return "Hello World!"
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/auth/login', methods=['POST']) # 登录接口
|
|
||||||
def login():
|
|
||||||
headers = request.headers
|
|
||||||
id_pwd = headers['Authorization']
|
|
||||||
id_pwd = base64.b64decode(id_pwd[6:]).decode()
|
|
||||||
name, password = id_pwd.split(':', 1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
token = server.auth.arc_login(name, password)
|
|
||||||
if token is not None:
|
|
||||||
r = {"success": True, "token_type": "Bearer"}
|
|
||||||
r['access_token'] = token
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(104) # 用户名或密码错误
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/', methods=['POST']) # 注册接口
|
|
||||||
def register():
|
|
||||||
name = request.form['name']
|
|
||||||
password = request.form['password']
|
|
||||||
try:
|
|
||||||
user_id, token, error_code = server.auth.arc_register(name, password)
|
|
||||||
if user_id is not None:
|
|
||||||
r = {"success": True, "value": {
|
|
||||||
'user_id': user_id, 'access_token': token}}
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(error_code) # 应该是101,用户名被占用,毕竟电子邮箱、设备号没记录
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/compose/aggregate', methods=['GET']) # 用户信息获取
|
|
||||||
def aggregate():
|
|
||||||
calls = request.args.get('calls')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
if calls == '[{ "endpoint": "/user/me", "id": 0 }]': # 极其沙雕的判断,我猜get的参数就两种
|
|
||||||
r = server.info.arc_aggregate_small(user_id)
|
|
||||||
else:
|
|
||||||
r = server.info.arc_aggregate_big(user_id)
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/me/character', methods=['POST']) # 角色切换
|
|
||||||
def character_change():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
character_id = request.form['character']
|
|
||||||
skill_sealed = request.form['skill_sealed']
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
flag = server.setme.change_char(
|
|
||||||
user_id, character_id, skill_sealed)
|
|
||||||
if flag:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"character": character_id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/<path:path>/toggle_uncap', methods=['POST']) # 角色觉醒切换
|
|
||||||
def character_uncap(path):
|
|
||||||
character_id = int(path[22:])
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = server.setme.change_char_uncap(user_id, character_id)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"character": [r]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/friend/me/add', methods=['POST']) # 加好友
|
|
||||||
def add_friend():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
friend_code = request.form['friend_code']
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
friend_id = server.auth.code_get_id(friend_code)
|
|
||||||
if user_id is not None and friend_id is not None:
|
|
||||||
r = server.setme.arc_add_friend(user_id, friend_id)
|
|
||||||
if r is not None and r != 602 and r != 604:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"updatedAt": "2020-09-07T07:32:12.740Z",
|
|
||||||
"createdAt": "2020-09-06T10:05:18.471Z",
|
|
||||||
"friends": r
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
if r is not None:
|
|
||||||
return error_return(r)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
if friend_id is None:
|
|
||||||
return error_return(401)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/friend/me/delete', methods=['POST']) # 删好友
|
|
||||||
def delete_friend():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
friend_id = int(request.form['friend_id'])
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
if user_id is not None and friend_id is not None:
|
|
||||||
r = server.setme.arc_delete_friend(user_id, friend_id)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"updatedAt": "2020-09-07T07:32:12.740Z",
|
|
||||||
"createdAt": "2020-09-06T10:05:18.471Z",
|
|
||||||
"friends": r
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
if friend_id is None:
|
|
||||||
return error_return(401)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song/friend', methods=['GET']) # 好友排名,默认最多50
|
|
||||||
def song_score_friend():
|
|
||||||
song_id = request.args.get('song_id')
|
|
||||||
difficulty = request.args.get('difficulty')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = server.arcscore.arc_score_friend(user_id, song_id, difficulty)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song/me', methods=['GET']) # 我的排名,默认最多20
|
|
||||||
def song_score_me():
|
|
||||||
song_id = request.args.get('song_id')
|
|
||||||
difficulty = request.args.get('difficulty')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = server.arcscore.arc_score_me(user_id, song_id, difficulty)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song', methods=['GET']) # TOP20
|
|
||||||
def song_score_top():
|
|
||||||
song_id = request.args.get('song_id')
|
|
||||||
difficulty = request.args.get('difficulty')
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = server.arcscore.arc_score_top(song_id, difficulty)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/song', methods=['POST']) # 成绩上传
|
|
||||||
def song_score_post():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
song_id = request.form['song_id']
|
|
||||||
difficulty = int(request.form['difficulty'])
|
|
||||||
score = int(request.form['score'])
|
|
||||||
shiny_perfect_count = int(request.form['shiny_perfect_count'])
|
|
||||||
perfect_count = int(request.form['perfect_count'])
|
|
||||||
near_count = int(request.form['near_count'])
|
|
||||||
miss_count = int(request.form['miss_count'])
|
|
||||||
health = int(request.form['health'])
|
|
||||||
modifier = int(request.form['modifier'])
|
|
||||||
beyond_gauge = int(request.form['beyond_gauge'])
|
|
||||||
clear_type = int(request.form['clear_type'])
|
|
||||||
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = server.arcscore.arc_score_post(user_id, song_id, difficulty, score, shiny_perfect_count,
|
|
||||||
perfect_count, near_count, miss_count, health, modifier, beyond_gauge, clear_type)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {"user_rating": r}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/score/token', methods=['GET']) # 成绩上传所需的token,显然我不想验证
|
|
||||||
def score_token():
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"token": "1145141919810"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/me/save', methods=['GET']) # 从云端同步
|
|
||||||
def cloud_get():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
r = server.arcscore.arc_all_get(user_id)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/user/me/save', methods=['POST']) # 向云端同步
|
|
||||||
def cloud_post():
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
scores_data = request.form['scores_data']
|
|
||||||
clearlamps_data = request.form['clearlamps_data']
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
server.arcscore.arc_all_post(user_id, scores_data, clearlamps_data)
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/12/purchase/me/redeem', methods=['POST']) # 兑换码,自然没有用
|
|
||||||
def redeem():
|
|
||||||
return error_return(504)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/coffee/<path:path>', methods=['POST']) # 三个设置,写在最后降低优先级
|
|
||||||
def sys_set(path):
|
|
||||||
set_arg = path[10:]
|
|
||||||
headers = request.headers
|
|
||||||
token = headers['Authorization']
|
|
||||||
token = token[7:]
|
|
||||||
value = request.form['value']
|
|
||||||
|
|
||||||
try:
|
|
||||||
user_id = server.auth.token_get_id(token)
|
|
||||||
if user_id is not None:
|
|
||||||
server.setme.arc_sys_set(user_id, value, set_arg)
|
|
||||||
r = server.info.arc_aggregate_small(user_id)
|
|
||||||
r['value'] = r['value'][0]['value']
|
|
||||||
return jsonify(r)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
except:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
path = r'setting.ini'
|
|
||||||
config.read(path, encoding="utf-8")
|
|
||||||
HOST = config.get('CONFIG', 'HOST')
|
|
||||||
PORT = config.get('CONFIG', 'PORT')
|
|
||||||
app.config.from_mapping(SECRET_KEY='1145141919810')
|
|
||||||
app.register_blueprint(web.login.bp)
|
|
||||||
app.register_blueprint(web.index.bp)
|
|
||||||
|
|
||||||
app.run(HOST, PORT)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
|
||||||
|
|
||||||
# Made By Lost 2020.9.11
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
python main.py
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,149 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import hashlib
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
def arc_login(name: str, password: str) -> str: # 登录判断
|
|
||||||
# 查询数据库中的user表,验证账号密码,返回并记录token
|
|
||||||
# token采用user_id和时间戳连接后hash生成(真的是瞎想的,没用bear)
|
|
||||||
# 密码和token的加密方式为 SHA-256
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
|
||||||
c.execute('''select user_id from user where name = :name and password = :password''', {
|
|
||||||
'name': name, 'password': hash_pwd})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
user_id = str(x[0])
|
|
||||||
now = int(time.time() * 1000)
|
|
||||||
token = hashlib.sha256((user_id + str(now)).encode("utf8")).hexdigest()
|
|
||||||
c.execute(
|
|
||||||
'''select exists(select * from login where user_id = :user_id)''', {"user_id": user_id})
|
|
||||||
|
|
||||||
if c.fetchone() == (1,): # 删掉多余token
|
|
||||||
c.execute('''delete from login where user_id = :user_id''',
|
|
||||||
{'user_id': user_id})
|
|
||||||
|
|
||||||
c.execute('''insert into login(access_token, user_id) values(:access_token, :user_id)''', {
|
|
||||||
'user_id': user_id, 'access_token': token})
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return token
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def arc_register(name: str, password: str): # 注册
|
|
||||||
# 账号注册,只记录hash密码和用户名,生成user_id和user_code,自动登录返回token
|
|
||||||
# token和密码的处理同登录部分
|
|
||||||
|
|
||||||
def build_user_code(c):
|
|
||||||
# 生成9位的user_code,用的自然是随机
|
|
||||||
import random
|
|
||||||
flag = True
|
|
||||||
while flag:
|
|
||||||
user_code = ''.join([str(random.randint(0, 9)) for i in range(9)])
|
|
||||||
c.execute('''select exists(select * from user where user_code = :user_code)''',
|
|
||||||
{'user_code': user_code})
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
flag = False
|
|
||||||
return user_code
|
|
||||||
|
|
||||||
def build_user_id(c):
|
|
||||||
# 生成user_id,往后加1
|
|
||||||
c.execute('''select max(user_id) from user''')
|
|
||||||
x = c.fetchone()
|
|
||||||
if x[0] is not None:
|
|
||||||
return x[0] + 1
|
|
||||||
else:
|
|
||||||
return 2000001
|
|
||||||
|
|
||||||
# def insert_user_char(c, user_id):
|
|
||||||
# # 为用户添加所有可用角色
|
|
||||||
# for i in range(0, 38):
|
|
||||||
# if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]:
|
|
||||||
# sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
# i)+''',30,25000,25000,90,90,90,'',0,0,'',0,1,1)'''
|
|
||||||
# c.execute(sql)
|
|
||||||
# else:
|
|
||||||
# if i != 5:
|
|
||||||
# sql = 'insert into user_char values('+str(user_id)+','+str(
|
|
||||||
# i)+''',30,25000,25000,90,90,90,'',0,0,'',0,0,0)'''
|
|
||||||
# c.execute(sql)
|
|
||||||
def insert_user_char(c, user_id):
|
|
||||||
# 为用户添加所有可用角色
|
|
||||||
c.execute('''select * from character''')
|
|
||||||
x = c.fetchall()
|
|
||||||
if x != []:
|
|
||||||
for i in x:
|
|
||||||
c.execute('''insert into user_char values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o)''', {
|
|
||||||
'a': user_id, 'b': i[0], 'c': i[2], 'd': i[3], 'e': i[4], 'f': i[5], 'g': i[6], 'h': i[7], 'i': i[8], 'j': i[9], 'k': i[10], 'l': i[11], 'm': i[12], 'n': i[14], 'o': i[15]})
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
|
|
||||||
c.execute(
|
|
||||||
'''select exists(select * from user where name = :name)''', {'name': name})
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
user_code = build_user_code(c)
|
|
||||||
user_id = build_user_id(c)
|
|
||||||
now = int(time.time() * 1000)
|
|
||||||
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
|
|
||||||
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled)
|
|
||||||
values(:user_id, :name, :password, :join_date, :user_code, 0, 0, 0, 0, 0, 0, -1, 0)
|
|
||||||
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
|
|
||||||
c.execute('''insert into recent30(user_id) values(:user_id)''', {
|
|
||||||
'user_id': user_id})
|
|
||||||
|
|
||||||
token = hashlib.sha256(
|
|
||||||
(str(user_id) + str(now)).encode("utf8")).hexdigest()
|
|
||||||
c.execute('''insert into login(access_token, user_id) values(:access_token, :user_id)''', {
|
|
||||||
'user_id': user_id, 'access_token': token})
|
|
||||||
|
|
||||||
insert_user_char(c, user_id)
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return user_id, token, 0
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None, None, 101
|
|
||||||
|
|
||||||
|
|
||||||
def token_get_id(token: str):
|
|
||||||
# 用token获取id,没有考虑不同用户token相同情况,说不定会有bug
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select user_id from login where access_token = :token''', {
|
|
||||||
'token': token})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return x[0]
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def code_get_id(user_code):
|
|
||||||
# 用user_code获取id
|
|
||||||
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select user_id from user where user_code = :a''',
|
|
||||||
{'a': user_code})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return x[0]
|
|
||||||
else:
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
4060
v1.2/server/info.py
4060
v1.2/server/info.py
File diff suppressed because it is too large
Load Diff
@@ -1,155 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import server.info
|
|
||||||
|
|
||||||
|
|
||||||
def b2int(x):
|
|
||||||
# int与布尔值转换
|
|
||||||
if x:
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def int2b(x):
|
|
||||||
# int与布尔值转换
|
|
||||||
if x is None or x == 0:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def change_char(user_id, character_id, skill_sealed):
|
|
||||||
# 角色改变,包括技能封印的改变,返回成功与否的布尔值
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
|
||||||
{'a': user_id, 'b': character_id})
|
|
||||||
x = c.fetchone()
|
|
||||||
if x is not None:
|
|
||||||
if skill_sealed == 'false':
|
|
||||||
skill_sealed = False
|
|
||||||
else:
|
|
||||||
skill_sealed = True
|
|
||||||
c.execute('''update user set is_skill_sealed = :a, character_id = :b, is_char_uncapped = :c, is_char_uncapped_override = :d where user_id = :e''', {
|
|
||||||
'a': b2int(skill_sealed), 'b': character_id, 'c': x[0], 'd': x[1], 'e': user_id})
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return True
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def change_char_uncap(user_id, character_id):
|
|
||||||
# 角色觉醒改变,返回字典
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
|
||||||
{'a': user_id, 'b': character_id})
|
|
||||||
x = c.fetchone()
|
|
||||||
r = None
|
|
||||||
if x is not None and x[0] == 1:
|
|
||||||
c.execute('''update user set is_char_uncapped_override = :a where user_id = :b''', {
|
|
||||||
'a': b2int(x[1] == 0), 'b': user_id})
|
|
||||||
c.execute('''update user_char set is_uncapped_override = :a where user_id = :b and character_id = :c''', {
|
|
||||||
'a': b2int(x[1] == 0), 'b': user_id, 'c': character_id})
|
|
||||||
c.execute('''select * from user_char where user_id = :a and character_id = :b''',
|
|
||||||
{'a': user_id, 'b': character_id})
|
|
||||||
y = c.fetchone()
|
|
||||||
c.execute(
|
|
||||||
'''select name from character where character_id = :x''', {'x': y[1]})
|
|
||||||
z = c.fetchone()
|
|
||||||
if z is not None:
|
|
||||||
char_name = z[0]
|
|
||||||
if y is not None:
|
|
||||||
r = {
|
|
||||||
"is_uncapped_override": int2b(y[14]),
|
|
||||||
"is_uncapped": int2b(y[13]),
|
|
||||||
"uncap_cores": [],
|
|
||||||
"char_type": y[12],
|
|
||||||
"skill_id_uncap": y[11],
|
|
||||||
"skill_requires_uncap": int2b(y[10]),
|
|
||||||
"skill_unlock_level": y[9],
|
|
||||||
"skill_id": y[8],
|
|
||||||
"overdrive": y[7],
|
|
||||||
"prog": y[6],
|
|
||||||
"frag": y[5],
|
|
||||||
"level_exp": y[4],
|
|
||||||
"exp": y[3],
|
|
||||||
"level": y[2],
|
|
||||||
"name": char_name,
|
|
||||||
"character_id": y[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def arc_sys_set(user_id, value, set_arg):
|
|
||||||
# 三个设置,PTT隐藏、体力满通知、最爱角色,无返回
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
if 'favorite_character' in set_arg:
|
|
||||||
value = int(value)
|
|
||||||
c.execute('''update user set favorite_character = :a where user_id = :b''', {
|
|
||||||
'a': value, 'b': user_id})
|
|
||||||
|
|
||||||
else:
|
|
||||||
if value == 'false':
|
|
||||||
value = False
|
|
||||||
else:
|
|
||||||
value = True
|
|
||||||
|
|
||||||
if 'is_hide_rating' in set_arg:
|
|
||||||
c.execute('''update user set is_hide_rating = :a where user_id = :b''', {
|
|
||||||
'a': b2int(value), 'b': user_id})
|
|
||||||
if 'max_stamina_notification_enabled' in set_arg:
|
|
||||||
c.execute('''update user set max_stamina_notification_enabled = :a where user_id = :b''', {
|
|
||||||
'a': b2int(value), 'b': user_id})
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def arc_add_friend(user_id, friend_id):
|
|
||||||
# 加好友,返回好友列表,或者是错误码602、604
|
|
||||||
if user_id == friend_id:
|
|
||||||
return 604
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
|
||||||
{'x': user_id, 'y': friend_id})
|
|
||||||
r = None
|
|
||||||
if c.fetchone() == (0,):
|
|
||||||
c.execute('''insert into friend values(:a, :b)''',
|
|
||||||
{'a': user_id, 'b': friend_id})
|
|
||||||
r = server.info.get_user_friend(c, user_id)
|
|
||||||
|
|
||||||
else:
|
|
||||||
return 602
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def arc_delete_friend(user_id, friend_id):
|
|
||||||
# 删好友,返回好友列表
|
|
||||||
conn = sqlite3.connect('./database/arcaea_database.db')
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
|
||||||
{'x': user_id, 'y': friend_id})
|
|
||||||
r = None
|
|
||||||
if c.fetchone() == (1,):
|
|
||||||
c.execute('''delete from friend where user_id_me = :x and user_id_other = :y''',
|
|
||||||
{'x': user_id, 'y': friend_id})
|
|
||||||
|
|
||||||
r = server.info.get_user_friend(c, user_id)
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
return r
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
[CONFIG]
|
|
||||||
HOST = 192.168.1.113
|
|
||||||
PORT = 80
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user