feature (chromecast): canary release with chromecast image

This commit is contained in:
MickaelK
2024-09-11 00:34:10 +10:00
parent d53ac30497
commit 1a39eae6d3
8 changed files with 119 additions and 88 deletions

View File

@ -82,17 +82,6 @@ async function setup_blue_death_screen() {
}; };
} }
// async function setup_chromecast() {
// if (!window.CONFIG["enable_chromecast"]) {
// return Promise.resolve();
// } else if (!("chrome" in window)) {
// return Promise.resolve();
// } else if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
// return Promise.resolve();
// }
// return window.Chromecast.init();
// }
async function setup_history() { async function setup_history() {
window.history.replaceState({}, ""); window.history.replaceState({}, "");
} }

View File

@ -6,76 +6,60 @@ export async function init() {
} else if (location.hostname === "localhost" || location.hostname === "127.0.0.1") { } else if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
return Promise.resolve(); return Promise.resolve();
} }
// return Chromecast.init(); return Chromecast.init();
} }
// import { Session } from "./session"; export const Chromecast = new class ChromecastManager {
// import { currentShare, objectGet } from "../helpers/"; init() {
return new Promise((resolve) => {
const script = document.createElement("script");
script.src = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
script.onerror = () => resolve(null);
window["__onGCastApiAvailable"] = function(isAvailable) {
if (isAvailable) window.cast.framework.CastContext.getInstance().setOptions({
receiverApplicationId: window.chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
autoJoinPolicy: window.chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED,
});
resolve(null);
};
document.head.appendChild(script);
});
}
// class ChromecastManager { createLink(apiPath) {
// init() { const target = new URL(location.origin + apiPath);
// return new Promise((done) => { const shareID = new URLSearchParams(location.search).get("search");
// const script = document.createElement("script"); if (shareID) target.searchParams.append("share", shareID);
// script.src = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"; return target.toString();
// script.onerror = () => done() }
// window["__onGCastApiAvailable"] = function(isAvailable) {
// if (isAvailable) cast.framework.CastContext.getInstance().setOptions({
// receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
// autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED,
// });
// done();
// };
// document.head.appendChild(script)
// });
// }
// origin() { createRequest(mediaInfo) {
// return location.origin; if (!window.BEARER_TOKEN) throw new Error("Invalid account");
// }; // TODO: it would be much much nicer to set the authorization from an HTTP header
// but this would require to create a custom web receiver app, setup accounts on
// google, etc,... Until that happens, we're setting the authorization within the
// url. Once we have that app, the authorisation will come from a customData field
// of a chrome.cast.media.LoadRequest
const target = new URL(mediaInfo.contentId);
target.searchParams.append("authorization", window.BEARER_TOKEN);
mediaInfo.contentId = target.toString();
return new window.chrome.cast.media.LoadRequest(mediaInfo);
}
// createLink(apiPath) { context() {
// const shareID = currentShare(); if (!window.chrome?.cast?.isAvailable) return;
// if (shareID) { return window.cast.framework.CastContext.getInstance();
// const target = new URL(this.origin() + apiPath); }
// target.searchParams.append("share", shareID);
// return target.toString();
// }
// const target = new URL(this.origin() + apiPath)
// return target.toString();
// }
// createRequest(mediaInfo) { session() {
// let prior = Promise.resolve(); const context = this.context();
// if (!Session.authorization) prior = Session.currentUser(); if (!context) return;
// return prior.then(() => { return context.getCurrentSession();
// if (!Session.authorization) throw new Error("Invalid account"); }
// // TODO: it would be much much nicer to set the authorization from an HTTP header
// // but this would require to create a custom web receiver app, setup accounts on
// // google, etc,... Until that happens, we're setting the authorization within the
// // url. Once we have that app, the authorisation will come from a customData field
// // of a chrome.cast.media.LoadRequest
// const target = new URL(mediaInfo.contentId);
// target.searchParams.append("authorization", Session.authorization);
// mediaInfo.contentId = target.toString();
// return new chrome.cast.media.LoadRequest(mediaInfo);
// });
// }
// context() { media() {
// if (!objectGet(window.chrome, ["cast", "isAvailable"])) { const session = this.session();
// return; if (!session) return;
// } return session.getMediaSession();
// return cast.framework.CastContext.getInstance(); }
// } }();
// session() {
// const context = this.context();
// if (!context) return;
// return context.getCurrentSession();
// }
// media() {
// const session = this.session();
// if (!session) return;
// return session.getMediaSession();
// }
// }
// export const Chromecast = new ChromecastManager();

View File

@ -8,7 +8,10 @@ export function getSession() {
method: "GET", method: "GET",
responseType: "json" responseType: "json"
}).pipe( }).pipe(
rxjs.map(({ responseJSON }) => responseJSON.result) rxjs.map(({ responseJSON }) => responseJSON.result),
rxjs.tap(({ authorization }) => {
if (authorization) window.BEARER_TOKEN = authorization;
}),
); );
} }

View File

@ -198,7 +198,7 @@ export default async function(render) {
return rxjs.of(null).pipe( return rxjs.of(null).pipe(
rxjs.tap(() => toggleLoader(true)), rxjs.tap(() => toggleLoader(true)),
rxjs.mergeMap(() => createSession(formData)), rxjs.mergeMap(() => createSession(formData)),
rxjs.tap(({ responseJSON, responseHeaders }) => { rxjs.tap(({ responseJSON }) => {
let redirectURL = toHref("/files/"); let redirectURL = toHref("/files/");
const GET = getURLParams(); const GET = getURLParams();
if (GET["next"]) redirectURL = GET["next"]; if (GET["next"]) redirectURL = GET["next"];

View File

@ -13,7 +13,7 @@ export default function(render) {
effect(deleteSession().pipe( effect(deleteSession().pipe(
rxjs.mergeMap(setup_config), rxjs.mergeMap(setup_config),
rxjs.tap(() => { rxjs.tap(() => {
window.CONFIG["logout"] ? location.href = window.CONFIG["logout"] : navigate(toHref("/")) window.CONFIG["logout"] ? location.href = window.CONFIG["logout"] : navigate(toHref("/"));
}), }),
rxjs.catchError(ctrlError(render)), rxjs.catchError(ctrlError(render)),
)); ));

View File

@ -1,11 +1,15 @@
import { createElement, createRender } from "../../lib/skeleton/index.js"; import { createElement, createRender, onDestroy } from "../../lib/skeleton/index.js";
import { toHref } from "../../lib/skeleton/router.js";
import rxjs, { effect, onLoad, onClick } from "../../lib/rx.js"; import rxjs, { effect, onLoad, onClick } from "../../lib/rx.js";
import { animate } from "../../lib/animate.js"; import { animate } from "../../lib/animate.js";
import { extname } from "../../lib/path.js";
import { loadCSS } from "../../helpers/loader.js"; import { loadCSS } from "../../helpers/loader.js";
import { qs } from "../../lib/dom.js"; import { qs } from "../../lib/dom.js";
import { createLoader } from "../../components/loader.js"; import { createLoader } from "../../components/loader.js";
import notification from "../../components/notification.js";
import t from "../../locales/index.js"; import t from "../../locales/index.js";
import ctrlError from "../ctrl_error.js"; import ctrlError from "../ctrl_error.js";
import { Chromecast } from "../../model/chromecast.js";
import { transition, getFilename, getDownloadUrl } from "./common.js"; import { transition, getFilename, getDownloadUrl } from "./common.js";
@ -44,6 +48,7 @@ export default function(render) {
buttonDownload(getFilename(), getDownloadUrl()), buttonDownload(getFilename(), getDownloadUrl()),
buttonFullscreen(qs($page, ".component_image_container")), buttonFullscreen(qs($page, ".component_image_container")),
buttonInfo({ toggle: toggleInfo }), buttonInfo({ toggle: toggleInfo }),
buttonChromecast(getFilename(), getDownloadUrl()),
); );
effect(onLoad($photo).pipe( effect(onLoad($photo).pipe(
@ -85,6 +90,13 @@ export default function(render) {
componentPager(createRender(qs($page, ".component_pager"))); componentPager(createRender(qs($page, ".component_pager")));
} }
export function init() {
return Promise.all([
loadCSS(import.meta.url, "./application_image.css"),
initPager(), initMetadata(),
]);
}
function buttonInfo({ toggle }) { function buttonInfo({ toggle }) {
const $el = createElement(` const $el = createElement(`
<span> <span>
@ -98,9 +110,51 @@ function buttonInfo({ toggle }) {
return $el; return $el;
} }
export function init() { function buttonChromecast(filename, downloadURL) {
return Promise.all([ const context = Chromecast.context();
loadCSS(import.meta.url, "./application_image.css"), if (!context) return;
initPager(), initMetadata(),
]); const chromecastSetup = (event) => {
switch (event.sessionState) {
case window.cast.framework.SessionState.SESSION_STARTED:
chromecastLoader();
break;
}
};
const chromecastLoader = () => {
const session = Chromecast.session();
if (!session) return;
const link = Chromecast.createLink("/" + toHref(downloadURL));
const media = new window.chrome.cast.media.MediaInfo(
link,
window.CONFIG.mime[extname(filename)],
);
media.metadata = new window.chrome.cast.media.PhotoMediaMetadata();
media.metadata.title = filename;
media.metadata.images = [
new window.chrome.cast.Image(location.origin + "/" + toHref("/assets/icons/photo.png")),
];
try {
const req = Chromecast.createRequest(media);
session.loadMedia(req);
} catch (err) {
console.error(err);
notification.error(t("Cannot establish a connection"));
}
};
context.addEventListener(
window.cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
chromecastSetup,
);
onDestroy(() => context.removeEventListener(
window.cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
chromecastSetup,
));
const media = Chromecast.media();
if (media && media.media && media.media.mediaCategory === "IMAGE") chromecastLoader();
return document.createElement("google-cast-launcher");
} }

View File

@ -30,7 +30,6 @@ export default async function(render) {
const map = window.L.map("map"); const map = window.L.map("map");
const fileview = [getFilename()]; const fileview = [getFilename()];
for (let i=0; i<fileview.length; i++) { for (let i=0; i<fileview.length; i++) {
await cat(fileview[i]).pipe(rxjs.mergeMap(async(content) => { await cat(fileview[i]).pipe(rxjs.mergeMap(async(content) => {

4
public/global.d.ts vendored
View File

@ -1,10 +1,12 @@
interface Window { interface Window {
chrome: object; chrome: any;
cast: any;
overrides: { overrides: {
[key: string]: any; [key: string]: any;
"xdg-open"?: (mime: string) => void; "xdg-open"?: (mime: string) => void;
}; };
CONFIG: Config; CONFIG: Config;
BEARER_TOKEN?: string;
} }
interface Config { interface Config {