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() {
window.history.replaceState({}, "");
}

View File

@ -6,76 +6,60 @@ export async function init() {
} else if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
return Promise.resolve();
}
// return Chromecast.init();
return Chromecast.init();
}
// import { Session } from "./session";
// import { currentShare, objectGet } from "../helpers/";
export const Chromecast = new class ChromecastManager {
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 {
// init() {
// return new Promise((done) => {
// const script = document.createElement("script");
// script.src = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
// 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)
// });
// }
createLink(apiPath) {
const target = new URL(location.origin + apiPath);
const shareID = new URLSearchParams(location.search).get("search");
if (shareID) target.searchParams.append("share", shareID);
return target.toString();
}
// origin() {
// return location.origin;
// };
createRequest(mediaInfo) {
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) {
// const shareID = currentShare();
// if (shareID) {
// 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();
// }
context() {
if (!window.chrome?.cast?.isAvailable) return;
return window.cast.framework.CastContext.getInstance();
}
// createRequest(mediaInfo) {
// let prior = Promise.resolve();
// if (!Session.authorization) prior = Session.currentUser();
// return prior.then(() => {
// 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);
// });
// }
session() {
const context = this.context();
if (!context) return;
return context.getCurrentSession();
}
// context() {
// if (!objectGet(window.chrome, ["cast", "isAvailable"])) {
// return;
// }
// 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();
media() {
const session = this.session();
if (!session) return;
return session.getMediaSession();
}
}();

View File

@ -8,7 +8,10 @@ export function getSession() {
method: "GET",
responseType: "json"
}).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(
rxjs.tap(() => toggleLoader(true)),
rxjs.mergeMap(() => createSession(formData)),
rxjs.tap(({ responseJSON, responseHeaders }) => {
rxjs.tap(({ responseJSON }) => {
let redirectURL = toHref("/files/");
const GET = getURLParams();
if (GET["next"]) redirectURL = GET["next"];

View File

@ -13,7 +13,7 @@ export default function(render) {
effect(deleteSession().pipe(
rxjs.mergeMap(setup_config),
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)),
));

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 { animate } from "../../lib/animate.js";
import { extname } from "../../lib/path.js";
import { loadCSS } from "../../helpers/loader.js";
import { qs } from "../../lib/dom.js";
import { createLoader } from "../../components/loader.js";
import notification from "../../components/notification.js";
import t from "../../locales/index.js";
import ctrlError from "../ctrl_error.js";
import { Chromecast } from "../../model/chromecast.js";
import { transition, getFilename, getDownloadUrl } from "./common.js";
@ -44,6 +48,7 @@ export default function(render) {
buttonDownload(getFilename(), getDownloadUrl()),
buttonFullscreen(qs($page, ".component_image_container")),
buttonInfo({ toggle: toggleInfo }),
buttonChromecast(getFilename(), getDownloadUrl()),
);
effect(onLoad($photo).pipe(
@ -85,6 +90,13 @@ export default function(render) {
componentPager(createRender(qs($page, ".component_pager")));
}
export function init() {
return Promise.all([
loadCSS(import.meta.url, "./application_image.css"),
initPager(), initMetadata(),
]);
}
function buttonInfo({ toggle }) {
const $el = createElement(`
<span>
@ -98,9 +110,51 @@ function buttonInfo({ toggle }) {
return $el;
}
export function init() {
return Promise.all([
loadCSS(import.meta.url, "./application_image.css"),
initPager(), initMetadata(),
]);
function buttonChromecast(filename, downloadURL) {
const context = Chromecast.context();
if (!context) return;
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 fileview = [getFilename()];
for (let i=0; i<fileview.length; i++) {
await cat(fileview[i]).pipe(rxjs.mergeMap(async(content) => {

4
public/global.d.ts vendored
View File

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