mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2026-02-09 01:07:27 +08:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
941a79ccc7 | ||
|
|
62902a561c | ||
|
|
1660bc5899 | ||
|
|
d577246d28 | ||
|
|
9fd626468e | ||
|
|
c51a1b4e85 | ||
|
|
0e42123417 | ||
|
|
e216e6144b | ||
|
|
b70c435a4a | ||
|
|
eb03d2be93 | ||
|
|
fcb5d264ef | ||
|
|
d617951e1f | ||
|
|
febf931f1a | ||
|
|
981961d6a1 | ||
|
|
a90380df4c | ||
|
|
4f66f492fc | ||
|
|
df181f104e | ||
|
|
a890a9af4a |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.log
|
||||||
39
README.md
39
README.md
@@ -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.
Binary file not shown.
@@ -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):
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
0
latest version/log/error.log
Normal file
0
latest version/log/error.log
Normal 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__':
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
python main.py
|
python -B main.py
|
||||||
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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": {
|
||||||
|
|||||||
29
latest version/server/init.py
Normal file
29
latest version/server/init.py
Normal 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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
[CONFIG]
|
|
||||||
HOST = 192.168.1.113
|
|
||||||
PORT = 80
|
|
||||||
|
|
||||||
[WEB]
|
|
||||||
USERNAME = admin
|
|
||||||
PASSWORD = admin
|
|
||||||
131
latest version/setting.py
Normal file
131
latest version/setting.py
Normal 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
|
||||||
|
'''
|
||||||
|
--------------------
|
||||||
|
'''
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user