refactor: make download and transfer events durable

This commit is contained in:
jxxghp
2026-08-22 08:03:00 +08:00
parent c5de1c7b1b
commit 820f7e8850
26 changed files with 1134 additions and 184 deletions
+2 -32
View File
@@ -1,12 +1,12 @@
import time
from typing import Any, Optional
from sqlalchemy import Integer, String, Float, JSON, Index, delete, or_, select
from sqlalchemy import Integer, String, Float, JSON, Index, or_, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, Session, mapped_column
from app.db.base import get_id_column, Base
from app.db.decorators import db_query, db_update, async_db_query, async_db_update
from app.db.decorators import async_db_query, db_query
from app.db.models._constraints import media_identity_constraint
from app.schemas.types import MUSIC_ENTITY_RECORDING, MediaSource
@@ -363,36 +363,6 @@ class Subscribe(Base):
result = await db.execute(query)
return result.scalars().first()
@db_update
def delete_by_media_identity(
self, db: Session, media_source: MediaSource, media_id: str,
season: Optional[int] = None,
) -> bool:
"""按规范媒体身份删除订阅。"""
model = type(self)
statement = delete(model).where(
model.media_source == media_source,
model.media_id == str(media_id),
)
if season is not None:
statement = statement.where(model.season == season)
db.execute(statement, execution_options={"synchronize_session": False})
return True
@async_db_update
async def async_delete_by_media_identity(
self, db: AsyncSession, media_source: MediaSource, media_id: str,
season: Optional[int] = None,
) -> bool:
"""异步按规范媒体身份删除订阅。"""
rows = await self.async_list_by_media_identity(
db, media_source=media_source, media_id=media_id
)
for row in rows:
if season is None or row.season == season:
await row.async_delete(db, row.id)
return True
@classmethod
@db_query
def list_by_username(cls, db: Session, username: str, state: Optional[str] = None, mtype: Optional[str] = None):
+17
View File
@@ -1,6 +1,7 @@
from typing import Dict, List, Optional, cast
from sqlalchemy import delete as sqlalchemy_delete, update as sqlalchemy_update
from sqlalchemy.orm import Session
from app.db.base import DbOper
from app.db.models.downloadhistory import DownloadHistory, DownloadFiles
@@ -60,6 +61,15 @@ class DownloadHistoryOper(DbOper):
"""
DownloadHistory(**kwargs).create(self._db)
def stage_add(self, payload: dict) -> DownloadHistory:
"""在调用方同步 Session 中暂存下载历史并返回已分配 ID 的记录。"""
if not isinstance(self._db, Session):
raise RuntimeError("下载历史事务写入需要调用方提供同步 Session")
history = DownloadHistory(**payload)
self._db.add(history)
self._db.flush()
return history
def add_files(self, file_items: List[dict]):
"""
新增下载历史文件
@@ -68,6 +78,13 @@ class DownloadHistoryOper(DbOper):
downloadfile = DownloadFiles(**file_item)
downloadfile.create(self._db)
def stage_add_files(self, file_items: List[dict]) -> None:
"""在调用方事务内批量暂存下载文件,不逐条提交。"""
if not isinstance(self._db, Session):
raise RuntimeError("下载文件事务写入需要调用方提供同步 Session")
self._db.add_all(DownloadFiles(**item) for item in file_items)
self._db.flush()
def truncate_files(self):
"""
清空下载历史文件记录
+19
View File
@@ -2,6 +2,7 @@ import time
from typing import Any, List, Optional
from sqlalchemy import delete as sqlalchemy_delete
from sqlalchemy.orm import Session
from app.db.base import DbOper
from app.db.models.transferhistory import TransferHistory
@@ -272,6 +273,24 @@ class TransferHistoryOper(DbOper):
kwargs["src_storage"],
)
def stage_replace_by_src(self, **kwargs) -> TransferHistory:
"""在调用方事务内按源路径替换整理历史并返回已分配 ID 的新记录。"""
if not isinstance(self._db, Session):
raise RuntimeError("整理历史事务写入需要调用方提供同步 Session")
kwargs["src_storage"] = kwargs.get("src_storage") or "local"
kwargs["date"] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
self._db.execute(
sqlalchemy_delete(TransferHistory).where(
TransferHistory.src == kwargs.get("src"),
TransferHistory.src_storage == kwargs["src_storage"],
)
)
self._db.flush()
history = TransferHistory(**kwargs)
self._db.add(history)
self._db.flush()
return history
def update_download_hash(self, historyid, download_hash):
"""
补充转移记录download_hash