mirror of
https://github.com/zoriya/react-native-omni.git
synced 2026-08-05 05:36:17 +00:00
feat(chromecast): support custom subtitle broadcast
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.5.3",
|
"@biomejs/biome": "2.5.3",
|
||||||
|
"@types/chromecast-caf-sender": "^1.0.11",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"@types/react": "19.2.17",
|
"@types/react": "19.2.17",
|
||||||
"nitrogen": "0.36.1",
|
"nitrogen": "0.36.1",
|
||||||
@@ -596,6 +597,10 @@
|
|||||||
|
|
||||||
"@types/bonjour": ["@types/bonjour@3.5.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ=="],
|
"@types/bonjour": ["@types/bonjour@3.5.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ=="],
|
||||||
|
|
||||||
|
"@types/chrome": ["@types/chrome@0.2.2", "", { "dependencies": { "@types/filesystem": "*", "@types/har-format": "*" } }, "sha512-8rSMZ4cvo2xmaSyQg0sN5yRL7oiDkntLoiHxUhfwQnv1mvnkrdoZ25SlNrKWmYKaeP50WvrfWj1pmc02+U9KKw=="],
|
||||||
|
|
||||||
|
"@types/chromecast-caf-sender": ["@types/chromecast-caf-sender@1.0.11", "", { "dependencies": { "@types/chrome": "*" } }, "sha512-Pv3xvNYtxD/cTM/tKfuZRlLasvpxAm+CFni0GJd6Cp8XgiZS9g9tMZkR1uymsi5fIFv057SZKKAWVFFgy7fJtw=="],
|
||||||
|
|
||||||
"@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="],
|
"@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="],
|
||||||
|
|
||||||
"@types/connect-history-api-fallback": ["@types/connect-history-api-fallback@1.5.4", "", { "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" } }, "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw=="],
|
"@types/connect-history-api-fallback": ["@types/connect-history-api-fallback@1.5.4", "", { "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" } }, "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw=="],
|
||||||
@@ -606,6 +611,12 @@
|
|||||||
|
|
||||||
"@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.8", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA=="],
|
"@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.8", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA=="],
|
||||||
|
|
||||||
|
"@types/filesystem": ["@types/filesystem@0.0.36", "", { "dependencies": { "@types/filewriter": "*" } }, "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA=="],
|
||||||
|
|
||||||
|
"@types/filewriter": ["@types/filewriter@0.0.33", "", {}, "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g=="],
|
||||||
|
|
||||||
|
"@types/har-format": ["@types/har-format@1.2.16", "", {}, "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A=="],
|
||||||
|
|
||||||
"@types/html-minifier-terser": ["@types/html-minifier-terser@6.1.0", "", {}, "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg=="],
|
"@types/html-minifier-terser": ["@types/html-minifier-terser@6.1.0", "", {}, "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg=="],
|
||||||
|
|
||||||
"@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="],
|
"@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="],
|
||||||
|
|||||||
@@ -69,6 +69,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.5.3",
|
"@biomejs/biome": "2.5.3",
|
||||||
|
"@types/chromecast-caf-sender": "^1.0.11",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"@types/react": "19.2.17",
|
"@types/react": "19.2.17",
|
||||||
"nitrogen": "0.36.1",
|
"nitrogen": "0.36.1",
|
||||||
|
|||||||
+13
-17
@@ -244,26 +244,22 @@ export class WebOmniPlayer implements OmniPlayer {
|
|||||||
this.setOverlaySubtitle(overlay ?? null);
|
this.setOverlaySubtitle(overlay ?? null);
|
||||||
|
|
||||||
if (this.castStatus === "connected") {
|
if (this.castStatus === "connected") {
|
||||||
try {
|
window.cast.framework.CastContext.getInstance()
|
||||||
// if the cast receiver handles overlay subtitles like us, send this message.
|
.getCurrentSession()
|
||||||
const ctx = (
|
?.sendMessage("urn:x-cast:dev.zoriya.omni", {
|
||||||
window as unknown as {
|
subtitle: overlay?.id ?? null,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: cast sender SDK global
|
})
|
||||||
cast?: { framework?: { CastContext?: { getInstance(): any } } };
|
.catch(() => {});
|
||||||
}
|
|
||||||
).cast?.framework?.CastContext?.getInstance?.();
|
|
||||||
ctx
|
|
||||||
?.getCurrentSession?.()
|
|
||||||
?.sendMessage("urn:x-cast:dev.zoriya.omni", {
|
|
||||||
subtitle: overlay?.id ?? null,
|
|
||||||
})
|
|
||||||
?.catch?.(() => {});
|
|
||||||
} catch {
|
|
||||||
// no active cast session / sender SDK not loaded
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To be used on a callback of a chromecast session, it only changes the local state
|
||||||
|
applyRemoteSubtitle(id: string | null): void {
|
||||||
|
this.setOverlaySubtitle(
|
||||||
|
id ? (this.overlaySubtitles.find((s) => s.id === id) ?? null) : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private setOverlaySubtitle(sub: Subtitle | null): void {
|
private setOverlaySubtitle(sub: Subtitle | null): void {
|
||||||
if (this.overlaySubtitle === sub) return;
|
if (this.overlaySubtitle === sub) return;
|
||||||
this.overlaySubtitle = sub;
|
this.overlaySubtitle = sub;
|
||||||
|
|||||||
@@ -72,6 +72,44 @@ const PlayerInitializer = ({
|
|||||||
player.showNotification = showNotification;
|
player.showNotification = showNotification;
|
||||||
}, [showNotification]);
|
}, [showNotification]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const ctx = window.cast?.framework?.CastContext?.getInstance();
|
||||||
|
if (!window.cast?.framework || !ctx) return;
|
||||||
|
|
||||||
|
let attached: cast.framework.CastSession | null = null;
|
||||||
|
|
||||||
|
const onSessionChange = () => {
|
||||||
|
const session = ctx.getCurrentSession();
|
||||||
|
if (!session || session === attached) return;
|
||||||
|
attached = session;
|
||||||
|
session.addMessageListener(
|
||||||
|
"urn:x-cast:dev.zoriya.omni",
|
||||||
|
(_ns: string, message: string) => {
|
||||||
|
let data: unknown;
|
||||||
|
try {
|
||||||
|
data = JSON.parse(message);
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (data && typeof data === "object" && "subtitle" in data) {
|
||||||
|
const id = (data as { subtitle?: unknown }).subtitle;
|
||||||
|
player.applyRemoteSubtitle(typeof id === "string" ? id : null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
onSessionChange();
|
||||||
|
ctx.addEventListener(
|
||||||
|
window.cast?.framework.CastContextEventType.SESSION_STATE_CHANGED,
|
||||||
|
onSessionChange,
|
||||||
|
);
|
||||||
|
return () =>
|
||||||
|
ctx.removeEventListener(
|
||||||
|
window.cast?.framework.CastContextEventType.SESSION_STATE_CHANGED,
|
||||||
|
onSessionChange,
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return <PlayerCtx.Provider value={player}>{children}</PlayerCtx.Provider>;
|
return <PlayerCtx.Provider value={player}>{children}</PlayerCtx.Provider>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
|
"types": ["chromecast-caf-sender"],
|
||||||
"verbatimModuleSyntax": true
|
"verbatimModuleSyntax": true
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
|||||||
Reference in New Issue
Block a user