Skip to content

Commit 4248ea0

Browse files
committed
FUCK(LevelRecordInfo): 移除不必要的初始化
- 移除惰性加载机制,改为使用build()方法进行数据构建 - 添加NEW评级类型到Rating枚举中 - 使用default_factory替代default设置date字段 - 新增_raw_rank私有字段用于存储原始难度索引 - 优化init方法为build方法,统一处理数据构建逻辑 - 移除多余的Any类型导入
1 parent 21b8e11 commit 4248ea0

3 files changed

Lines changed: 56 additions & 131 deletions

File tree

phi-plugin/apps/user.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ async def _(session: Uninfo, _input: Match):
270270
totsongs = 0
271271
totRating: dict[
272272
Literal[
273+
"NEW",
273274
"phi",
274275
"FC",
275276
"V",
Lines changed: 40 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from datetime import datetime
22
from pathlib import Path
3-
from typing import Any, Literal
3+
from typing import Literal
44

55
from pydantic import BaseModel, Field
66

@@ -22,6 +22,7 @@ class LevelRecordInfo(BaseModel):
2222
rank: LevelItem | str = ""
2323
"""Level"""
2424
Rating: Literal[
25+
"NEW",
2526
"phi",
2627
"FC",
2728
"V",
@@ -45,139 +46,55 @@ class LevelRecordInfo(BaseModel):
4546
"""推分建议"""
4647
num: int = Field(default=0, exclude=True)
4748
"""是 Best 几"""
48-
date: datetime = Field(default=datetime.now(), exclude=True)
49+
date: datetime = Field(default_factory=datetime.now, exclude=True)
4950
"""更新时间(iso)"""
51+
_raw_rank: str | int = Field(default="", exclude=True)
5052

51-
# 私有字段
52-
lazy_song_id: str = Field(default="", exclude=True)
53-
lazy_index: int = Field(default=0, exclude=True)
54-
lazy_raw_data: dict[str, Any] | None = Field(default=None, exclude=True)
55-
is_lazy: bool = Field(default=False, exclude=True)
56-
initialized: bool = Field(default=True, exclude=True) # 默认为已初始化
57-
58-
@classmethod
59-
def lazy_init(cls, data: dict, id: str, index: int) -> "LevelRecordInfo":
53+
def build(self,) -> None: # type: ignore[override]
6054
"""
61-
惰性初始化方法,只设置基本字段
55+
构建所需的完整数据
6256
"""
63-
# 检查数据是否包含完整字段,如果包含则直接初始化
64-
if cls._is_data_complete(data):
65-
# 数据已经完整,直接创建实例而不调用 init
66-
instance = cls(**data)
67-
# 标记为已初始化
68-
instance.initialized = True
69-
instance.is_lazy = False
70-
return instance
71-
# 数据不完整,使用惰性加载
72-
instance = cls(
73-
fc=data.get("fc", False),
74-
score=data.get("score", 0),
75-
acc=data.get("acc", 0.0),
76-
)
77-
instance.lazy_raw_data = data
78-
instance.lazy_song_id = id
79-
instance.lazy_index = index
80-
instance.is_lazy = True
81-
instance.initialized = False
82-
return instance
8357

84-
@classmethod
85-
def _is_data_complete(cls, data: dict) -> bool:
86-
"""
87-
检查传入数据是否包含完整字段
88-
"""
89-
# 定义完整字段列表
90-
complete_fields = [
91-
"song",
92-
"rank",
93-
"difficulty",
94-
"rks",
95-
"Rating",
96-
"illustration",
97-
]
58+
# rank 可能传的是 int / str,这里统一一下
59+
if isinstance(self._raw_rank, int):
60+
rank_key: LevelItem | str = getInfo.Level[self._raw_rank]
61+
self.rank = rank_key
62+
else:
63+
rank_key = self.rank
9864

99-
# 检查是否包含完整字段
100-
return all(field in data for field in complete_fields)
65+
# rating
66+
self.Rating = Rating(self.score, self.fc)
10167

102-
def _ensure_initialized(self):
103-
"""
104-
确保完全初始化
105-
"""
106-
if not self.initialized and self.is_lazy and self.lazy_raw_data is not None:
107-
# 完整初始化
108-
full_instance = LevelRecordInfo.init(
109-
self.lazy_raw_data, self.lazy_song_id, self.lazy_index
110-
)
111-
# 复制所有字段
112-
for field_name in LevelRecordInfo.model_fields:
113-
setattr(self, field_name, getattr(full_instance, field_name))
114-
self.initialized = True
115-
self.is_lazy = False
68+
if song := getInfo.idgetsong(self.id):
69+
info = getInfo.info(song)
70+
else:
71+
info = None
72+
if not info:
73+
self.song = self.id
74+
self.difficulty = 0.0
75+
self.rks = 0.0
76+
return
11677

117-
# 重写 __getattribute__ 实现惰性加载
118-
def __getattribute__(self, name: str):
119-
# 避免无限递归,对特殊属性直接返回
120-
if name in {
121-
"initialized",
122-
"is_lazy",
123-
"lazy_raw_data",
124-
"lazy_song_id",
125-
"lazy_index",
126-
}:
127-
return object.__getattribute__(self, name)
78+
self.song = info.song
12879

129-
# 检查是否是模型字段且需要初始化
130-
if name in {
131-
"song",
132-
"rank",
133-
"difficulty",
134-
"rks",
135-
"Rating",
136-
"illustration",
137-
} and not object.__getattribute__(self, "initialized"):
138-
object.__getattribute__(self, "_ensure_initialized")()
139-
return object.__getattribute__(self, name)
80+
# illustration
81+
ill = getInfo.getill(self.song)
82+
self.illustration = ill
14083

141-
@classmethod
142-
def init(cls, data: dict, id: str, rank: int | str) -> "LevelRecordInfo":
143-
"""
144-
:param data: 原始数据
145-
:param id: 曲目id
146-
:param rank: 难度
147-
"""
148-
data_ = {"fc": data["fc"], "score": data["score"], "acc": data["acc"], "id": id}
149-
song = getInfo.idgetsong(id)
150-
info = getInfo.info(song) if song else None
151-
data_["rank"] = (
152-
getInfo.Level[rank] if isinstance(rank, int) else rank
153-
) # EZ HD IN AT LEGACY
154-
data_["Rating"] = Rating(data_["score"], data_["fc"]) # V S A
155-
if not info:
156-
data_["song"] = id
157-
data_["difficulty"] = 0
158-
data_["rks"] = 0
159-
return cls(**data_)
160-
data_["song"] = info.song # 曲名
161-
data_["illustration"] = getInfo.getill(data_["song"]) # 曲绘链接
162-
difficulty = (
163-
info.chart[data_["rank"]].difficulty
164-
if data_["rank"] in info.chart
165-
else None
166-
)
167-
if info.chart and difficulty:
168-
assert isinstance(difficulty, float)
169-
data_["difficulty"] = difficulty # 难度
170-
data_["rks"] = fCompute.rks(data_["acc"], data_["difficulty"]) # 等效rks
84+
chart = info.chart
85+
if chart and rank_key in chart and chart[rank_key].difficulty:
86+
diff_val = chart[rank_key].difficulty
87+
assert isinstance(diff_val, float)
88+
self.difficulty = diff_val
89+
self.rks = fCompute.rks(self.acc, self.difficulty)
17190
else:
172-
data_["difficulty"] = 0
173-
data_["rks"] = 0
174-
return cls(**data_)
91+
self.difficulty = 0.0
92+
self.rks = 0.0
17593

176-
@classmethod
177-
def to_tuple(cls) -> tuple[float, int, datetime, bool]:
94+
def to_tuple(self) -> tuple[float, int, datetime, bool]:
17895
return (
179-
cls.acc,
180-
cls.score,
181-
cls.date,
182-
cls.fc,
96+
self.acc,
97+
self.score,
98+
self.date,
99+
self.fc,
183100
)

phi-plugin/model/cls/common.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,21 @@ class Save(BaseModel):
238238

239239
@field_validator("gameRecord", mode="before")
240240
@classmethod
241-
def parse_game_record(cls, v):
242-
return {
243-
song_id: [
244-
LevelRecordInfo.lazy_init(record, song_id, index)
245-
for index, record in enumerate(records)
246-
]
247-
for song_id, records in v.items()
248-
}
241+
def parse_game_record(cls, v: dict[str, list[dict[str, Any]]]):
242+
"""
243+
只做轻量加工:把原始记录补上 id 和 rank,
244+
不在这里构造 LevelRecordInfo,交给 Pydantic + model_post_init。
245+
"""
246+
result: dict[str, list[dict[str, Any]]] = {}
247+
for song_id, records in v.items():
248+
new_list: list[dict[str, Any]] = []
249+
for idx, record in enumerate(records):
250+
# 你要求的三个参数:data(dict) + id + rank
251+
record["id"] = song_id
252+
record["_raw_rank"] = idx # 0/1/2/3 -> EZ/HD/IN/AT,在 model_post_init 里转换
253+
new_list.append(record)
254+
result[song_id] = new_list
255+
return result
249256

250257
@field_validator("saveInfo", mode="before")
251258
@classmethod

0 commit comments

Comments
 (0)