mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-11-01 10:56:31 +08:00
feature (chromecast): canary release with chromecast image
This commit is contained in:
@ -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({}, "");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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"];
|
||||||
|
|||||||
@ -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)),
|
||||||
));
|
));
|
||||||
|
|||||||
@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
4
public/global.d.ts
vendored
@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user