···396396 containerElement = container;
397397 },
398398 setMeta() {},
399399- setCaption(caption) {
400400- // If we have a video element and captions are available,
401401- // set up the tracks - AirPlay requires VTT format
402402- if (videoElement && caption && caption.srtData) {
403403- // Subtitles are handled via the track element in VideoContainer.tsx
404404- // convertSubtitlesToObjectUrl already handles the conversion to VTT
405405- }
406406- },
399399+ setCaption() {},
407400408401 pause() {
409402 videoElement?.pause();
+15-88
src/components/player/display/chromecast.ts
···77 DisplayInterfaceEvents,
88 DisplayMeta,
99} from "@/components/player/display/displayInterface";
1010-import {
1111- convertSubtitlesToObjectUrl,
1212- convertSubtitlesToVtt,
1313-} from "@/components/player/utils/captions";
1410import { LoadableSource } from "@/stores/player/utils/qualities";
1511import { processCdnLink } from "@/utils/cdn";
1612import {
···2622 instance: cast.framework.CastContext;
2723}
28242525+/*
2626+ ** Chromecasting is unfinished, here is its limitations:
2727+ ** 1. Captions - chromecast requires only VTT, but needs it from a URL. we only have SRT urls
2828+ ** 2. HLS - we've having some issues with content types. sometimes it loads, sometimes it doesn't
2929+ */
3030+2931export function makeChromecastDisplayInterface(
3032 ops: ChromeCastDisplayInterfaceOptions,
3133): DisplayInterface {
···4345 title: "",
4446 type: MWMediaType.MOVIE,
4547 };
4848+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4649 let caption: DisplayCaption | null = null;
4747- let captionUrl: string | null = null;
48504951 function listenForEvents() {
5052 const listen = async (e: cast.framework.RemotePlayerChangedEvent) => {
···98100 };
99101 }
100102101101- function setupCaptions(): chrome.cast.media.Track[] | null {
102102- if (!caption || !caption.srtData) return null;
103103-104104- try {
105105- // Convert SRT to VTT and create an object URL
106106- captionUrl = convertSubtitlesToObjectUrl(caption.srtData);
107107-108108- // Create a text track for Chromecast
109109- const track = new chrome.cast.media.Track(
110110- 1, // trackId
111111- chrome.cast.media.TrackType.TEXT,
112112- );
113113-114114- track.trackContentId = captionUrl;
115115- track.trackContentType = "text/vtt";
116116- track.subtype = chrome.cast.media.TextTrackType.SUBTITLES;
117117- track.name = caption.language;
118118- track.language = caption.language;
119119-120120- return [track];
121121- } catch (error) {
122122- console.error("Error setting up captions for Chromecast:", error);
123123- return null;
124124- }
125125- }
126126-127103 function setupSource() {
128104 if (!source) {
129105 ops.controller?.stop();
130106 return;
131107 }
132108133133- // Determine correct content type
134134- let contentType = "video/mp4";
135135- if (source.type === "hls") {
136136- // Use MIME type that's best supported by Chromecast for HLS
137137- contentType = "application/vnd.apple.mpegurl";
138138- }
109109+ let type = "video/mp4";
110110+ if (source.type === "hls") type = "application/x-mpegurl";
139111140112 const metaData = new chrome.cast.media.GenericMediaMetadata();
141113 metaData.title = meta.title;
142114143143- // Create media info with proper content ID and content type
144144- const mediaInfo = new chrome.cast.media.MediaInfo(
145145- processCdnLink(source.url), // Use processed URL as the content ID
146146- contentType,
147147- );
148148-149149- // The contentUrl property doesn't exist on the type, use properly typed properties instead
115115+ const mediaInfo = new chrome.cast.media.MediaInfo("video", type);
116116+ (mediaInfo as any).contentUrl = processCdnLink(source.url);
150117 mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED;
151118 mediaInfo.metadata = metaData;
152119 mediaInfo.customData = {
153120 playbackRate,
154121 };
155122156156- // Set up captions if available
157157- const tracks = setupCaptions();
158158- if (tracks && tracks.length > 0) {
159159- mediaInfo.tracks = tracks;
160160- }
161161-162123 const request = new chrome.cast.media.LoadRequest(mediaInfo);
163124 request.autoplay = true;
164125 request.currentTime = startAt;
165126166127 if (source.type === "hls") {
167128 const staticMedia = chrome.cast.media as any;
168168- // Set HLS-specific properties to improve reliability
169169- if (staticMedia.HlsSegmentFormat) {
170170- const media = request.media as any;
171171- media.hlsSegmentFormat = staticMedia.HlsSegmentFormat.FMP4;
172172- media.hlsVideoSegmentFormat = staticMedia.HlsVideoSegmentFormat.FMP4;
173173- // Set additional properties to improve HLS compatibility
174174- media.streamType = chrome.cast.media.StreamType.BUFFERED;
175175- media.hlsPreload = true;
176176- }
129129+ const media = request.media as any;
130130+ media.hlsSegmentFormat = staticMedia.HlsSegmentFormat.FMP4;
131131+ media.hlsVideoSegmentFormat = staticMedia.HlsVideoSegmentFormat.FMP4;
177132 }
178133179179- // Load the media on the Chromecast session
180134 const session = ops.instance.getCurrentSession();
181181- if (session) {
182182- session.loadMedia(request).catch((error) => {
183183- console.error("Error loading media on Chromecast:", error);
184184- emit("error", {
185185- message: `Chromecast error: ${error.message || "Failed to load media"}`,
186186- errorName: "ChromecastLoadError",
187187- type: "global",
188188- });
189189- });
190190- }
135135+ session?.loadMedia(request);
191136 }
192137193138 function setSource() {
···221166 stopListening();
222167 destroyVideoElement();
223168 fscreen.removeEventListener("fullscreenchange", fullscreenChange);
224224- // Clean up caption URL object if it exists
225225- if (captionUrl) {
226226- try {
227227- URL.revokeObjectURL(captionUrl);
228228- } catch (e) {
229229- // Ignore errors during cleanup
230230- }
231231- }
232169 },
233170 load(loadOps) {
234171 source = loadOps.source;
···240177 // cant control qualities
241178 },
242179 setCaption(newCaption) {
243243- // Clean up previous caption URL if it exists
244244- if (captionUrl) {
245245- try {
246246- URL.revokeObjectURL(captionUrl);
247247- captionUrl = null;
248248- } catch (e) {
249249- // Ignore errors during cleanup
250250- }
251251- }
252252-253180 caption = newCaption;
254181 setSource();
255182 },