fix(ci): satisfy backend lint checks
This commit is contained in:
+59
-50
@@ -64,9 +64,7 @@ async def _background_api_with_fallback(function, fallback, /, *args, **kwargs):
|
||||
|
||||
task = asyncio.create_task(_background_api(function, *args, **kwargs))
|
||||
try:
|
||||
return await asyncio.wait_for(
|
||||
asyncio.shield(task), timeout=API_READ_DEADLINE_SECONDS
|
||||
)
|
||||
return await asyncio.wait_for(asyncio.shield(task), timeout=API_READ_DEADLINE_SECONDS)
|
||||
except TimeoutError:
|
||||
# asyncio.to_thread cannot stop a running database call. Let it refresh
|
||||
# the service cache, consume any eventual exception, and serve the last
|
||||
@@ -627,9 +625,7 @@ def _set_session(
|
||||
*,
|
||||
client_key: str = "local",
|
||||
) -> dict:
|
||||
token, csrf, expires = app.auth.login(
|
||||
password, remember_device=remember_device, client_key=client_key
|
||||
)
|
||||
token, csrf, expires = app.auth.login(password, remember_device=remember_device, client_key=client_key)
|
||||
return _set_cookie(
|
||||
response,
|
||||
app,
|
||||
@@ -1390,13 +1386,11 @@ def home_feed(
|
||||
for row in tag_rows
|
||||
]
|
||||
unorganized_items = (
|
||||
videos(app, current_user, organized=False, sort="added", limit=item_limit)
|
||||
if unorganized_count
|
||||
else []
|
||||
videos(app, current_user, organized=False, sort="added", limit=item_limit) if unorganized_count else []
|
||||
)
|
||||
hide_unorganized = unorganized_count <= item_limit and {
|
||||
item["id"] for item in unorganized_items
|
||||
} == {item["id"] for item in recent}
|
||||
hide_unorganized = unorganized_count <= item_limit and {item["id"] for item in unorganized_items} == {
|
||||
item["id"] for item in recent
|
||||
}
|
||||
actor_items = sorted(
|
||||
(item for item in list_actors(app, current_user) if int(item["video_count"] or 0) > 0),
|
||||
key=lambda item: (-int(item["video_count"] or 0), str(item["name"]).casefold()),
|
||||
@@ -1788,9 +1782,7 @@ async def jobs(
|
||||
if page is not None:
|
||||
if page < 1 or page_size < 1 or page_size > 50:
|
||||
raise HTTPException(422, "page 必须大于 0,page_size 必须在 1–50 之间")
|
||||
return await _background_api(
|
||||
app.jobs.paginate, page, page_size, lane=lane, status=status
|
||||
)
|
||||
return await _background_api(app.jobs.paginate, page, page_size, lane=lane, status=status)
|
||||
return await _background_api(app.jobs.list, limit, lane=lane, status=status)
|
||||
|
||||
|
||||
@@ -1905,27 +1897,43 @@ async def search(
|
||||
if isinstance(rebuild, dict) and rebuild.get("status") in {"running", "failed"}:
|
||||
if rebuild.get("status") == "running":
|
||||
with app.db.read() as conn:
|
||||
remaining = int(conn.execute(
|
||||
"SELECT count(*) FROM videos WHERE available=1 AND audio_index_revision<?",
|
||||
(SPEECH_INDEX_REVISION,),
|
||||
).fetchone()[0])
|
||||
active = int(conn.execute(
|
||||
"SELECT count(*) FROM jobs WHERE kind='transcribe_audio' AND status IN ('queued','running')"
|
||||
).fetchone()[0])
|
||||
failed = int(conn.execute(
|
||||
"SELECT count(*) FROM jobs WHERE kind='transcribe_audio' AND status='failed' AND finished_at>=?",
|
||||
(rebuild.get("started_at") or "",),
|
||||
).fetchone()[0])
|
||||
remaining = int(
|
||||
conn.execute(
|
||||
"SELECT count(*) FROM videos WHERE available=1 AND audio_index_revision<?",
|
||||
(SPEECH_INDEX_REVISION,),
|
||||
).fetchone()[0]
|
||||
)
|
||||
active = int(
|
||||
conn.execute(
|
||||
"SELECT count(*) FROM jobs WHERE kind='transcribe_audio' AND status IN ('queued','running')"
|
||||
).fetchone()[0]
|
||||
)
|
||||
failed = int(
|
||||
conn.execute(
|
||||
"SELECT count(*) FROM jobs WHERE kind='transcribe_audio' AND status='failed' AND finished_at>=?", # noqa: E501
|
||||
(rebuild.get("started_at") or "",),
|
||||
).fetchone()[0]
|
||||
)
|
||||
if active == 0:
|
||||
status = "completed" if remaining == 0 else "failed"
|
||||
rebuild = {**rebuild, "status": status, "remaining": remaining, "failed_jobs": failed, "finished_at": utcnow()}
|
||||
rebuild = {
|
||||
**rebuild,
|
||||
"status": status,
|
||||
"remaining": remaining,
|
||||
"failed_jobs": failed,
|
||||
"finished_at": utcnow(),
|
||||
}
|
||||
app.db.set_setting("audio_rebuild", rebuild)
|
||||
if rebuild.get("status") == "completed":
|
||||
rebuild = {}
|
||||
else:
|
||||
requested = set(body.recognition_types or [])
|
||||
if "audio" in requested:
|
||||
message = "音频索引全库重建存在失败任务,修复前音频搜索保持暂停" if rebuild.get("status") == "failed" else "音频索引正在全库重建,音频搜索暂时不可用"
|
||||
message = (
|
||||
"音频索引全库重建存在失败任务,修复前音频搜索保持暂停"
|
||||
if rebuild.get("status") == "failed"
|
||||
else "音频索引正在全库重建,音频搜索暂时不可用"
|
||||
)
|
||||
raise HTTPException(409, message)
|
||||
if body.recognition_types is None:
|
||||
body.recognition_types = ["visual", "ocr", "person", "subtitle", "metadata"]
|
||||
@@ -1969,8 +1977,7 @@ async def search(
|
||||
cjk = sum("\u3400" <= character <= "\u9fff" for character in compact)
|
||||
if compact and ((cjk == len(compact) and cjk < 2) or (cjk == 0 and len(compact) < 3)):
|
||||
result["query_notice"] = (
|
||||
"关键词过短,仅进行精确人物、标签和标题匹配;"
|
||||
"搜索语音/OCR 至少输入 2 个汉字或 3 个拉丁字符。"
|
||||
"关键词过短,仅进行精确人物、标签和标题匹配;搜索语音/OCR 至少输入 2 个汉字或 3 个拉丁字符。"
|
||||
)
|
||||
return result
|
||||
except ValueError as exc:
|
||||
@@ -2161,17 +2168,23 @@ def speech_rebuild_status(
|
||||
if not isinstance(state, dict) or state.get("status") != "running":
|
||||
return state
|
||||
with app.db.read() as conn:
|
||||
completed = int(conn.execute(
|
||||
"SELECT count(*) FROM videos WHERE available=1 AND audio_index_revision>=?",
|
||||
(SPEECH_INDEX_REVISION,),
|
||||
).fetchone()[0])
|
||||
remaining = int(conn.execute(
|
||||
"SELECT count(*) FROM videos WHERE available=1 AND audio_index_revision<?",
|
||||
(SPEECH_INDEX_REVISION,),
|
||||
).fetchone()[0])
|
||||
active = int(conn.execute(
|
||||
"SELECT count(*) FROM jobs WHERE kind='transcribe_audio' AND status IN ('queued','running')"
|
||||
).fetchone()[0])
|
||||
completed = int(
|
||||
conn.execute(
|
||||
"SELECT count(*) FROM videos WHERE available=1 AND audio_index_revision>=?",
|
||||
(SPEECH_INDEX_REVISION,),
|
||||
).fetchone()[0]
|
||||
)
|
||||
remaining = int(
|
||||
conn.execute(
|
||||
"SELECT count(*) FROM videos WHERE available=1 AND audio_index_revision<?",
|
||||
(SPEECH_INDEX_REVISION,),
|
||||
).fetchone()[0]
|
||||
)
|
||||
active = int(
|
||||
conn.execute(
|
||||
"SELECT count(*) FROM jobs WHERE kind='transcribe_audio' AND status IN ('queued','running')"
|
||||
).fetchone()[0]
|
||||
)
|
||||
state = {**state, "completed": completed, "remaining": remaining, "active_jobs": active}
|
||||
if remaining == 0 and active == 0:
|
||||
state = {**state, "status": "completed", "finished_at": utcnow()}
|
||||
@@ -2201,9 +2214,9 @@ def video_transcript(
|
||||
raise HTTPException(404, "视频不存在")
|
||||
total = int(
|
||||
conn.execute(
|
||||
"SELECT count(*) FROM text_entries WHERE video_id=? AND kind='audio' "
|
||||
"AND coalesce(quality_score,1)>=0.55",
|
||||
(video_id,),
|
||||
"SELECT count(*) FROM text_entries WHERE video_id=? AND kind='audio' "
|
||||
"AND coalesce(quality_score,1)>=0.55",
|
||||
(video_id,),
|
||||
).fetchone()[0]
|
||||
)
|
||||
rows = conn.execute(
|
||||
@@ -2658,9 +2671,7 @@ async def list_uploads(
|
||||
source_id,
|
||||
query,
|
||||
)
|
||||
return await _background_api_with_fallback(
|
||||
app.uploads.list, app.uploads.cached_list, limit
|
||||
)
|
||||
return await _background_api_with_fallback(app.uploads.list, app.uploads.cached_list, limit)
|
||||
|
||||
|
||||
@router.post("/v1/uploads", status_code=201)
|
||||
@@ -3032,9 +3043,7 @@ def restore_trash(
|
||||
"ORDER BY updated_at DESC LIMIT 1",
|
||||
(item["source_id"], item["original_key"], item["physical_original_path"]),
|
||||
).fetchone()
|
||||
if item
|
||||
and item["storage_backend"] == "openlist_native"
|
||||
and item["physical_original_path"]
|
||||
if item and item["storage_backend"] == "openlist_native" and item["physical_original_path"]
|
||||
else None
|
||||
)
|
||||
key = app.storage.restore(trash_id)
|
||||
|
||||
@@ -86,14 +86,13 @@ class UploadService:
|
||||
recovery_state = str(result.get("recovery_state") or "")
|
||||
if status in {"failed", "cancelled"} and recovery_state in {"", "receiving"}:
|
||||
original = Path(str(result.get("temp_path") or "")).is_file()
|
||||
encrypted = bool(
|
||||
result.get("external_local_path")
|
||||
and Path(str(result["external_local_path"])).is_file()
|
||||
)
|
||||
encrypted = bool(result.get("external_local_path") and Path(str(result["external_local_path"])).is_file())
|
||||
catalog = bool(result.get("failure_stage") == "catalog" and result.get("target_key"))
|
||||
recovery_state = "available" if original or encrypted else "catalog" if catalog else "missing"
|
||||
result["recovery_state"] = recovery_state
|
||||
result["recovery_mode"] = "original" if original else "encrypted" if encrypted else "catalog" if catalog else None
|
||||
result["recovery_mode"] = (
|
||||
"original" if original else "encrypted" if encrypted else "catalog" if catalog else None
|
||||
)
|
||||
result["deduplicated"] = bool(result.get("deduplicated", False))
|
||||
result.pop("temp_path", None)
|
||||
result.pop("target_key", None)
|
||||
@@ -136,15 +135,15 @@ class UploadService:
|
||||
local_done = phase not in {"receiving", "queued", "encrypting", "local_processing"}
|
||||
remote_required = result.get("storage_backend") == "openlist_native"
|
||||
remote_done = (
|
||||
(not remote_required)
|
||||
or phase in {"cataloging", "ai_queued", "completed"}
|
||||
or status == "completed"
|
||||
(not remote_required) or phase in {"cataloging", "ai_queued", "completed"} or status == "completed"
|
||||
)
|
||||
catalog_done = phase in {"ai_queued", "completed"} or status == "completed"
|
||||
|
||||
def step_state(done: bool, active: bool) -> str:
|
||||
if terminal_state:
|
||||
return terminal_state
|
||||
return "completed" if done else "active" if active else "pending"
|
||||
|
||||
result["stages"] = [
|
||||
{
|
||||
"key": "receiving",
|
||||
@@ -427,6 +426,7 @@ class UploadService:
|
||||
received = list(range(total_chunks)) if staged_path is not None else []
|
||||
bytes_received = size_bytes if staged_path is not None else 0
|
||||
try:
|
||||
|
||||
def insert_upload(conn):
|
||||
conn.execute(
|
||||
"INSERT INTO uploads(id,source_id,relative_path,filename,title,collection_id,collection_parent_id,"
|
||||
@@ -632,6 +632,7 @@ class UploadService:
|
||||
missing = sorted(set(range(upload["total_chunks"])) - set(upload["received_chunks"]))
|
||||
if missing:
|
||||
return {"completed": False, "missing_chunks": missing}
|
||||
|
||||
def queue_transfer(conn):
|
||||
job_id = self.jobs.enqueue(
|
||||
"transfer_upload",
|
||||
@@ -685,9 +686,7 @@ class UploadService:
|
||||
def _refresh_recovery_state(self, upload_id: str) -> str:
|
||||
upload = self._get(upload_id)
|
||||
original = Path(upload["temp_path"]).is_file()
|
||||
encrypted = bool(
|
||||
upload.get("external_local_path") and Path(str(upload["external_local_path"])).is_file()
|
||||
)
|
||||
encrypted = bool(upload.get("external_local_path") and Path(str(upload["external_local_path"])).is_file())
|
||||
catalog = bool(upload.get("failure_stage") == "catalog" and upload.get("target_key"))
|
||||
state = "available" if original or encrypted else "catalog" if catalog else "missing"
|
||||
mode = "original" if original else "encrypted" if encrypted else "catalog" if catalog else None
|
||||
@@ -706,9 +705,7 @@ class UploadService:
|
||||
if upload["status"] not in {"failed", "cancelled", "completed"}:
|
||||
raise ValueError("任务仍在执行,请先取消")
|
||||
if upload.get("storage_backend") == "openlist_native" and self.openlist_native is not None:
|
||||
self.openlist_native.cleanup(
|
||||
upload["source_id"], upload_id, upload.get("external_staged_path")
|
||||
)
|
||||
self.openlist_native.cleanup(upload["source_id"], upload_id, upload.get("external_staged_path"))
|
||||
Path(upload["temp_path"]).unlink(missing_ok=True)
|
||||
with self.db.transaction() as conn:
|
||||
conn.execute("DELETE FROM ingest_guards WHERE upload_id=?", (upload_id,))
|
||||
@@ -736,9 +733,7 @@ class UploadService:
|
||||
)
|
||||
else:
|
||||
staged_local = (
|
||||
upload.get("external_local_path")
|
||||
if upload.get("storage_backend") == "openlist_native"
|
||||
else None
|
||||
upload.get("external_local_path") if upload.get("storage_backend") == "openlist_native" else None
|
||||
)
|
||||
if not Path(upload["temp_path"]).is_file() and not (staged_local and Path(staged_local).is_file()):
|
||||
raise ValueError("上传暂存文件不存在,无法重试")
|
||||
@@ -1058,9 +1053,7 @@ class UploadService:
|
||||
|
||||
if not upload.get("external_source_path"):
|
||||
path = Path(upload["temp_path"])
|
||||
paths = self.openlist_native.prepare(
|
||||
upload["source_id"], upload_id, str(target_key), path
|
||||
)
|
||||
paths = self.openlist_native.prepare(upload["source_id"], upload_id, str(target_key), path)
|
||||
self.db.write_with_retry(
|
||||
lambda conn: conn.execute(
|
||||
"UPDATE uploads SET status='transferring',phase='external_copying',"
|
||||
@@ -1469,9 +1462,7 @@ class UploadService:
|
||||
temp_path = Path(upload["temp_path"])
|
||||
external_local = upload.get("external_local_path")
|
||||
recoverable_native = bool(
|
||||
upload.get("storage_backend") == "openlist_native"
|
||||
and external_local
|
||||
and Path(external_local).is_file()
|
||||
upload.get("storage_backend") == "openlist_native" and external_local and Path(external_local).is_file()
|
||||
)
|
||||
if not committed and not temp_path.is_file() and not recoverable_native:
|
||||
expires = datetime.now(UTC) + timedelta(hours=self.settings.upload_failed_hours)
|
||||
|
||||
Reference in New Issue
Block a user