mirror of
				https://github.com/mickael-kerjean/filestash.git
				synced 2025-11-01 02:43:35 +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
	 MickaelK
					MickaelK