mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2026-02-14 20:37:27 +08:00
[Refactor] Init files Encoding & Refresh rating
- Now initial files can be other encoding types which are supported by JSON module - Code refactor for refreshing all scores' rating
This commit is contained in:
@@ -51,7 +51,7 @@ class SonglistParser:
|
|||||||
self.parse()
|
self.parse()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_available_file(song_id: str, file_name: str) -> list:
|
def is_available_file(song_id: str, file_name: str) -> bool:
|
||||||
'''判断文件是否允许被下载'''
|
'''判断文件是否允许被下载'''
|
||||||
if song_id not in SonglistParser.songs:
|
if song_id not in SonglistParser.songs:
|
||||||
# songlist没有,则只限制文件名
|
# songlist没有,则只限制文件名
|
||||||
|
|||||||
@@ -90,10 +90,10 @@ class DatabaseInit:
|
|||||||
self.c.execute('''insert into item values(?,?,?)''',
|
self.c.execute('''insert into item values(?,?,?)''',
|
||||||
('anni5tix', 'anni5tix', 1))
|
('anni5tix', 'anni5tix', 1))
|
||||||
|
|
||||||
with open(self.pack_path, 'r') as f:
|
with open(self.pack_path, 'rb') as f:
|
||||||
self.insert_purchase_item(load(f))
|
self.insert_purchase_item(load(f))
|
||||||
|
|
||||||
with open(self.single_path, 'r') as f:
|
with open(self.single_path, 'rb') as f:
|
||||||
self.insert_purchase_item(load(f))
|
self.insert_purchase_item(load(f))
|
||||||
|
|
||||||
self.c.execute(
|
self.c.execute(
|
||||||
@@ -105,7 +105,7 @@ class DatabaseInit:
|
|||||||
def course_init(self) -> None:
|
def course_init(self) -> None:
|
||||||
'''初始化课题信息'''
|
'''初始化课题信息'''
|
||||||
courses = []
|
courses = []
|
||||||
with open(self.course_path, 'r', encoding='utf-8') as f:
|
with open(self.course_path, 'rb') as f:
|
||||||
courses = load(f)
|
courses = load(f)
|
||||||
for i in courses:
|
for i in courses:
|
||||||
x = Course(self.c).from_dict(i)
|
x = Course(self.c).from_dict(i)
|
||||||
|
|||||||
54
latest version/core/operation.py
Normal file
54
latest version/core/operation.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
from .sql import Connect, Sql
|
||||||
|
from .score import Score
|
||||||
|
|
||||||
|
|
||||||
|
class BaseOperation:
|
||||||
|
name: str = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self.run(*args, **kwargs)
|
||||||
|
|
||||||
|
def run(self, *args, **kwargs):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class RefreshAllScoreRating(BaseOperation):
|
||||||
|
'''
|
||||||
|
刷新所有成绩的评分
|
||||||
|
'''
|
||||||
|
name = 'refresh_all_score_rating'
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# 追求效率,不用Song类,尽量不用对象
|
||||||
|
with Connect() as c:
|
||||||
|
c.execute(
|
||||||
|
'''select song_id, rating_pst, rating_prs, rating_ftr, rating_byn from chart''')
|
||||||
|
x = c.fetchall()
|
||||||
|
|
||||||
|
songs = [i[0] for i in x]
|
||||||
|
c.execute(
|
||||||
|
f'''update best_score set rating=0 where song_id not in ({','.join(['?']*len(songs))})''', songs)
|
||||||
|
|
||||||
|
for i in x:
|
||||||
|
for j in range(0, 4):
|
||||||
|
defnum = -10 # 没在库里的全部当做定数-10
|
||||||
|
if i[j+1] is not None and i[j+1] > 0:
|
||||||
|
defnum = float(i[j+1]) / 10
|
||||||
|
|
||||||
|
c.execute('''select user_id, score from best_score where song_id=:a and difficulty=:b''', {
|
||||||
|
'a': i[0], 'b': j})
|
||||||
|
y = c.fetchall()
|
||||||
|
values = []
|
||||||
|
where_values = []
|
||||||
|
for k in y:
|
||||||
|
ptt = Score.calculate_rating(defnum, k[1])
|
||||||
|
if ptt < 0:
|
||||||
|
ptt = 0
|
||||||
|
values.append((ptt,))
|
||||||
|
where_values.append((k[0], i[0], j))
|
||||||
|
if values:
|
||||||
|
Sql(c).update_many('best_score', ['rating'], values, [
|
||||||
|
'user_id', 'song_id', 'difficulty'], where_values)
|
||||||
@@ -103,7 +103,7 @@ class Score:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def calculate_rating(defnum: int, score: int) -> float:
|
def calculate_rating(defnum: int, score: int) -> float:
|
||||||
'''计算rating,谱面定数小于等于0视为Unrank,这里的defnum = Chart const'''
|
'''计算rating,谱面定数小于等于0视为Unrank,返回值会为-1,这里的defnum = Chart const'''
|
||||||
if not defnum or defnum <= 0:
|
if not defnum or defnum <= 0:
|
||||||
# 谱面没定数或者定数小于等于0被视作Unrank
|
# 谱面没定数或者定数小于等于0被视作Unrank
|
||||||
return -1
|
return -1
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ class Connect:
|
|||||||
class Query:
|
class Query:
|
||||||
'''查询参数类'''
|
'''查询参数类'''
|
||||||
|
|
||||||
def __init__(self, query_able: list = None, quzzy_query_able: list = None, sort_able: list = None) -> None:
|
def __init__(self, query_able: list = None, fuzzy_query_able: list = None, sort_able: list = None) -> None:
|
||||||
self.query_able: list = query_able # None表示不限制
|
self.query_able: list = query_able # None表示不限制
|
||||||
self.quzzy_query_able: list = quzzy_query_able # None表示不限制
|
self.fuzzy_query_able: list = fuzzy_query_able # None表示不限制
|
||||||
self.sort_able: list = sort_able
|
self.sort_able: list = sort_able
|
||||||
|
|
||||||
self.__limit: int = -1
|
self.__limit: int = -1
|
||||||
@@ -115,7 +115,7 @@ class Query:
|
|||||||
def fuzzy_query_append(self, fuzzy_query: dict) -> None:
|
def fuzzy_query_append(self, fuzzy_query: dict) -> None:
|
||||||
if not isinstance(fuzzy_query, dict):
|
if not isinstance(fuzzy_query, dict):
|
||||||
raise InputError(api_error_code=-101)
|
raise InputError(api_error_code=-101)
|
||||||
if self.quzzy_query_able is not None and fuzzy_query and not set(fuzzy_query).issubset(set(self.quzzy_query_able)):
|
if self.fuzzy_query_able is not None and fuzzy_query and not set(fuzzy_query).issubset(set(self.fuzzy_query_able)):
|
||||||
raise InputError(api_error_code=-102)
|
raise InputError(api_error_code=-102)
|
||||||
if not self.__fuzzy_query:
|
if not self.__fuzzy_query:
|
||||||
self.__fuzzy_query = fuzzy_query
|
self.__fuzzy_query = fuzzy_query
|
||||||
@@ -216,7 +216,7 @@ class Sql:
|
|||||||
return ('insert into ' if insert_type is None else 'insert or ' + insert_type + ' into ') + table_name + ('(' + ','.join(key) + ')' if key else '') + ' values(' + ','.join(['?'] * (len(key) if value_len is None else value_len)) + ')'
|
return ('insert into ' if insert_type is None else 'insert or ' + insert_type + ' into ') + table_name + ('(' + ','.join(key) + ')' if key else '') + ' values(' + ','.join(['?'] * (len(key) if value_len is None else value_len)) + ')'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_update_sql(table_name: str, d: dict = {}, query: 'Query' = None) -> str:
|
def get_update_sql(table_name: str, d: dict = None, query: 'Query' = None):
|
||||||
if not d:
|
if not d:
|
||||||
return None
|
return None
|
||||||
sql_list = []
|
sql_list = []
|
||||||
@@ -245,6 +245,13 @@ class Sql:
|
|||||||
|
|
||||||
return sql, sql_list
|
return sql, sql_list
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_update_many_sql(table_name: str, key: list = None, where_key: list = None) -> str:
|
||||||
|
'''拼接update语句,这里不用Query类,也不用字典,请注意只返回sql语句'''
|
||||||
|
if not key or not where_key:
|
||||||
|
return None
|
||||||
|
return f"update {table_name} set {','.join([f'{k}=?' for k in key])} where {' and '.join([f'{k}=?' for k in where_key])}"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_delete_sql(table_name: str, query: 'Query' = None):
|
def get_delete_sql(table_name: str, query: 'Query' = None):
|
||||||
'''拼接删除语句,query中只有query和fuzzy_query会被处理'''
|
'''拼接删除语句,query中只有query和fuzzy_query会被处理'''
|
||||||
@@ -304,6 +311,13 @@ class Sql:
|
|||||||
sql, sql_list = self.get_update_sql(table_name, d, query)
|
sql, sql_list = self.get_update_sql(table_name, d, query)
|
||||||
self.c.execute(sql, sql_list)
|
self.c.execute(sql, sql_list)
|
||||||
|
|
||||||
|
def update_many(self, table_name: str, key: list, value_list: list, where_key: list, where_value_list: list) -> None:
|
||||||
|
'''单表内行update多句sql语句,这里不用Query类,也不用字典,要求值list长度一致,有点像insert_many'''
|
||||||
|
if not key or not value_list or not where_key or not where_value_list or not len(key) == len(value_list[0]) or not len(where_key) == len(where_value_list[0]) or not len(value_list) == len(where_value_list):
|
||||||
|
raise ValueError
|
||||||
|
self.c.executemany(self.get_update_many_sql(
|
||||||
|
table_name, key, where_key), [x + y for x, y in zip(value_list, where_value_list)])
|
||||||
|
|
||||||
def delete(self, table_name: str, query: 'Query' = None) -> None:
|
def delete(self, table_name: str, query: 'Query' = None) -> None:
|
||||||
'''删除,query中只有query和fuzzy_query会被处理'''
|
'''删除,query中只有query和fuzzy_query会被处理'''
|
||||||
sql, sql_list = self.get_delete_sql(table_name, query)
|
sql, sql_list = self.get_delete_sql(table_name, query)
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
from core.sql import Connect
|
|
||||||
|
|
||||||
|
|
||||||
def calculate_rating(defnum, score):
|
|
||||||
# 计算rating
|
|
||||||
if score >= 10000000:
|
|
||||||
ptt = defnum + 2
|
|
||||||
elif score < 9800000:
|
|
||||||
ptt = defnum + (score-9500000) / 300000
|
|
||||||
if ptt < 0 and defnum != -10:
|
|
||||||
ptt = 0
|
|
||||||
else:
|
|
||||||
ptt = defnum + 1 + (score-9800000) / 200000
|
|
||||||
|
|
||||||
return ptt
|
|
||||||
|
|
||||||
|
|
||||||
def refresh_all_score_rating():
|
|
||||||
# 刷新所有best成绩的rating
|
|
||||||
error = 'Unknown error.'
|
|
||||||
|
|
||||||
with Connect() as c:
|
|
||||||
c.execute(
|
|
||||||
'''select song_id, rating_pst, rating_prs, rating_ftr, rating_byn from chart''')
|
|
||||||
x = c.fetchall()
|
|
||||||
|
|
||||||
if x:
|
|
||||||
song_list = [i[0] for i in x]
|
|
||||||
with Connect() as c:
|
|
||||||
c.execute('''update best_score set rating=0 where song_id not in ({0})'''.format(
|
|
||||||
','.join(['?']*len(song_list))), tuple(song_list))
|
|
||||||
for i in x:
|
|
||||||
for j in range(0, 4):
|
|
||||||
defnum = -10 # 没在库里的全部当做定数-10
|
|
||||||
if i is not None:
|
|
||||||
defnum = float(i[j+1]) / 10
|
|
||||||
if defnum <= 0:
|
|
||||||
defnum = -10 # 缺少难度的当做定数-10
|
|
||||||
|
|
||||||
c.execute('''select user_id, score from best_score where song_id=:a and difficulty=:b''', {
|
|
||||||
'a': i[0], 'b': j})
|
|
||||||
y = c.fetchall()
|
|
||||||
if y:
|
|
||||||
for k in y:
|
|
||||||
ptt = calculate_rating(defnum, k[1])
|
|
||||||
if ptt < 0:
|
|
||||||
ptt = 0
|
|
||||||
|
|
||||||
c.execute('''update best_score set rating=:a where user_id=:b and song_id=:c and difficulty=:d''', {
|
|
||||||
'a': ptt, 'b': k[0], 'c': i[0], 'd': j})
|
|
||||||
error = None
|
|
||||||
|
|
||||||
else:
|
|
||||||
error = 'No song data.'
|
|
||||||
|
|
||||||
return error
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
import os
|
|
||||||
from shutil import copy, copy2
|
|
||||||
|
|
||||||
from core.sql import Connect
|
|
||||||
from database.database_initialize import ARCAEA_SERVER_VERSION, main
|
|
||||||
from web.system import update_database
|
|
||||||
|
|
||||||
|
|
||||||
def try_rename(path, new_path):
|
|
||||||
# 尝试重命名文件,并尝试避免命名冲突,返回最终路径
|
|
||||||
final_path = new_path
|
|
||||||
if os.path.exists(new_path):
|
|
||||||
i = 1
|
|
||||||
while os.path.exists(new_path + str(i)):
|
|
||||||
i += 1
|
|
||||||
os.rename(path, new_path + str(i))
|
|
||||||
final_path = new_path + str(i)
|
|
||||||
else:
|
|
||||||
os.rename(path, new_path)
|
|
||||||
|
|
||||||
return final_path
|
|
||||||
|
|
||||||
|
|
||||||
def check_before_run(app):
|
|
||||||
# 运行前检查关键文件,返回布尔值,其实是因为有人经常忘了
|
|
||||||
|
|
||||||
f = True
|
|
||||||
|
|
||||||
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
|
|
||||||
try:
|
|
||||||
app.logger.info(
|
|
||||||
'Try to new the file `database/arcaea_database.db`.')
|
|
||||||
main('./database/')
|
|
||||||
app.logger.info(
|
|
||||||
'Success to new the file `database/arcaea_database.db`.')
|
|
||||||
f = True
|
|
||||||
except:
|
|
||||||
app.logger.warning(
|
|
||||||
'Fail to new the file `database/arcaea_database.db`.')
|
|
||||||
|
|
||||||
else:
|
|
||||||
with Connect() as c:
|
|
||||||
try:
|
|
||||||
c.execute('''select value from config where id="version"''')
|
|
||||||
x = c.fetchone()
|
|
||||||
except:
|
|
||||||
x = None
|
|
||||||
|
|
||||||
# 数据库自动更新,不强求
|
|
||||||
if not x or x[0] != ARCAEA_SERVER_VERSION:
|
|
||||||
app.logger.warning(
|
|
||||||
'Maybe the file `database/arcaea_database.db` is an old version.')
|
|
||||||
try:
|
|
||||||
app.logger.info(
|
|
||||||
'Try to update the file `database/arcaea_database.db`.')
|
|
||||||
|
|
||||||
path = try_rename('database/arcaea_database.db',
|
|
||||||
'database/arcaea_database.db.bak')
|
|
||||||
|
|
||||||
try:
|
|
||||||
copy2(path, 'database/arcaea_database.db')
|
|
||||||
except:
|
|
||||||
copy(path, 'database/arcaea_database.db')
|
|
||||||
|
|
||||||
if os.path.isfile("database/old_arcaea_database.db"):
|
|
||||||
os.remove('database/old_arcaea_database.db')
|
|
||||||
|
|
||||||
try_rename('database/arcaea_database.db',
|
|
||||||
'database/old_arcaea_database.db')
|
|
||||||
|
|
||||||
main('./database/')
|
|
||||||
update_database()
|
|
||||||
|
|
||||||
app.logger.info(
|
|
||||||
'Success to update the file `database/arcaea_database.db`.')
|
|
||||||
|
|
||||||
except:
|
|
||||||
app.logger.warning(
|
|
||||||
'Fail to update the file `database/arcaea_database.db`.')
|
|
||||||
|
|
||||||
return f
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
from core.error import ArcError
|
|
||||||
from core.present import UserPresent, UserPresentList
|
from core.present import UserPresent, UserPresentList
|
||||||
from core.sql import Connect
|
from core.sql import Connect
|
||||||
from core.user import UserOnline
|
from core.user import UserOnline
|
||||||
from flask import Blueprint, request
|
from flask import Blueprint, request
|
||||||
|
|
||||||
from .auth import auth_required
|
from .auth import auth_required
|
||||||
from .func import arc_try, error_return, success_return
|
from .func import arc_try, success_return
|
||||||
|
|
||||||
bp = Blueprint('present', __name__, url_prefix='/present')
|
bp = Blueprint('present', __name__, url_prefix='/present')
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import server.arcscore
|
|
||||||
from core.download import DownloadList, initialize_songfile
|
from core.download import DownloadList, initialize_songfile
|
||||||
from core.init import FileChecker
|
from core.init import FileChecker
|
||||||
|
from core.operation import RefreshAllScoreRating
|
||||||
from core.rank import RankList
|
from core.rank import RankList
|
||||||
from core.sql import Connect
|
from core.sql import Connect
|
||||||
from flask import Blueprint, flash, redirect, render_template, request, url_for
|
from flask import Blueprint, flash, redirect, render_template, request, url_for
|
||||||
@@ -302,11 +302,8 @@ def update_song_hash():
|
|||||||
@login_required
|
@login_required
|
||||||
def update_song_rating():
|
def update_song_rating():
|
||||||
# 更新所有分数的rating
|
# 更新所有分数的rating
|
||||||
error = server.arcscore.refresh_all_score_rating()
|
RefreshAllScoreRating().run()
|
||||||
if error:
|
flash('数据刷新成功 Success refresh data.')
|
||||||
flash(error)
|
|
||||||
else:
|
|
||||||
flash('数据刷新成功 Success refresh data.')
|
|
||||||
return render_template('web/updatedatabase.html')
|
return render_template('web/updatedatabase.html')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user