feat: .md download bundles thumbnails, auto-cache on channel add
- Bulk 'Download .md' now also caches thumbnails (one action does both); removed the redundant standalone Thumbnails button from the bulk action bar. - Scrape UX optimization: batch job skips videos whose .md already exists (just caches their thumbnail) instead of re-extracting. - Auto-thumbnails: on addChannel, thumbnails cache in the background so a newly-attached channel's catalog looks populated immediately, even before any .md is generated. - Thumbnail fallback: pending videos without a stored thumbnail URL use the canonical https://i.ytimg.com/vi/<id>/hqdefault.jpg, so every video shows a thumbnail (and /api/thumbnails/{id} never 404s — redirects if uncached). - New helpers in pipeline.py: thumbnail_url_for() + cache_thumbnail().
This commit is contained in:
@@ -108,12 +108,14 @@ class JobManager:
|
||||
return (name, row.channel_id, url)
|
||||
|
||||
def _run_batch(self, job_id: str, opts: dict[str, Any]) -> None:
|
||||
from ..pipeline import process_video as _process_video, cache_thumbnail
|
||||
video_ids = opts.get("video_ids") or []
|
||||
cookie_path = opts.get("cookies_file") or resolve_active_path(self.store)
|
||||
thumb_dir = Path(self.cfg.output_dir_resolved).parent / "thumbnails"
|
||||
total = len(video_ids)
|
||||
self.store.update_job(job_id, status="running", total=total, completed=0)
|
||||
self._emit(job_id, "progress", {"completed": 0, "total": total})
|
||||
self._emit(job_id, "log", {"msg": f"processing {total} videos"})
|
||||
self._emit(job_id, "log", {"msg": f"processing {total} videos (.md + thumbnails)"})
|
||||
cfg = _clone_config(self.cfg)
|
||||
if opts.get("languages"):
|
||||
cfg.languages = opts["languages"]
|
||||
@@ -129,12 +131,20 @@ class JobManager:
|
||||
completed += 1
|
||||
self.store.update_job(job_id, completed=completed)
|
||||
continue
|
||||
channel_name, channel_id, channel_url = self._resolve_channel_for_video(vid)
|
||||
status = process_video(
|
||||
row, cfg, self.store, channel_name, channel_id, channel_url,
|
||||
cookies_file=cookie_path,
|
||||
on_log=lambda m: self._emit(job_id, "log", {"msg": m}),
|
||||
)
|
||||
# UX optimization: skip re-extracting videos whose .md already exists — just ensure thumbnail cached.
|
||||
md_path = Path(cfg.output_dir_resolved).parent / row.markdown_path if row.markdown_path else None
|
||||
if row.status == "done" and row.markdown_path and md_path and md_path.exists():
|
||||
cache_thumbnail(self.store, vid, thumb_dir)
|
||||
status = "done"
|
||||
self._emit(job_id, "log", {"msg": f"cached {vid} (md already present)"})
|
||||
else:
|
||||
channel_name, channel_id, channel_url = self._resolve_channel_for_video(vid)
|
||||
status = _process_video(
|
||||
row, cfg, self.store, channel_name, channel_id, channel_url,
|
||||
cookies_file=cookie_path,
|
||||
on_log=lambda m: self._emit(job_id, "log", {"msg": m}),
|
||||
)
|
||||
cache_thumbnail(self.store, vid, thumb_dir)
|
||||
completed += 1
|
||||
self.store.update_job(job_id, completed=completed)
|
||||
self._emit(job_id, "progress", {"completed": completed, "total": total, "video_id": vid, "status": status})
|
||||
|
||||
Reference in New Issue
Block a user