diff --git a/src/hooks/useChromecastAvailable.ts b/src/hooks/useChromecastAvailable.ts
new file mode 100644
index 00000000..6190a288
--- /dev/null
+++ b/src/hooks/useChromecastAvailable.ts
@@ -0,0 +1,110 @@
+///
+
+import { isChromecastAvailable } from "@/setup/chromecast";
+import { useEffect, useRef, useState } from "react";
+
+export function useChromecastAvailable() {
+ const [available, setAvailable] = useState
(null);
+
+ useEffect(() => {
+ isChromecastAvailable((bool) => setAvailable(bool));
+ }, []);
+
+ return available;
+}
+
+export function useChromecast() {
+ const available = useChromecastAvailable();
+ const instance = useRef(null);
+ const remotePlayerController =
+ useRef(null);
+
+ function startCast() {
+ const movieMeta = new chrome.cast.media.MovieMediaMetadata();
+ movieMeta.title = "Big Buck Bunny";
+
+ const mediaInfo = new chrome.cast.media.MediaInfo("hello", "video/mp4");
+ (mediaInfo as any).contentUrl =
+ "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
+ mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED;
+ mediaInfo.metadata = movieMeta;
+
+ const request = new chrome.cast.media.LoadRequest(mediaInfo);
+ request.autoplay = true;
+
+ const session = instance.current?.getCurrentSession();
+ console.log("testing", session);
+ if (!session) return;
+
+ session
+ .loadMedia(request)
+ .then(() => {
+ console.log("Media is loaded");
+ })
+ .catch((e: any) => {
+ console.error(e);
+ });
+ }
+
+ function stopCast() {
+ const session = instance.current?.getCurrentSession();
+ if (!session) return;
+
+ const controller = remotePlayerController.current;
+ if (!controller) return;
+ controller.stop();
+ }
+
+ useEffect(() => {
+ if (!available) return;
+
+ // setup instance if not already
+ if (!instance.current) {
+ const ins = cast.framework.CastContext.getInstance();
+ ins.setOptions({
+ receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
+ autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED,
+ });
+ instance.current = ins;
+ }
+
+ // setup player if not already
+ if (!remotePlayerController.current) {
+ const player = new cast.framework.RemotePlayer();
+ const controller = new cast.framework.RemotePlayerController(player);
+ remotePlayerController.current = controller;
+ }
+
+ // setup event listener
+ function listenToEvents(e: cast.framework.RemotePlayerChangedEvent) {
+ console.log("chromecast event", e);
+ }
+ function connectionChanged(e: cast.framework.RemotePlayerChangedEvent) {
+ console.log("chromecast event connection changed", e);
+ }
+ remotePlayerController.current.addEventListener(
+ cast.framework.RemotePlayerEventType.PLAYER_STATE_CHANGED,
+ listenToEvents
+ );
+ remotePlayerController.current.addEventListener(
+ cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED,
+ connectionChanged
+ );
+
+ return () => {
+ remotePlayerController.current?.removeEventListener(
+ cast.framework.RemotePlayerEventType.PLAYER_STATE_CHANGED,
+ listenToEvents
+ );
+ remotePlayerController.current?.removeEventListener(
+ cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED,
+ connectionChanged
+ );
+ };
+ }, [available]);
+
+ return {
+ startCast,
+ stopCast,
+ };
+}
diff --git a/src/index.tsx b/src/index.tsx
index bd0fcf88..1a7a7aa0 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -8,6 +8,7 @@ import App from "@/setup/App";
import "@/setup/i18n";
import "@/setup/index.css";
import "@/backend";
+import { initializeChromecast } from "./setup/chromecast";
// initialize
const key =
@@ -15,6 +16,7 @@ const key =
if (key) {
(window as any).initMW(conf().BASE_PROXY_URL, key);
}
+initializeChromecast();
// TODO video todos:
// - captions
diff --git a/src/setup/App.tsx b/src/setup/App.tsx
index 6ab1374c..5f1b2b11 100644
--- a/src/setup/App.tsx
+++ b/src/setup/App.tsx
@@ -6,7 +6,9 @@ import { NotFoundPage } from "@/views/notfound/NotFoundView";
import { MediaView } from "@/views/media/MediaView";
import { SearchView } from "@/views/search/SearchView";
import { MWMediaType } from "@/backend/metadata/types";
+import { TestView } from "@/views/TestView";
+// TODO remove test view
function App() {
return (
@@ -16,6 +18,7 @@ function App() {
+
void)[] = [];
+let _available: boolean | null = null;
+
+function init(available: boolean) {
+ _available = available;
+ callbacks.forEach((cb) => cb(available));
+}
+
+export function isChromecastAvailable(cb: (available: boolean) => void) {
+ if (_available !== null) return cb(_available);
+ callbacks.push(cb);
+}
+
+export function initializeChromecast() {
+ window.__onGCastApiAvailable = (isAvailable) => {
+ init(isAvailable);
+ };
+
+ // add script if doesnt exist yet
+ const exists = !!document.getElementById("chromecast-script");
+ if (!exists) {
+ const script = document.createElement("script");
+ script.setAttribute("src", CHROMECAST_SENDER_SDK);
+ script.setAttribute("id", "chromecast-script");
+ document.body.appendChild(script);
+ }
+}
diff --git a/src/views/TestView.tsx b/src/views/TestView.tsx
new file mode 100644
index 00000000..f9cd6502
--- /dev/null
+++ b/src/views/TestView.tsx
@@ -0,0 +1,35 @@
+import {
+ useChromecast,
+ useChromecastAvailable,
+} from "@/hooks/useChromecastAvailable";
+import { useEffect, useRef } from "react";
+
+function ChromeCastButton() {
+ const ref = useRef(null);
+ const available = useChromecastAvailable();
+
+ useEffect(() => {
+ if (!available) return;
+ const tag = document.createElement("google-cast-launcher");
+ tag.setAttribute("id", "castbutton");
+ ref.current?.appendChild(tag);
+ }, [available]);
+
+ return ;
+}
+
+export function TestView() {
+ const { startCast, stopCast } = useChromecast();
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/yarn.lock b/yarn.lock
index 2b105f10..1335083b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -20,9 +20,9 @@
"@colors/colors@1.5.0":
"version" "1.5.0"
-"@esbuild/darwin-arm64@0.16.5":
- "integrity" "sha512-4HlbUMy50cRaHGVriBjShs46WRPshtnVOqkxEGhEuDuJhgZ3regpWzaQxXOcDXFvVwue8RiqDAAcOi/QlVLE6Q=="
- "resolved" "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.5.tgz"
+"@esbuild/linux-x64@0.16.5":
+ "integrity" "sha512-vsOwzKN+4NenUTyuoWLmg5dAuO8JKuLD9MXSeENA385XucuOZbblmOMwwgPlHsgVRtSjz38riqPJU2ALI/CWYQ=="
+ "resolved" "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.5.tgz"
"version" "0.16.5"
"@eslint/eslintrc@^1.3.3":
@@ -98,8 +98,8 @@
"@nodelib/fs.scandir" "2.1.5"
"fastq" "^1.6.0"
-"@npmcli/arborist@^6.1.6":
- "version" "6.1.6"
+"@npmcli/arborist@^6.1.5":
+ "version" "6.1.5"
dependencies:
"@isaacs/string-locale-compare" "^1.1.0"
"@npmcli/fs" "^3.1.0"
@@ -135,8 +135,8 @@
"treeverse" "^3.0.0"
"walk-up-path" "^1.0.0"
-"@npmcli/config@^6.1.1":
- "version" "6.1.1"
+"@npmcli/config@^6.1.0":
+ "version" "6.1.0"
dependencies:
"@npmcli/map-workspaces" "^3.0.0"
"ini" "^3.0.0"
@@ -233,9 +233,14 @@
"read-package-json-fast" "^3.0.0"
"which" "^3.0.0"
-"@swc/core-darwin-arm64@1.3.22":
- "integrity" "sha512-MMhtPsuXp8gpUgr9bs+RZQ2IyFGiUNDG93usCDAFgAF+6VVp+YaAVjET/3/Bx5Lk2WAt0RxT62C9KTEw1YMo3w=="
- "resolved" "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.22.tgz"
+"@swc/core-linux-x64-gnu@1.3.22":
+ "integrity" "sha512-FLkbiqsdXsVIFZi6iedx4rSBGX8x0vo/5aDlklSxJAAYOcQpO0QADKP5Yr65iMT1d6ABCt2d+/StpGLF7GWOcA=="
+ "resolved" "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.22.tgz"
+ "version" "1.3.22"
+
+"@swc/core-linux-x64-musl@1.3.22":
+ "integrity" "sha512-giBuw+Z0Bq6fpZ0Y5TcfpcQwf9p/cE1fOQyO/K1XSTn/haQOqFi7421Jq/dFThSARZiXw1u9Om9VFbwxr8VI+A=="
+ "resolved" "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.22.tgz"
"version" "1.3.22"
"@swc/core@^1.3.21":
@@ -262,16 +267,48 @@
"@tootallnate/once@2":
"version" "2.0.0"
+"@types/chrome@*":
+ "integrity" "sha512-VSjQu1k6a/rAfuqR1Gi/oxHZj4+t6+LG+GobNI3ZWI6DQ+fmphNSF6TrLHG6BYK2bXc9Gb4c1uXFKRRVLaGl5Q=="
+ "resolved" "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.210.tgz"
+ "version" "0.0.210"
+ dependencies:
+ "@types/filesystem" "*"
+ "@types/har-format" "*"
+
+"@types/chromecast-caf-sender@^1.0.5":
+ "integrity" "sha512-8d6RRCOYYiKzDyFJKAYKOp7Eo0kUfj9imnLQj0uuh/QGSz8euL9OOeKmh8XizqTcKW5tXva6li0mRYtnvzVIcA=="
+ "resolved" "https://registry.npmjs.org/@types/chromecast-caf-sender/-/chromecast-caf-sender-1.0.5.tgz"
+ "version" "1.0.5"
+ dependencies:
+ "@types/chrome" "*"
+
"@types/crypto-js@^4.1.1":
"integrity" "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA=="
"resolved" "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz"
"version" "4.1.1"
+"@types/filesystem@*":
+ "integrity" "sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ=="
+ "resolved" "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.32.tgz"
+ "version" "0.0.32"
+ dependencies:
+ "@types/filewriter" "*"
+
+"@types/filewriter@*":
+ "integrity" "sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ=="
+ "resolved" "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.29.tgz"
+ "version" "0.0.29"
+
"@types/fscreen@^1.0.1":
"integrity" "sha512-hV2d0BreihMGtrg+EdAFOIl/O2EL5vhAheHJUztGE/lPFZIN8ZCpGFL8hCbtyi1CfhKjDRCf47sHjP+FwJ4q0Q=="
"resolved" "https://registry.npmjs.org/@types/fscreen/-/fscreen-1.0.1.tgz"
"version" "1.0.1"
+"@types/har-format@*":
+ "integrity" "sha512-o0J30wqycjF5miWDKYKKzzOU1ZTLuA42HZ4HE7/zqTOc/jTLdQ5NhYWvsRQo45Nfi1KHoRdNhteSI4BAxTF1Pg=="
+ "resolved" "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.10.tgz"
+ "version" "1.2.10"
+
"@types/history@^4.7.11":
"integrity" "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA=="
"resolved" "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz"
@@ -886,9 +923,9 @@
"version" "3.26.1"
"core-js@^3.6.5":
- "integrity" "sha512-9ashVQskuh5AZEZ1JdQWp1GqSoC1e1G87MzRqg2gIfVAQ7Qn9K+uFj8EcniUFA4P2NLZfV+TOlX1SzoKfo+s7w=="
- "resolved" "https://registry.npmjs.org/core-js/-/core-js-3.27.2.tgz"
- "version" "3.27.2"
+ "integrity" "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww=="
+ "resolved" "https://registry.npmjs.org/core-js/-/core-js-3.27.1.tgz"
+ "version" "3.27.1"
"cross-fetch@3.1.5":
"integrity" "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw=="
@@ -1050,6 +1087,13 @@
"resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz"
"version" "9.2.2"
+"encoding@^0.1.0":
+ "integrity" "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="
+ "resolved" "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz"
+ "version" "0.1.13"
+ dependencies:
+ "iconv-lite" "^0.6.2"
+
"encoding@^0.1.13":
"version" "0.1.13"
dependencies:
@@ -1489,11 +1533,6 @@
"resolved" "https://registry.npmjs.org/fscreen/-/fscreen-1.2.0.tgz"
"version" "1.2.0"
-"fsevents@~2.3.2":
- "integrity" "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="
- "resolved" "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz"
- "version" "2.3.2"
-
"function-bind@^1.1.1":
"integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
"resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
@@ -2015,16 +2054,16 @@
"version" "1.1.4"
"json5@^1.0.1":
- "integrity" "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow=="
- "resolved" "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz"
- "version" "1.0.1"
+ "integrity" "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="
+ "resolved" "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz"
+ "version" "1.0.2"
dependencies:
"minimist" "^1.2.0"
"json5@^2.2.0":
- "integrity" "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA=="
- "resolved" "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz"
- "version" "2.2.1"
+ "integrity" "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
+ "resolved" "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz"
+ "version" "2.2.3"
"jsonparse@^1.3.1":
"version" "1.3.1"
@@ -2069,10 +2108,10 @@
"npm-package-arg" "^10.1.0"
"npm-registry-fetch" "^14.0.3"
-"libnpmdiff@^5.0.7":
- "version" "5.0.7"
+"libnpmdiff@^5.0.6":
+ "version" "5.0.6"
dependencies:
- "@npmcli/arborist" "^6.1.6"
+ "@npmcli/arborist" "^6.1.5"
"@npmcli/disparity-colors" "^3.0.0"
"@npmcli/installed-package-contents" "^2.0.0"
"binary-extensions" "^2.2.0"
@@ -2082,10 +2121,10 @@
"pacote" "^15.0.7"
"tar" "^6.1.13"
-"libnpmexec@^5.0.7":
- "version" "5.0.7"
+"libnpmexec@^5.0.6":
+ "version" "5.0.6"
dependencies:
- "@npmcli/arborist" "^6.1.6"
+ "@npmcli/arborist" "^6.1.5"
"@npmcli/run-script" "^6.0.0"
"chalk" "^4.1.0"
"ci-info" "^3.7.0"
@@ -2098,10 +2137,10 @@
"semver" "^7.3.7"
"walk-up-path" "^1.0.0"
-"libnpmfund@^4.0.7":
- "version" "4.0.7"
+"libnpmfund@^4.0.6":
+ "version" "4.0.6"
dependencies:
- "@npmcli/arborist" "^6.1.6"
+ "@npmcli/arborist" "^6.1.5"
"libnpmhook@^9.0.1":
"version" "9.0.1"
@@ -2115,10 +2154,10 @@
"aproba" "^2.0.0"
"npm-registry-fetch" "^14.0.3"
-"libnpmpack@^5.0.7":
- "version" "5.0.7"
+"libnpmpack@^5.0.6":
+ "version" "5.0.6"
dependencies:
- "@npmcli/arborist" "^6.1.6"
+ "@npmcli/arborist" "^6.1.5"
"@npmcli/run-script" "^6.0.0"
"npm-package-arg" "^10.1.0"
"pacote" "^15.0.7"
@@ -2281,9 +2320,9 @@
"encoding" "^0.1.13"
"minipass-fetch@^3.0.0":
- "version" "3.0.1"
+ "version" "3.0.0"
dependencies:
- "minipass" "^4.0.0"
+ "minipass" "^3.1.6"
"minipass-sized" "^1.0.3"
"minizlib" "^2.1.2"
optionalDependencies:
@@ -2492,13 +2531,13 @@
"version" "1.0.1"
"npm@^9.2.0":
- "integrity" "sha512-ydRVmnWEVXmc3DCM+F9BjiNj3IHkZ3Mwz5VbJYS2BpY/6d4PcKxNW+Xb0vzGeE6PkVhLcPxwhoIi+RFV2fSfEA=="
- "resolved" "https://registry.npmjs.org/npm/-/npm-9.3.1.tgz"
- "version" "9.3.1"
+ "integrity" "sha512-oypVdaWGHDuV79RXLvp+B9gh6gDyAmoHKrQ0/JBYTWWx5D8/+AAxFdZC84fSIiyDdyW4qfrSyYGKhekxDOaMXQ=="
+ "resolved" "https://registry.npmjs.org/npm/-/npm-9.2.0.tgz"
+ "version" "9.2.0"
dependencies:
"@isaacs/string-locale-compare" "^1.1.0"
- "@npmcli/arborist" "^6.1.6"
- "@npmcli/config" "^6.1.1"
+ "@npmcli/arborist" "^6.1.5"
+ "@npmcli/config" "^6.1.0"
"@npmcli/map-workspaces" "^3.0.0"
"@npmcli/package-json" "^3.0.0"
"@npmcli/run-script" "^6.0.0"
@@ -2520,12 +2559,12 @@
"is-cidr" "^4.0.2"
"json-parse-even-better-errors" "^3.0.0"
"libnpmaccess" "^7.0.1"
- "libnpmdiff" "^5.0.7"
- "libnpmexec" "^5.0.7"
- "libnpmfund" "^4.0.7"
+ "libnpmdiff" "^5.0.6"
+ "libnpmexec" "^5.0.6"
+ "libnpmfund" "^4.0.6"
"libnpmhook" "^9.0.1"
"libnpmorg" "^5.0.1"
- "libnpmpack" "^5.0.7"
+ "libnpmpack" "^5.0.6"
"libnpmpublish" "^7.0.6"
"libnpmsearch" "^6.0.1"
"libnpmteam" "^5.0.1"
@@ -2554,6 +2593,7 @@
"read" "~1.0.7"
"read-package-json" "^6.0.0"
"read-package-json-fast" "^3.0.1"
+ "rimraf" "^3.0.2"
"semver" "^7.3.8"
"ssri" "^10.0.1"
"tar" "^6.1.13"