18 Commits
v2.1 ... v2.3.2

Author SHA1 Message Date
Lost-MSth
941a79ccc7 Update to v2.3.2 2021-04-09 14:42:14 +08:00
Lost-MSth
62902a561c Add an option 2021-04-05 14:45:50 +08:00
Lost-MSth
1660bc5899 Merge branch 'master' of https://github.com/Lost-MSth/Arcaea-server 2021-04-05 13:20:42 +08:00
Lost-MSth
d577246d28 Revert "Revert "Fix some bugs""
This reverts commit 9fd626468e.
2021-04-05 13:20:36 +08:00
Lost-MSth
9fd626468e Revert "Fix some bugs"
This reverts commit c51a1b4e85.
2021-04-05 13:19:32 +08:00
Lost-MSth
c51a1b4e85 Fix some bugs
Fix the fanmade cloud save (add a switch in setting)

Add SSL switch

Fix 'my rank' in game, if there is not enough people behind you, now it will show 20 people as expected
2021-04-05 13:02:56 +08:00
Lost-MSth
0e42123417 Update README.md
Well, it is not 4.1 now.
2021-04-02 22:03:35 +08:00
Lost-MSth
e216e6144b Update README.md 2021-04-01 17:05:53 +08:00
Lost-MSth
b70c435a4a Update to v2.3.1 2021-04-01 17:02:56 +08:00
Lost-MSth
eb03d2be93 Update README.md 2021-03-14 22:37:59 +08:00
Lost-MSth
fcb5d264ef Add something and fix something
Add character values.
Do something about #16.
Fix a problem about relative path.
2021-03-14 22:33:13 +08:00
Lost-MSth
d617951e1f Fix a bug(Follow last commit)
Ctrl c and Ctrl v,
A bug appears!
2021-03-09 20:09:58 +08:00
Lost-MSth
febf931f1a Fix something
I don't know if it is a bug and I haven't test it.

Maybe it makes low version arcaea can log in.
2021-03-09 19:47:54 +08:00
Lost-MSth
981961d6a1 Update README.md 2021-03-09 14:20:54 +08:00
Lost-MSth
a90380df4c Create error.log 2021-03-09 13:55:09 +08:00
Lost-MSth
4f66f492fc Update to v2.3 2021-03-09 13:46:49 +08:00
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
24 changed files with 2106 additions and 1799 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.log

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
@@ -29,14 +36,16 @@ This is a small local Arcaea server based on Python and Flask, which can simulat
- 后台自定义信息 Customize some things in the background - 后台自定义信息 Customize some things in the background
- 成绩校验 Score check - 成绩校验 Score check
- 下载校验 Download check - 下载校验 Download check
- 服务器日志 Server log
没有以下 We don't have 没有以下 We don't have
- 角色数值 Character characteristic value
- 服务器安全性保证 Server security assurance - 服务器安全性保证 Server security assurance
- 世界模式下的搭档升级、觉醒,以及某些奖励的获取 Partner upgrading, uncapping, and receiving some rewards in the world mode
可能有问题 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
只是很有趣,用处探索中。 只是很有趣,用处探索中。
@@ -51,25 +60,26 @@ It is just so interesting. What it can do is under exploration.
## 更新日志 Update log ## 更新日志 Update log
只保留最新版本 Only keep the latest version. 只保留最新版本 Only keep the latest version.
> 提醒:更新时请注意保留原先的数据库,以防数据丢失 > 提醒:更新时请注意保留原先的数据库,以防数据丢失。使用前请先运行**database_initialize.py**以获得初始数据库。
> >
> 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.
> Before using, please run **database_initialize.py** to get the initial database.
### Version 2.1 ### Version 2.3.2
- 适用于Arcaea 3.5.0版本 For Arcaea 3.5.0 - 适用于Arcaea 3.5.4版本 For Arcaea 3.5.4
- 更新了歌曲数据库 Update the song database. - 更新了歌曲数据库 Update the song database.
-搭档**阿莱乌斯**、**希尔**、**伊莎贝尔**已解锁 Unlock the new characters **Areus**, **Seele** and **Isabelle**. -增运行前关键性文件检查 Add checking critical files before running.
- 源韵强化机制修改,现在源点会正常扣去 The mechanism of Memory Boost has been modified. Now the memories will be decreased normally. - 新增可下载数据的客户端校验更新 Add client verification update of downloadable data.
- 优化了代码结构 Optimize the code structure. - 新增歌曲成绩的谱面校验 Add checking chart file when submitting the song score.
- 修复了一些Bug Fix some bugs. - 修复了一些Bug Fix some bugs.
## 运行环境与依赖 Running environment and requirements ## 运行环境与依赖 Running environment and requirements
- Windows操作系统 Windows operating system - Windows/Linux/Mac OS/Android
- Python 3 - Python 3
- Flask模块 Flask module - Flask module
- Charles - Charles (optional)
<!--
## 环境搭建 Environment construction ## 环境搭建 Environment construction
[中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) [中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA)
[English](https://github.com/Lost-MSth/Arcaea-server/wiki/Environment-construction) [English](https://github.com/Lost-MSth/Arcaea-server/wiki/Environment-construction)
@@ -81,6 +91,7 @@ It is just so interesting. What it can do is under exploration.
## 注意 Attentions ## 注意 Attentions
[中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E6%B3%A8%E6%84%8F) [中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E6%B3%A8%E6%84%8F)
[English](https://github.com/Lost-MSth/Arcaea-server/wiki/Attentions) [English](https://github.com/Lost-MSth/Arcaea-server/wiki/Attentions)
-->
## 鸣谢 Thanks ## 鸣谢 Thanks
歌曲数据库来自 Using song database from 歌曲数据库来自 Using song database from

Binary file not shown.

View File

@@ -37,10 +37,11 @@ ticket int,
prog_boost 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,
@@ -235,24 +236,44 @@ 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', 'Areus', 'Seele', 'Isabelle'] 'Ayu', 'Eto & Luna', 'Yume', 'Seine & Hikari', 'Saya', 'Tairitsu & Chuni Penguin', 'Chuni Penguin', 'Haruna', 'Nono', 'MTA-XXX', 'MDA-21', 'Kanae', 'Hikari(Fantasia)', 'Tairitsu(Sonata)', 'Sia', 'DORO*C', 'Tairitsu(Tempest)', 'Brillante', 'Ilith(Summer)', 'Etude', 'Alice & Tenniel', 'Luna & Mia', 'Areus', 'Seele', 'Isabelle', 'Mir']
skill_id = ['gauge_easy', '', '', '', 'note_mirror', '', '', 'gauge_hard', 'frag_plus_10_pack_stellights', 'gauge_easy|frag_plus_15_pst&prs', 'gauge_hard|fail_frag_minus_100', 'frag_plus_5_side_light', 'visual_hide_hp', 'frag_plus_5_side_conflict', 'challenge_fullcombo_0gauge', 'gauge_overflow', 'gauge_easy|note_mirror', 'note_mirror', 'visual_tomato_pack_tonesphere', skill_id = ['gauge_easy', '', '', '', 'note_mirror', '', '', 'gauge_hard', 'frag_plus_10_pack_stellights', 'gauge_easy|frag_plus_15_pst&prs', 'gauge_hard|fail_frag_minus_100', 'frag_plus_5_side_light', 'visual_hide_hp', 'frag_plus_5_side_conflict', 'challenge_fullcombo_0gauge', 'gauge_overflow', 'gauge_easy|note_mirror', 'note_mirror', 'visual_tomato_pack_tonesphere',
'frag_rng_ayu', 'gaugestart_30|gaugegain_70', 'combo_100-frag_1', 'audio_gcemptyhit_pack_groovecoaster', 'gauge_saya', 'gauge_chuni', 'kantandeshou', 'gauge_haruna', 'frags_nono', 'gauge_pandora', 'gauge_regulus', 'omatsuri_daynight', '', '', 'sometimes(note_mirror|frag_plus_5)', 'scoreclear_aa|visual_scoregauge', 'gauge_tempest', 'gauge_hard', 'gauge_ilith_summer', '', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle'] 'frag_rng_ayu', 'gaugestart_30|gaugegain_70', 'combo_100-frag_1', 'audio_gcemptyhit_pack_groovecoaster', 'gauge_saya', 'gauge_chuni', 'kantandeshou', 'gauge_haruna', 'frags_nono', 'gauge_pandora', 'gauge_regulus', 'omatsuri_daynight', '', '', 'sometimes(note_mirror|frag_plus_5)', 'scoreclear_aa|visual_scoregauge', 'gauge_tempest', 'gauge_hard', 'gauge_ilith_summer', '', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle', 'gauge_exhaustion']
skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', '', '', 'shirabe_entry_fee', skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', '', '', 'shirabe_entry_fee',
'', '', '', '', '', '', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] '', '', '', '', '', '', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
for i in range(0, 44): frag = [88, 90, 100, 75, 80, 0, 70, 79, 65, 40, 50, 80, 90, 92, 0, 61, 67, 92, 85, 50, 86, 62,
65, 85, 67, 88, 74, 0.5, 105, 80, 95, 50, 80, 87, 71, 50, 95, 0, 80, 75, 50, 70, 80, 100, 65]
prog = [71, 90, 80, 75, 100, 0, 90, 102, 84, 78, 105, 67, 63, 78, 0, 99, 80, 66, 46, 83, 40, 83,
80, 90, 93, 50, 96, 88, 99, 108, 75, 80, 50, 64, 55, 100, 100, 110, 80, 50, 74, 90, 80, 80, 56]
overdrive = [71, 90, 57, 75, 80, 0, 95, 79, 65, 31, 50, 59, 90, 68, 0, 78, 50, 70, 62, 49, 64,
56, 73, 95, 67, 84, 80, 88, 79, 80, 50, 80, 80, 63, 25, 50, 82, 55, 50, 95, 55, 70, 100, 80, 90]
char_type = [1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 2, 0, 0, 0, 2, 3, 1, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 2, 2, 1]
print(len(char))
print(len(skill_id))
print(len(skill_id_uncap))
print(len(frag))
print(len(prog))
print(len(overdrive))
print(len(char_type))
for i in range(0, 45):
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21, 42, 43]: 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(:a,:b,30,25000,25000,:c,:d,:e,:f,0,0,:g,:h,'',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, {'a': i, 'b': char[i], 'c': frag[i], 'd': prog[i],
c.execute(sql) 'e': overdrive[i], 'f': skill_id[i], 'g': skill_id_uncap[i], 'h': char_type[i]})
else: else:
if i != 5: if i != 5:
sql = 'insert into character values('+str( sql = '''insert into character values(:a,:b,20,10000,10000,:c,:d,:e,:f,0,0,:g,:h,'',0,0)'''
i)+',"'+char[i]+'''",30,25000,25000,90,90,90,"'''+skill_id[i]+'''",0,0,"'''+skill_id_uncap[i]+'''",0,'',0,0)''' c.execute(sql, {'a': i, 'b': char[i], 'c': frag[i], 'd': prog[i],
c.execute(sql) 'e': overdrive[i], 'f': skill_id[i], 'g': skill_id_uncap[i], 'h': char_type[i]})
def b2int(x): def b2int(x):

View File

@@ -3,154 +3,154 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "core", "id": "core",
"_id": "6008c2ff36651a07ebc52ca9", "_id": "6046bab736651a07ebc537db",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 400,
"orig_price": 500, "orig_price": 500,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "shiawase", "name": "shiawase",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "shiawase", "id": "shiawase",
"_id": "6008c2ff36651a07ebc52ce0", "_id": "6046bab736651a07ebc53823",
"is_available": true "is_available": true
}, { }, {
"type": "character", "type": "character",
"id": "kou", "id": "kou",
"_id": "6008c2ff36651a07ebc52cdf", "_id": "6046bab736651a07ebc53822",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 250,
"orig_price": 500, "orig_price": 500,
"discount_from": 1552089600000, "discount_from": 1615248000000,
"discount_to": 1552694399000 "discount_to": 1615852799000
}, { }, {
"name": "dynamix", "name": "dynamix",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "dynamix", "id": "dynamix",
"_id": "6008c2ff36651a07ebc52ce4", "_id": "6046bab736651a07ebc53827",
"is_available": true "is_available": true
}, { }, {
"type": "character", "type": "character",
"id": "sapphire", "id": "sapphire",
"_id": "6008c2ff36651a07ebc52ce3", "_id": "6046bab736651a07ebc53826",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 250,
"orig_price": 500, "orig_price": 500,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "mirai", "name": "mirai",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "mirai", "id": "mirai",
"_id": "6008c2ff36651a07ebc52cdc", "_id": "6046bab736651a07ebc5381d",
"is_available": true "is_available": true
}, { }, {
"type": "character", "type": "character",
"id": "lethe", "id": "lethe",
"_id": "6008c2ff36651a07ebc52cdb", "_id": "6046bab736651a07ebc5381c",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 250,
"orig_price": 500, "orig_price": 500,
"discount_from": 1552089600000, "discount_from": 1615248000000,
"discount_to": 1552694399000 "discount_to": 1615852799000
}, { }, {
"name": "yugamu", "name": "yugamu",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "yugamu", "id": "yugamu",
"_id": "6008c2ff36651a07ebc52caa", "_id": "6046bab736651a07ebc537dc",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 400,
"orig_price": 500, "orig_price": 500,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "lanota", "name": "lanota",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "lanota", "id": "lanota",
"_id": "6008c2ff36651a07ebc52cd0", "_id": "6046bab736651a07ebc537e8",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 250,
"orig_price": 500, "orig_price": 500,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "nijuusei", "name": "nijuusei",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "nijuusei", "id": "nijuusei",
"_id": "6008c2ff36651a07ebc52cab", "_id": "6046bab736651a07ebc537dd",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 250,
"orig_price": 500, "orig_price": 500,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "rei", "name": "rei",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "rei", "id": "rei",
"_id": "6008c2ff36651a07ebc52cc5", "_id": "6046bab736651a07ebc537f6",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 400,
"orig_price": 500, "orig_price": 500,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "tonesphere", "name": "tonesphere",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "tonesphere", "id": "tonesphere",
"_id": "6008c2ff36651a07ebc52cd2", "_id": "6046bab736651a07ebc537ea",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 250,
"orig_price": 500, "orig_price": 500,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "groovecoaster", "name": "groovecoaster",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "groovecoaster", "id": "groovecoaster",
"_id": "6008c2ff36651a07ebc52ca1", "_id": "6046bab736651a07ebc53812",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 250,
"orig_price": 500, "orig_price": 500,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "zettai", "name": "zettai",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "zettai", "id": "zettai",
"_id": "6008c2ff36651a07ebc52cc7", "_id": "6046bab736651a07ebc537f8",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 250,
"orig_price": 500, "orig_price": 500,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "chunithm", "name": "chunithm",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "chunithm", "id": "chunithm",
"_id": "6008c2ff36651a07ebc52cbb", "_id": "6046bab736651a07ebc53806",
"is_available": true "is_available": true
}], }],
"price": 300, "price": 300,
@@ -160,47 +160,55 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "prelude", "id": "prelude",
"_id": "6008c2ff36651a07ebc52ca2", "_id": "6046bab736651a07ebc53813",
"is_available": true "is_available": true
}], }],
"price": 400, "price": 250,
"orig_price": 400 "orig_price": 400,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "omatsuri", "name": "omatsuri",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "omatsuri", "id": "omatsuri",
"_id": "6008c2ff36651a07ebc52cc8", "_id": "6046bab736651a07ebc537f9",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 250,
"orig_price": 500 "orig_price": 500,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "vs", "name": "vs",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "vs", "id": "vs",
"_id": "6008c2ff36651a07ebc52cbe", "_id": "6046bab736651a07ebc53809",
"is_available": true "is_available": true
}], }],
"price": 500, "price": 400,
"orig_price": 500 "orig_price": 500,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "extend", "name": "extend",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "extend", "id": "extend",
"_id": "6008c2ff36651a07ebc52ca5", "_id": "6046bab736651a07ebc53816",
"is_available": true "is_available": true
}], }],
"price": 700, "price": 500,
"orig_price": 700 "orig_price": 700,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "alice", "name": "alice",
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "alice", "id": "alice",
"_id": "6008c2ff36651a07ebc52ccd", "_id": "6046bab736651a07ebc537fe",
"is_available": true "is_available": true
}], }],
"orig_price": 500, "orig_price": 500,
@@ -210,7 +218,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "alice_append_1", "id": "alice_append_1",
"_id": "6008c2ff36651a07ebc52cb4", "_id": "6046bab736651a07ebc537e6",
"is_available": true "is_available": true
}], }],
"orig_price": 300, "orig_price": 300,
@@ -220,7 +228,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "ongeki", "id": "ongeki",
"_id": "6008c2ff36651a07ebc52cc1", "_id": "6046bab736651a07ebc5380c",
"is_available": true "is_available": true
}], }],
"orig_price": 400, "orig_price": 400,
@@ -230,7 +238,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "maimai", "id": "maimai",
"_id": "6008c2ff36651a07ebc52ca8", "_id": "6046bab736651a07ebc53819",
"is_available": true "is_available": true
}], }],
"orig_price": 400, "orig_price": 400,
@@ -240,7 +248,7 @@
"items": [{ "items": [{
"type": "pack", "type": "pack",
"id": "chunithm_append_1", "id": "chunithm_append_1",
"_id": "6008c2ff36651a07ebc52cda", "_id": "6046bab736651a07ebc537f2",
"is_available": true "is_available": true
}], }],
"orig_price": 300, "orig_price": 300,

View File

@@ -12,55 +12,55 @@
"items": [{ "items": [{
"id": "dataerror", "id": "dataerror",
"type": "single", "type": "single",
"_id": "6008c2ff36651a07ebc52cb5", "_id": "606f9f5636651a07ebc541f3",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "yourvoiceso", "name": "yourvoiceso",
"items": [{ "items": [{
"id": "yourvoiceso", "id": "yourvoiceso",
"type": "single", "type": "single",
"_id": "6008c2ff36651a07ebc52cc2", "_id": "606f9f5636651a07ebc54201",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "crosssoul", "name": "crosssoul",
"items": [{ "items": [{
"id": "crosssoul", "id": "crosssoul",
"type": "single", "type": "single",
"_id": "6008c2ff36651a07ebc52ccf", "_id": "606f9f5636651a07ebc5420e",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "impurebird", "name": "impurebird",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "impurebird", "id": "impurebird",
"_id": "6008c2ff36651a07ebc52cb6", "_id": "606f9f5636651a07ebc541f4",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "auxesia", "name": "auxesia",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "auxesia", "id": "auxesia",
"_id": "6008c2ff36651a07ebc52c9d", "_id": "606f9f5636651a07ebc5420f",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -72,43 +72,43 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "modelista", "id": "modelista",
"_id": "6008c2ff36651a07ebc52cc3", "_id": "606f9f5636651a07ebc54202",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "yozakurafubuki", "name": "yozakurafubuki",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "yozakurafubuki", "id": "yozakurafubuki",
"_id": "6008c2ff36651a07ebc52cb7", "_id": "606f9f5636651a07ebc541f5",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "surrender", "name": "surrender",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "surrender", "id": "surrender",
"_id": "6008c2ff36651a07ebc52c9e", "_id": "606f9f5636651a07ebc54210",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "metallicpunisher", "name": "metallicpunisher",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "metallicpunisher", "id": "metallicpunisher",
"_id": "6008c2ff36651a07ebc52cc4", "_id": "606f9f5636651a07ebc54203",
"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": "6008c2ff36651a07ebc52cb8", "_id": "606f9f5636651a07ebc541f6",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -128,79 +128,79 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "bethere", "id": "bethere",
"_id": "6008c2ff36651a07ebc52c9f", "_id": "606f9f5636651a07ebc54211",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "callmyname", "name": "callmyname",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "callmyname", "id": "callmyname",
"_id": "6008c2ff36651a07ebc52cd1", "_id": "606f9f5636651a07ebc5421c",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "fallensquare", "name": "fallensquare",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "fallensquare", "id": "fallensquare",
"_id": "6008c2ff36651a07ebc52cac", "_id": "606f9f5636651a07ebc541e9",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "dropdead", "name": "dropdead",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "dropdead", "id": "dropdead",
"_id": "6008c2ff36651a07ebc52cb9", "_id": "606f9f5636651a07ebc541f7",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "alexandrite", "name": "alexandrite",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "alexandrite", "id": "alexandrite",
"_id": "6008c2ff36651a07ebc52ca0", "_id": "606f9f5636651a07ebc54212",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "astraltale", "name": "astraltale",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "astraltale", "id": "astraltale",
"_id": "6008c2ff36651a07ebc52cc6", "_id": "606f9f5636651a07ebc54205",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "phantasia", "name": "phantasia",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "phantasia", "id": "phantasia",
"_id": "6008c2ff36651a07ebc52cad", "_id": "606f9f5636651a07ebc541ea",
"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": "6008c2ff36651a07ebc52cba", "_id": "606f9f5636651a07ebc541f8",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -220,75 +220,79 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "libertas", "id": "libertas",
"_id": "6008c2ff36651a07ebc52cd3", "_id": "606f9f5636651a07ebc5421e",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "dottodot", "name": "dottodot",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "dottodot", "id": "dottodot",
"_id": "6008c2ff36651a07ebc52cae", "_id": "606f9f5636651a07ebc541eb",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "dreadnought", "name": "dreadnought",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "dreadnought", "id": "dreadnought",
"_id": "6008c2ff36651a07ebc52cd4", "_id": "606f9f5636651a07ebc5421f",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "mirzam", "name": "mirzam",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "mirzam", "id": "mirzam",
"_id": "6008c2ff36651a07ebc52caf", "_id": "606f9f5636651a07ebc541ec",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100, "orig_price": 100,
"discount_from": 1583712000000, "discount_from": 1615248000000,
"discount_to": 1584316799000 "discount_to": 1615852799000
}, { }, {
"name": "heavenlycaress", "name": "heavenlycaress",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "heavenlycaress", "id": "heavenlycaress",
"_id": "6008c2ff36651a07ebc52cbc", "_id": "606f9f5636651a07ebc541fa",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "filament", "name": "filament",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "filament", "id": "filament",
"_id": "6008c2ff36651a07ebc52ca3", "_id": "606f9f5636651a07ebc54215",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "avantraze", "name": "avantraze",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "avantraze", "id": "avantraze",
"_id": "6008c2ff36651a07ebc52cd5", "_id": "606f9f5636651a07ebc54220",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -298,17 +302,19 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "battlenoone", "id": "battlenoone",
"_id": "6008c2ff36651a07ebc52cc9", "_id": "606f9f5636651a07ebc54208",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "saikyostronger", "name": "saikyostronger",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "saikyostronger", "id": "saikyostronger",
"_id": "6008c2ff36651a07ebc52cb0", "_id": "606f9f5636651a07ebc541ed",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -318,67 +324,79 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "izana", "id": "izana",
"_id": "6008c2ff36651a07ebc52cbd", "_id": "606f9f5636651a07ebc541fb",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "einherjar", "name": "einherjar",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "einherjar", "id": "einherjar",
"_id": "6008c2ff36651a07ebc52ca4", "_id": "606f9f5636651a07ebc54216",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "laqryma", "name": "laqryma",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "laqryma", "id": "laqryma",
"_id": "6008c2ff36651a07ebc52cd6", "_id": "606f9f5636651a07ebc54221",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "amygdata", "name": "amygdata",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "amygdata", "id": "amygdata",
"_id": "6008c2ff36651a07ebc52cca", "_id": "606f9f5636651a07ebc54209",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "altale", "name": "altale",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "altale", "id": "altale",
"_id": "6008c2ff36651a07ebc52cb1", "_id": "606f9f5636651a07ebc541ee",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "feelssoright", "name": "feelssoright",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "feelssoright", "id": "feelssoright",
"_id": "6008c2ff36651a07ebc52cd7", "_id": "606f9f5636651a07ebc54222",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "scarletcage", "name": "scarletcage",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "scarletcage", "id": "scarletcage",
"_id": "6008c2ff36651a07ebc52ccb", "_id": "606f9f5636651a07ebc5420a",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -388,7 +406,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "teriqma", "id": "teriqma",
"_id": "6008c2ff36651a07ebc52cb2", "_id": "606f9f5636651a07ebc541ef",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -398,27 +416,31 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "mahoroba", "id": "mahoroba",
"_id": "6008c2ff36651a07ebc52cbf", "_id": "606f9f5636651a07ebc541fd",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "badtek", "name": "badtek",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "badtek", "id": "badtek",
"_id": "6008c2ff36651a07ebc52cd8", "_id": "606f9f5636651a07ebc54223",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "maliciousmischance", "name": "maliciousmischance",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "maliciousmischance", "id": "maliciousmischance",
"_id": "6008c2ff36651a07ebc52ccc", "_id": "606f9f5636651a07ebc54218",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -428,7 +450,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "buchigireberserker", "id": "buchigireberserker",
"_id": "6008c2ff36651a07ebc52cb3", "_id": "606f9f5636651a07ebc541f0",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -438,17 +460,19 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "galaxyfriends", "id": "galaxyfriends",
"_id": "6008c2ff36651a07ebc52cc0", "_id": "606f9f5636651a07ebc541fe",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
"orig_price": 100 "orig_price": 100,
"discount_from": 1615248000000,
"discount_to": 1615852799000
}, { }, {
"name": "xeraphinite", "name": "xeraphinite",
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "xeraphinite", "id": "xeraphinite",
"_id": "6008c2ff36651a07ebc52ca7", "_id": "606f9f5636651a07ebc54219",
"is_available": true "is_available": true
}], }],
"orig_price": 100, "orig_price": 100,
@@ -458,7 +482,7 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "xanatos", "id": "xanatos",
"_id": "6008c2ff36651a07ebc52cd9", "_id": "606f9f5636651a07ebc54224",
"is_available": true "is_available": true
}], }],
"price": 100, "price": 100,
@@ -468,7 +492,27 @@
"items": [{ "items": [{
"type": "single", "type": "single",
"id": "attraqtia", "id": "attraqtia",
"_id": "6008c2ff36651a07ebc52cce", "_id": "606f9f5636651a07ebc5420d",
"is_available": true
}],
"orig_price": 100,
"price": 100
}, {
"name": "gimmedablood",
"items": [{
"type": "single",
"id": "gimmedablood",
"_id": "606f9f5636651a07ebc541f2",
"is_available": true
}],
"orig_price": 100,
"price": 100
}, {
"name": "bassline",
"items": [{
"type": "single",
"id": "bassline",
"_id": "606f9f5636651a07ebc54200",
"is_available": true "is_available": true
}], }],
"orig_price": 100, "orig_price": 100,

View File

View File

@@ -1,6 +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
from logging.config import dictConfig from logging.config import dictConfig
import configparser from setting import Config
import base64 import base64
import server.auth import server.auth
import server.info import server.info
@@ -11,7 +13,9 @@ import web.index
import server.arcworld import server.arcworld
import server.arcdownload import server.arcdownload
import server.arcpurchase import server.arcpurchase
import server.init
import os import os
import sys
app = Flask(__name__) app = Flask(__name__)
@@ -87,32 +91,37 @@ def login():
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)
try: if 'DeviceId' in headers:
token, error_code = server.auth.arc_login(name, password) device_id = headers['DeviceId']
if not error_code: else:
r = {"success": True, "token_type": "Bearer"} device_id = 'low_version'
r['access_token'] = token
return jsonify(r) token, error_code = server.auth.arc_login(name, password, device_id)
else: if not error_code:
return error_return(error_code) r = {"success": True, "token_type": "Bearer"}
except: r['access_token'] = token
return error_return(108) return jsonify(r)
else:
return error_return(error_code)
@app.route('/latte/13/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: if 'device_id' in request.form:
user_id, token, error_code = server.auth.arc_register(name, password) device_id = request.form['device_id']
if user_id is not None: else:
r = {"success": True, "value": { device_id = 'low_version'
'user_id': user_id, 'access_token': token}}
return jsonify(r) user_id, token, error_code = server.auth.arc_register(
else: name, password, device_id)
return error_return(error_code) # 应该是101用户名被占用毕竟电子邮箱、设备号没记录 if user_id is not None:
except: r = {"success": True, "value": {
return error_return(108) 'user_id': user_id, 'access_token': token}}
return jsonify(r)
else:
return error_return(error_code) # 应该是101用户名被占用毕竟电子邮箱没记录
# 集成式请求,没想到什么好办法处理,就先这样写着 # 集成式请求,没想到什么好办法处理,就先这样写着
@@ -149,7 +158,9 @@ def character_change(user_id):
@app.route('/latte/<path:path>/toggle_uncap', methods=['POST']) # 角色觉醒切换 @app.route('/latte/<path:path>/toggle_uncap', methods=['POST']) # 角色觉醒切换
@server.auth.auth_required(request) @server.auth.auth_required(request)
def character_uncap(user_id, path): def character_uncap(user_id, path):
character_id = int(path[22:]) while '//' in path:
path = path.replace('//', '/')
character_id = int(path[21:])
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({
@@ -280,7 +291,7 @@ def song_score_post(user_id):
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,
@@ -512,24 +523,58 @@ def sys_set(user_id, path):
def main(): def main():
config = configparser.ConfigParser() os.chdir(sys.path[0]) # 更改工作路径,以便于愉快使用相对路径
path = r'setting.ini' app.config.from_mapping(SECRET_KEY=Config.SECRET_KEY)
config.read(path, encoding="utf-8") app.config['SESSION_TYPE'] = 'filesystem'
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)
dictConfig({ log_dict = {
'version': 1, 'version': 1,
'formatters': {'default': {
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
}},
'root': { 'root': {
'level': 'INFO' 'level': 'INFO',
'handlers': ['wsgi', 'error_file']
},
'handlers': {
'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream',
'formatter': 'default'
},
"error_file": {
"class": "logging.handlers.RotatingFileHandler",
"maxBytes": 1024 * 1024,
"backupCount": 1,
"encoding": "utf-8",
"level": "ERROR",
"formatter": "default",
"filename": "./log/error.log"
}
},
'formatters': {
'default': {
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
}
} }
}) }
if Config.ALLOW_LOG_INFO:
log_dict['root']['handlers'] = ['wsgi', 'info_file', 'error_file']
log_dict['handlers']['info_file'] = {
"class": "logging.handlers.RotatingFileHandler",
"maxBytes": 1024 * 1024,
"backupCount": 1,
"encoding": "utf-8",
"level": "INFO",
"formatter": "default",
"filename": "./log/info.log"
}
dictConfig(log_dict)
if not server.init.check_before_run(app):
app.logger.error('Something wrong. The server will not run.')
input('Press ENTER key to exit.')
sys.exit()
app.logger.info("Start to initialize data in 'songfile' table...") app.logger.info("Start to initialize data in 'songfile' table...")
try: try:
@@ -541,7 +586,11 @@ def main():
else: else:
app.logger.info('Complete!') app.logger.info('Complete!')
app.run(HOST, PORT) if Config.SSL_CERT and Config.SSL_KEY:
app.run(Config.HOST, Config.PORT, ssl_context=(
Config.SSL_CERT, Config.SSL_KEY))
else:
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

@@ -4,9 +4,10 @@ from flask import url_for
import sqlite3 import sqlite3
from server.sql import Connect 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):
@@ -24,7 +25,24 @@ def get_file_md5(file_path):
return myhash.hexdigest() return myhash.hexdigest()
def get_one_song(c, user_id, song_id, file_dir='./database/songs'): def get_url(file_path, **kwargs):
# 获取下载地址
t = ''
if 't' in kwargs:
t = kwargs['t']
if Config.DOWNLOAD_LINK_PREFIX:
prefix = Config.DOWNLOAD_LINK_PREFIX
if prefix[-1] != '/':
prefix += '/'
return prefix + file_path + '?t=' + t
else:
return url_for('download', file_path=file_path, t=t, _external=True)
def get_one_song(c, user_id, song_id, file_dir='./database/songs', url_flag=True):
# 获取一首歌的下载链接,返回字典 # 获取一首歌的下载链接,返回字典
dir_list = os.listdir(os.path.join(file_dir, song_id)) dir_list = os.listdir(os.path.join(file_dir, song_id))
re = {} re = {}
@@ -36,7 +54,6 @@ def get_one_song(c, user_id, song_id, file_dir='./database/songs'):
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 os.path.isfile(os.path.join(file_dir, song_id, i)) and i in ['0.aff', '1.aff', '2.aff', '3.aff', 'base.ogg']:
token = hashlib.md5( token = hashlib.md5(
(str(user_id) + song_id + i + str(now)).encode(encoding='UTF-8')).hexdigest() (str(user_id) + song_id + i + str(now)).encode(encoding='UTF-8')).hexdigest()
token = token[:8]
if i == 'base.ogg': if i == 'base.ogg':
c.execute( c.execute(
@@ -47,8 +64,12 @@ def get_one_song(c, user_id, song_id, file_dir='./database/songs'):
else: else:
checksum = get_file_md5(os.path.join( checksum = get_file_md5(os.path.join(
file_dir, song_id, 'base.ogg')) file_dir, song_id, 'base.ogg'))
re['audio'] = {"checksum": checksum,
"url": url_for('download', file_path=song_id+'/base.ogg', t=token, _external=True)} if url_flag:
re['audio'] = {"checksum": checksum, "url": get_url(
file_path=song_id+'/base.ogg', t=token)}
else:
re['audio'] = {"checksum": checksum}
else: else:
if 'chart' not in re: if 'chart' not in re:
re['chart'] = {} re['chart'] = {}
@@ -59,23 +80,28 @@ def get_one_song(c, user_id, song_id, file_dir='./database/songs'):
checksum = x[0] checksum = x[0]
else: else:
checksum = get_file_md5(os.path.join(file_dir, song_id, i)) checksum = get_file_md5(os.path.join(file_dir, song_id, i))
re['chart'][i[0]] = {"checksum": checksum,
"url": url_for('download', file_path=song_id+'/'+i, t=token, _external=True)}
c.execute('''insert into download_token values(:a,:b,:c,:d,:e)''', { if url_flag:
'a': user_id, 'b': song_id, 'c': i, 'd': token, 'e': now}) re['chart'][i[0]] = {"checksum": checksum, "url": get_url(
file_path=song_id+'/'+i, t=token)}
else:
re['chart'][i[0]] = {"checksum": checksum}
if url_flag:
c.execute('''insert into download_token values(:a,:b,:c,:d,:e)''', {
'a': user_id, 'b': song_id, 'c': i, 'd': token, 'e': now})
return {song_id: re} return {song_id: re}
def get_all_songs(user_id, file_dir='./database/songs'): def get_all_songs(user_id, file_dir='./database/songs', url_flag=True):
# 获取所有歌的下载链接,返回字典 # 获取所有歌的下载链接,返回字典
dir_list = os.listdir(file_dir) dir_list = os.listdir(file_dir)
re = {} re = {}
with Connect() as c: with Connect() as c:
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, file_dir)) re.update(get_one_song(c, user_id, i, file_dir, url_flag))
return re return re

File diff suppressed because it is too large Load Diff

View File

@@ -3,9 +3,10 @@ import time
import server.arcworld import server.arcworld
from server.sql import Connect from server.sql import Connect
import functools 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多返回个error code # 查询数据库中的user表验证账号密码返回并记录token多返回个error code
# token采用user_id和时间戳连接后hash生成真的是瞎想的没用bear # token采用user_id和时间戳连接后hash生成真的是瞎想的没用bear
# 密码和token的加密方式为 SHA-256 # 密码和token的加密方式为 SHA-256
@@ -27,14 +28,32 @@ def arc_login(name: str, password: str) -> str: # 登录判断
token = hashlib.sha256( token = hashlib.sha256(
(user_id + str(now)).encode("utf8")).hexdigest() (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: # 对相同设备进行删除
c.execute('''delete from login where login_device=:a''', {
'a': device_id})
should_delete_num = len(
device_list) + 1 - device_list.count(device_id) - Config.LOGIN_DEVICE_NUMBER_LIMIT
if should_delete_num >= 1: # 删掉多余token
c.execute('''delete from login where rowid in (select rowid from login where user_id=:user_id limit :a);''',
{'user_id': user_id, 'a': int(should_delete_num)})
c.execute('''insert into login(access_token, user_id, login_device) values(:access_token, :user_id, :device_id)''', {
'user_id': user_id, 'access_token': token, 'device_id': device_id})
error_code = None error_code = None
else: else:
# 密码错误 # 密码错误
@@ -46,7 +65,7 @@ def arc_login(name: str, password: str) -> str: # 登录判断
return token, error_code 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和密码的处理同登录部分
@@ -92,16 +111,16 @@ def arc_register(name: str, password: str): # 注册
user_id = build_user_id(c) user_id = build_user_id(c)
now = int(time.time() * 1000) now = int(time.time() * 1000)
c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt, c.execute('''insert into user(user_id, name, password, join_date, user_code, rating_ptt,
character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled, current_map, ticket) character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, is_hide_rating, favorite_character, max_stamina_notification_enabled, current_map, ticket, prog_boost)
values(:user_id, :name, :password, :join_date, :user_code, 0, 0, 0, 0, 0, 0, -1, 0, '', 0) values(:user_id, :name, :password, :join_date, :user_code, 0, 0, 0, 0, 0, 0, -1, 0, '', :memories, 0)
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd}) ''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd, 'memories': Config.DEFAULT_MEMORIES})
c.execute('''insert into recent30(user_id) values(:user_id)''', { c.execute('''insert into recent30(user_id) values(:user_id)''', {
'user_id': user_id}) 'user_id': user_id})
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)
error_code = 0 error_code = 0
@@ -149,9 +168,10 @@ def auth_required(request):
user_id = None user_id = None
with Connect() as c: with Connect() as c:
headers = request.headers headers = request.headers
token = headers['Authorization'] if 'Authorization' in headers:
token = token[7:] token = headers['Authorization']
user_id = token_get_id(token) token = token[7:]
user_id = token_get_id(token)
if user_id is not None: if user_id is not None:
return view(user_id, *args, **kwargs) return view(user_id, *args, **kwargs)

View File

@@ -1,7 +1,9 @@
from server.sql import Connect from server.sql import Connect
import server.arcworld import server.arcworld
import server.arcpurchase import server.arcpurchase
import server.arcdownload
import time import time
from setting import Config
def int2b(x): def int2b(x):
@@ -174,7 +176,7 @@ def get_value_0(c, user_id):
if x[27] and x[27] != 0: if x[27] and x[27] != 0:
prog_boost = 300 prog_boost = 300
r = {"is_aprilfools": False, r = {"is_aprilfools": Config.IS_APRILFOOLS,
"curr_available_maps": [], "curr_available_maps": [],
"character_stats": user_character, "character_stats": user_character,
"friends": get_user_friend(c, user_id), "friends": get_user_friend(c, user_id),
@@ -197,10 +199,9 @@ def get_value_0(c, user_id):
"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", "moonheart3", "glow"], "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", "lifeispiano"],
"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),
"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"]
"characters": characters, "characters": characters,
"cores": [], "cores": [],
"recent_score": get_recent_score(c, user_id), "recent_score": get_recent_score(c, user_id),
@@ -226,7 +227,7 @@ def arc_aggregate_small(user_id):
def arc_aggregate_big(user_id): def arc_aggregate_big(user_id):
# 返回用户数据和地图歌曲信息 # 返回比较全的用户数据
r = {"success": False} r = {"success": False}
with Connect() as c: with Connect() as c:
r = {"success": True, r = {"success": True,
@@ -238,7 +239,7 @@ def arc_aggregate_big(user_id):
"value": server.arcpurchase.get_item(c, 'pack') "value": server.arcpurchase.get_item(c, 'pack')
}, { }, {
"id": 2, "id": 2,
"value": {} "value": server.arcdownload.get_all_songs(user_id, url_flag=False)
}, { }, {
"id": 3, "id": 3,
"value": { "value": {

View File

@@ -0,0 +1,29 @@
import os
def check_before_run(app):
# 运行前检查关键文件,返回布尔值,其实是因为有人经常忘了
f = True
if not os.path.exists('setting.py'):
app.logger.warning('File `setting.py` is missing.')
f = False
if not os.path.exists('database'):
app.logger.warning('Folder `database` is missing.')
f = False
if not os.path.exists('database/songs'):
app.logger.warning('Folder `database/songs` is missing.')
f = False
if not os.path.exists('database/arcaea_database.db'):
app.logger.warning('File `database/arcaea_database.db` is missing.')
f = False
if not os.path.exists('database/arcsong.db'):
app.logger.warning('File `database/arcsong.db` is missing.')
f = False
return f

View File

@@ -1,4 +1,6 @@
import sqlite3 import sqlite3
from flask import current_app
import traceback
class Connect(): class Connect():
@@ -22,4 +24,8 @@ class Connect():
self.conn.commit() self.conn.commit()
self.conn.close() self.conn.close()
if exc_type is not None:
current_app.logger.error(
traceback.format_exception(exc_type, exc_val, exc_tb))
return True return True

View File

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

131
latest version/setting.py Normal file
View File

@@ -0,0 +1,131 @@
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'
'''
--------------------
'''
'''
--------------------
SSL证书路径
留空则使用HTTP
SSL certificate path
If left blank, use HTTP.
'''
SSL_CERT = '' # *.pem
SSL_KEY = '' # *.key
'''
--------------------
'''
'''
--------------------
愚人节模式开关
Switch of April Fool's Day
'''
IS_APRILFOOLS = True
'''
--------------------
'''
'''
--------------------
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'
'''
--------------------
'''
'''
--------------------
歌曲下载地址前缀,留空则自动获取
Song download address prefix
If left blank, it will be obtained automatically.
'''
DOWNLOAD_LINK_PREFIX = '' # http://***.com/download/
'''
--------------------
'''
'''
--------------------
玩家歌曲下载的24小时次数限制每个文件算一次
Player's song download limit times in 24 hours, once per file
'''
DOWNLOAD_TIMES_LIMIT = 3000
'''
歌曲下载链接的有效时长,单位:秒
Effective duration of song download link, unit: seconds
'''
DOWNLOAD_TIME_GAP_LIMIT = 1000
'''
--------------------
'''
'''
--------------------
Arcaea登录的最大允许设备数量最小值为1
The maximum number of devices allowed to log in Arcaea, minimum: 1
'''
LOGIN_DEVICE_NUMBER_LIMIT = 1
'''
是否允许同设备多应用共存登录
If logging in from multiple applications on the same device is allowed
'''
ALLOW_LOGIN_SAME_DEVICE = False
'''
--------------------
'''
'''
--------------------
是否记录详细的服务器日志
If recording detailed server logs is enabled
'''
ALLOW_LOG_INFO = False
'''
--------------------
'''
'''
--------------------
用户注册时的默认记忆源点数量
The default amount of memories at the time of user registration
'''
DEFAULT_MEMORIES = 0
'''
--------------------
'''
'''
--------------------
是否强制使用全解锁云端存档
If forcing full unlocked cloud save is enabled
'''
SAVE_FULL_UNLOCK = False
'''
--------------------
'''

View File

@@ -11,6 +11,9 @@
<div class="name">{{user['name']}} <div class="name">{{user['name']}}
<span class="rank">UID: {{user['user_id']}}</span> <span class="rank">UID: {{user['user_id']}}</span>
<span class="rank">User code: {{user['user_code']}}</span> <span class="rank">User code: {{user['user_code']}}</span>
{% if user['ban_flag'] %}
<span class="rank">Banned</span>
{% endif %}
</div> </div>
<div class="join-date">注册于 Registered in: {{user['join_date']}}</div> <div class="join-date">注册于 Registered in: {{user['join_date']}}</div>
<div class="ptt">PTT: {{'%0.2f'|format(user['rating_ptt']/100|float)}}</div> <div class="ptt">PTT: {{'%0.2f'|format(user['rating_ptt']/100|float)}}</div>

View File

@@ -22,6 +22,9 @@
<div class="name">{{user['name']}} <div class="name">{{user['name']}}
<span class="rank">UID: {{user['user_id']}}</span> <span class="rank">UID: {{user['user_id']}}</span>
<span class="rank">User code: {{user['user_code']}}</span> <span class="rank">User code: {{user['user_code']}}</span>
{% if user['ban_flag'] %}
<span class="rank">Banned</span>
{% endif %}
</div> </div>
<div class="join-date">注册于 Registered in: {{user['join_date']}}</div> <div class="join-date">注册于 Registered in: {{user['join_date']}}</div>
<div class="ptt">Memories: {{user['ticket']}}</div> <div class="ptt">Memories: {{user['ticket']}}</div>
@@ -161,7 +164,7 @@
{% if recent %} {% if recent %}
<div class="title">Recent 30</div> <div class="title">Recent 30</div>
{% for i in recent %} {% for i in recent %}
{% if i %} {% if i %}
<div class="score-item"> <div class="score-item">
<span class="song-title"> <span class="song-title">

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,8 @@
from flask import (Blueprint, flash, g, redirect, from flask import (Blueprint, flash, g, redirect,
render_template, request, session, url_for) render_template, request, session, url_for)
import functools import functools
import configparser from setting import Config
import hashlib
bp = Blueprint('login', __name__, url_prefix='/web') bp = Blueprint('login', __name__, url_prefix='/web')
@@ -15,18 +16,16 @@ 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 hash_session = username + \
hashlib.sha256(password.encode("utf8")).hexdigest()
hash_session = hashlib.sha256(
hash_session.encode("utf8")).hexdigest()
session['user_id'] = hash_session
return redirect(url_for('index.index')) return redirect(url_for('index.index'))
flash(error) flash(error)
@@ -48,16 +47,14 @@ 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() hash_session = Config.USERNAME + \
path = r'setting.ini' hashlib.sha256(Config.PASSWORD.encode("utf8")).hexdigest()
config.read(path, encoding="utf-8") hash_session = hashlib.sha256(hash_session.encode("utf8")).hexdigest()
USERNAME = config.get('WEB', 'USERNAME')
PASSWORD = config.get('WEB', 'PASSWORD')
if x != USERNAME + PASSWORD: if x != hash_session:
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

@@ -1,5 +1,5 @@
import os import os
import sqlite3 from server.sql import Connect
import time import time
import json import json
import server.arcscore import server.arcscore
@@ -179,46 +179,34 @@ def update_database():
# 对于arcaea_datebase.db更新一些表并用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') with Connect('./database/old_arcaea_database.db') as c1:
c1 = conn1.cursor() with Connect() as c2:
conn2 = sqlite3.connect('./database/arcaea_database.db')
c2 = conn2.cursor()
update_one_table(c1, c2, 'user') update_one_table(c1, c2, 'user')
update_one_table(c1, c2, 'friend') update_one_table(c1, c2, 'friend')
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, '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, 'redeem')
update_one_table(c1, c2, 'user_redeem') update_one_table(c1, c2, 'user_redeem')
update_user_char(c2) update_user_char(c2)
conn1.commit()
conn1.close()
conn2.commit()
conn2.close()
os.remove('database/old_arcaea_database.db') os.remove('database/old_arcaea_database.db')
# songs # songs
if os.path.isfile("database/old_arcsong.db") and os.path.isfile("database/arcsong.db"): if os.path.isfile("database/old_arcsong.db") and os.path.isfile("database/arcsong.db"):
conn1 = sqlite3.connect('./database/old_arcsong.db') with Connect('./database/old_arcsong.db') as c1:
c1 = conn1.cursor() with Connect('./database/arcsong.db') as c2:
conn2 = sqlite3.connect('./database/arcsong.db')
c2 = conn2.cursor()
update_one_table(c1, c2, 'songs') update_one_table(c1, c2, 'songs')
conn1.commit()
conn1.close()
conn2.commit()
conn2.close()
os.remove('database/old_arcsong.db') os.remove('database/old_arcsong.db')
@@ -257,34 +245,31 @@ def unlock_user_item(c, user_id):
def get_all_item(): def get_all_item():
# 所有购买数据查询 # 所有购买数据查询
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor() c.execute('''select * from item''')
c.execute('''select * from item''') x = c.fetchall()
x = c.fetchall() re = []
re = [] if x:
if x: for i in x:
for i in x: discount_from = None
discount_from = None discount_to = None
discount_to = None
if i[5] and i[5] >= 0: if i[5] and i[5] >= 0:
discount_from = time.strftime( discount_from = time.strftime(
"%Y-%m-%d %H:%M:%S", time.localtime(int(i[5])/1000)) "%Y-%m-%d %H:%M:%S", time.localtime(int(i[5])/1000))
if i[6] and i[6] >= 0: if i[6] and i[6] >= 0:
discount_to = time.strftime( discount_to = time.strftime(
"%Y-%m-%d %H:%M:%S", time.localtime(int(i[6])//1000)) "%Y-%m-%d %H:%M:%S", time.localtime(int(i[6])//1000))
re.append({'item_id': i[0], re.append({'item_id': i[0],
'type': i[1], 'type': i[1],
'is_available': int2b(i[2]), 'is_available': int2b(i[2]),
'price': i[3], 'price': i[3],
'orig_price': i[4], 'orig_price': i[4],
'discount_from': discount_from, 'discount_from': discount_from,
'discount_to': discount_to 'discount_to': discount_to
}) })
conn.commit()
conn.close()
return re return re
@@ -346,19 +331,16 @@ def add_one_present(present_id, expire_ts, description, items):
# 添加一个奖励 # 添加一个奖励
message = None message = None
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor() c.execute(
c.execute( '''select exists(select * from present where present_id=:a)''', {'a': present_id})
'''select exists(select * from present where present_id=:a)''', {'a': present_id}) if c.fetchone() == (0,):
if c.fetchone() == (0,): c.execute('''insert into present values(:a,:b,:c,:d)''', {
c.execute('''insert into present values(:a,:b,:c,:d)''', { 'a': present_id, 'b': expire_ts, 'c': items, 'd': description})
'a': present_id, 'b': expire_ts, 'c': items, 'd': description}) message = '添加成功 Successfully add it.'
message = '添加成功 Successfully add it.' else:
else: message = '奖励已存在 The present exists.'
message = '奖励已存在 The present exists.'
conn.commit()
conn.close()
return message return message
@@ -366,21 +348,18 @@ def delete_one_present(present_id):
# 删除一个奖励 # 删除一个奖励
message = None message = None
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor() c.execute(
c.execute( '''select exists(select * from present where present_id=:a)''', {'a': present_id})
'''select exists(select * from present where present_id=:a)''', {'a': present_id}) if c.fetchone() == (1,):
if c.fetchone() == (1,): c.execute('''delete from present where present_id = :a''',
c.execute('''delete from present where present_id = :a''', {'a': present_id})
{'a': present_id}) c.execute('''delete from user_present where present_id =:a''', {
c.execute('''delete from user_present where present_id =:a''', { 'a': present_id})
'a': present_id}) message = '删除成功 Successfully delete it.'
message = '删除成功 Successfully delete it.' else:
else: message = '奖励不存在 The present does not exist.'
message = '奖励不存在 The present does not exist.'
conn.commit()
conn.close()
return message return message
@@ -423,19 +402,16 @@ def add_one_redeem(code, redeem_type, items):
# 添加一个兑换码 # 添加一个兑换码
message = None message = None
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor() c.execute(
c.execute( '''select exists(select * from redeem where code=:a)''', {'a': code})
'''select exists(select * from redeem where code=:a)''', {'a': code}) if c.fetchone() == (0,):
if c.fetchone() == (0,): c.execute('''insert into redeem values(:a,:b,:c)''', {
c.execute('''insert into redeem values(:a,:b,:c)''', { 'a': code, 'b': items, 'c': redeem_type})
'a': code, 'b': items, 'c': redeem_type}) message = '添加成功 Successfully add it.'
message = '添加成功 Successfully add it.' else:
else: message = '兑换码已存在 The redeem code exists.'
message = '兑换码已存在 The redeem code exists.'
conn.commit()
conn.close()
return message return message
@@ -443,21 +419,19 @@ def add_some_random_redeem(amount, redeem_type, items):
# 随机生成一堆10位的兑换码 # 随机生成一堆10位的兑换码
message = None message = None
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor() i = 1
i = 1 while i <= amount:
while i <= amount: code = random_str()
code = random_str() c.execute(
c.execute( '''select exists(select * from redeem where code=:a)''', {'a': code})
'''select exists(select * from redeem where code=:a)''', {'a': code}) if c.fetchone() == (0,):
if c.fetchone() == (0,): c.execute('''insert into redeem values(:a,:b,:c)''',
c.execute('''insert into redeem values(:a,:b,:c)''', {'a': code, 'b': items, 'c': redeem_type})
{'a': code, 'b': items, 'c': redeem_type}) i += 1
i += 1
message = '添加成功 Successfully add it.'
message = '添加成功 Successfully add it.'
conn.commit()
conn.close()
return message return message
@@ -465,19 +439,17 @@ def delete_one_redeem(code):
# 删除一个兑换码 # 删除一个兑换码
message = None message = None
conn = sqlite3.connect('./database/arcaea_database.db') with Connect() as c:
c = conn.cursor() c.execute(
c.execute( '''select exists(select * from redeem where code=:a)''', {'a': code})
'''select exists(select * from redeem where code=:a)''', {'a': code}) if c.fetchone() == (1,):
if c.fetchone() == (1,): c.execute('''delete from redeem where code = :a''', {'a': code})
c.execute('''delete from redeem where code = :a''', {'a': code}) c.execute(
c.execute('''delete from user_redeem where code =:a''', {'a': code}) '''delete from user_redeem where code =:a''', {'a': code})
message = '删除成功 Successfully delete it.' message = '删除成功 Successfully delete it.'
else: else:
message = '兑换码不存在 The redeem code does not exist.' message = '兑换码不存在 The redeem code does not exist.'
conn.commit()
conn.close()
return message return message

View File

@@ -49,6 +49,10 @@ def get_user(c, user_id):
if x[20]: if x[20]:
time_played = time.strftime('%Y-%m-%d %H:%M:%S', time_played = time.strftime('%Y-%m-%d %H:%M:%S',
time.localtime(int(x[20])//1000)) time.localtime(int(x[20])//1000))
if x[2] == '':
ban_flag = True
else:
ban_flag = False
r = {'name': x[1], r = {'name': x[1],
'user_id': user_id, 'user_id': user_id,
@@ -65,7 +69,8 @@ def get_user(c, user_id):
'time_played': time_played, 'time_played': time_played,
'clear_type': x[21], 'clear_type': x[21],
'rating': x[22], 'rating': x[22],
'ticket': x[26] 'ticket': x[26],
'ban_flag': ban_flag
} }
return r return r