diff --git a/k-tv-backend/infra/src/jellyfin.rs b/k-tv-backend/infra/src/jellyfin.rs index 369eabd..52a4c47 100644 --- a/k-tv-backend/infra/src/jellyfin.rs +++ b/k-tv-backend/infra/src/jellyfin.rs @@ -153,13 +153,15 @@ impl IMediaProvider for JellyfinMediaProvider { Ok(body.items.into_iter().next().and_then(map_jellyfin_item)) } - /// Build a direct-play stream URL for a Jellyfin item. + /// Build a stream URL for a Jellyfin item. /// - /// Uses `static=true` to request the original file without transcoding. - /// The API key is embedded in the URL so the player does not need separate auth. + /// Requests H.264 video + AAC audio in an MP4 container so that all + /// major browsers can play it natively. Jellyfin will direct-play if the + /// source already matches; otherwise it transcodes on the fly. + /// The API key is embedded in the URL so the player needs no separate auth. async fn get_stream_url(&self, item_id: &MediaItemId) -> DomainResult { Ok(format!( - "{}/Videos/{}/stream?static=true&api_key={}", + "{}/Videos/{}/stream?videoCodec=h264&audioCodec=aac&container=mp4&api_key={}", self.config.base_url, item_id.as_ref(), self.config.api_key, diff --git a/k-tv-frontend/app/(main)/dashboard/components/edit-channel-sheet.tsx b/k-tv-frontend/app/(main)/dashboard/components/edit-channel-sheet.tsx index 716949e..9c78081 100644 --- a/k-tv-frontend/app/(main)/dashboard/components/edit-channel-sheet.tsx +++ b/k-tv-frontend/app/(main)/dashboard/components/edit-channel-sheet.tsx @@ -66,12 +66,14 @@ function NumberInput({ onChange, min, max, + step, placeholder, }: { value: number | ""; onChange: (v: number | "") => void; min?: number; max?: number; + step?: number | "any"; placeholder?: string; }) { return ( @@ -79,6 +81,7 @@ function NumberInput({ type="number" min={min} max={max} + step={step} value={value} placeholder={placeholder} onChange={(e) => @@ -229,11 +232,12 @@ function BlockEditor({ block, onChange, onRemove }: BlockEditorProps) {
- - + setField("start_time", v + ":00")} - placeholder="20:00" + onChange={(e) => setField("start_time", e.target.value + ":00")} + className="w-full rounded-md border border-zinc-700 bg-zinc-800 px-3 py-2 text-sm text-zinc-100 focus:border-zinc-500 focus:outline-none" /> @@ -443,6 +447,7 @@ function RecyclePolicyEditor({ policy, onChange }: RecyclePolicyEditorProps) { } min={0} max={1} + step={0.01} placeholder="0.1" />