9 Commits
v1.9 ... v2.2

Author SHA1 Message Date
Lost-MSth
df181f104e Update to v2.2
close #13
2021-02-11 15:26:58 +08:00
Lost-MSth
a890a9af4a Waiting for updating and fix some bugs
It will be released soon because lowiro will update in some days.
Fix many bugs and I forgot them. :<

I push this because there's a small but serious safety problem. It should be fixed immediately.

Oh, and this update needs you to login in arcaea again because a new function is added.
2021-02-08 14:45:10 +08:00
Lost-MSth
c6bb4c9afb Update to v2.1 2021-01-21 14:42:57 +08:00
Lost-MSth
98358ad216 Fix two small bugs. 2021-01-10 16:29:18 +08:00
Lost-MSth
e0e6128826 Update README.md 2021-01-08 14:53:50 +08:00
Lost-MSth
08872399cc Update to v2.0
close #11
close #10
close #9
2021-01-08 14:51:37 +08:00
Lost-MSth
29a6cfaac1 Fix a bug. 2021-01-02 15:09:34 +08:00
Lost-MSth
f25bd4130e Update a midway version (waiting for offical update)
Add some things and fix some bugs.
It will not have a description.
2020-12-29 11:29:36 +08:00
Lost-MSth
68c757f9d7 Fix a bug 2020-12-22 13:07:49 +08:00
28 changed files with 3108 additions and 2681 deletions

View File

@@ -2,14 +2,21 @@
一个微型的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 ## 特性 Features
有以下 We have 有以下 We have
- 登录、注册 Login and registration - 登录、注册 Login and registration
- 多设备登录 Multi device login
- 成绩上传 Score upload - 成绩上传 Score upload
- PTT - PTT
- 排名 Rank - 排名 Rank
@@ -20,6 +27,7 @@ This is a small local Arcaea server based on Python and Flask, which can simulat
- 自定义歌曲下载 Customizable songs download - 自定义歌曲下载 Customizable songs download
- 单曲和曲包购买(没啥用) Single songs and song packs purchase(useless) - 单曲和曲包购买(没啥用) Single songs and song packs purchase(useless)
- 奖励系统 Present system - 奖励系统 Present system
- 兑换码系统 Redeem code system
- 全角色立绘 All character drawings - 全角色立绘 All character drawings
- 角色技能 Character skills - 角色技能 Character skills
- 自定义角色属性 Customizable characters attributes - 自定义角色属性 Customizable characters attributes
@@ -31,12 +39,12 @@ This is a small local Arcaea server based on Python and Flask, which can simulat
没有以下 We don't have 没有以下 We don't have
- 角色数值 Character characteristic value - 角色数值 Character characteristic value
- 数据同步的时间记录 The record of time for data synchronization
- 服务器安全性保证 Server security assurance - 服务器安全性保证 Server security assurance
可能有问题 There may be problems 可能有问题 There may be problems
- Recent 30 - Recent 30
- 一些歌曲的解锁 Some Songs' unlocking - 一些歌曲的解锁 Some songs' unlocking
- 同设备多共存登录 Multiple app logins on the same device
## 说明 Statement ## 说明 Statement
只是很有趣,用处探索中。 只是很有趣,用处探索中。
@@ -55,12 +63,17 @@ It is just so interesting. What it can do is under exploration.
> >
> Tips: When updating, please keep the original database in case of data loss. > Tips: When updating, please keep the original database in case of data loss.
### Version 1.9 ### Version 2.2
- 适用于Arcaea 3.4.0版本 For Arcaea 3.4.0 - 适用于Arcaea 3.5.1版本 For Arcaea 3.5.1
- 更新了歌曲数据库 Update the song database. - 更新了歌曲数据库 Update the song database.
-搭档**Luna & Mia**已解锁 Unlock the new character **Luna & Mia**. -增多设备登录 Add multi device login.
- 新增了奖励系统 Add the present system. - 修改了配置文件结构 The configuration file structure has been modified.
- 修复了一些Bug Fix some bugs. - 优化了代码结构 Optimize the code structure.
- 修复了一堆Bug Fix many bugs.
> 提醒:本次更新需重新登录
>
> Tip: You need to log in Arcaea again in this update.
## 运行环境与依赖 Running environment and requirements ## 运行环境与依赖 Running environment and requirements

Binary file not shown.

View File

@@ -33,13 +33,15 @@ rating real,
favorite_character int, favorite_character int,
max_stamina_notification_enabled int, max_stamina_notification_enabled int,
current_map text, current_map text,
ticket int ticket int,
prog_boost int
);''') );''')
c.execute('''create table if not exists login(access_token text, c.execute('''create table if not exists login(access_token text,
user_id int primary key, user_id int,
last_login_time int, login_time int,
last_login_ip text, login_ip text,
last_login_device text login_device text,
primary key(access_token, user_id)
);''') );''')
c.execute('''create table if not exists friend(user_id_me int, c.execute('''create table if not exists friend(user_id_me int,
user_id_other int, user_id_other int,
@@ -206,7 +208,8 @@ clearedsongs_data text,
unlocklist_data text, unlocklist_data text,
installid_data text, installid_data text,
devicemodelname_data text, devicemodelname_data text,
story_data text story_data text,
createdAt int
);''') );''')
c.execute('''create table if not exists present(present_id text primary key, c.execute('''create table if not exists present(present_id text primary key,
expire_ts int, expire_ts int,
@@ -217,19 +220,32 @@ c.execute('''create table if not exists user_present(user_id int,
present_id text, present_id text,
primary key(user_id, present_id) 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', 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'] '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']
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', 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'] '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']
skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', '', '', 'shirabe_entry_fee', skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', '', '', 'shirabe_entry_fee',
'', '', '', '', '', '', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] '', '', '', '', '', '', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
for i in range(0, 41): for i in range(0, 44):
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]: if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21, 42, 43]:
sql = 'insert into character values('+str( 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)''' i)+',"'+char[i]+'''",30,25000,25000,90,90,90,"'''+skill_id[i]+'''",0,0,"'''+skill_id_uncap[i]+'''",0,'',1,1)'''
c.execute(sql) c.execute(sql)

View File

@@ -3,7 +3,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "core", "id": "core",
"_id": "5fdab049a6e343038b0582d4", "_id": "6008c2ff36651a07ebc52ca9",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -15,12 +15,12 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "shiawase", "id": "shiawase",
"_id": "5fdab049a6e343038b058314", "_id": "6008c2ff36651a07ebc52ce0",
"is_available": true "is_available": true
}, { }, {
"type": "character", "type": "character",
"id": "kou", "id": "kou",
"_id": "5fdab049a6e343038b058313", "_id": "6008c2ff36651a07ebc52cdf",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -32,12 +32,12 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "dynamix", "id": "dynamix",
"_id": "5fdab049a6e343038b05831c", "_id": "6008c2ff36651a07ebc52ce4",
"is_available": true "is_available": true
}, { }, {
"type": "character", "type": "character",
"id": "sapphire", "id": "sapphire",
"_id": "5fdab049a6e343038b05831b", "_id": "6008c2ff36651a07ebc52ce3",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -49,12 +49,12 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "mirai", "id": "mirai",
"_id": "5fdab049a6e343038b058318", "_id": "6008c2ff36651a07ebc52cdc",
"is_available": true "is_available": true
}, { }, {
"type": "character", "type": "character",
"id": "lethe", "id": "lethe",
"_id": "5fdab049a6e343038b058317", "_id": "6008c2ff36651a07ebc52cdb",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -66,7 +66,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "yugamu", "id": "yugamu",
"_id": "5fdab049a6e343038b0582d5", "_id": "6008c2ff36651a07ebc52caa",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -78,7 +78,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "lanota", "id": "lanota",
"_id": "5fdab049a6e343038b058305", "_id": "6008c2ff36651a07ebc52cd0",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -90,7 +90,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "nijuusei", "id": "nijuusei",
"_id": "5fdab049a6e343038b0582d6", "_id": "6008c2ff36651a07ebc52cab",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -102,7 +102,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "rei", "id": "rei",
"_id": "5fdab049a6e343038b0582fb", "_id": "6008c2ff36651a07ebc52cc5",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -114,7 +114,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "tonesphere", "id": "tonesphere",
"_id": "5fdab049a6e343038b058307", "_id": "6008c2ff36651a07ebc52cd2",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -126,7 +126,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "groovecoaster", "id": "groovecoaster",
"_id": "5fdab049a6e343038b0582f1", "_id": "6008c2ff36651a07ebc52ca1",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -138,7 +138,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "zettai", "id": "zettai",
"_id": "5fdab049a6e343038b0582fd", "_id": "6008c2ff36651a07ebc52cc7",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -150,7 +150,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "chunithm", "id": "chunithm",
"_id": "5fdab049a6e343038b0582e5", "_id": "6008c2ff36651a07ebc52cbb",
"is_available": true "is_available": true
}], }],
"price": 300, "price": 300,
@@ -160,7 +160,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "prelude", "id": "prelude",
"_id": "5fdab049a6e343038b0582f2", "_id": "6008c2ff36651a07ebc52ca2",
"is_available": true "is_available": true
}], }],
"price": 400, "price": 400,
@@ -170,7 +170,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "omatsuri", "id": "omatsuri",
"_id": "5fdab049a6e343038b0582fe", "_id": "6008c2ff36651a07ebc52cc8",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -180,7 +180,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "vs", "id": "vs",
"_id": "5fdab049a6e343038b0582e8", "_id": "6008c2ff36651a07ebc52cbe",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 500,
@@ -190,7 +190,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "extend", "id": "extend",
"_id": "5fdab049a6e343038b0582f5", "_id": "6008c2ff36651a07ebc52ca5",
"is_available": true "is_available": true
}], }],
"price": 700, "price": 700,
@@ -200,7 +200,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "alice", "id": "alice",
"_id": "5fdab049a6e343038b058303", "_id": "6008c2ff36651a07ebc52ccd",
"is_available": true "is_available": true
}], }],
"orig_price": 500, "orig_price": 500,
@@ -210,7 +210,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "alice_append_1", "id": "alice_append_1",
"_id": "5fdab049a6e343038b0582df", "_id": "6008c2ff36651a07ebc52cb4",
"is_available": true "is_available": true
}], }],
"orig_price": 300, "orig_price": 300,
@@ -220,9 +220,29 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "ongeki", "id": "ongeki",
"_id": "5fdab049a6e343038b0582eb", "_id": "6008c2ff36651a07ebc52cc1",
"is_available": true "is_available": true
}], }],
"orig_price": 400, "orig_price": 400,
"price": 400 "price": 400
}, {
"name": "maimai",
"items": [{
"type": "pack",
"id": "maimai",
"_id": "6008c2ff36651a07ebc52ca8",
"is_available": true
}],
"orig_price": 400,
"price": 400
}, {
"name": "chunithm_append_1",
"items": [{
"type": "pack",
"id": "chunithm_append_1",
"_id": "6008c2ff36651a07ebc52cda",
"is_available": true
}],
"orig_price": 300,
"price": 300
}] }]

View File

@@ -12,7 +12,7 @@
"items": [{ "items": [{
"id": "dataerror", "id": "dataerror",
"type": "single", "type": "single",
"_id": "5fdab049a6e343038b0582ec", "_id": "6008c2ff36651a07ebc52cb5",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -24,7 +24,7 @@
"items": [{ "items": [{
"id": "yourvoiceso", "id": "yourvoiceso",
"type": "single", "type": "single",
"_id": "5fdab049a6e343038b0582f8", "_id": "6008c2ff36651a07ebc52cc2",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -36,7 +36,7 @@
"items": [{ "items": [{
"id": "crosssoul", "id": "crosssoul",
"type": "single", "type": "single",
"_id": "5fdab049a6e343038b058304", "_id": "6008c2ff36651a07ebc52ccf",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -48,7 +48,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "impurebird", "id": "impurebird",
"_id": "5fdab049a6e343038b0582e0", "_id": "6008c2ff36651a07ebc52cb6",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -60,7 +60,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "auxesia", "id": "auxesia",
"_id": "5fdab049a6e343038b0582ed", "_id": "6008c2ff36651a07ebc52c9d",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -72,7 +72,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "modelista", "id": "modelista",
"_id": "5fdab049a6e343038b0582f9", "_id": "6008c2ff36651a07ebc52cc3",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -84,7 +84,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "yozakurafubuki", "id": "yozakurafubuki",
"_id": "5fdab049a6e343038b0582e1", "_id": "6008c2ff36651a07ebc52cb7",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -96,7 +96,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "surrender", "id": "surrender",
"_id": "5fdab049a6e343038b0582ee", "_id": "6008c2ff36651a07ebc52c9e",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -108,7 +108,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "metallicpunisher", "id": "metallicpunisher",
"_id": "5fdab049a6e343038b0582fa", "_id": "6008c2ff36651a07ebc52cc4",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -118,7 +118,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "carminescythe", "id": "carminescythe",
"_id": "5fdab049a6e343038b0582e2", "_id": "6008c2ff36651a07ebc52cb8",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -128,7 +128,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "bethere", "id": "bethere",
"_id": "5fdab049a6e343038b0582ef", "_id": "6008c2ff36651a07ebc52c9f",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -140,7 +140,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "callmyname", "id": "callmyname",
"_id": "5fdab049a6e343038b058306", "_id": "6008c2ff36651a07ebc52cd1",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -152,7 +152,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "fallensquare", "id": "fallensquare",
"_id": "5fdab049a6e343038b0582d7", "_id": "6008c2ff36651a07ebc52cac",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -164,7 +164,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "dropdead", "id": "dropdead",
"_id": "5fdab049a6e343038b0582e3", "_id": "6008c2ff36651a07ebc52cb9",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -176,7 +176,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "alexandrite", "id": "alexandrite",
"_id": "5fdab049a6e343038b0582f0", "_id": "6008c2ff36651a07ebc52ca0",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -188,7 +188,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "astraltale", "id": "astraltale",
"_id": "5fdab049a6e343038b0582fc", "_id": "6008c2ff36651a07ebc52cc6",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -200,7 +200,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "phantasia", "id": "phantasia",
"_id": "5fdab049a6e343038b0582d8", "_id": "6008c2ff36651a07ebc52cad",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -210,7 +210,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "empireofwinter", "id": "empireofwinter",
"_id": "5fdab049a6e343038b0582e4", "_id": "6008c2ff36651a07ebc52cba",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -220,7 +220,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "libertas", "id": "libertas",
"_id": "5fdab049a6e343038b058308", "_id": "6008c2ff36651a07ebc52cd3",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -232,7 +232,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "dottodot", "id": "dottodot",
"_id": "5fdab049a6e343038b0582d9", "_id": "6008c2ff36651a07ebc52cae",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -244,7 +244,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "dreadnought", "id": "dreadnought",
"_id": "5fdab049a6e343038b058309", "_id": "6008c2ff36651a07ebc52cd4",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -256,7 +256,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "mirzam", "id": "mirzam",
"_id": "5fdab049a6e343038b0582da", "_id": "6008c2ff36651a07ebc52caf",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -268,7 +268,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "heavenlycaress", "id": "heavenlycaress",
"_id": "5fdab049a6e343038b0582e6", "_id": "6008c2ff36651a07ebc52cbc",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -278,7 +278,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "filament", "id": "filament",
"_id": "5fdab049a6e343038b0582f3", "_id": "6008c2ff36651a07ebc52ca3",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -288,7 +288,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "avantraze", "id": "avantraze",
"_id": "5fdab049a6e343038b05830a", "_id": "6008c2ff36651a07ebc52cd5",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -298,7 +298,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "battlenoone", "id": "battlenoone",
"_id": "5fdab049a6e343038b0582ff", "_id": "6008c2ff36651a07ebc52cc9",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -308,7 +308,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "saikyostronger", "id": "saikyostronger",
"_id": "5fdab049a6e343038b0582db", "_id": "6008c2ff36651a07ebc52cb0",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -318,7 +318,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "izana", "id": "izana",
"_id": "5fdab049a6e343038b0582e7", "_id": "6008c2ff36651a07ebc52cbd",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -328,7 +328,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "einherjar", "id": "einherjar",
"_id": "5fdab049a6e343038b0582f4", "_id": "6008c2ff36651a07ebc52ca4",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -338,7 +338,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "laqryma", "id": "laqryma",
"_id": "5fdab049a6e343038b05830b", "_id": "6008c2ff36651a07ebc52cd6",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -348,7 +348,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "amygdata", "id": "amygdata",
"_id": "5fdab049a6e343038b058300", "_id": "6008c2ff36651a07ebc52cca",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -358,7 +358,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "altale", "id": "altale",
"_id": "5fdab049a6e343038b0582dc", "_id": "6008c2ff36651a07ebc52cb1",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -368,7 +368,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "feelssoright", "id": "feelssoright",
"_id": "5fdab049a6e343038b05830c", "_id": "6008c2ff36651a07ebc52cd7",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -378,7 +378,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "scarletcage", "id": "scarletcage",
"_id": "5fdab049a6e343038b058301", "_id": "6008c2ff36651a07ebc52ccb",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -388,7 +388,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "teriqma", "id": "teriqma",
"_id": "5fdab049a6e343038b0582dd", "_id": "6008c2ff36651a07ebc52cb2",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -398,7 +398,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "mahoroba", "id": "mahoroba",
"_id": "5fdab049a6e343038b0582e9", "_id": "6008c2ff36651a07ebc52cbf",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -408,7 +408,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "badtek", "id": "badtek",
"_id": "5fdab049a6e343038b05830d", "_id": "6008c2ff36651a07ebc52cd8",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -418,7 +418,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "maliciousmischance", "id": "maliciousmischance",
"_id": "5fdab049a6e343038b058302", "_id": "6008c2ff36651a07ebc52ccc",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -428,7 +428,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "buchigireberserker", "id": "buchigireberserker",
"_id": "5fdab049a6e343038b0582de", "_id": "6008c2ff36651a07ebc52cb3",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -438,7 +438,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "galaxyfriends", "id": "galaxyfriends",
"_id": "5fdab049a6e343038b0582ea", "_id": "6008c2ff36651a07ebc52cc0",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -448,7 +448,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "xeraphinite", "id": "xeraphinite",
"_id": "5fdab049a6e343038b0582f7", "_id": "6008c2ff36651a07ebc52ca7",
"is_available": true "is_available": true
}], }],
"orig_price": 100, "orig_price": 100,
@@ -458,9 +458,19 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "xanatos", "id": "xanatos",
"_id": "5fdab049a6e343038b05830e", "_id": "6008c2ff36651a07ebc52cd9",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100
}, {
"name": "attraqtia",
"items": [{
"type": "single",
"id": "attraqtia",
"_id": "6008c2ff36651a07ebc52cce",
"is_available": true
}],
"orig_price": 100,
"price": 100
}] }]

View File

@@ -1,5 +1,8 @@
# encoding: utf-8
from flask import Flask, request, jsonify, make_response, send_from_directory from flask import Flask, request, jsonify, make_response, send_from_directory
import configparser from logging.config import dictConfig
from setting import Config
import base64 import base64
import server.auth import server.auth
import server.info import server.info
@@ -80,74 +83,56 @@ def favicon():
return app.send_static_file('favicon.ico') return app.send_static_file('favicon.ico')
@app.route('/coffee/12/auth/login', methods=['POST']) # 登录接口 @app.route('/latte/13/auth/login', methods=['POST']) # 登录接口
def login(): def login():
headers = request.headers headers = request.headers
id_pwd = headers['Authorization'] id_pwd = headers['Authorization']
id_pwd = base64.b64decode(id_pwd[6:]).decode() id_pwd = base64.b64decode(id_pwd[6:]).decode()
name, password = id_pwd.split(':', 1) name, password = id_pwd.split(':', 1)
device_id = headers['DeviceId']
try: token, error_code = server.auth.arc_login(name, password, device_id)
token = server.auth.arc_login(name, password) if not error_code:
if token is not None:
r = {"success": True, "token_type": "Bearer"} r = {"success": True, "token_type": "Bearer"}
r['access_token'] = token r['access_token'] = token
return jsonify(r) return jsonify(r)
else: else:
return error_return(104) # 用户名或密码错误 return error_return(error_code)
except:
return error_return(108)
@app.route('/coffee/12/user/', methods=['POST']) # 注册接口 @app.route('/latte/13/user/', methods=['POST']) # 注册接口
def register(): def register():
name = request.form['name'] name = request.form['name']
password = request.form['password'] password = request.form['password']
try: device_id = request.form['device_id']
user_id, token, error_code = server.auth.arc_register(name, password) user_id, token, error_code = server.auth.arc_register(
name, password, device_id)
if user_id is not None: if user_id is not None:
r = {"success": True, "value": { r = {"success": True, "value": {
'user_id': user_id, 'access_token': token}} 'user_id': user_id, 'access_token': token}}
return jsonify(r) return jsonify(r)
else: else:
return error_return(error_code) # 应该是101用户名被占用毕竟电子邮箱、设备号没记录 return error_return(error_code) # 应该是101用户名被占用毕竟电子邮箱没记录
except:
return error_return(108)
# 集成式请求,没想到什么好办法处理,就先这样写着 # 集成式请求,没想到什么好办法处理,就先这样写着
@app.route('/coffee/12/compose/aggregate', methods=['GET']) @app.route('/latte/13/compose/aggregate', methods=['GET'])
def aggregate(): @server.auth.auth_required(request)
def aggregate(user_id):
calls = request.args.get('calls') 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的参数就两种 if calls == '[{ "endpoint": "/user/me", "id": 0 }]': # 极其沙雕的判断我猜get的参数就两种
r = server.info.arc_aggregate_small(user_id) r = server.info.arc_aggregate_small(user_id)
else: else:
r = server.info.arc_aggregate_big(user_id) r = server.info.arc_aggregate_big(user_id)
return jsonify(r) return jsonify(r)
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/user/me/character', methods=['POST']) # 角色切换 @app.route('/latte/13/user/me/character', methods=['POST']) # 角色切换
def character_change(): @server.auth.auth_required(request)
headers = request.headers def character_change(user_id):
token = headers['Authorization']
token = token[7:]
character_id = request.form['character'] character_id = request.form['character']
skill_sealed = request.form['skill_sealed'] skill_sealed = request.form['skill_sealed']
try:
user_id = server.auth.token_get_id(token) flag = server.setme.change_char(user_id, character_id, skill_sealed)
if user_id is not None:
flag = server.setme.change_char(
user_id, character_id, skill_sealed)
if flag: if flag:
return jsonify({ return jsonify({
"success": True, "success": True,
@@ -158,21 +143,14 @@ def character_change():
}) })
else: else:
return error_return(108) return error_return(108)
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/<path:path>/toggle_uncap', methods=['POST']) # 角色觉醒切换 @app.route('/latte/<path:path>/toggle_uncap', methods=['POST']) # 角色觉醒切换
def character_uncap(path): @server.auth.auth_required(request)
character_id = int(path[22:]) def character_uncap(user_id, path):
headers = request.headers while '//' in path:
token = headers['Authorization'] path = path.replace('//', '/')
token = token[7:] character_id = int(path[21:])
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) r = server.setme.change_char_uncap(user_id, character_id)
if r is not None: if r is not None:
return jsonify({ return jsonify({
@@ -184,22 +162,14 @@ def character_uncap(path):
}) })
else: else:
return error_return(108) return error_return(108)
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/friend/me/add', methods=['POST']) # 加好友 @app.route('/latte/13/friend/me/add', methods=['POST']) # 加好友
def add_friend(): @server.auth.auth_required(request)
headers = request.headers def add_friend(user_id):
token = headers['Authorization']
token = token[7:]
friend_code = request.form['friend_code'] friend_code = request.form['friend_code']
try:
user_id = server.auth.token_get_id(token)
friend_id = server.auth.code_get_id(friend_code) friend_id = server.auth.code_get_id(friend_code)
if user_id is not None and friend_id is not None: if friend_id is not None:
r = server.setme.arc_add_friend(user_id, friend_id) r = server.setme.arc_add_friend(user_id, friend_id)
if r is not None and r != 602 and r != 604: if r is not None and r != 602 and r != 604:
return jsonify({ return jsonify({
@@ -217,23 +187,14 @@ def add_friend():
else: else:
return error_return(108) return error_return(108)
else: else:
if friend_id is None:
return error_return(401) return error_return(401)
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/friend/me/delete', methods=['POST']) # 删好友 @app.route('/latte/13/friend/me/delete', methods=['POST']) # 删好友
def delete_friend(): @server.auth.auth_required(request)
headers = request.headers def delete_friend(user_id):
token = headers['Authorization']
token = token[7:]
friend_id = int(request.form['friend_id']) friend_id = int(request.form['friend_id'])
try: if friend_id is not None:
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) r = server.setme.arc_delete_friend(user_id, friend_id)
if r is not None: if r is not None:
return jsonify({ return jsonify({
@@ -248,24 +209,14 @@ def delete_friend():
else: else:
return error_return(108) return error_return(108)
else: else:
if friend_id is None:
return error_return(401) return error_return(401)
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/score/song/friend', methods=['GET']) # 好友排名默认最多50 @app.route('/latte/13/score/song/friend', methods=['GET']) # 好友排名默认最多50
def song_score_friend(): @server.auth.auth_required(request)
def song_score_friend(user_id):
song_id = request.args.get('song_id') song_id = request.args.get('song_id')
difficulty = request.args.get('difficulty') 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) r = server.arcscore.arc_score_friend(user_id, song_id, difficulty)
if r is not None: if r is not None:
return jsonify({ return jsonify({
@@ -274,22 +225,13 @@ def song_score_friend():
}) })
else: else:
return error_return(108) return error_return(108)
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/score/song/me', methods=['GET']) # 我的排名默认最多20 @app.route('/latte/13/score/song/me', methods=['GET']) # 我的排名默认最多20
def song_score_me(): @server.auth.auth_required(request)
def song_score_me(user_id):
song_id = request.args.get('song_id') song_id = request.args.get('song_id')
difficulty = request.args.get('difficulty') 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) r = server.arcscore.arc_score_me(user_id, song_id, difficulty)
if r is not None: if r is not None:
return jsonify({ return jsonify({
@@ -298,22 +240,13 @@ def song_score_me():
}) })
else: else:
return error_return(108) return error_return(108)
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/score/song', methods=['GET']) # TOP20 @app.route('/latte/13/score/song', methods=['GET']) # TOP20
def song_score_top(): @server.auth.auth_required(request)
def song_score_top(user_id):
song_id = request.args.get('song_id') song_id = request.args.get('song_id')
difficulty = request.args.get('difficulty') 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) r = server.arcscore.arc_score_top(song_id, difficulty)
if r is not None: if r is not None:
return jsonify({ return jsonify({
@@ -322,17 +255,11 @@ def song_score_top():
}) })
else: else:
return error_return(108) return error_return(108)
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/score/song', methods=['POST']) # 成绩上传 @app.route('/latte/13/score/song', methods=['POST']) # 成绩上传
def song_score_post(): @server.auth.auth_required(request)
headers = request.headers def song_score_post(user_id):
token = headers['Authorization']
token = token[7:]
song_token = request.form['song_token'] song_token = request.form['song_token']
song_hash = request.form['song_hash'] song_hash = request.form['song_hash']
song_id = request.form['song_id'] song_id = request.form['song_id']
@@ -348,16 +275,13 @@ def song_score_post():
clear_type = int(request.form['clear_type']) clear_type = int(request.form['clear_type'])
submission_hash = request.form['submission_hash'] submission_hash = request.form['submission_hash']
try:
user_id = server.auth.token_get_id(token)
if user_id is not None:
# 增加成绩校验 # 增加成绩校验
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): 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) return error_return(107)
r, re = server.arcscore.arc_score_post(user_id, song_id, difficulty, score, shiny_perfect_count, 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) perfect_count, near_count, miss_count, health, modifier, beyond_gauge, clear_type)
if r: if r is not None:
if re: if re:
return jsonify({ return jsonify({
"success": True, "success": True,
@@ -370,13 +294,9 @@ def song_score_post():
}) })
else: else:
return error_return(108) return error_return(108)
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/score/token', methods=['GET']) # 成绩上传所需的token显然我不想验证 @app.route('/latte/13/score/token', methods=['GET']) # 成绩上传所需的token显然我不想验证
def score_token(): def score_token():
return jsonify({ return jsonify({
"success": True, "success": True,
@@ -387,15 +307,10 @@ def score_token():
# 世界模式成绩上传所需的token无验证 # 世界模式成绩上传所需的token无验证
@app.route('/coffee/12/score/token/world', methods=['GET']) @app.route('/latte/13/score/token/world', methods=['GET'])
def score_token_world(): @server.auth.auth_required(request)
headers = request.headers def score_token_world(user_id):
token = headers['Authorization']
token = token[7:]
args = request.args args = request.args
try:
user_id = server.auth.token_get_id(token)
if user_id:
server.arcworld.play_world_song(user_id, args) server.arcworld.play_world_song(user_id, args)
return jsonify({ return jsonify({
"success": True, "success": True,
@@ -405,20 +320,11 @@ def score_token_world():
"token": "13145201919810" "token": "13145201919810"
} }
}) })
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/user/me/save', methods=['GET']) # 从云端同步 @app.route('/latte/13/user/me/save', methods=['GET']) # 从云端同步
def cloud_get(): @server.auth.auth_required(request)
headers = request.headers def cloud_get(user_id):
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) r = server.arcscore.arc_all_get(user_id)
if r is not None: if r is not None:
return jsonify({ return jsonify({
@@ -427,17 +333,11 @@ def cloud_get():
}) })
else: else:
return error_return(108) return error_return(108)
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/user/me/save', methods=['POST']) # 向云端同步 @app.route('/latte/13/user/me/save', methods=['POST']) # 向云端同步
def cloud_post(): @server.auth.auth_required(request)
headers = request.headers def cloud_post(user_id):
token = headers['Authorization']
token = token[7:]
scores_data = request.form['scores_data'] scores_data = request.form['scores_data']
clearlamps_data = request.form['clearlamps_data'] clearlamps_data = request.form['clearlamps_data']
clearedsongs_data = request.form['clearedsongs_data'] clearedsongs_data = request.form['clearedsongs_data']
@@ -445,9 +345,7 @@ def cloud_post():
installid_data = request.form['installid_data'] installid_data = request.form['installid_data']
devicemodelname_data = request.form['devicemodelname_data'] devicemodelname_data = request.form['devicemodelname_data']
story_data = request.form['story_data'] story_data = request.form['story_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, clearedsongs_data, server.arcscore.arc_all_post(user_id, scores_data, clearlamps_data, clearedsongs_data,
unlocklist_data, installid_data, devicemodelname_data, story_data) unlocklist_data, installid_data, devicemodelname_data, story_data)
return jsonify({ return jsonify({
@@ -456,26 +354,33 @@ def cloud_post():
"user_id": user_id "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: else:
return error_return(108) return jsonify({
except: "success": True,
return error_return(108) "value": {"coupon": ""}
})
else:
@app.route('/coffee/12/purchase/me/redeem', methods=['POST']) # 兑换码,依然没有用 return error_return(error_code)
def redeem():
return error_return(504)
# 礼物确认 # 礼物确认
@app.route('/coffee/12/present/me/claim/<present_id>', methods=['POST']) @app.route('/latte/13/present/me/claim/<present_id>', methods=['POST'])
def claim_present(present_id): @server.auth.auth_required(request)
headers = request.headers def claim_present(user_id, present_id):
token = headers['Authorization']
token = token[7:]
try:
user_id = server.auth.token_get_id(token)
if user_id is not None:
flag = server.arcpurchase.claim_user_present(user_id, present_id) flag = server.arcpurchase.claim_user_present(user_id, present_id)
if flag: if flag:
return jsonify({ return jsonify({
@@ -483,42 +388,39 @@ def claim_present(present_id):
}) })
else: else:
return error_return(108) return error_return(108)
else:
return error_return(108)
except:
return error_return(108)
# 购买,为了world模式boost一下 @app.route('/latte/13/purchase/me/item', methods=['POST']) # 购买world模式boost
@app.route('/coffee/12/purchase/me/item', methods=['POST']) @server.auth.auth_required(request)
def item(): def prog_boost(user_id):
return jsonify({ re = {"success": False}
"success": True 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('/coffee/12/purchase/me/pack', methods=['POST']) # 曲包和单曲购买 @app.route('/latte/13/purchase/me/pack', methods=['POST']) # 曲包和单曲购买
def pack(): @server.auth.auth_required(request)
headers = request.headers def pack(user_id):
token = headers['Authorization']
token = token[7:]
try:
user_id = server.auth.token_get_id(token)
if user_id:
if 'pack_id' in request.form: if 'pack_id' in request.form:
return jsonify(server.arcpurchase.buy_pack(user_id, request.form['pack_id'])) return jsonify(server.arcpurchase.buy_pack(user_id, request.form['pack_id']))
if 'single_id' in request.form: if 'single_id' in request.form:
return jsonify(server.arcpurchase.buy_single(user_id, request.form['single_id'])) return jsonify(server.arcpurchase.buy_single(user_id, request.form['single_id']))
else:
return error_return(108)
except:
return error_return(108)
return jsonify({ return jsonify({
"success": True "success": True
}) })
@app.route('/coffee/12/purchase/bundle/single', methods=['GET']) # 单曲购买信息获取 @app.route('/latte/13/purchase/bundle/single', methods=['GET']) # 单曲购买信息获取
def single(): def single():
return jsonify({ return jsonify({
"success": True, "success": True,
@@ -526,15 +428,9 @@ def single():
}) })
@app.route('/coffee/12/world/map/me', methods=['GET']) # 获得世界模式信息,所有地图 @app.route('/latte/13/world/map/me', methods=['GET']) # 获得世界模式信息,所有地图
def world_all(): @server.auth.auth_required(request)
headers = request.headers def world_all(user_id):
token = headers['Authorization']
token = token[7:]
try:
user_id = server.auth.token_get_id(token)
if user_id:
return jsonify({ return jsonify({
"success": True, "success": True,
"value": { "value": {
@@ -543,39 +439,21 @@ def world_all():
"maps": server.arcworld.get_world_all(user_id) "maps": server.arcworld.get_world_all(user_id)
} }
}) })
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/world/map/me/', methods=['POST']) # 进入地图 @app.route('/latte/13/world/map/me/', methods=['POST']) # 进入地图
def world_in(): @server.auth.auth_required(request)
headers = request.headers def world_in(user_id):
token = headers['Authorization']
token = token[7:]
map_id = request.form['map_id'] map_id = request.form['map_id']
try:
user_id = server.auth.token_get_id(token)
if user_id:
return jsonify({ return jsonify({
"success": True, "success": True,
"value": server.arcworld.get_user_world(user_id, map_id) "value": server.arcworld.get_user_world(user_id, map_id)
}) })
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/world/map/me/<map_id>', methods=['GET']) # 获得单个地图完整信息 @app.route('/latte/13/world/map/me/<map_id>', methods=['GET']) # 获得单个地图完整信息
def world_one(map_id): @server.auth.auth_required(request)
headers = request.headers def world_one(user_id, map_id):
token = headers['Authorization']
token = token[7:]
try:
user_id = server.auth.token_get_id(token)
if user_id:
server.arcworld.change_user_current_map(user_id, map_id) server.arcworld.change_user_current_map(user_id, map_id)
return jsonify({ return jsonify({
"success": True, "success": True,
@@ -585,21 +463,12 @@ def world_one(map_id):
"maps": [server.arcworld.get_user_world_info(user_id, map_id)] "maps": [server.arcworld.get_user_world_info(user_id, map_id)]
} }
}) })
else:
return error_return(108)
except:
return error_return(108)
@app.route('/coffee/12/serve/download/me/song', methods=['GET']) # 歌曲下载 @app.route('/latte/13/serve/download/me/song', methods=['GET']) # 歌曲下载
def download_song(): @server.auth.auth_required(request)
headers = request.headers def download_song(user_id):
token = headers['Authorization']
token = token[7:]
song_ids = request.args.getlist('sid') song_ids = request.args.getlist('sid')
try:
user_id = server.auth.token_get_id(token)
if user_id:
if server.arcdownload.is_able_download(user_id): if server.arcdownload.is_able_download(user_id):
re = {} re = {}
if not song_ids: if not song_ids:
@@ -613,16 +482,12 @@ def download_song():
}) })
else: else:
return error_return(903) return error_return(903)
else:
return error_return(108)
except:
return error_return(108)
@app.route('/download/<path:file_path>', methods=['GET']) # 下载 @app.route('/download/<path:file_path>', methods=['GET']) # 下载
def download(file_path): def download(file_path):
t = request.args.get('t')
try: try:
t = request.args.get('t')
message = server.arcdownload.is_token_able_download(t) message = server.arcdownload.is_token_able_download(t)
if message == 0: if message == 0:
path = os.path.join('./database/songs', file_path) path = os.path.join('./database/songs', file_path)
@@ -636,38 +501,43 @@ def download(file_path):
return error_return(108) return error_return(108)
@app.route('/coffee/<path:path>', methods=['POST']) # 三个设置,写在最后降低优先级 @app.route('/latte/<path:path>', methods=['POST']) # 三个设置,写在最后降低优先级
def sys_set(path): @server.auth.auth_required(request)
def sys_set(user_id, path):
set_arg = path[10:] set_arg = path[10:]
headers = request.headers
token = headers['Authorization']
token = token[7:]
value = request.form['value'] 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) server.setme.arc_sys_set(user_id, value, set_arg)
r = server.info.arc_aggregate_small(user_id) r = server.info.arc_aggregate_small(user_id)
r['value'] = r['value'][0]['value'] r['value'] = r['value'][0]['value']
return jsonify(r) return jsonify(r)
else:
return error_return(108)
except:
return error_return(108)
def main(): def main():
config = configparser.ConfigParser() app.config.from_mapping(SECRET_KEY=Config.SECRET_KEY)
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.login.bp)
app.register_blueprint(web.index.bp) app.register_blueprint(web.index.bp)
app.run(HOST, PORT) dictConfig({
'version': 1,
'formatters': {'default': {
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
}},
'root': {
'level': 'INFO'
}
})
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__': if __name__ == '__main__':

View File

@@ -1 +1 @@
python main.py python -B main.py

View File

@@ -2,10 +2,12 @@ import os
import hashlib import hashlib
from flask import url_for from flask import url_for
import sqlite3 import sqlite3
from server.sql import Connect
import time import time
from setting import Config
time_limit = 3000 # 每个玩家24小时下载次数限制 time_limit = Config.DOWNLOAD_TIMES_LIMIT # 每个玩家24小时下载次数限制
time_gap_limit = 1000 # 下载链接有效秒数 time_gap_limit = Config.DOWNLOAD_TIME_GAP_LIMIT # 下载链接有效秒数
def get_file_md5(file_path): def get_file_md5(file_path):
@@ -13,13 +15,13 @@ def get_file_md5(file_path):
if not os.path.isfile(file_path): if not os.path.isfile(file_path):
return None return None
myhash = hashlib.md5() myhash = hashlib.md5()
f = open(file_path, 'rb') with open(file_path, 'rb') as f:
while True: while True:
b = f.read(8096) b = f.read(8096)
if not b: if not b:
break break
myhash.update(b) myhash.update(b)
f.close()
return myhash.hexdigest() return myhash.hexdigest()
@@ -38,12 +40,27 @@ def get_one_song(c, user_id, song_id, file_dir='./database/songs'):
token = token[:8] token = token[:8]
if i == 'base.ogg': if i == 'base.ogg':
re['audio'] = {"checksum": get_file_md5(os.path.join(file_dir, song_id, '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)} "url": url_for('download', file_path=song_id+'/base.ogg', t=token, _external=True)}
else: else:
if 'chart' not in re: if 'chart' not in re:
re['chart'] = {} re['chart'] = {}
re['chart'][i[0]] = {"checksum": get_file_md5(os.path.join(file_dir, song_id, i)), 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)} "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)''', { c.execute('''insert into download_token values(:a,:b,:c,:d,:e)''', {
@@ -56,35 +73,28 @@ def get_all_songs(user_id, file_dir='./database/songs'):
# 获取所有歌的下载链接,返回字典 # 获取所有歌的下载链接,返回字典
dir_list = os.listdir(file_dir) dir_list = os.listdir(file_dir)
re = {} re = {}
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
for i in dir_list: for i in dir_list:
if os.path.isdir(os.path.join(file_dir, i)): if os.path.isdir(os.path.join(file_dir, i)):
re.update(get_one_song(c, user_id, i)) re.update(get_one_song(c, user_id, i, file_dir))
conn.commit()
conn.close()
return re return re
def get_some_songs(user_id, song_ids): def get_some_songs(user_id, song_ids):
# 获取一些歌的下载链接,返回字典 # 获取一些歌的下载链接,返回字典
re = {} re = {}
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
for song_id in song_ids: for song_id in song_ids:
re.update(get_one_song(c, user_id, song_id)) re.update(get_one_song(c, user_id, song_id))
conn.commit()
conn.close()
return re return re
def is_token_able_download(t): def is_token_able_download(t):
# token是否可以下载返回错误码0即可以 # token是否可以下载返回错误码0即可以
errorcode = 0 errorcode = 108
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
c.execute('''select * from download_token where token = :t limit 1''', c.execute('''select * from download_token where token = :t limit 1''',
{'t': t}) {'t': t})
x = c.fetchone() x = c.fetchone()
@@ -96,21 +106,19 @@ def is_token_able_download(t):
if y and y[0] <= time_limit: if y and y[0] <= time_limit:
c.execute('''insert into user_download values(:a,:b,:c)''', { c.execute('''insert into user_download values(:a,:b,:c)''', {
'a': x[0], 'b': x[3], 'c': now}) 'a': x[0], 'b': x[3], 'c': now})
errorcode = 0
else: else:
errorcode = 903 errorcode = 903
else: else:
errorcode = 108 errorcode = 108
conn.commit()
conn.close()
return errorcode return errorcode
def is_able_download(user_id): def is_able_download(user_id):
# 是否可以下载,返回布尔值 # 是否可以下载,返回布尔值
f = True f = False
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
now = int(time.time()) now = int(time.time())
c.execute( c.execute(
'''delete from user_download where user_id = :a and time <= :b''', {'a': user_id, 'b': now - 24*3600}) '''delete from user_download where user_id = :a and time <= :b''', {'a': user_id, 'b': now - 24*3600})
@@ -118,10 +126,50 @@ def is_able_download(user_id):
'''select count(*) from user_download where user_id = :a''', {'a': user_id}) '''select count(*) from user_download where user_id = :a''', {'a': user_id})
y = c.fetchone() y = c.fetchone()
if y and y[0] <= time_limit: if y and y[0] <= time_limit:
pass f = True
else: else:
f = False 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.commit()
conn.close() conn.close()
return f return error

View File

@@ -1,4 +1,4 @@
import sqlite3 from server.sql import Connect
import time import time
import json import json
@@ -41,26 +41,17 @@ def get_item(c, type='pack'):
def get_single_purchase(): def get_single_purchase():
# main里面没开数据库这里写一下代替 # main里面没开数据库这里写一下代替
conn = sqlite3.connect('./database/arcaea_database.db') re = []
c = conn.cursor() with Connect() as c:
re = get_item(c, type='single') re = get_item(c, type='single')
conn.commit()
conn.close()
return re return re
def buy_pack(user_id, pack_id): def buy_item(c, user_id, price):
# 曲包购买,返回字典 # 购买接口,返回成功与否标识符和剩余源点数
conn = sqlite3.connect('./database/arcaea_database.db') c.execute('''select ticket from user where user_id = :a''',
c = conn.cursor() {'a': user_id})
c.execute('''select price from item where item_id = :a''', {'a': pack_id})
price = c.fetchone()
if price:
price = price[0]
else:
price = 0
c.execute('''select ticket from user where user_id = :a''', {'a': user_id})
ticket = c.fetchone() ticket = c.fetchone()
if ticket: if ticket:
ticket = ticket[0] ticket = ticket[0]
@@ -68,28 +59,41 @@ def buy_pack(user_id, pack_id):
ticket = 0 ticket = 0
if ticket < price: if ticket < price:
conn.commit() return False, ticket
conn.close()
return {
"success": False
}
c.execute('''update user set ticket = :b where user_id = :a''', c.execute('''update user set ticket = :b where user_id = :a''',
{'a': user_id, 'b': ticket-price}) {'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')''', c.execute('''insert into user_item values(:a,:b,'pack')''',
{'a': user_id, 'b': pack_id}) {'a': user_id, 'b': pack_id})
conn.commit() re = {"success": True}
conn.close()
return { return re
"success": True
}
def buy_single(user_id, single_id): def buy_single(user_id, single_id):
# 单曲购买,返回字典 # 单曲购买,返回字典
conn = sqlite3.connect('./database/arcaea_database.db') re = {"success": False}
c = conn.cursor() with Connect() as c:
c.execute('''select price from item where item_id = :a''', c.execute('''select price from item where item_id = :a''',
{'a': single_id}) {'a': single_id})
price = c.fetchone() price = c.fetchone()
@@ -98,30 +102,30 @@ def buy_single(user_id, single_id):
else: else:
price = 0 price = 0
c.execute('''select ticket from user where user_id = :a''', {'a': user_id}) flag, ticket = buy_item(c, user_id, price)
ticket = c.fetchone()
if ticket:
ticket = ticket[0]
else:
ticket = 0
if ticket < price: if flag:
conn.commit()
conn.close()
return {
"success": False
}
c.execute('''update user set ticket = :b where user_id = :a''',
{'a': user_id, 'b': ticket-price})
c.execute('''insert into user_item values(:a,:b,'single')''', c.execute('''insert into user_item values(:a,:b,'single')''',
{'a': user_id, 'b': single_id}) {'a': user_id, 'b': single_id})
re = {"success": True}
conn.commit() return re
conn.close()
return {
"success": True 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): def get_user_present(c, user_id):
@@ -146,13 +150,10 @@ def get_user_present(c, user_id):
def claim_user_present(user_id, present_id): def claim_user_present(user_id, present_id):
# 确认并删除用户奖励,返回成功与否的布尔值 # 确认并删除用户奖励,返回成功与否的布尔值
flag = False flag = False
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
c.execute('''select exists(select * from user_present where user_id=:a and present_id=:b)''', c.execute('''select exists(select * from user_present where user_id=:a and present_id=:b)''',
{'a': user_id, 'b': present_id}) {'a': user_id, 'b': present_id})
if c.fetchone() == (1,): if c.fetchone() == (1,):
flag = True
c.execute('''delete from user_present where user_id=:a and present_id=:b''', c.execute('''delete from user_present where user_id=:a and present_id=:b''',
{'a': user_id, 'b': present_id}) {'a': user_id, 'b': present_id})
c.execute('''select * from present where present_id=:b''', c.execute('''select * from present where present_id=:b''',
@@ -170,11 +171,49 @@ def claim_user_present(user_id, present_id):
ticket += int(i['amount']) ticket += int(i['amount'])
c.execute('''update user set ticket=:b where user_id=:a''', { c.execute('''update user set ticket=:b where user_id=:a''', {
'a': user_id, 'b': ticket}) 'a': user_id, 'b': ticket})
flag = True
else: else:
# 过期 # 过期
flag = False flag = False
conn.commit()
conn.close()
return flag 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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -1,43 +1,71 @@
import sqlite3
import hashlib import hashlib
import time import time
import server.arcworld import server.arcworld
from server.sql import Connect
import functools
from setting import Config
def arc_login(name: str, password: str) -> str: # 登录判断 def arc_login(name: str, password: str, device_id: str): # 登录判断
# 查询数据库中的user表验证账号密码返回并记录token # 查询数据库中的user表验证账号密码返回并记录token多返回个error code
# token采用user_id和时间戳连接后hash生成真的是瞎想的没用bear # token采用user_id和时间戳连接后hash生成真的是瞎想的没用bear
# 密码和token的加密方式为 SHA-256 # 密码和token的加密方式为 SHA-256
conn = sqlite3.connect('./database/arcaea_database.db') error_code = 108
c = conn.cursor() token = None
with Connect() as c:
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest() hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
c.execute('''select user_id from user where name = :name and password = :password''', { c.execute('''select user_id, password from user where name = :name''', {
'name': name, 'password': hash_pwd}) 'name': name})
x = c.fetchone() x = c.fetchone()
if x is not None: if x is not None:
if x[1] == '':
# 账号封禁
error_code = 106
elif x[1] == hash_pwd:
user_id = str(x[0]) user_id = str(x[0])
now = int(time.time() * 1000) now = int(time.time() * 1000)
token = hashlib.sha256((user_id + str(now)).encode("utf8")).hexdigest() token = hashlib.sha256(
(user_id + str(now)).encode("utf8")).hexdigest()
c.execute( c.execute(
'''select exists(select * from login where user_id = :user_id)''', {"user_id": user_id}) '''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('')
if c.fetchone() == (1,): # 删掉多余token should_delete_num = len(
c.execute('''delete from login where user_id = :user_id''', device_list) + 1 - Config.LOGIN_DEVICE_NUMBER_LIMIT
{'user_id': user_id})
c.execute('''insert into login(access_token, user_id) values(:access_token, :user_id)''', { if not Config.ALLOW_LOGIN_SAME_DEVICE:
'user_id': user_id, 'access_token': token}) if device_id in device_list: # 对相同设备进行删除
conn.commit() c.execute('''delete from login where login_device=:a''', {
conn.close() 'a': device_id})
return token should_delete_num = len(
device_list) + 1 - device_list.count(device_id) - Config.LOGIN_DEVICE_NUMBER_LIMIT
conn.commit() if should_delete_num >= 1: # 删掉多余token
conn.close() c.execute('''delete from login where rowid in (select rowid from login where user_id=:user_id limit :a);''',
return None {'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): # 注册 def arc_register(name: str, password: str, device_id: str): # 注册
# 账号注册只记录hash密码和用户名生成user_id和user_code自动登录返回token # 账号注册只记录hash密码和用户名生成user_id和user_code自动登录返回token
# token和密码的处理同登录部分 # token和密码的处理同登录部分
@@ -71,8 +99,10 @@ def arc_register(name: str, password: str): # 注册
c.execute('''insert into user_char values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o)''', { 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]}) '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') user_id = None
c = conn.cursor() token = None
error_code = 108
with Connect() as c:
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest() hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
c.execute( c.execute(
'''select exists(select * from user where name = :name)''', {'name': name}) '''select exists(select * from user where name = :name)''', {'name': name})
@@ -89,50 +119,63 @@ def arc_register(name: str, password: str): # 注册
token = hashlib.sha256( token = hashlib.sha256(
(str(user_id) + str(now)).encode("utf8")).hexdigest() (str(user_id) + str(now)).encode("utf8")).hexdigest()
c.execute('''insert into login(access_token, user_id) values(:access_token, :user_id)''', { 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}) 'user_id': user_id, 'access_token': token, 'device_id': device_id})
insert_user_char(c, user_id) insert_user_char(c, user_id)
conn.commit() error_code = 0
conn.close()
return user_id, token, 0
else: else:
conn.commit() error_code = 101
conn.close()
return None, None, 101 return user_id, token, error_code
def token_get_id(token: str): def token_get_id(token: str):
# 用token获取id没有考虑不同用户token相同情况说不定会有bug # 用token获取id没有考虑不同用户token相同情况说不定会有bug
conn = sqlite3.connect('./database/arcaea_database.db') user_id = None
c = conn.cursor() with Connect() as c:
c.execute('''select user_id from login where access_token = :token''', { c.execute('''select user_id from login where access_token = :token''', {
'token': token}) 'token': token})
x = c.fetchone() x = c.fetchone()
if x is not None: if x is not None:
conn.commit() user_id = x[0]
conn.close()
return x[0] return user_id
else:
conn.commit()
conn.close()
return None
def code_get_id(user_code): def code_get_id(user_code):
# 用user_code获取id # 用user_code获取id
conn = sqlite3.connect('./database/arcaea_database.db') user_id = None
c = conn.cursor()
with Connect() as c:
c.execute('''select user_id from user where user_code = :a''', c.execute('''select user_id from user where user_code = :a''',
{'a': user_code}) {'a': user_code})
x = c.fetchone() x = c.fetchone()
if x is not None: if x is not None:
conn.commit() user_id = x[0]
conn.close()
return 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: else:
conn.commit() return '''{"success":false,"error_code":108}'''
conn.close()
return None return wrapped_view
return decorator

View File

@@ -1,4 +1,4 @@
import sqlite3 from server.sql import Connect
import server.arcworld import server.arcworld
import server.arcpurchase import server.arcpurchase
import time import time
@@ -170,6 +170,9 @@ def get_value_0(c, user_id):
characters = [] characters = []
for i in user_character: for i in user_character:
characters.append(i['character_id']) characters.append(i['character_id'])
prog_boost = 0
if x[27] and x[27] != 0:
prog_boost = 300
r = {"is_aprilfools": False, r = {"is_aprilfools": False,
"curr_available_maps": [], "curr_available_maps": [],
@@ -189,12 +192,12 @@ def get_value_0(c, user_id):
"is_locked_name_duplicate": False, "is_locked_name_duplicate": False,
"is_skill_sealed": int2b(x[7]), "is_skill_sealed": int2b(x[7]),
"current_map": x[25], "current_map": x[25],
"prog_boost": 0, "prog_boost": prog_boost,
"next_fragstam_ts": -1, "next_fragstam_ts": -1,
"max_stamina_ts": 1586274871917, "max_stamina_ts": 1586274871917,
"stamina": 12, "stamina": 12,
"world_unlocks": ["scenery_chap1", "scenery_chap2", "scenery_chap3", "scenery_chap4", "scenery_chap5"], "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"], "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), # ["dataerror", "yourvoiceso", "crosssoul", "impurebird", "auxesia", "modelista", "yozakurafubuki", "surrender", "metallicpunisher", "carminescythe", "bethere", "callmyname", "fallensquare", "dropdead", "alexandrite", "astraltale", "phantasia", "empireofwinter", "libertas", "dottodot", "dreadnought", "mirzam", "heavenlycaress", "filament", "avantraze", "battlenoone", "saikyostronger", "izana", "einherjar", "laqryma", "amygdata", "altale", "feelssoright", "scarletcage", "teriqma", "mahoroba", "badtek", "maliciousmischance", "buchigireberserker", "galaxyfriends", "xeraphinite", "xanatos"] "singles": get_user_singles(c, user_id), # ["dataerror", "yourvoiceso", "crosssoul", "impurebird", "auxesia", "modelista", "yozakurafubuki", "surrender", "metallicpunisher", "carminescythe", "bethere", "callmyname", "fallensquare", "dropdead", "alexandrite", "astraltale", "phantasia", "empireofwinter", "libertas", "dottodot", "dreadnought", "mirzam", "heavenlycaress", "filament", "avantraze", "battlenoone", "saikyostronger", "izana", "einherjar", "laqryma", "amygdata", "altale", "feelssoright", "scarletcage", "teriqma", "mahoroba", "badtek", "maliciousmischance", "buchigireberserker", "galaxyfriends", "xeraphinite", "xanatos"]
"packs": get_user_packs(c, user_id), "packs": get_user_packs(c, user_id),
# ["vs", "extend", "dynamix", "prelude", "core", "yugamu", "omatsuri", "zettai", "mirai", "shiawase", "chunithm", "nijuusei", "groovecoaster", "rei", "tonesphere", "lanota"] # ["vs", "extend", "dynamix", "prelude", "core", "yugamu", "omatsuri", "zettai", "mirai", "shiawase", "chunithm", "nijuusei", "groovecoaster", "rei", "tonesphere", "lanota"]
@@ -211,24 +214,21 @@ def get_value_0(c, user_id):
def arc_aggregate_small(user_id): def arc_aggregate_small(user_id):
# 返回用户数据 # 返回用户数据
conn = sqlite3.connect('./database/arcaea_database.db') r = {"success": False}
c = conn.cursor() with Connect() as c:
r = {"success": True, r = {"success": True,
"value": [{ "value": [{
"id": 0, "id": 0,
"value": get_value_0(c, user_id) "value": get_value_0(c, user_id)
}]} }]}
conn.commit()
conn.close()
return r return r
def arc_aggregate_big(user_id): def arc_aggregate_big(user_id):
# 返回用户数据和地图歌曲信息 # 返回用户数据和地图歌曲信息
r = {"success": False}
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
r = {"success": True, r = {"success": True,
"value": [{ "value": [{
"id": 0, "id": 0,
@@ -353,6 +353,4 @@ def arc_aggregate_big(user_id):
} }
]} ]}
conn.commit()
conn.close()
return r return r

View File

@@ -1,4 +1,4 @@
import sqlite3 from server.sql import Connect
import server.info import server.info
@@ -20,8 +20,9 @@ def int2b(x):
def change_char(user_id, character_id, skill_sealed): def change_char(user_id, character_id, skill_sealed):
# 角色改变,包括技能封印的改变,返回成功与否的布尔值 # 角色改变,包括技能封印的改变,返回成功与否的布尔值
conn = sqlite3.connect('./database/arcaea_database.db') re = False
c = conn.cursor()
with Connect() as c:
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''', 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}) {'a': user_id, 'b': character_id})
x = c.fetchone() x = c.fetchone()
@@ -33,23 +34,19 @@ def change_char(user_id, character_id, skill_sealed):
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''', { 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}) 'a': b2int(skill_sealed), 'b': character_id, 'c': x[0], 'd': x[1], 'e': user_id})
conn.commit() re = True
conn.close()
return True
conn.commit() return re
conn.close()
return False
def change_char_uncap(user_id, character_id): def change_char_uncap(user_id, character_id):
# 角色觉醒改变,返回字典 # 角色觉醒改变,返回字典
conn = sqlite3.connect('./database/arcaea_database.db') r = None
c = conn.cursor() with Connect() as c:
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''', 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}) {'a': user_id, 'b': character_id})
x = c.fetchone() x = c.fetchone()
r = None
if x is not None and x[0] == 1: if x is not None and x[0] == 1:
c.execute('''update user set is_char_uncapped_override = :a where user_id = :b''', { c.execute('''update user set is_char_uncapped_override = :a where user_id = :b''', {
'a': b2int(x[1] == 0), 'b': user_id}) 'a': b2int(x[1] == 0), 'b': user_id})
@@ -83,15 +80,12 @@ def change_char_uncap(user_id, character_id):
"character_id": y[1] "character_id": y[1]
} }
conn.commit()
conn.close()
return r return r
def arc_sys_set(user_id, value, set_arg): def arc_sys_set(user_id, value, set_arg):
# 三个设置PTT隐藏、体力满通知、最爱角色无返回 # 三个设置PTT隐藏、体力满通知、最爱角色无返回
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
if 'favorite_character' in set_arg: if 'favorite_character' in set_arg:
value = int(value) value = int(value)
c.execute('''update user set favorite_character = :a where user_id = :b''', { c.execute('''update user set favorite_character = :a where user_id = :b''', {
@@ -110,8 +104,6 @@ def arc_sys_set(user_id, value, set_arg):
c.execute('''update user set max_stamina_notification_enabled = :a where user_id = :b''', { c.execute('''update user set max_stamina_notification_enabled = :a where user_id = :b''', {
'a': b2int(value), 'b': user_id}) 'a': b2int(value), 'b': user_id})
conn.commit()
conn.close()
return None return None
@@ -119,37 +111,32 @@ def arc_add_friend(user_id, friend_id):
# 加好友返回好友列表或者是错误码602、604 # 加好友返回好友列表或者是错误码602、604
if user_id == friend_id: if user_id == friend_id:
return 604 return 604
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor() r = None
with Connect() as c:
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''', c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
{'x': user_id, 'y': friend_id}) {'x': user_id, 'y': friend_id})
r = None
if c.fetchone() == (0,): if c.fetchone() == (0,):
c.execute('''insert into friend values(:a, :b)''', c.execute('''insert into friend values(:a, :b)''',
{'a': user_id, 'b': friend_id}) {'a': user_id, 'b': friend_id})
r = server.info.get_user_friend(c, user_id) r = server.info.get_user_friend(c, user_id)
else: else:
return 602 r = 602
conn.commit()
conn.close()
return r return r
def arc_delete_friend(user_id, friend_id): def arc_delete_friend(user_id, friend_id):
# 删好友,返回好友列表 # 删好友,返回好友列表
conn = sqlite3.connect('./database/arcaea_database.db') r = None
c = conn.cursor() with Connect() as c:
c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''', c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
{'x': user_id, 'y': friend_id}) {'x': user_id, 'y': friend_id})
r = None
if c.fetchone() == (1,): if c.fetchone() == (1,):
c.execute('''delete from friend where user_id_me = :x and user_id_other = :y''', c.execute('''delete from friend where user_id_me = :x and user_id_other = :y''',
{'x': user_id, 'y': friend_id}) {'x': user_id, 'y': friend_id})
r = server.info.get_user_friend(c, user_id) r = server.info.get_user_friend(c, user_id)
conn.commit()
conn.close()
return r return r

View File

@@ -0,0 +1,25 @@
import sqlite3
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()
return True

View File

@@ -1,7 +0,0 @@
[CONFIG]
HOST = 192.168.1.113
PORT = 80
[WEB]
USERNAME = admin
PASSWORD = admin

67
latest version/setting.py Normal file
View File

@@ -0,0 +1,67 @@
class Config():
'''
This is the setting file. You can change some parameters here.
'''
'''
--------------------
主机的地址和端口号
Host and port of your server
'''
HOST = '192.168.1.101'
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
'''
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 multiple applications on the same device to log in is allowed
'''
ALLOW_LOGIN_SAME_DEVICE = False
'''
--------------------
'''

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View File

@@ -17,10 +17,13 @@
<a href="{{ url_for('index.all_character') }}">角色信息查询 All characters</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_item') }}">购买信息查询 All items</a></br></br>
<a href="{{ url_for('index.all_present') }}">奖励信息查询 All presents</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> <a href="{{ url_for('index.single_chart_top') }}">单个铺面排行榜查询 Single song chart tops</a>
<hr> <hr>
<h1>系统方面 System</h1> <h1>系统方面 System</h1>
<a href="{{ url_for('index.update_database') }}">数据库更新 Update databases</a></br></br> <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.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_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_character') }}">角色修改 Change the characters</a></br></br>
@@ -28,7 +31,9 @@
<a href="{{ url_for('index.change_user') }}">用户信息修改 Change user information</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_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.change_present') }}">奖励修改 Change the presents</a></br></br>
<a href="{{ url_for('index.deliver_present') }}">奖励分发 Deliver the presents</a> <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 %} {% endblock %}

View 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 %}

View File

@@ -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 %}

View File

@@ -3,7 +3,7 @@ from flask import (
) )
from web.login import login_required from web.login import login_required
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
import sqlite3 from server.sql import Connect
import web.webscore import web.webscore
import web.system import web.system
import time import time
@@ -43,8 +43,7 @@ def single_player_score():
user_code = request.form['user_code'] user_code = request.form['user_code']
error = None error = None
if name or user_code: if name or user_code:
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
if user_code: if user_code:
c.execute('''select user_id from user where user_code=:a''', { c.execute('''select user_id from user where user_code=:a''', {
'a': user_code}) 'a': user_code})
@@ -61,8 +60,6 @@ def single_player_score():
error = '无成绩 No score.' error = '无成绩 No score.'
else: else:
error = '玩家不存在 The player does not exist.' error = '玩家不存在 The player does not exist.'
conn.commit()
conn.close()
else: else:
error = '输入为空 Null Input.' error = '输入为空 Null Input.'
@@ -84,8 +81,7 @@ def single_player_ptt():
user_code = request.form['user_code'] user_code = request.form['user_code']
error = None error = None
if name or user_code: if name or user_code:
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
if user_code: if user_code:
c.execute('''select user_id from user where user_code=:a''', { c.execute('''select user_id from user where user_code=:a''', {
'a': user_code}) 'a': user_code})
@@ -99,7 +95,8 @@ def single_player_ptt():
user_id = user_id[0] user_id = user_id[0]
user = web.webscore.get_user(c, user_id) user = web.webscore.get_user(c, user_id)
posts = web.webscore.get_user_score(c, user_id, 30) posts = web.webscore.get_user_score(c, user_id, 30)
recent, recentptt = web.webscore.get_user_recent30(c, user_id) recent, recentptt = web.webscore.get_user_recent30(
c, user_id)
if not posts: if not posts:
error = '无成绩 No score.' error = '无成绩 No score.'
else: else:
@@ -111,8 +108,6 @@ def single_player_ptt():
else: else:
error = '玩家不存在 The player does not exist.' error = '玩家不存在 The player does not exist.'
conn.commit()
conn.close()
else: else:
error = '输入为空 Null Input.' error = '输入为空 Null Input.'
@@ -128,11 +123,10 @@ def single_player_ptt():
@login_required @login_required
def all_player(): def all_player():
# 所有玩家数据按照ptt排序 # 所有玩家数据按照ptt排序
conn = sqlite3.connect('./database/arcaea_database.db') error = None
c = conn.cursor() with Connect() as c:
c.execute('''select * from user order by rating_ptt DESC''') c.execute('''select * from user order by rating_ptt DESC''')
x = c.fetchall() x = c.fetchall()
error = None
if x: if x:
posts = [] posts = []
for i in x: for i in x:
@@ -164,8 +158,6 @@ def all_player():
else: else:
error = '没有玩家数据 No player data.' error = '没有玩家数据 No player data.'
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
return render_template('web/allplayer.html') return render_template('web/allplayer.html')
@@ -184,11 +176,10 @@ def all_song():
else: else:
return None return None
conn = sqlite3.connect('./database/arcsong.db') error = None
c = conn.cursor() with Connect('./database/arcsong.db') as c:
c.execute('''select * from songs''') c.execute('''select * from songs''')
x = c.fetchall() x = c.fetchall()
error = None
if x: if x:
posts = [] posts = []
for i in x: for i in x:
@@ -202,8 +193,6 @@ def all_song():
else: else:
error = '没有铺面数据 No song data.' error = '没有铺面数据 No song data.'
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
return render_template('web/allsong.html') return render_template('web/allsong.html')
@@ -221,15 +210,13 @@ def single_chart_top():
if difficulty.isdigit(): if difficulty.isdigit():
difficulty = int(difficulty) difficulty = int(difficulty)
error = None error = None
conn = sqlite3.connect('./database/arcsong.db') x = None
c = conn.cursor() with Connect('./database/arcsong.db') as c:
song_name = '%'+song_name+'%' song_name = '%'+song_name+'%'
c.execute('''select sid, name_en from songs where sid like :a limit 1''', c.execute('''select sid, name_en from songs where sid like :a limit 1''',
{'a': song_name}) {'a': song_name})
x = c.fetchone() x = c.fetchone()
conn.commit()
conn.close()
print(x)
if x: if x:
song_id = x[0] song_id = x[0]
posts = server.arcscore.arc_score_top(song_id, difficulty, -1) posts = server.arcscore.arc_score_top(song_id, difficulty, -1)
@@ -317,8 +304,8 @@ def add_song():
song_id = song_id[:200] song_id = song_id[:200]
if len(name_en) >= 256: if len(name_en) >= 256:
name_en = name_en[:200] name_en = name_en[:200]
conn = sqlite3.connect('./database/arcsong.db')
c = conn.cursor() with Connect('./database/arcsong.db') as c:
c.execute( c.execute(
'''select exists(select * from songs where sid=:a)''', {'a': song_id}) '''select exists(select * from songs where sid=:a)''', {'a': song_id})
if c.fetchone() == (0,): if c.fetchone() == (0,):
@@ -328,9 +315,6 @@ def add_song():
else: else:
error = '歌曲已存在 The song exists.' error = '歌曲已存在 The song exists.'
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
@@ -344,8 +328,7 @@ def delete_song():
error = None error = None
song_id = request.form['sid'] song_id = request.form['sid']
conn = sqlite3.connect('./database/arcsong.db') with Connect('./database/arcsong.db') as c:
c = conn.cursor()
c.execute( c.execute(
'''select exists(select * from songs where sid=:a)''', {'a': song_id}) '''select exists(select * from songs where sid=:a)''', {'a': song_id})
if c.fetchone() == (1,): if c.fetchone() == (1,):
@@ -354,8 +337,6 @@ def delete_song():
else: else:
error = "歌曲不存在 The song doesn't exist." error = "歌曲不存在 The song doesn't exist."
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
@@ -366,12 +347,10 @@ def delete_song():
@login_required @login_required
def all_character(): def all_character():
# 所有角色数据 # 所有角色数据
error = None
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
c.execute('''select * from character''') c.execute('''select * from character''')
x = c.fetchall() x = c.fetchall()
error = None
if x: if x:
posts = [] posts = []
for i in x: for i in x:
@@ -389,8 +368,6 @@ def all_character():
else: else:
error = '没有角色数据 No character data.' error = '没有角色数据 No character data.'
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
return render_template('web/allchar.html') return render_template('web/allchar.html')
@@ -403,7 +380,7 @@ def all_character():
def change_character(): def change_character():
# 修改角色数据 # 修改角色数据
skill_ids = ['No_skill', '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', skill_ids = ['No_skill', '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', 'frags_kou', 'visual_ink', 'shirabe_entry_fee', 'frags_yume', 'note_mirror|visual_hide_far', 'frags_ongeki'] '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', 'frags_kou', 'visual_ink', 'shirabe_entry_fee', 'frags_yume', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle', 'gauge_exhaustion']
return render_template('web/changechar.html', skill_ids=skill_ids) return render_template('web/changechar.html', skill_ids=skill_ids)
@@ -443,8 +420,7 @@ def edit_char():
flash(error) flash(error)
return redirect(url_for('index.change_character')) return redirect(url_for('index.change_character'))
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
c.execute( c.execute(
'''select exists(select * from character where character_id=:a)''', {'a': character_id}) '''select exists(select * from character where character_id=:a)''', {'a': character_id})
if c.fetchone() == (1,): if c.fetchone() == (1,):
@@ -484,9 +460,6 @@ def edit_char():
else: else:
error = '角色不存在 The character does not exist.' error = '角色不存在 The character does not exist.'
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
@@ -497,11 +470,8 @@ def edit_char():
@login_required @login_required
def update_character(): def update_character():
# 更新角色数据 # 更新角色数据
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
web.system.update_user_char(c) web.system.update_user_char(c)
conn.commit()
conn.close()
flash('数据更新成功 Success update data.') flash('数据更新成功 Success update data.')
return redirect(url_for('index.change_character')) return redirect(url_for('index.change_character'))
@@ -535,8 +505,7 @@ def edit_user():
flash(error) flash(error)
return redirect(url_for('index.change_user')) return redirect(url_for('index.change_user'))
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
# 全修改 # 全修改
if 'name' not in request.form and 'user_code' not in request.form: if 'name' not in request.form and 'user_code' not in request.form:
@@ -583,8 +552,6 @@ def edit_user():
if flag: if flag:
error = '输入为空 Null Input.' error = '输入为空 Null Input.'
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
@@ -614,8 +581,7 @@ def edit_user_purchase():
flash('输入为空 Null Input.') flash('输入为空 Null Input.')
return redirect(url_for('index.change_user_purchase')) return redirect(url_for('index.change_user_purchase'))
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
# 全修改 # 全修改
if 'name' not in request.form and 'user_code' not in request.form: if 'name' not in request.form and 'user_code' not in request.form:
@@ -659,8 +625,6 @@ def edit_user_purchase():
if flag: if flag:
error = '输入为空 Null Input.' error = '输入为空 Null Input.'
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
@@ -730,8 +694,7 @@ def change_item():
flash(error) flash(error)
return redirect(url_for('index.change_item')) return redirect(url_for('index.change_item'))
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
c.execute( c.execute(
'''select exists(select * from item where item_id=:a and type=:b)''', {'a': item_id, 'b': item_type}) '''select exists(select * from item where item_id=:a and type=:b)''', {'a': item_id, 'b': item_type})
if c.fetchone() == (1,): if c.fetchone() == (1,):
@@ -762,8 +725,6 @@ def change_item():
else: else:
error = '购买项目不存在 The item does not exist.' error = '购买项目不存在 The item does not exist.'
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
@@ -783,8 +744,7 @@ def update_user_save():
name = None name = None
user_code = None user_code = None
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
# 全修改 # 全修改
if 'name' not in request.form and 'user_code' not in request.form: if 'name' not in request.form and 'user_code' not in request.form:
@@ -819,8 +779,6 @@ def update_user_save():
if flag: if flag:
error = '输入为空 Null Input.' error = '输入为空 Null Input.'
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
@@ -832,11 +790,10 @@ def update_user_save():
def all_present(): def all_present():
# 所有奖励数据 # 所有奖励数据
conn = sqlite3.connect('./database/arcaea_database.db') error = None
c = conn.cursor() with Connect() as c:
c.execute('''select * from present''') c.execute('''select * from present''')
x = c.fetchall() x = c.fetchall()
error = None
if x: if x:
posts = [] posts = []
for i in x: for i in x:
@@ -854,8 +811,6 @@ def all_present():
else: else:
error = '没有奖励数据 No present data.' error = '没有奖励数据 No present data.'
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
return render_template('web/allpresent.html') return render_template('web/allpresent.html')
@@ -941,12 +896,9 @@ def deliver_present():
user_code = None user_code = None
present_id = request.form['present_id'] present_id = request.form['present_id']
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor()
if not web.system.is_present_available(c, present_id): if not web.system.is_present_available(c, present_id):
flash("奖励不存在 The present does not exist.") flash("奖励不存在 The present does not exist.")
conn.commit()
conn.close()
return render_template('web/deliverpresent.html') return render_template('web/deliverpresent.html')
# 全修改 # 全修改
@@ -980,9 +932,268 @@ def deliver_present():
if flag: if flag:
error = '输入为空 Null Input.' error = '输入为空 Null Input.'
conn.commit()
conn.close()
if error: if error:
flash(error) flash(error)
return render_template('web/deliverpresent.html') return render_template('web/deliverpresent.html')
@bp.route('/allredeem', methods=['GET'])
@login_required
def all_redeem():
# 所有兑换码数据
error = None
with Connect() as c:
c.execute('''select * from redeem''')
x = c.fetchall()
if x:
posts = []
for i in x:
items = json.loads(i[1])
items_string = ''
for j in items:
items_string = items_string + '\n' + \
str(j['id']) + ': ' + str(j['amount'])
posts.append({'code': i[0],
'items': items_string,
'type': i[2]
})
else:
error = '没有兑换码数据 No redeem code data.'
if error:
flash(error)
return render_template('web/allredeem.html')
else:
return render_template('web/allredeem.html', posts=posts)
@bp.route('/changeredeem', methods=['GET'])
@login_required
def change_redeem():
# 修改兑换码数据
return render_template('web/changeredeem.html')
@bp.route('/changeredeem/addredeem', methods=['POST'])
@login_required
def add_redeem():
# 添加兑换码数据
print(request.form)
code = request.form['code']
amount = request.form['amount']
redeem_type = request.form['type']
fragment = request.form['fragment']
ticket = request.form['ticket']
try:
if amount:
amount = int(amount)
if ticket:
ticket = int(ticket)
if fragment:
fragment = int(fragment)
except:
flash('数据错误 Wrong data.')
return redirect(url_for('index.change_redeem'))
items = []
if ticket:
items.append({'type': 'memory', 'id': 'memory', 'amount': ticket})
if fragment:
items.append(
{'type': 'fragment', 'id': 'fragment', 'amount': fragment})
if items == []:
flash('奖励为空 No items.')
return redirect(url_for('index.change_redeem'))
if code and not amount:
if len(code) > 20 or len(code) < 10:
flash('兑换码长度不合适 Inappropriate length of redeem code.')
return redirect(url_for('index.change_redeem'))
message = web.system.add_one_redeem(
code, redeem_type, json.dumps(items))
elif amount and not code:
if amount <= 0 or amount > 1000:
flash('数量错误 Wrong amount.')
return redirect(url_for('index.change_redeem'))
message = web.system.add_some_random_redeem(
amount, redeem_type, json.dumps(items))
elif amount and code:
flash('只能使用一种添加方式 Only one add method can be used.')
return redirect(url_for('index.change_redeem'))
else:
flash('空输入 Null input.')
return redirect(url_for('index.change_redeem'))
if message:
flash(message)
return redirect(url_for('index.change_redeem'))
@bp.route('/changeredeem/deleteredeem', methods=['POST'])
@login_required
def delete_redeem():
# 删除兑换码数据
code = request.form['code']
message = web.system.delete_one_redeem(code)
if message:
flash(message)
return redirect(url_for('index.change_redeem'))
@bp.route('/redeem/<code>', methods=['GET'])
@login_required
def one_redeem(code):
# 某个兑换码的用户使用情况数据
error = None
with Connect() as c:
c.execute(
'''select user_id, name, user_code from user where user_id in (select user_id from user_redeem where code=:a)''', {'a': code})
x = c.fetchall()
if x:
posts = []
for i in x:
posts.append({'user_id': i[0],
'name': i[1],
'user_code': i[2]
})
else:
error = '没有数据 No data.'
if error:
flash(error)
return render_template('web/redeem.html', code=code)
else:
return render_template('web/redeem.html', posts=posts, code=code)
@bp.route('/changeuserpwd', methods=['GET', 'POST'])
@login_required
def edit_userpwd():
# 修改用户密码
if request.method == 'GET':
return render_template('web/changeuserpwd.html')
error = None
name = request.form['name']
user_code = request.form['user_code']
pwd = request.form['pwd']
pwd2 = request.form['pwd2']
if pwd != pwd2:
flash('两次输入的密码不一致 Entered passwords differ!')
return render_template('web/changeuserpwd.html')
else:
if len(pwd) < 8 or len(pwd) > 20:
flash('密码太长或太短 Password is too long or too short!')
return render_template('web/changeuserpwd.html')
with Connect() as c:
if name or user_code:
if user_code:
c.execute('''select user_id from user where user_code=:a''', {
'a': user_code})
else:
c.execute(
'''select user_id from user where name=:a''', {'a': name})
user_id = c.fetchone()
if user_id:
user_id = user_id[0]
web.system.change_userpwd(c, user_id, pwd)
flash('用户密码修改成功 Successfully edit the user information.')
else:
error = '玩家不存在 The player does not exist.'
else:
error = '输入为空 Null Input.'
if error:
flash(error)
return redirect(url_for('index.edit_userpwd'))
@bp.route('/banuser', methods=['POST', 'GET'])
@login_required
def ban_user():
# 封禁用户
if request.method == 'GET':
return render_template('web/banuser.html')
error = None
name = request.form['name']
user_code = request.form['user_code']
with Connect() as c:
if name or user_code:
if user_code:
c.execute('''select user_id from user where user_code=:a''', {
'a': user_code})
else:
c.execute(
'''select user_id from user where name=:a''', {'a': name})
user_id = c.fetchone()
if user_id:
user_id = user_id[0]
web.system.ban_one_user(c, user_id)
flash('用户封禁成功 Successfully ban the user.')
else:
error = '玩家不存在 The player does not exist.'
else:
error = '输入为空 Null Input.'
if error:
flash(error)
return redirect(url_for('index.ban_user'))
@bp.route('/banuser/deleteuserscore', methods=['POST'])
@login_required
def delete_user_score():
# 删除用户所有成绩
error = None
name = request.form['name']
user_code = request.form['user_code']
with Connect() as c:
if name or user_code:
if user_code:
c.execute('''select user_id from user where user_code=:a''', {
'a': user_code})
else:
c.execute(
'''select user_id from user where name=:a''', {'a': name})
user_id = c.fetchone()
if user_id:
user_id = user_id[0]
web.system.clear_user_score(c, user_id)
flash("用户成绩删除成功 Successfully delete the user's scores.")
else:
error = '玩家不存在 The player does not exist.'
else:
error = '输入为空 Null Input.'
if error:
flash(error)
return redirect(url_for('index.ban_user'))

View File

@@ -2,7 +2,7 @@
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
import configparser from setting import Config
bp = Blueprint('login', __name__, url_prefix='/web') bp = Blueprint('login', __name__, url_prefix='/web')
@@ -15,18 +15,12 @@ def login():
password = request.form['password'] password = request.form['password']
error = None error = None
config = configparser.ConfigParser() if username != Config.USERNAME or password != Config.PASSWORD:
path = r'setting.ini'
config.read(path, encoding="utf-8")
USERNAME = config.get('WEB', 'USERNAME')
PASSWORD = config.get('WEB', 'PASSWORD')
if username != USERNAME and password != 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'] = USERNAME + PASSWORD session['user_id'] = Config.USERNAME + Config.PASSWORD
return redirect(url_for('index.index')) return redirect(url_for('index.index'))
flash(error) flash(error)
@@ -48,16 +42,10 @@ def login_required(view):
def wrapped_view(**kwargs): def wrapped_view(**kwargs):
x = session.get('user_id') x = session.get('user_id')
config = configparser.ConfigParser() if x != Config.USERNAME + Config.PASSWORD:
path = r'setting.ini'
config.read(path, encoding="utf-8")
USERNAME = config.get('WEB', 'USERNAME')
PASSWORD = config.get('WEB', 'PASSWORD')
if x != USERNAME + PASSWORD:
return redirect(url_for('login.login')) return redirect(url_for('login.login'))
g.user = {'user_id': x, 'username': USERNAME} g.user = {'user_id': x, 'username': Config.USERNAME}
return view(**kwargs) return view(**kwargs)
return wrapped_view return wrapped_view

View File

@@ -3,6 +3,8 @@ import sqlite3
import time import time
import json import json
import server.arcscore import server.arcscore
import hashlib
from random import Random
def int2b(x): def int2b(x):
@@ -13,6 +15,17 @@ def int2b(x):
return True 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): def get_table_info(c, table_name):
# 得到表结构,返回主键列表和字段名列表 # 得到表结构,返回主键列表和字段名列表
pk = [] pk = []
@@ -85,8 +98,25 @@ def get_sql_insert_table(table_name, field, value):
return sql, sql_dict 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): def update_one_table(c1, c2, table_name):
# 从c1向c2更新数据表c2中存在的信息不变 # 从c1向c2更新数据表c1中存在的信息不变
c1.execute( c1.execute(
'''select * from sqlite_master where type = 'table' and name = :a''', {'a': table_name}) '''select * from sqlite_master where type = 'table' and name = :a''', {'a': table_name})
c2.execute( c2.execute(
@@ -117,7 +147,11 @@ def update_one_table(c1, c2, table_name):
sql = 'select exists(' + sql + ')' sql = 'select exists(' + sql + ')'
c2.execute(sql, sql_dict) c2.execute(sql, sql_dict)
if c2.fetchone() == (0,): 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( sql, sql_dict = get_sql_insert_table(
table_name, field, list(y[i])) table_name, field, list(y[i]))
c2.execute(sql, sql_dict) c2.execute(sql, sql_dict)
@@ -142,7 +176,7 @@ def update_user_char(c):
def update_database(): def update_database():
# 将old数据库不存在数据加入到新数据库上并删除old数据库 # 将old数据库不存在数据加入到新数据库上并删除old数据库
# 对于arcaea_datebase.db更新best_scorefriendrecent30useruser_world, user_item, user_save, login, present, user_present并用character数据更新user_char # 对于arcaea_datebase.db更新一些表,并用character数据更新user_char
# 对于arcsong.db更新songs # 对于arcsong.db更新songs
if os.path.isfile("database/old_arcaea_database.db") and os.path.isfile("database/arcaea_database.db"): if os.path.isfile("database/old_arcaea_database.db") and os.path.isfile("database/arcaea_database.db"):
conn1 = sqlite3.connect('./database/old_arcaea_database.db') conn1 = sqlite3.connect('./database/old_arcaea_database.db')
@@ -155,11 +189,14 @@ def update_database():
update_one_table(c1, c2, 'best_score') update_one_table(c1, c2, 'best_score')
update_one_table(c1, c2, 'recent30') update_one_table(c1, c2, 'recent30')
update_one_table(c1, c2, 'user_world') 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_item')
update_one_table(c1, c2, 'user_save') update_one_table(c1, c2, 'user_save')
update_one_table(c1, c2, 'login') update_one_table(c1, c2, 'login')
update_one_table(c1, c2, 'present') update_one_table(c1, c2, 'present')
update_one_table(c1, c2, 'user_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) update_user_char(c2)
@@ -270,6 +307,8 @@ def update_one_save(c, user_id):
for i in scores: for i in scores:
rating = server.arcscore.get_one_ptt( rating = server.arcscore.get_one_ptt(
i['song_id'], i['difficulty'], i['score']) i['song_id'], i['difficulty'], i['score'])
if rating < 0:
rating = 0
try: try:
index = clear_song_id_difficulty.index( index = clear_song_id_difficulty.index(
i['song_id'] + str(i['difficulty'])) i['song_id'] + str(i['difficulty']))
@@ -378,3 +417,90 @@ def deliver_all_user_present(c, present_id):
{'a': i[0], 'b': present_id}) {'a': i[0], 'b': present_id})
return return
def add_one_redeem(code, redeem_type, items):
# 添加一个兑换码
message = None
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
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.'
conn.commit()
conn.close()
return message
def add_some_random_redeem(amount, redeem_type, items):
# 随机生成一堆10位的兑换码
message = None
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
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.'
conn.commit()
conn.close()
return message
def delete_one_redeem(code):
# 删除一个兑换码
message = None
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
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.'
conn.commit()
conn.close()
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