fix: unify task workspace directory resolution
This commit is contained in:
@ -4,6 +4,7 @@ import json
|
||||
from pathlib import Path
|
||||
|
||||
from biliup_next.app.retry_meta import retry_meta_for_step
|
||||
from biliup_next.infra.workspace_paths import resolve_task_work_dir
|
||||
|
||||
|
||||
class ControlPlaneSerializer:
|
||||
@ -78,7 +79,7 @@ class ControlPlaneSerializer:
|
||||
task = task or self.state["repo"].get_task(task_id)
|
||||
if task is None:
|
||||
return {}
|
||||
session_dir = Path(str(self.state["settings"]["paths"]["session_dir"])) / task.title
|
||||
session_dir = resolve_task_work_dir(task)
|
||||
source_path = Path(task.source_path)
|
||||
split_dir = session_dir / "split_video"
|
||||
|
||||
@ -246,7 +247,7 @@ class ControlPlaneSerializer:
|
||||
task = task or self.state["repo"].get_task(task_id)
|
||||
if task is None:
|
||||
return None
|
||||
session_dir = Path(str(self.state["settings"]["paths"]["session_dir"])) / task.title
|
||||
session_dir = resolve_task_work_dir(task)
|
||||
path = session_dir / filename
|
||||
if not path.exists():
|
||||
return None
|
||||
|
||||
@ -5,6 +5,7 @@ from pathlib import Path
|
||||
import re
|
||||
|
||||
from biliup_next.core.models import ActionRecord, SessionBinding, TaskContext, utc_now_iso
|
||||
from biliup_next.infra.workspace_paths import resolve_task_work_dir
|
||||
|
||||
|
||||
class SessionDeliveryService:
|
||||
@ -222,10 +223,10 @@ class SessionDeliveryService:
|
||||
return None
|
||||
return bvid
|
||||
|
||||
def _full_video_bvid_path(self, task_title: str) -> Path:
|
||||
session_dir = Path(str(self.settings["paths"]["session_dir"])) / task_title
|
||||
session_dir.mkdir(parents=True, exist_ok=True)
|
||||
return session_dir / "full_video_bvid.txt"
|
||||
def _full_video_bvid_path(self, task) -> Path: # type: ignore[no-untyped-def]
|
||||
work_dir = resolve_task_work_dir(task)
|
||||
work_dir.mkdir(parents=True, exist_ok=True)
|
||||
return work_dir / "full_video_bvid.txt"
|
||||
|
||||
def _upsert_session_binding_for_context(self, context: TaskContext, full_video_bvid: str, now: str) -> None:
|
||||
self.repo.upsert_session_binding(
|
||||
@ -253,6 +254,6 @@ class SessionDeliveryService:
|
||||
context.updated_at = now
|
||||
self.repo.upsert_task_context(context)
|
||||
self._upsert_session_binding_for_context(context, full_video_bvid, now)
|
||||
path = self._full_video_bvid_path(task.title)
|
||||
path = self._full_video_bvid_path(task)
|
||||
path.write_text(full_video_bvid, encoding="utf-8")
|
||||
return path
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from biliup_next.infra.task_repository import TaskRepository
|
||||
from biliup_next.infra.workspace_paths import resolve_task_work_dir
|
||||
|
||||
|
||||
class WorkspaceCleanupService:
|
||||
@ -15,7 +15,7 @@ class WorkspaceCleanupService:
|
||||
if task is None:
|
||||
raise RuntimeError(f"task not found: {task_id}")
|
||||
|
||||
session_dir = Path(str(settings["session_dir"])) / task.title
|
||||
session_dir = resolve_task_work_dir(task)
|
||||
removed: list[str] = []
|
||||
skipped: list[str] = []
|
||||
|
||||
|
||||
10
src/biliup_next/infra/workspace_paths.py
Normal file
10
src/biliup_next/infra/workspace_paths.py
Normal file
@ -0,0 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def resolve_task_work_dir(task) -> Path: # type: ignore[no-untyped-def]
|
||||
source = Path(task.source_path).resolve()
|
||||
if source.is_file() or source.suffix:
|
||||
return source.parent
|
||||
return source
|
||||
@ -11,6 +11,7 @@ from biliup_next.core.models import Task
|
||||
from biliup_next.core.providers import ProviderManifest
|
||||
from biliup_next.infra.adapters.bilibili_api import BilibiliApiAdapter
|
||||
from biliup_next.infra.adapters.full_video_locator import resolve_full_video_bvid
|
||||
from biliup_next.infra.workspace_paths import resolve_task_work_dir
|
||||
|
||||
|
||||
class BilibiliCollectionProvider:
|
||||
@ -29,7 +30,7 @@ class BilibiliCollectionProvider:
|
||||
)
|
||||
|
||||
def sync(self, task: Task, target: str, settings: dict[str, Any]) -> dict[str, object]:
|
||||
session_dir = Path(str(settings["session_dir"])) / task.title
|
||||
session_dir = resolve_task_work_dir(task)
|
||||
cookies = self.bilibili_api.load_cookies(Path(str(settings["cookies_file"])))
|
||||
csrf = cookies.get("bili_jct")
|
||||
if not csrf:
|
||||
|
||||
@ -11,6 +11,7 @@ from biliup_next.core.models import Task
|
||||
from biliup_next.core.providers import ProviderManifest
|
||||
from biliup_next.infra.adapters.bilibili_api import BilibiliApiAdapter
|
||||
from biliup_next.infra.adapters.full_video_locator import resolve_full_video_bvid
|
||||
from biliup_next.infra.workspace_paths import resolve_task_work_dir
|
||||
|
||||
|
||||
class BilibiliTopCommentProvider:
|
||||
@ -28,7 +29,7 @@ class BilibiliTopCommentProvider:
|
||||
)
|
||||
|
||||
def comment(self, task: Task, settings: dict[str, Any]) -> dict[str, object]:
|
||||
session_dir = Path(str(settings["session_dir"])) / task.title
|
||||
session_dir = resolve_task_work_dir(task)
|
||||
songs_path = session_dir / "songs.txt"
|
||||
songs_json_path = session_dir / "songs.json"
|
||||
bvid_path = session_dir / "bvid.txt"
|
||||
@ -164,14 +165,13 @@ class BilibiliTopCommentProvider:
|
||||
|
||||
def _build_split_comment(self, task: Task, settings: dict[str, Any]) -> tuple[str, str | None]:
|
||||
repo = settings.get("__repo")
|
||||
session_dir_root = Path(str(settings["session_dir"]))
|
||||
if repo is None or not hasattr(repo, "get_task_context") or not hasattr(repo, "list_task_contexts_by_session_key"):
|
||||
session_dir = session_dir_root / task.title
|
||||
session_dir = resolve_task_work_dir(task)
|
||||
return self._build_split_comment_content(session_dir / "songs.json", session_dir / "songs.txt"), None
|
||||
|
||||
context = repo.get_task_context(task.id)
|
||||
if context is None or not context.session_key or context.session_key.startswith("task:"):
|
||||
session_dir = session_dir_root / task.title
|
||||
session_dir = resolve_task_work_dir(task)
|
||||
return self._build_split_comment_content(session_dir / "songs.json", session_dir / "songs.txt"), None
|
||||
|
||||
ordered_contexts = self._ordered_session_contexts(repo, context.session_key)
|
||||
@ -183,7 +183,10 @@ class BilibiliTopCommentProvider:
|
||||
|
||||
blocks: list[str] = []
|
||||
for index, session_context in enumerate(ordered_contexts, start=1):
|
||||
task_dir = session_dir_root / session_context.task_id
|
||||
session_task = repo.get_task(session_context.task_id)
|
||||
if session_task is None:
|
||||
continue
|
||||
task_dir = resolve_task_work_dir(session_task)
|
||||
content = self._build_split_comment_content(task_dir / "songs.json", task_dir / "songs.txt")
|
||||
if not content:
|
||||
continue
|
||||
@ -195,13 +198,13 @@ class BilibiliTopCommentProvider:
|
||||
def _build_full_comment_content(self, task: Task, settings: dict[str, Any]) -> tuple[str, str | None]:
|
||||
repo = settings.get("__repo")
|
||||
if repo is None or not hasattr(repo, "get_task_context") or not hasattr(repo, "list_task_contexts_by_session_key"):
|
||||
session_dir = Path(str(settings["session_dir"])) / task.title
|
||||
session_dir = resolve_task_work_dir(task)
|
||||
content = session_dir.joinpath("songs.txt").read_text(encoding="utf-8").strip()
|
||||
return content, None if content else "timeline_comment_empty"
|
||||
|
||||
context = repo.get_task_context(task.id)
|
||||
if context is None or not context.session_key or context.session_key.startswith("task:"):
|
||||
session_dir = Path(str(settings["session_dir"])) / task.title
|
||||
session_dir = resolve_task_work_dir(task)
|
||||
content = session_dir.joinpath("songs.txt").read_text(encoding="utf-8").strip()
|
||||
return content, None if content else "timeline_comment_empty"
|
||||
|
||||
@ -214,7 +217,10 @@ class BilibiliTopCommentProvider:
|
||||
|
||||
blocks: list[str] = []
|
||||
for index, session_context in enumerate(ordered_contexts, start=1):
|
||||
task_dir = Path(str(settings["session_dir"])) / session_context.task_id
|
||||
session_task = repo.get_task(session_context.task_id)
|
||||
if session_task is None:
|
||||
continue
|
||||
task_dir = resolve_task_work_dir(session_task)
|
||||
songs_path = task_dir / "songs.txt"
|
||||
if not songs_path.exists():
|
||||
continue
|
||||
|
||||
@ -11,6 +11,7 @@ from biliup_next.core.errors import ModuleError
|
||||
from biliup_next.core.models import PublishRecord, Task, utc_now_iso
|
||||
from biliup_next.core.providers import ProviderManifest
|
||||
from biliup_next.infra.adapters.biliup_cli import BiliupCliAdapter
|
||||
from biliup_next.infra.workspace_paths import resolve_task_work_dir
|
||||
|
||||
|
||||
class BiliupCliPublishProvider:
|
||||
@ -28,7 +29,7 @@ class BiliupCliPublishProvider:
|
||||
)
|
||||
|
||||
def publish(self, task: Task, clip_videos: list, settings: dict[str, Any]) -> PublishRecord:
|
||||
work_dir = Path(str(settings["session_dir"])) / task.title
|
||||
work_dir = resolve_task_work_dir(task)
|
||||
bvid_file = work_dir / "bvid.txt"
|
||||
upload_done = work_dir / "upload_done.flag"
|
||||
publish_log = work_dir / "publish.log"
|
||||
|
||||
@ -8,6 +8,7 @@ from typing import Any
|
||||
from biliup_next.core.models import Artifact, PublishRecord, TaskContext, utc_now_iso
|
||||
from biliup_next.core.registry import Registry
|
||||
from biliup_next.infra.task_repository import TaskRepository
|
||||
from biliup_next.infra.workspace_paths import resolve_task_work_dir
|
||||
|
||||
|
||||
class PublishService:
|
||||
@ -26,7 +27,7 @@ class PublishService:
|
||||
if len(session_contexts) <= 1:
|
||||
clip_videos = self._clip_videos_for_task(task_id)
|
||||
record = provider.publish(task, clip_videos, settings)
|
||||
self._persist_publish_success(task_id, task.title, record, settings)
|
||||
self._persist_publish_success(task, record)
|
||||
return record
|
||||
|
||||
anchor_context = session_contexts[0]
|
||||
@ -41,7 +42,7 @@ class PublishService:
|
||||
title=task.title,
|
||||
published_at=utc_now_iso(),
|
||||
)
|
||||
self._persist_publish_success(task_id, task.title, record, settings)
|
||||
self._persist_publish_success(task, record)
|
||||
return record
|
||||
|
||||
clip_videos = self._session_clip_videos(session_contexts)
|
||||
@ -64,7 +65,7 @@ class PublishService:
|
||||
title=record.title,
|
||||
published_at=record.published_at,
|
||||
)
|
||||
self._persist_publish_success(context.task_id, session_task.title, session_record, settings)
|
||||
self._persist_publish_success(session_task, session_record)
|
||||
return PublishRecord(
|
||||
id=None,
|
||||
task_id=task_id,
|
||||
@ -75,12 +76,13 @@ class PublishService:
|
||||
published_at=record.published_at,
|
||||
)
|
||||
|
||||
def _persist_publish_success(self, task_id: str, task_title: str, record: PublishRecord, settings: dict[str, object]) -> None:
|
||||
def _persist_publish_success(self, task, record: PublishRecord) -> None: # type: ignore[no-untyped-def]
|
||||
task_id = task.id
|
||||
self.repo.add_publish_record(record)
|
||||
if record.bvid:
|
||||
session_dir = Path(str(settings.get("session_dir", "session"))) / task_title
|
||||
session_dir.mkdir(parents=True, exist_ok=True)
|
||||
bvid_path_obj = session_dir / "bvid.txt"
|
||||
work_dir = resolve_task_work_dir(task)
|
||||
work_dir.mkdir(parents=True, exist_ok=True)
|
||||
bvid_path_obj = work_dir / "bvid.txt"
|
||||
bvid_path_obj.write_text(record.bvid, encoding="utf-8")
|
||||
self.repo.add_artifact(
|
||||
Artifact(
|
||||
@ -120,12 +122,11 @@ class PublishService:
|
||||
return aggregated
|
||||
|
||||
def _shared_session_bvid(self, contexts: list[TaskContext], settings: dict[str, object]) -> str | None:
|
||||
session_dir_root = Path(str(settings.get("session_dir", "session")))
|
||||
for context in contexts:
|
||||
task = self.repo.get_task(context.task_id)
|
||||
if task is None:
|
||||
continue
|
||||
bvid_path = session_dir_root / task.title / "bvid.txt"
|
||||
bvid_path = resolve_task_work_dir(task) / "bvid.txt"
|
||||
if bvid_path.exists():
|
||||
bvid = bvid_path.read_text(encoding="utf-8").strip()
|
||||
if bvid.startswith("BV"):
|
||||
@ -138,8 +139,7 @@ class PublishService:
|
||||
contexts: list[TaskContext],
|
||||
settings: dict[str, object],
|
||||
) -> dict[str, Any]: # type: ignore[no-untyped-def]
|
||||
session_dir_root = Path(str(settings.get("session_dir", "session")))
|
||||
anchor_work_dir = (session_dir_root / anchor_task.title).resolve()
|
||||
anchor_work_dir = resolve_task_work_dir(anchor_task)
|
||||
anchor_work_dir.mkdir(parents=True, exist_ok=True)
|
||||
aggregate_txt_lines: list[str] = []
|
||||
aggregate_songs: list[dict[str, object]] = []
|
||||
@ -148,7 +148,7 @@ class PublishService:
|
||||
task = self.repo.get_task(context.task_id)
|
||||
if task is None:
|
||||
continue
|
||||
task_work_dir = (session_dir_root / task.title).resolve()
|
||||
task_work_dir = resolve_task_work_dir(task)
|
||||
songs_txt = task_work_dir / "songs.txt"
|
||||
songs_json = task_work_dir / "songs.json"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user