feat(downloads): clickable channels + poster fallback for thumbnail-less sources
Two visual gaps for non-catalog downloads: - Channel link: YouTube already exposes channel_url; Facebook exposes none but a numeric uploader_id that resolves at facebook.com/<id>. `_uploader_url` derives it so the auto-detected channel renders as a real clickable link. - Poster: a source with no thumbnail (e.g. a direct reddit HLS URL) showed a blank image box. The worker now cuts a representative frame with ffmpeg (`ensure_poster`) into the `<base>.jpg` sidecar and records `poster_path` (migration 0050). The card, the public watch page (<video poster> + og:image), and link previews fall back to it via new authed + public poster endpoints. Adds `app.downloads.backfill` (one-off, re-run-safe) to fill uploader_url (re-extract YouTube/Facebook metadata) and posters for pre-existing downloads.
This commit is contained in:
parent
374ad4ddc4
commit
cb170dfd32
12 changed files with 251 additions and 8 deletions
|
|
@ -66,7 +66,8 @@ function StatusPill({ job }: { job: DownloadJob }) {
|
|||
}
|
||||
|
||||
function Thumb({ job }: { job: DownloadJob }) {
|
||||
const url = job.asset?.thumbnail_url;
|
||||
// Prefer the source thumbnail; fall back to our generated poster for thumbnail-less sources.
|
||||
const url = job.asset?.thumbnail_url || job.poster_url;
|
||||
return (
|
||||
<div className="w-28 aspect-video shrink-0 rounded-lg overflow-hidden bg-surface border border-border">
|
||||
{url ? <img src={url} alt="" loading="lazy" className="w-full h-full object-cover" /> : null}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ type Meta = {
|
|||
duration_s?: number | null;
|
||||
allow_download?: boolean;
|
||||
file_url?: string;
|
||||
poster_url?: string | null;
|
||||
};
|
||||
|
||||
// Compact display of a URL: drop the protocol + trailing slash so it fits on one line.
|
||||
|
|
@ -175,6 +176,7 @@ export default function WatchPage() {
|
|||
controls
|
||||
playsInline
|
||||
src={meta.file_url}
|
||||
poster={meta.poster_url || undefined}
|
||||
className="max-h-[80vh] max-w-full mx-auto block"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue