Merge pull request 'develop' (#15) from develop into prism_plus_support

Reviewed-on: https://gitea.tendokyu.moe/SoulGateKey/artemis/pulls/15
This commit is contained in:
SoulGateKey
2025-09-16 17:54:52 +00:00
5 changed files with 51 additions and 26 deletions

View File

@@ -283,6 +283,18 @@ crypto:
"23_chn": ["0000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "0000000000000000"] "23_chn": ["0000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "0000000000000000"]
``` ```
| Option | Info |
|-----------------|------------------------------------------------------|
| `chart_deliver` | This option is used to delivery charts to the client |
If you would like to use chart delivery, set this option to `True` and configure the directory to read from. Then put charts in your chart folder like this:
```
chart_folder/23/music001736/001736_00.ma2
chart_folder/23/music001736/001736_01.ma2 # PRiSM
chart_folder/24/music001901/001901_00.ma2
chart_folder/24/music001901/001901_01.ma2 # PRiSM PLUS
```
## Hatsune Miku Project Diva ## Hatsune Miku Project Diva
### SBZV ### SBZV

View File

@@ -258,9 +258,9 @@ class Mai2DX(Mai2Base):
if kind_id is not None: if kind_id is not None:
await self.data.item.put_favorite(user_id, kind_id, fav["itemIdList"]) await self.data.item.put_favorite(user_id, kind_id, fav["itemIdList"])
if "userFavoritemusicList" in upsert and len(upsert["userFavoritemusicList"]) > 0: # added in BUDDiES+
for fav in upsert["userFavoritemusicList"]: if "isNewFavoritemusicList" in upsert and upsert["isNewFavoritemusicList"] != "" and "userFavoritemusicList" in upsert:
await self.data.item.add_fav_music(user_id, fav["id"], fav["orderId"]) await self.data.item.put_fav_music(user_id, ((fav["id"], fav["orderId"]) for fav in upsert["userFavoritemusicList"]))
if ( if (
"userFriendSeasonRankingList" in upsert "userFriendSeasonRankingList" in upsert

View File

@@ -34,6 +34,7 @@ class Mai2Prism(Mai2BuddiesPlus):
padded_music_id = str(data["musicId"]).zfill(6) padded_music_id = str(data["musicId"]).zfill(6)
padded_level_id = str(data["level"]).zfill(2) padded_level_id = str(data["level"]).zfill(2)
music_folder = f"music{padded_music_id}"
if data["type"] == 0: if data["type"] == 0:
target_filename = f"{padded_music_id}_{padded_level_id}.ma2" target_filename = f"{padded_music_id}_{padded_level_id}.ma2"
@@ -42,11 +43,11 @@ class Mai2Prism(Mai2BuddiesPlus):
elif data["type"] == 2: elif data["type"] == 2:
target_filename = f"{padded_music_id}_{padded_level_id}_R.ma2" target_filename = f"{padded_music_id}_{padded_level_id}_R.ma2"
else: else:
self.logger.error("Valid MusicScore type!") self.logger.error("Invalid MusicScore type!")
return {"gameMusicScore": {"musicId": data["musicId"], "level": data["level"], "type": data["type"], "scoreData": ""}} return {"gameMusicScore": {"musicId": data["musicId"], "level": data["level"], "type": data["type"], "scoreData": ""}}
chart_path = os.path.join(self.game_config.charts.chart_folder, target_filename) chart_path = os.path.join(self.game_config.charts.chart_folder, str(self.version), music_folder, target_filename)
if os.path.isfile(chart_path): if os.path.isfile(chart_path):
with open(chart_path, 'rb') as file: with open(chart_path, 'rb') as file:
file_content = file.read() file_content = file.read()
@@ -60,7 +61,7 @@ class Mai2Prism(Mai2BuddiesPlus):
} }
} }
else: else:
self.logger.warning(f"Chart {target_filename} not found!") self.logger.warning(f"Version {self.version} Chart {target_filename} not found!")
return {"gameMusicScore": {"musicId": data["musicId"], "level": data["level"], "type": data["type"], "scoreData": ""}} return {"gameMusicScore": {"musicId": data["musicId"], "level": data["level"], "type": data["type"], "scoreData": ""}}

View File

@@ -1,7 +1,8 @@
from collections.abc import Iterable
from datetime import datetime from datetime import datetime
from typing import Dict, List, Optional from typing import Dict, List, Optional
from sqlalchemy import Column, Table, UniqueConstraint, and_, or_ from sqlalchemy import Column, Table, UniqueConstraint, and_, or_, not_
from sqlalchemy.dialects.mysql import insert from sqlalchemy.dialects.mysql import insert
from sqlalchemy.engine import Row from sqlalchemy.engine import Row
from sqlalchemy.schema import ForeignKey from sqlalchemy.schema import ForeignKey
@@ -550,25 +551,36 @@ class Mai2ItemData(BaseData):
if result: if result:
return result.fetchall() return result.fetchall()
async def add_fav_music(self, user_id: int, music_id: int, order_id: Optional[int] = None) -> Optional[int]: async def put_fav_music(self, user_id: int, fav_list: Iterable[tuple[int, Optional[int]]]) -> Optional[int]:
sql = insert(fav_music).values( row_count = 0
user = user_id, processed_music_ids = []
musicId = music_id,
orderId = order_id
)
conflict = sql.on_duplicate_key_update(orderId = order_id) for music_id, order_id in fav_list:
sql = insert(fav_music).values(
user = user_id,
musicId = music_id,
orderId = order_id
)
result = await self.execute(conflict) conflict = sql.on_duplicate_key_update(orderId = order_id)
if result: result = await self.execute(conflict)
return result.lastrowid
self.logger.error(f"Failed to add music {music_id} as favorite for user {user_id}!") processed_music_ids.append(music_id)
async def remove_fav_music(self, user_id: int, music_id: int) -> None: if not result:
result = await self.execute(fav_music.delete(and_(fav_music.c.user == user_id, fav_music.c.musicId == music_id))) self.logger.error(f"Failed to add music {music_id} as favorite for user {user_id}!")
if not result: continue
self.logger.error(f"Failed to remove music {music_id} as favorite for user {user_id}!")
row_count += result.rowcount
clear_stale_entries_stmt = fav_music.delete(and_(fav_music.c.user == user_id, not_(fav_music.c.musicId.in_(processed_music_ids))))
result = await self.execute(clear_stale_entries_stmt)
if result is None:
self.logger.error(f"Failed to clear stale favorite music entries for user {user_id}!")
return None
return row_count + result.rowcount
async def put_card( async def put_card(
self, self,

View File

@@ -254,7 +254,7 @@ class Mai2StaticData(BaseData):
async def put_card(self, version: int, card_id: int, card_name: str, opt_id: int = None, **card_data) -> int: async def put_card(self, version: int, card_id: int, card_name: str, opt_id: int = None, **card_data) -> int:
sql = insert(cards).values( sql = insert(cards).values(
version=version, cardId=card_id, cardName=card_name, opt=coalesce(cards.c.opt, opt_id) **card_data version=version, cardId=card_id, cardName=card_name, opt=coalesce(cards.c.opt, opt_id), **card_data
) )
conflict = sql.on_duplicate_key_update(opt=coalesce(cards.c.opt, opt_id), **card_data) conflict = sql.on_duplicate_key_update(opt=coalesce(cards.c.opt, opt_id), **card_data)