feat(video): add video upload with remux/transcode playback

Add video as a media kind in photos: streaming upload with per-kind
limits, ffprobe metadata, poster frame reusing the image variant
pipeline, and a playback object (remux when web-compatible, else
h264/yuv420p/aac transcode). Video jobs run on a separate pool with a
long lease. Frontend gains a video viewer, grid badge/duration and
video upload.
This commit is contained in:
iu
2026-10-11 20:37:53 +03:00
parent d059d042f0
commit d38ede0201
52 changed files with 2717 additions and 82 deletions
@@ -50,6 +50,14 @@
const isSelected = (id: string) => selectedIds.includes(id);
const isCursor = (i: number) => cursorIndex === i;
function formatDuration(ms?: number): string {
if (!ms || ms <= 0) return '';
const total = Math.round(ms / 1000);
const m = Math.floor(total / 60);
const s = total % 60;
return `${m}:${String(s).padStart(2, '0')}`;
}
const tabIndexFor = (i: number) =>
cursorIndex == null ? (i === 0 ? 0 : -1) : isCursor(i) ? 0 : -1;
@@ -117,6 +125,21 @@
360
</span>
{/if}
{#if photo.kind === 'video'}
<span
class="absolute top-1 left-1 inline-flex items-center justify-center rounded bg-black/60 p-1 text-white"
aria-label="Видео"
>
<Icon name="play_arrow" class="size-4" />
</span>
{#if formatDuration(photo.duration_ms)}
<span
class="absolute bottom-1 left-1 rounded bg-black/70 px-1.5 py-0.5 text-[10px] font-medium text-white"
>
{formatDuration(photo.duration_ms)}
</span>
{/if}
{/if}
<span
class="bg-bg/70 text-text absolute right-1 bottom-1 flex items-center gap-1.5 rounded px-1.5 py-0.5 text-xs"
>