Update to v1.7

close #1
close #2
This commit is contained in:
Lost-MSth
2020-11-27 21:35:35 +08:00
parent 30690b2fbf
commit dfcbb6f9c0
22 changed files with 1635 additions and 296 deletions

View File

@@ -18,23 +18,24 @@ This is a small local Arcaea server based on Python and Flask, which can simulat
- 爬梯 Climbing steps
- 自定义世界模式 Customizable World Mode
- 自定义歌曲下载 Customizable songs download
- 单曲和曲包购买(没啥用) Single songs and song packs purchase(useless)
- 全角色立绘 All character drawings
- 角色技能 Character skills
- 自定义角色属性 Customizable characters attributes
- 全剧情解锁 Unlock all the stories
- 后台查 Background search scores
- 后台自定义歌曲定数 Customize chart consts in the background
- 后台查 Background search
- 后台自定义信息 Customize some things in the background
- 成绩校验 Score check
- 下载校验 Download check
没有以下 We don't have
- 角色数值 Character characteristic value
- 购买 Purchase
- 歌曲解锁、曲包解锁 Songs unlocking and music packs unlocking
- 数据同步的时间和设备记录 The record of time and device for data synchronization
- 服务器安全性保证 Server security assurance
可能有问题 There may be problems
- Recent 30
- 一些歌曲的解锁 Some Songs' unlocking
## 说明 Statement
只是很有趣,用处探索中。
@@ -53,13 +54,16 @@ It is just so interesting. What it can do is under exploration.
>
> Tips: When updating, please keep the original database in case of data loss.
### Version 1.6
- 适用于Arcaea 3.2.3版本 For Arcaea 3.2.3
### Version 1.7
- 仍然适用于Arcaea 3.2.3版本 Still for Arcaea 3.2.3
- 更新了歌曲数据库 Update the song database.
- 新增了自定义角色属性 Add customizable characters attributes.
- 用户的记忆源点可以修改了,但仍然没有实际用途 The users' memories can be modified, but still is of no practical use.
- 网页端安全性增强,用户名及密码可修改 The security of webpage is enhanced, and the username and password can be modified now.
- 改进了数据库更新方式,可以一定程度上应对数据表结构修改 The method of database updating is improved, which can deal with the modification of data table structure to some extent.
- 新增了购买系统,包括单曲购买和曲包购买 Add purchase system, including single purchase and pack purchase.
- 后台查询与修改项目增多 Increase background query and modification items.
- 新增用户下载量限制和下载校验 Add user download limit and download verification.
- 新增了**梦**的语音 Add the voice of **Yume**.
- 新增了网站图标 Add a favicon.
- 尝试解锁了所有的场景 Try to unlock all the scenes.
- 修复了一些Bug Fix some bugs.
## 运行环境与依赖 Running environment and requirements
- Windows操作系统 Windows operating system
@@ -83,6 +87,8 @@ It is just so interesting. What it can do is under exploration.
歌曲数据库来自 Using song database from
[BotArcAPI releases](https://github.com/TheSnowfield/BotArcAPI/releases)
网站图标来自 Using favicon from [black fate - てんてん - pixiv](https://www.pixiv.net/artworks/82374369)
## 联系方式 Contact
如有必要,可以联系本人 Contact me if necessary
邮箱 Emailth84292@foxmail.com

Binary file not shown.

View File

@@ -1,6 +1,7 @@
import sqlite3
import hashlib
import time
import json
# 数据库初始化文件删掉arcaea_database.db文件后运行即可谨慎使用
@@ -171,41 +172,98 @@ fragment_multiply int,
prog_boost_multiply int,
primary key(user_id, song_id, difficulty)
);''')
c.execute('''create table if not exists download_token(user_id int,
song_id text,
file_name text,
token text,
time int,
primary key(user_id, song_id, file_name)
);''')
c.execute('''create table if not exists user_download(user_id int,
token text,
time int,
primary key(user_id, token, time)
);''')
c.execute('''create table if not exists item(item_id text,
type text,
is_available int,
price int,
orig_price int,
discount_from int,
discount_to int,
_id text,
primary key(item_id, type)
);''')
c.execute('''create table if not exists user_item(user_id int,
item_id text,
type text,
primary key(user_id, item_id, type)
);''')
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']
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']
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','']
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', '']
skill_id_uncap = ['','','frags_kou','','visual_ink','','','','','','','','','shirabe_entry_fee','','','','','','','','frags_yume','','','','','','','','','','','','','','','','','']
skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', '', '', 'shirabe_entry_fee',
'', '', '', '', '', '', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
for i in range(0, 39):
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]:
sql = 'insert into character values('+str(i)+',"'+char[i]+'''",30,25000,25000,90,90,90,"'''+skill_id[i]+'''",0,0,"'''+skill_id_uncap[i]+'''",0,'',1,1)'''
sql = 'insert into character values('+str(
i)+',"'+char[i]+'''",30,25000,25000,90,90,90,"'''+skill_id[i]+'''",0,0,"'''+skill_id_uncap[i]+'''",0,'',1,1)'''
c.execute(sql)
else:
if i != 5:
sql = 'insert into character values('+str(i)+',"'+char[i]+'''",30,25000,25000,90,90,90,"'''+skill_id[i]+'''",0,0,"'''+skill_id_uncap[i]+'''",0,'',0,0)'''
sql = 'insert into character values('+str(
i)+',"'+char[i]+'''",30,25000,25000,90,90,90,"'''+skill_id[i]+'''",0,0,"'''+skill_id_uncap[i]+'''",0,'',0,0)'''
c.execute(sql)
def b2int(x):
# int与布尔值转换
if x:
return 1
else:
return 0
def insert_items(c, items):
# 物品数据导入
for i in items:
if 'discount_from' not in i:
discount_from = -1
else:
discount_from = i['discount_from']
if 'discount_to' not in i:
discount_to = -1
else:
discount_to = i['discount_to']
for j in i['items']:
if "_id" not in j:
_id = ''
else:
_id = j['_id']
if j['type'] != 'character':
c.execute('''insert into item(item_id, type, is_available, price, orig_price, discount_from, discount_to, _id) values(:a,:b,:c,:d,:e,:f,:g,:h)''', {
'a': j['id'], 'b': j['type'], 'c': b2int(j['is_available']), 'd': i['price'], 'e': i['orig_price'], 'f': discount_from, 'g': discount_to, 'h': _id})
f = open('singles.json', 'r')
singles = json.load(f)
f.close()
insert_items(c, singles)
f = open('packs.json', 'r')
packs = json.load(f)
f.close()
insert_items(c, packs)
conn.commit()
conn.close()
def arc_register(name: str, password: str):
def build_user_code(c):
return '123456789'
@@ -213,17 +271,17 @@ def arc_register(name: str, password: str):
def build_user_id(c):
return 2000000
## def insert_user_char(c, user_id):
## for i in range(0, 38):
## if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]:
## sql = 'insert into user_char values('+str(user_id)+','+str(
## i)+''',30,25000,25000,90,90,90,'',0,0,'',0,1,1)'''
## c.execute(sql)
## else:
## if i != 5:
## sql = 'insert into user_char values('+str(user_id)+','+str(
## i)+''',30,25000,25000,90,90,90,'',0,0,'',0,0,0)'''
## c.execute(sql)
# def insert_user_char(c, user_id):
# for i in range(0, 38):
# if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21]:
# sql = 'insert into user_char values('+str(user_id)+','+str(
# i)+''',30,25000,25000,90,90,90,'',0,0,'',0,1,1)'''
# c.execute(sql)
# else:
# if i != 5:
# sql = 'insert into user_char values('+str(user_id)+','+str(
# i)+''',30,25000,25000,90,90,90,'',0,0,'',0,0,0)'''
# c.execute(sql)
def insert_user_char(c, user_id):
# 为用户添加所有可用角色
c.execute('''select * from character''')
@@ -233,7 +291,6 @@ def arc_register(name: str, password: str):
c.execute('''insert into user_char values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o)''', {
'a': user_id, 'b': i[0], 'c': i[2], 'd': i[3], 'e': i[4], 'f': i[5], 'g': i[6], 'h': i[7], 'i': i[8], 'j': i[9], 'k': i[10], 'l': i[11], 'm': i[12], 'n': i[14], 'o': i[15]})
conn = sqlite3.connect('arcaea_database.db')
c = conn.cursor()
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
@@ -249,7 +306,8 @@ def arc_register(name: str, password: str):
''', {'user_code': user_code, 'user_id': user_id, 'join_date': now, 'name': name, 'password': hash_pwd})
c.execute('''insert into recent30(user_id) values(:user_id)''', {
'user_id': user_id})
c.execute('''insert into best_score values(2000000,'vexaria',3,10000000,100,0,0,0,100,0,1599667200,3,3,10.8)''')
c.execute(
'''insert into best_score values(2000000,'vexaria',3,10000000,100,0,0,0,100,0,1599667200,3,3,10.8)''')
insert_user_char(c, user_id)
conn.commit()
conn.close()

View File

@@ -0,0 +1,70 @@
{
"map_id": "byd_lumia",
"is_legacy": false,
"chapter": 1001,
"available_from": -1,
"available_to": 9999999999999,
"is_repeatable": false,
"require_id": "lumia2",
"require_type": "chart_unlock",
"coordinate": "650,-650",
"is_beyond": true,
"stamina_cost": 3,
"beyond_health": 150,
"character_affinity": [0, 15, 14, 16],
"affinity_multiplier": [2.4, 1.9, 2.4, 2.9],
"step_count": 6,
"custom_bg": "",
"curr_position": 0,
"curr_capture": 0,
"is_locked": false,
"steps": [{
"map_id": "byd_lumia",
"position": 0,
"capture": 10,
"restrict_id": "core",
"restrict_type": "pack_id"
}, {
"map_id": "byd_lumia",
"position": 1,
"capture": 20,
"items": [{
"type": "fragment",
"amount": 200
}]
}, {
"map_id": "byd_lumia",
"position": 2,
"capture": 30,
"items": [{
"type": "core",
"id": "core_generic",
"amount": 1
}]
}, {
"map_id": "byd_lumia",
"position": 3,
"capture": 40,
"items": [{
"type": "fragment",
"amount": 250
}]
}, {
"map_id": "byd_lumia",
"position": 4,
"capture": 50,
"items": [{
"type": "core",
"id": "core_generic",
"amount": 1
}]
}, {
"map_id": "byd_lumia",
"position": 5,
"capture": 0,
"items": [{
"id": "lumia3",
"type": "world_song"
}]
}]
}

View File

@@ -0,0 +1,198 @@
[{
"name": "core",
"items": [{
"type": "pack",
"id": "core",
"_id": "5fb5b68a68273a03de60f205",
"is_available": true
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "shiawase",
"items": [{
"type": "pack",
"id": "shiawase",
"_id": "5fb5b68a68273a03de60f234",
"is_available": true
}, {
"type": "character",
"id": "kou",
"_id": "5fb5b68a68273a03de60f233",
"is_available": true
}],
"price": 500,
"orig_price": 500,
"discount_from": 1552089600000,
"discount_to": 1552694399000
}, {
"name": "dynamix",
"items": [{
"type": "pack",
"id": "dynamix",
"_id": "5fb5b68a68273a03de60f238",
"is_available": true
}, {
"type": "character",
"id": "sapphire",
"_id": "5fb5b68a68273a03de60f237",
"is_available": true
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "mirai",
"items": [{
"type": "pack",
"id": "mirai",
"_id": "5fb5b68a68273a03de60f23e",
"is_available": true
}, {
"type": "character",
"id": "lethe",
"_id": "5fb5b68a68273a03de60f23d",
"is_available": true
}],
"price": 500,
"orig_price": 500,
"discount_from": 1552089600000,
"discount_to": 1552694399000
}, {
"name": "yugamu",
"items": [{
"type": "pack",
"id": "yugamu",
"_id": "5fb5b68a68273a03de60f206",
"is_available": true
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "lanota",
"items": [{
"type": "pack",
"id": "lanota",
"_id": "5fb5b68a68273a03de60f211",
"is_available": true
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "nijuusei",
"items": [{
"type": "pack",
"id": "nijuusei",
"_id": "5fb5b68a68273a03de60f207",
"is_available": true
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "rei",
"items": [{
"type": "pack",
"id": "rei",
"_id": "5fb5b68a68273a03de60f1fd",
"is_available": true
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "tonesphere",
"items": [{
"type": "pack",
"id": "tonesphere",
"_id": "5fb5b68a68273a03de60f213",
"is_available": true
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "groovecoaster",
"items": [{
"type": "pack",
"id": "groovecoaster",
"_id": "5fb5b68a68273a03de60f22c",
"is_available": true
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "zettai",
"items": [{
"type": "pack",
"id": "zettai",
"_id": "5fb5b68a68273a03de60f1ff",
"is_available": true
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "chunithm",
"items": [{
"type": "pack",
"id": "chunithm",
"_id": "5fb5b68a68273a03de60f221",
"is_available": true
}],
"price": 300,
"orig_price": 300
}, {
"name": "prelude",
"items": [{
"type": "pack",
"id": "prelude",
"_id": "5fb5b68a68273a03de60f22d",
"is_available": true
}],
"price": 400,
"orig_price": 400
}, {
"name": "omatsuri",
"items": [{
"type": "pack",
"id": "omatsuri",
"_id": "5fb5b68a68273a03de60f200",
"is_available": true
}],
"price": 500,
"orig_price": 500
}, {
"name": "vs",
"items": [{
"type": "pack",
"id": "vs",
"_id": "5fb5b68a68273a03de60f224",
"is_available": true
}],
"price": 500,
"orig_price": 500
}, {
"name": "extend",
"items": [{
"type": "pack",
"id": "extend",
"_id": "5fb5b68a68273a03de60f230",
"is_available": true
}],
"price": 700,
"orig_price": 700
}]

View File

@@ -0,0 +1,466 @@
[{
"name": "testsingle",
"items": [{
"id": "testsingle",
"type": "single",
"is_available": false
}],
"price": 100,
"orig_price": 100
}, {
"name": "dataerror",
"items": [{
"id": "dataerror",
"type": "single",
"_id": "5fb5b68a68273a03de60f210",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "yourvoiceso",
"items": [{
"id": "yourvoiceso",
"type": "single",
"_id": "5fb5b68a68273a03de60f227",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "crosssoul",
"items": [{
"id": "crosssoul",
"type": "single",
"_id": "5fb5b68a68273a03de60f21b",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "impurebird",
"items": [{
"type": "single",
"id": "impurebird",
"_id": "5fb5b68a68273a03de60f21c",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "auxesia",
"items": [{
"type": "single",
"id": "auxesia",
"_id": "5fb5b68a68273a03de60f228",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1520413239000,
"discount_to": 1521072000000
}, {
"name": "modelista",
"items": [{
"type": "single",
"id": "modelista",
"_id": "5fb5b68a68273a03de60f1fb",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "yozakurafubuki",
"items": [{
"type": "single",
"id": "yozakurafubuki",
"_id": "5fb5b68a68273a03de60f21d",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "surrender",
"items": [{
"type": "single",
"id": "surrender",
"_id": "5fb5b68a68273a03de60f229",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "metallicpunisher",
"items": [{
"type": "single",
"id": "metallicpunisher",
"_id": "5fb5b68a68273a03de60f1fc",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "carminescythe",
"items": [{
"type": "single",
"id": "carminescythe",
"_id": "5fb5b68a68273a03de60f21e",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "bethere",
"items": [{
"type": "single",
"id": "bethere",
"_id": "5fb5b68a68273a03de60f22a",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "callmyname",
"items": [{
"type": "single",
"id": "callmyname",
"_id": "5fb5b68a68273a03de60f212",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "fallensquare",
"items": [{
"type": "single",
"id": "fallensquare",
"_id": "5fb5b68a68273a03de60f208",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "dropdead",
"items": [{
"type": "single",
"id": "dropdead",
"_id": "5fb5b68a68273a03de60f21f",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "alexandrite",
"items": [{
"type": "single",
"id": "alexandrite",
"_id": "5fb5b68a68273a03de60f22b",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "astraltale",
"items": [{
"type": "single",
"id": "astraltale",
"_id": "5fb5b68a68273a03de60f1fe",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "phantasia",
"items": [{
"type": "single",
"id": "phantasia",
"_id": "5fb5b68a68273a03de60f209",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "empireofwinter",
"items": [{
"type": "single",
"id": "empireofwinter",
"_id": "5fb5b68a68273a03de60f220",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "libertas",
"items": [{
"type": "single",
"id": "libertas",
"_id": "5fb5b68a68273a03de60f214",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "dottodot",
"items": [{
"type": "single",
"id": "dottodot",
"_id": "5fb5b68a68273a03de60f20a",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "dreadnought",
"items": [{
"type": "single",
"id": "dreadnought",
"_id": "5fb5b68a68273a03de60f215",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "mirzam",
"items": [{
"type": "single",
"id": "mirzam",
"_id": "5fb5b68a68273a03de60f20b",
"is_available": true
}],
"price": 100,
"orig_price": 100,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "heavenlycaress",
"items": [{
"type": "single",
"id": "heavenlycaress",
"_id": "5fb5b68a68273a03de60f222",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "filament",
"items": [{
"type": "single",
"id": "filament",
"_id": "5fb5b68a68273a03de60f22e",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "avantraze",
"items": [{
"type": "single",
"id": "avantraze",
"_id": "5fb5b68a68273a03de60f216",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "battlenoone",
"items": [{
"type": "single",
"id": "battlenoone",
"_id": "5fb5b68a68273a03de60f201",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "saikyostronger",
"items": [{
"type": "single",
"id": "saikyostronger",
"_id": "5fb5b68a68273a03de60f20c",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "izana",
"items": [{
"type": "single",
"id": "izana",
"_id": "5fb5b68a68273a03de60f223",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "einherjar",
"items": [{
"type": "single",
"id": "einherjar",
"_id": "5fb5b68a68273a03de60f22f",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "laqryma",
"items": [{
"type": "single",
"id": "laqryma",
"_id": "5fb5b68a68273a03de60f217",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "amygdata",
"items": [{
"type": "single",
"id": "amygdata",
"_id": "5fb5b68a68273a03de60f202",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "altale",
"items": [{
"type": "single",
"id": "altale",
"_id": "5fb5b68a68273a03de60f20d",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "feelssoright",
"items": [{
"type": "single",
"id": "feelssoright",
"_id": "5fb5b68a68273a03de60f218",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "scarletcage",
"items": [{
"type": "single",
"id": "scarletcage",
"_id": "5fb5b68a68273a03de60f203",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "teriqma",
"items": [{
"type": "single",
"id": "teriqma",
"_id": "5fb5b68a68273a03de60f20e",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "mahoroba",
"items": [{
"type": "single",
"id": "mahoroba",
"_id": "5fb5b68a68273a03de60f225",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "badtek",
"items": [{
"type": "single",
"id": "badtek",
"_id": "5fb5b68a68273a03de60f219",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "maliciousmischance",
"items": [{
"type": "single",
"id": "maliciousmischance",
"_id": "5fb5b68a68273a03de60f231",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "buchigireberserker",
"items": [{
"type": "single",
"id": "buchigireberserker",
"_id": "5fb5b68a68273a03de60f20f",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "galaxyfriends",
"items": [{
"type": "single",
"id": "galaxyfriends",
"_id": "5fb5b68a68273a03de60f226",
"is_available": true
}],
"price": 100,
"orig_price": 100
}, {
"name": "xeraphinite",
"items": [{
"type": "single",
"id": "xeraphinite",
"_id": "5fb5b68a68273a03de60f232",
"is_available": true
}],
"orig_price": 100,
"price": 100
}, {
"name": "xanatos",
"items": [{
"type": "single",
"id": "xanatos",
"_id": "5fb5b68a68273a03de60f21a",
"is_available": true
}],
"price": 100,
"orig_price": 100
}]

View File

@@ -9,13 +9,19 @@ import web.login
import web.index
import server.arcworld
import server.arcdownload
import server.arcpurchase
import os
app = Flask(__name__)
wsgi_app = app.wsgi_app
def error_return(error_code): # 错误返回
# -7 处理交易时发生了错误
# -5 所有的曲目都已经下载完毕
# -4 您的账号已在别处登录
# -3 无法连接至服务器
# 2 Arcaea服务器正在维护
# 5 请更新Arcaea到最新版本
# 100 无法在此ip地址下登录游戏
@@ -32,19 +38,27 @@ def error_return(error_code): # 错误返回
# 121 账户冻结
# 122 账户暂时冻结
# 123 账户被限制
# 124 你今天不能再使用这个IP地址创建新的账号
# 150 非常抱歉您已被限制使用此功能
# 151 目前无法使用此功能
# 401 用户不存在
# 403 无法连接至服务器
# 501 502 此物品目前无法获取
# 501 502 -6 此物品目前无法获取
# 504 无效的序列码
# 505 此序列码已被使用
# 506 你已拥有了此物品
# 601 好友列表已满
# 602 此用户已是好友
# 604 你不能加自己为好友
# 903 下载量超过了限制请24小时后重试
# 905 请在再次使用此功能前等待24小时
# 1001 设备数量达到上限
# 1002 设备已使用过功能
# 1002 设备已使用过功能
# 9801 下载歌曲时发生问题,请再试一次
# 9802 保存歌曲时发生问题,请检查设备空间容量
# 9905 没有在云端发现任何数据
# 9907 更新数据时发生了问题
# 9908 服务器只支持最新的版本请更新Arcaea
# 其它 发生未知错误
return jsonify({
"success": False,
@@ -57,6 +71,15 @@ def hello():
return "Hello World!"
@app.route('/favicon.ico', methods=['GET']) # 图标
def favicon():
# Pixiv ID: 82374369
# 我觉得这张图虽然并不是那么精细,但很有感觉,色彩的强烈对比下给人带来一种惊艳
# 然后在压缩之下什么也看不清了:(
return app.send_static_file('favicon.ico')
@app.route('/coffee/12/auth/login', methods=['POST']) # 登录接口
def login():
headers = request.headers
@@ -92,7 +115,8 @@ def register():
return error_return(108)
@app.route('/coffee/12/compose/aggregate', methods=['GET']) # 用户信息获取
# 集成式请求,没想到什么好办法处理,就先这样写着
@app.route('/coffee/12/compose/aggregate', methods=['GET'])
def aggregate():
calls = request.args.get('calls')
headers = request.headers
@@ -432,12 +456,20 @@ def cloud_post():
return error_return(108)
@app.route('/coffee/12/purchase/me/redeem', methods=['POST']) # 兑换码,然没有用
@app.route('/coffee/12/purchase/me/redeem', methods=['POST']) # 兑换码,然没有用
def redeem():
return error_return(504)
# 购买自然没有用只是为了world模式boost一下
# 礼物确认
@app.route('/coffee/12/present/me/claim/<present_id>', methods=['POST'])
def claim_present(present_id):
return jsonify({
"success": True
})
# 购买为了world模式boost一下
@app.route('/coffee/12/purchase/me/item', methods=['POST'])
def item():
return jsonify({
@@ -445,27 +477,32 @@ def item():
})
@app.route('/coffee/12/purchase/me/pack', methods=['POST']) # 购买,自然没有用
@app.route('/coffee/12/purchase/me/pack', methods=['POST']) # 曲包和单曲购买
def pack():
headers = request.headers
token = headers['Authorization']
token = token[7:]
try:
user_id = server.auth.token_get_id(token)
if user_id:
if 'pack_id' in request.form:
return jsonify(server.arcpurchase.buy_pack(user_id, request.form['pack_id']))
if 'single_id' in request.form:
return jsonify(server.arcpurchase.buy_single(user_id, request.form['single_id']))
else:
return error_return(108)
except:
return error_return(108)
return jsonify({
"success": True
})
@app.route('/coffee/12/purchase/bundle/single', methods=['GET']) # 单曲购买,自然没有用
@app.route('/coffee/12/purchase/bundle/single', methods=['GET']) # 单曲购买信息获取
def single():
return jsonify({
"success": True,
"value": [{
"name": "testsingle",
"items": [{
"id": "testsingle",
"type": "single",
"is_available": False
}],
"price": 100,
"orig_price": 100
}]
"value": server.arcpurchase.get_single_purchase()
})
@@ -475,6 +512,7 @@ def world_all():
token = headers['Authorization']
token = token[7:]
try:
user_id = server.auth.token_get_id(token)
if user_id:
return jsonify({
@@ -539,21 +577,22 @@ def download_song():
token = headers['Authorization']
token = token[7:]
song_ids = request.args.getlist('sid')
try:
user_id = server.auth.token_get_id(token)
if user_id:
re = {}
if not song_ids:
re = server.arcdownload.get_all_songs()
else:
for song_id in song_ids:
re.update(server.arcdownload.get_one_song(song_id))
if server.arcdownload.is_able_download(user_id):
re = {}
if not song_ids:
re = server.arcdownload.get_all_songs(user_id)
else:
re = server.arcdownload.get_some_songs(user_id, song_ids)
return jsonify({
"success": True,
"value": re
})
return jsonify({
"success": True,
"value": re
})
else:
return error_return(903)
else:
return error_return(108)
except:
@@ -562,12 +601,17 @@ def download_song():
@app.route('/download/<path:file_path>', methods=['GET']) # 下载
def download(file_path):
t = request.args.get('t')
try:
path = os.path.join('./database/songs', file_path)
if os.path.isfile(path) and not('../' in path or '..\\' in path):
return send_from_directory('./database/songs', file_path, as_attachment=True)
message = server.arcdownload.is_token_able_download(t)
if message == 0:
path = os.path.join('./database/songs', file_path)
if os.path.isfile(path) and not('../' in path or '..\\' in path):
return send_from_directory('./database/songs', file_path, as_attachment=True)
else:
return error_return(109)
else:
return error_return(109)
return error_return(message)
except:
return error_return(108)

View File

@@ -1,6 +1,11 @@
import os
import hashlib
from flask import url_for
import sqlite3
import time
time_limit = 3000 # 每个玩家24小时下载次数限制
time_gap_limit = 1000 # 下载链接有效秒数
def get_file_md5(file_path):
@@ -18,31 +23,105 @@ def get_file_md5(file_path):
return myhash.hexdigest()
def get_one_song(song_id, file_dir='./database/songs'):
def get_one_song(c, user_id, song_id, file_dir='./database/songs'):
# 获取一首歌的下载链接,返回字典
dir_list = os.listdir(os.path.join(file_dir, song_id))
re = {}
now = int(time.time())
c.execute('''delete from download_token where user_id=:a and song_id=:b''', {
'a': user_id, 'b': song_id})
for i in dir_list:
if os.path.isfile(os.path.join(file_dir, song_id, i)) and i in ['0.aff', '1.aff', '2.aff', '3.aff', 'base.ogg']:
token = hashlib.md5(
(str(user_id) + song_id + i + str(now)).encode(encoding='UTF-8')).hexdigest()
token = token[:8]
if i == 'base.ogg':
re['audio'] = {"checksum": get_file_md5(os.path.join(file_dir, song_id, 'base.ogg')),
"url": url_for('download', file_path=song_id+'/base.ogg', _external=True)}
"url": url_for('download', file_path=song_id+'/base.ogg', t=token, _external=True)}
else:
if 'chart' not in re:
re['chart'] = {}
re['chart'][i[0]] = {"checksum": get_file_md5(os.path.join(file_dir, song_id, i)),
"url": url_for('download', file_path=song_id+'/'+i, _external=True)}
"url": url_for('download', file_path=song_id+'/'+i, t=token, _external=True)}
c.execute('''insert into download_token values(:a,:b,:c,:d,:e)''', {
'a': user_id, 'b': song_id, 'c': i, 'd': token, 'e': now})
return {song_id: re}
def get_all_songs(file_dir='./database/songs'):
def get_all_songs(user_id, file_dir='./database/songs'):
# 获取所有歌的下载链接,返回字典
dir_list = os.listdir(file_dir)
re = {}
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
for i in dir_list:
if os.path.isdir(os.path.join(file_dir, i)):
re.update(get_one_song(i))
re.update(get_one_song(c, user_id, i))
conn.commit()
conn.close()
return re
def get_some_songs(user_id, song_ids):
# 获取一些歌的下载链接,返回字典
re = {}
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
for song_id in song_ids:
re.update(get_one_song(c, user_id, song_id))
conn.commit()
conn.close()
return re
def is_token_able_download(t):
# token是否可以下载返回错误码0即可以
errorcode = 0
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
c.execute('''select * from download_token where token = :t limit 1''',
{'t': t})
x = c.fetchone()
now = int(time.time())
if x and now - x[4] <= time_gap_limit:
c.execute(
'''select count(*) from user_download where user_id = :a''', {'a': x[0]})
y = c.fetchone()
if y and y[0] <= time_limit:
c.execute('''insert into user_download values(:a,:b,:c)''', {
'a': x[0], 'b': x[3], 'c': now})
else:
errorcode = 903
else:
errorcode = 108
conn.commit()
conn.close()
return errorcode
def is_able_download(user_id):
# 是否可以下载,返回布尔值
f = True
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
now = int(time.time())
c.execute(
'''delete from user_download where user_id = :a and time <= :b''', {'a': user_id, 'b': now - 24*3600})
c.execute(
'''select count(*) from user_download where user_id = :a''', {'a': user_id})
y = c.fetchone()
if y and y[0] <= time_limit:
pass
else:
f = False
conn.commit()
conn.close()
return f

View File

@@ -0,0 +1,122 @@
import sqlite3
def int2b(x):
# int与布尔值转换
if x is None or x == 0:
return False
else:
return True
def get_item(c, type='pack'):
# 读取packs内容返回字典列表
c.execute('''select * from item where type = :a''', {'a': type})
x = c.fetchall()
if not x:
return []
re = []
for i in x:
r = {"name": i[0],
"items": [{
"type": i[1],
"id": i[0],
"is_available": int2b(i[2])
}],
"price": i[3],
"orig_price": i[4]}
if i[5] > 0:
r['discount_from'] = i[5]
if i[6] > 0:
r['discount_to'] = i[6]
re.append(r)
return re
def get_single_purchase():
# main里面没开数据库这里写一下代替
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
re = get_item(c, type='single')
conn.commit()
conn.close()
return re
def buy_pack(user_id, pack_id):
# 曲包购买,返回字典
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
c.execute('''select price from item where item_id = :a''', {'a': pack_id})
price = c.fetchone()
if price:
price = price[0]
else:
price = 0
c.execute('''select ticket from user where user_id = :a''', {'a': user_id})
ticket = c.fetchone()
if ticket:
ticket = ticket[0]
else:
ticket = 0
if ticket < price:
conn.commit()
conn.close()
return {
"success": False
}
c.execute('''update user set ticket = :b where user_id = :a''',
{'a': user_id, 'b': ticket-price})
c.execute('''insert into user_item values(:a,:b,'pack')''',
{'a': user_id, 'b': pack_id})
conn.commit()
conn.close()
return {
"success": True
}
def buy_single(user_id, single_id):
# 单曲购买,返回字典
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
c.execute('''select price from item where item_id = :a''',
{'a': single_id})
price = c.fetchone()
if price:
price = price[0]
else:
price = 0
c.execute('''select ticket from user where user_id = :a''', {'a': user_id})
ticket = c.fetchone()
if ticket:
ticket = ticket[0]
else:
ticket = 0
if ticket < price:
conn.commit()
conn.close()
return {
"success": False
}
c.execute('''update user set ticket = :b where user_id = :a''',
{'a': user_id, 'b': ticket-price})
c.execute('''insert into user_item values(:a,:b,'single')''',
{'a': user_id, 'b': single_id})
conn.commit()
conn.close()
return {
"success": True
}

View File

@@ -1390,7 +1390,18 @@ def arc_all_get(user_id):
}, {
"complete": 1,
"unlock_key": "dreaminattraction|1|0"
}]
}, {
"complete": 1,
"unlock_key": "buchigireberserker|2|0"
}, {
"complete": 1,
"unlock_key": "gothiveofra|2|0"
}, {
"complete": 1,
"unlock_key": "gothiveofra|1|0"
}
]
}, "clearedsongs": {
"": song_1
},

View File

@@ -1,5 +1,7 @@
import sqlite3
import server.arcworld
import server.arcpurchase
import time
def int2b(x):
@@ -56,7 +58,7 @@ def get_user_character(c, user_id):
y = c.fetchone()
if y is not None:
char_name = y[0]
s.append({
char = {
"is_uncapped_override": int2b(i[14]),
"is_uncapped": int2b(i[13]),
"uncap_cores": [],
@@ -73,7 +75,10 @@ def get_user_character(c, user_id):
"level": i[2],
"name": char_name,
"character_id": i[1]
})
}
if i[1] == 21:
char["voice"] = [0, 1, 2, 3, 100, 1000, 1001]
s.append(char)
return s
else:
@@ -115,6 +120,34 @@ def get_user_friend(c, user_id):
return s
def get_user_singles(c, user_id):
# 得到用户的单曲,返回列表
c.execute('''select * from user_item where user_id = :user_id and type = "single"''',
{'user_id': user_id})
x = c.fetchall()
if not x:
return []
re = []
for i in x:
re.append(i[1])
return re
def get_user_packs(c, user_id):
# 得到用户的曲包,返回列表
c.execute('''select * from user_item where user_id = :user_id and type = "pack"''',
{'user_id': user_id})
x = c.fetchall()
if not x:
return []
re = []
for i in x:
re.append(i[1])
return re
def get_value_0(c, user_id):
# 构造value id=0的数据返回字典
c.execute('''select * from user where user_id = :x''', {'x': user_id})
@@ -148,10 +181,11 @@ def get_value_0(c, user_id):
"next_fragstam_ts": -1,
"max_stamina_ts": 1586274871917,
"stamina": 12,
"world_unlocks": [],
"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"],
"singles": ["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", "buchigireberserker2", "xeraphinite", "xanatos"],
"packs": ["vs", "extend", "dynamix", "prelude", "core", "yugamu", "omatsuri", "zettai", "mirai", "shiawase", "chunithm", "nijuusei", "groovecoaster", "rei", "tonesphere", "lanota"],
"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"],
"singles": get_user_singles(c, user_id), # ["dataerror", "yourvoiceso", "crosssoul", "impurebird", "auxesia", "modelista", "yozakurafubuki", "surrender", "metallicpunisher", "carminescythe", "bethere", "callmyname", "fallensquare", "dropdead", "alexandrite", "astraltale", "phantasia", "empireofwinter", "libertas", "dottodot", "dreadnought", "mirzam", "heavenlycaress", "filament", "avantraze", "battlenoone", "saikyostronger", "izana", "einherjar", "laqryma", "amygdata", "altale", "feelssoright", "scarletcage", "teriqma", "mahoroba", "badtek", "maliciousmischance", "buchigireberserker", "galaxyfriends", "xeraphinite", "xanatos"]
"packs": get_user_packs(c, user_id),
# ["vs", "extend", "dynamix", "prelude", "core", "yugamu", "omatsuri", "zettai", "mirai", "shiawase", "chunithm", "nijuusei", "groovecoaster", "rei", "tonesphere", "lanota"]
"characters": characters,
"cores": [],
"recent_score": get_recent_score(c, user_id),
@@ -189,185 +223,7 @@ def arc_aggregate_big(user_id):
"value": get_value_0(c, user_id)
}, {
"id": 1,
"value": [{
"name": "core",
"items": [{
"id": "core",
"type": "pack",
"is_available": True
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "shiawase",
"items": [{
"id": "shiawase",
"type": "pack",
"is_available": True
}, {
"id": "kou",
"type": "character",
"is_available": True
}],
"price": 500,
"orig_price": 500,
"discount_from": 1552089600000,
"discount_to": 1552694399000
}, {
"name": "dynamix",
"items": [{
"id": "dynamix",
"type": "pack",
"is_available": True
}, {
"id": "sapphire",
"type": "character",
"is_available": True
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "mirai",
"items": [{
"id": "mirai",
"type": "pack",
"is_available": True
}, {
"id": "lethe",
"type": "character",
"is_available": True
}],
"price": 500,
"orig_price": 500,
"discount_from": 1552089600000,
"discount_to": 1552694399000
}, {
"name": "yugamu",
"items": [{
"id": "yugamu",
"type": "pack",
"is_available": True
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "lanota",
"items": [{
"id": "lanota",
"type": "pack",
"is_available": True
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "nijuusei",
"items": [{
"id": "nijuusei",
"type": "pack",
"is_available": True
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "rei",
"items": [{
"id": "rei",
"type": "pack",
"is_available": True
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "tonesphere",
"items": [{
"id": "tonesphere",
"type": "pack",
"is_available": True
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "groovecoaster",
"items": [{
"id": "groovecoaster",
"type": "pack",
"is_available": True
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "zettai",
"items": [{
"id": "zettai",
"type": "pack",
"is_available": True
}],
"price": 500,
"orig_price": 500,
"discount_from": 1583712000000,
"discount_to": 1584316799000
}, {
"name": "chunithm",
"items": [{
"id": "chunithm",
"type": "pack",
"is_available": True
}],
"price": 300,
"orig_price": 300
}, {
"name": "prelude",
"items": [{
"id": "prelude",
"type": "pack",
"is_available": True
}],
"price": 400,
"orig_price": 400
}, {
"name": "omatsuri",
"items": [{
"id": "omatsuri",
"type": "pack",
"is_available": True
}],
"price": 500,
"orig_price": 500
}, {
"name": "vs",
"items": [{
"id": "vs",
"type": "pack",
"is_available": True
}],
"price": 500,
"orig_price": 500
}, {
"name": "extend",
"items": [{
"id": "extend",
"type": "pack",
"is_available": True
}],
"price": 700,
"orig_price": 700
}]
"value": server.arcpurchase.get_item(c, 'pack')
}, {
"id": 2,
"value": {}
@@ -377,7 +233,7 @@ def arc_aggregate_big(user_id):
"max_stamina": 12,
"stamina_recover_tick": 1800000,
"core_exp": 250,
"curr_ts": 1599547606825,
"curr_ts": int(time.time())*1000,
"level_steps": [{
"level": 1,
"level_exp": 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,51 @@
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}All items{% endblock %}</h1>
{% endblock %}
{% block content %}
{% if posts %}<br />
{% for item in posts %}
<div class="char-item">
<span>Id: </span>
<span class="name">{{item['item_id']}}</span>
<br />
<span>Type: </span>
<span class="char-num">{{item['type']}}</span>
<br />
<span>Is available: </span>
<span class="char-num">{{item['is_available']}}</span>
<br />
<span>Price: </span>
<span class="char-num">{{item['price']}}</span>
<br />
<span>Original price: </span>
<span class="char-num">{{item['orig_price']}}</span>
<br />
<span>Discount from: </span>
<span class="char-num">{{item['discount_from']}}</span>
<br />
<span>Discount to: </span>
<span class="char-num">{{item['discount_to']}}</span>
<br />
</div>
{% if not loop.last %}
<br />
<hr />
<br />
{% endif %}
{% endfor %}
{% endif %}
{% endblock %}

View File

@@ -13,7 +13,7 @@
<span class="rank">User code: {{user['user_code']}}</span>
</div>
<div class="join-date">注册于 Registered in: {{user['join_date']}}</div>
<div class="ptt">PTT: {{user['rating_ptt']//100 ~ '.' ~ user['rating_ptt']%100}}</div>
<div class="ptt">PTT: {{'%0.2f'|format(user['rating_ptt']/100|float)}}</div>
<div class="ptt">Memories: {{user['ticket']}}</div>
<div>
<div>Recent plays: </div>

View File

@@ -0,0 +1,41 @@
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Change the items{% endblock %}</h1>
{% endblock %}
{% block content %}
<form action="/web/changeitem" method="post">
<div class="title">Change the item</div>
<label for="item_id">ID of the item</label>
<input name="item_id" id="item_id" required>
<label for="type">Type</label>
<div>
<select name="type">
<option value='single'>Single</option>
<option value='pack'>Pack</option>
</select>
</div>
<br />
<div class="content">可修改项 Modifiable items:</div>
<div><label for="is_available">是否可用 Is available:</label>
<br />
<br />
<label><input type="radio" name="is_available" value=1>True</label>
<br />
<label><input type="radio" name="is_available" value=0>False</label>
</div>
<label for="price">Price</label>
<input name="price" id="price">
<label for="orig_price">Original price</label>
<input name="orig_price" id="orig_price">
<label for="discount_from">Discount from</label>
<input type="datetime-local" name="discount_from" id="discount_from">
<label for="discount_to">Discount to</label>
<input type="datetime-local" name="discount_to" id="discount_to">
<div class="content">如果某些不需要修改,留空即可</div>
<div class="content">If some things do not need to be modified, leave it blank.</div>
<div class="content">时间填写是一个HTML5控件</div>
<div class="content">Time filling is an HTML5 control.</div>
<input type="submit" value="Edit">
</form>
{% endblock %}

View File

@@ -25,4 +25,13 @@
<div class="content">At present, only memories can be modified.</div>
<input type="submit" value="Edit">
</form>
<br />
<hr />
<form action="/web/changeuser/edituser" method="post">
<div class="title">Edit all the users</div>
<label for="ticket">Memories</label>
<input name="ticket" id="ticket">
<input type="submit" value="Edit all">
</form>
{% endblock %}

View File

@@ -0,0 +1,44 @@
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Change user purchase information{% endblock %}</h1>
{% endblock %}
{% block content %}
<form action="/web/changeuserpurchase/edituser" method="post">
<div class="title">Edit the user</div>
<label for="name">Arcaea Username</label>
<input name="name" id="name">
or<br />
<label for="user_code">Arcaea User Code</label>
<input name="user_code" id="user_code">
<br />
<br />
<div>对所有单曲和曲包的操作 Operation to all singles and packs:
<br />
<br />
<label><input type="radio" name="method" value="0">解锁 Unlock</label>
<br />
<label><input type="radio" name="method" value="1">封绝 Lock</label>
</div>
<br />
<input type="submit" value="Execute">
</form>
<br />
<hr />
<form action="/web/changeuserpurchase/" method="post">
<div class="title">Edit all the users</div>
<br />
<div>对所有单曲和曲包的操作 Operation to all singles and packs:
<br />
<br />
<label><input type="radio" name="method" value="0">解锁 Unlock</label>
<br />
<label><input type="radio" name="method" value="1">封绝 Lock</label>
</div>
<br />
<input type="submit" value="Execute">
</form>
{% endblock %}

View File

@@ -15,13 +15,16 @@
<a href="{{ url_for('index.all_player') }}">所有玩家信息查询 All players</a></br></br>
<a href="{{ url_for('index.all_song') }}">铺面信息查询 All songs</a></br></br>
<a href="{{ url_for('index.all_character') }}">角色信息查询 All characters</a></br></br>
<a href="{{ url_for('index.all_item') }}">购买信息查询 All items</a></br></br>
<a href="{{ url_for('index.single_chart_top') }}">单个铺面排行榜查询 Single song chart tops</a>
<hr>
<h1>系统方面 System</h1>
<a href="{{ url_for('index.update_database') }}">数据库更新 Update databases</a></br></br>
<a href="{{ url_for('index.change_song') }}">歌曲修改 Change the songs</a></br></br>
<a href="{{ url_for('index.change_character') }}">角色修改 Change the characters</a></br></br>
<a href="{{ url_for('index.change_user') }}">用户信息修改 Change user information</a>
<a href="{{ url_for('index.change_item') }}">购买信息修改 Change the items</a></br></br>
<a href="{{ url_for('index.change_user') }}">用户信息修改 Change user information</a></br></br>
<a href="{{ url_for('index.change_user_purchase') }}">用户购买信息修改 Change user purchase information</a>
{% endblock %}

View File

@@ -25,7 +25,7 @@
</div>
<div class="join-date">注册于 Registered in: {{user['join_date']}}</div>
<div class="ptt">Memories: {{user['ticket']}}</div>
<div class="ptt">PTT: {{user['rating_ptt']//100 ~ '.' ~ user['rating_ptt']%100}}</div>
<div class="ptt">PTT: {{'%0.2f'|format(user['rating_ptt']/100|float)}}</div>
<div class="ptt">Best 30 PTT: {{bestptt}}</div>
<div class="ptt">Recent 10 PTT: {{recentptt}}</div>
<div>

View File

@@ -447,31 +447,31 @@ def edit_char():
c.execute(
'''select exists(select * from character where character_id=:a)''', {'a': character_id})
if c.fetchone() == (1,):
if not level and not frag and not prog and not overdrive and not skill_id and not skill_id_uncap:
if level is None and frag is None and prog is None and overdrive is None and skill_id is None and skill_id_uncap is None:
error = '无修改 No change.'
else:
sql = '''update character set level_exp=25000'''
sql_dict = {'character_id': character_id}
if level:
if level is not None:
sql += ', level = :level'
sql_dict['level'] = level
if frag:
if frag is not None:
sql += ', frag = :frag'
sql_dict['frag'] = frag
if prog:
if prog is not None:
sql += ', prog = :prog'
sql_dict['prog'] = prog
if overdrive:
if overdrive is not None:
sql += ', overdrive = :overdrive'
sql_dict['overdrive'] = overdrive
if skill_id:
if skill_id is not None:
sql += ', skill_id = :skill_id'
if skill_id == 'No_skill':
sql_dict['skill_id'] = ''
else:
sql_dict['skill_id'] = skill_id
if skill_id_uncap:
if skill_id_uncap is not None:
sql += ', skill_id_uncap = :skill_id_uncap'
if skill_id_uncap == 'No_skill':
sql_dict['skill_id_uncap'] = ''
@@ -520,12 +520,42 @@ def edit_user():
# 修改用户数据
error = None
name = request.form['name']
user_code = request.form['user_code']
flag = True
name = None
user_code = None
try:
ticket = request.form['ticket']
if ticket:
ticket = int(ticket)
else:
ticket = None
except:
error = '数据错误 Wrong data.'
flash(error)
return redirect(url_for('index.change_user'))
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
# 全修改
if 'name' not in request.form and 'user_code' not in request.form:
flag = False
if not ticket:
error = '无修改 No change.'
else:
sql = '''update user set ticket = :ticket'''
sql_dict = {'ticket': ticket}
c.execute(sql, sql_dict)
flash("全部用户信息修改成功 Successfully edit all the users' information.")
else:
name = request.form['name']
user_code = request.form['user_code']
# 指定修改
if name or user_code:
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
if user_code:
c.execute('''select user_id from user where user_code=:a''', {
'a': user_code})
@@ -537,16 +567,6 @@ def edit_user():
posts = []
if user_id:
user_id = user_id[0]
try:
ticket = request.form['ticket']
if ticket:
ticket = int(ticket)
else:
ticket = None
except:
error = '数据错误 Wrong data.'
flash(error)
return redirect(url_for('index.change_user'))
if not ticket:
error = '无修改 No change.'
@@ -560,12 +580,190 @@ def edit_user():
error = '玩家不存在 The player does not exist.'
else:
error = '输入为空 Null Input.'
if flag:
error = '输入为空 Null Input.'
conn.commit()
conn.close()
if error:
flash(error)
return redirect(url_for('index.change_user'))
@bp.route('/changeuserpurchase', methods=['GET'])
@login_required
def change_user_purchase():
# 修改用户购买
return render_template('web/changeuserpurchase.html')
@bp.route('/changeuserpurchase/edituser', methods=['POST'])
@login_required
def edit_user_purchase():
# 修改用户购买
error = None
flag = True
name = None
user_code = None
try:
method = request.form['method']
except:
flash('输入为空 Null Input.')
return redirect(url_for('index.change_user_purchase'))
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
# 全修改
if 'name' not in request.form and 'user_code' not in request.form:
flag = False
if method == '0':
web.system.unlock_all_user_item(c)
else:
c.execute('''delete from user_item''')
flash("全部用户购买信息修改成功 Successfully edit all the users' purchase information.")
else:
name = request.form['name']
user_code = request.form['user_code']
# 指定修改
if name or user_code:
if user_code:
c.execute('''select user_id from user where user_code=:a''', {
'a': user_code})
else:
c.execute(
'''select user_id from user where name=:a''', {'a': name})
user_id = c.fetchone()
posts = []
if user_id:
user_id = user_id[0]
if method == '0':
web.system.unlock_user_item(c, user_id)
else:
c.execute('''delete from user_item where user_id=:a''', {
'a': user_id})
flash('用户购买信息修改成功 Successfully edit the user purchase information.')
else:
error = '玩家不存在 The player does not exist.'
else:
if flag:
error = '输入为空 Null Input.'
conn.commit()
conn.close()
if error:
flash(error)
return redirect(url_for('index.change_user_purchase'))
@bp.route('/allitem', methods=['GET'])
@login_required
def all_item():
# 所有购买数据
error = None
posts = web.system.get_all_item()
if not posts:
error = '没有购买数据 No item data.'
if error:
flash(error)
return redirect(url_for('index.all_item'))
else:
return render_template('web/allitem.html', posts=posts)
@bp.route('/changeitem', methods=['GET', 'POST'])
@login_required
def change_item():
# 修改购买信息
error = None
if request.method == 'POST':
try:
item_id = request.form['item_id']
item_type = request.form['type']
price = request.form['price']
orig_price = request.form['orig_price']
discount_from = request.form['discount_from']
discount_to = request.form['discount_to']
try:
is_available = request.form['is_available']
if is_available:
is_available = int(is_available)
else:
is_available = None
except:
is_available = None
if price:
price = int(price)
else:
price = None
if orig_price:
orig_price = int(orig_price)
else:
orig_price = None
if discount_from:
discount_from = int(time.mktime(time.strptime(discount_from, "%Y-%m-%dT%H:%M"))) * 1000
else:
discount_from = None
if discount_to:
discount_to = int(time.mktime(time.strptime(discount_to, "%Y-%m-%dT%H:%M"))) * 1000
else:
discount_to = None
except:
error = '数据错误 Wrong data.'
flash(error)
return redirect(url_for('index.change_item'))
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
c.execute(
'''select exists(select * from item where item_id=:a and type=:b)''', {'a': item_id, 'b': item_type})
if c.fetchone() == (1,):
if is_available is None and price is None and orig_price is None and not discount_from and not discount_to:
error = '无修改 No change.'
else:
sql = '''update item set type=:type'''
sql_dict = {'item_id': item_id, 'type': item_type}
if price is not None:
sql += ', price = :price'
sql_dict['price'] = price
if orig_price is not None:
sql += ', orig_price = :orig_price'
sql_dict['orig_price'] = orig_price
if discount_from is not None:
sql += ', discount_from = :discount_from'
sql_dict['discount_from'] = discount_from
if discount_to is not None:
sql += ', discount_to = :discount_to'
sql_dict['discount_to'] = discount_to
if is_available is not None:
sql += ', is_available = :is_available'
sql_dict['is_available'] = is_available
sql += ' where item_id = :item_id and type = :type'
c.execute(sql, sql_dict)
flash('购买项目修改成功 Successfully edit the item.')
else:
error = '购买项目不存在 The item does not exist.'
conn.commit()
conn.close()
if error:
flash(error)
return render_template('web/changeitem.html')

View File

@@ -1,5 +1,14 @@
import os
import sqlite3
import time
def int2b(x):
# int与布尔值转换
if x is None or x == 0:
return False
else:
return True
def get_table_info(c, table_name):
@@ -76,6 +85,13 @@ def get_sql_insert_table(table_name, field, value):
def update_one_table(c1, c2, table_name):
# 从c1向c2更新数据表c2中存在的信息不变
c1.execute(
'''select * from sqlite_master where type = 'table' and name = :a''', {'a': table_name})
c2.execute(
'''select * from sqlite_master where type = 'table' and name = :a''', {'a': table_name})
if not c1.fetchone() or not c2.fetchone():
return 'error'
db1_pk, db1_name = get_table_info(c1, table_name)
db2_pk, db2_name = get_table_info(c2, table_name)
if db1_pk != db2_pk:
@@ -124,7 +140,7 @@ def update_user_char(c):
def update_database():
# 将old数据库不存在数据加入到新数据库上并删除old数据库
# 对于arcaea_datebase.db更新best_scorefriendrecent30useruser_world并用character数据更新user_char
# 对于arcaea_datebase.db更新best_scorefriendrecent30useruser_world, user_item并用character数据更新user_char
# 对于arcsong.db更新songs
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')
@@ -137,6 +153,7 @@ def update_database():
update_one_table(c1, c2, 'best_score')
update_one_table(c1, c2, 'recent30')
update_one_table(c1, c2, 'user_world')
update_one_table(c1, c2, 'user_item')
update_user_char(c2)
@@ -160,3 +177,69 @@ def update_database():
conn2.commit()
conn2.close()
os.remove('database/old_arcsong.db')
def unlock_all_user_item(c):
# 解锁所有用户购买
c.execute('''select user_id from user''')
x = c.fetchall()
c.execute('''select item_id, type from item''')
y = c.fetchall()
c.execute('''delete from user_item''')
if x and y:
for i in x:
for j in y:
c.execute('''insert into user_item values(:a,:b,:c)''', {
'a': i[0], 'b': j[0], 'c': j[1]})
return
def unlock_user_item(c, user_id):
# 解锁用户购买
c.execute('''select item_id, type from item''')
y = c.fetchall()
for j in y:
c.execute('''select exists(select * from user_item where user_id=:a and item_id=:b and type=:c)''', {
'a': user_id, 'b': j[0], 'c': j[1]})
if c.fetchone() == (0,):
c.execute('''insert into user_item values(:a,:b,:c)''', {
'a': user_id, 'b': j[0], 'c': j[1]})
return
def get_all_item():
# 所有购买数据查询
conn = sqlite3.connect('./database/arcaea_database.db')
c = conn.cursor()
c.execute('''select * from item''')
x = c.fetchall()
re = []
if x:
for i in x:
discount_from = None
discount_to = None
if i[5] and i[5] >= 0:
discount_from = time.strftime(
"%Y-%m-%d %H:%M:%S", time.localtime(int(i[5])/1000))
if i[6] and i[6] >= 0:
discount_to = time.strftime(
"%Y-%m-%d %H:%M:%S", time.localtime(int(i[6])//1000))
re.append({'item_id': i[0],
'type': i[1],
'is_available': int2b(i[2]),
'price': i[3],
'orig_price': i[4],
'discount_from': discount_from,
'discount_to': discount_to
})
conn.commit()
conn.close()
return re