mirror of
				https://github.com/mickael-kerjean/filestash.git
				synced 2025-10-31 18:16:00 +08:00 
			
		
		
		
	feature (chromecast): improve support for chromecast
This commit is contained in:
		| @ -2,7 +2,7 @@ import React from "react"; | |||||||
| import ReactDOM from "react-dom"; | import ReactDOM from "react-dom"; | ||||||
| import Router from "./router"; | import Router from "./router"; | ||||||
|  |  | ||||||
| import { Config, Log } from "./model/"; | import { Config, Log, Chromecast } from "./model/"; | ||||||
| import { http_get, setup_cache } from "./helpers/"; | import { http_get, setup_cache } from "./helpers/"; | ||||||
| import load from "little-loader"; | import load from "little-loader"; | ||||||
|  |  | ||||||
| @ -150,17 +150,5 @@ function setup_chromecast() { | |||||||
| 	} 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 new Promise((done) => { |     return Chromecast.init(); | ||||||
|         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) |  | ||||||
|     }); |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										73
									
								
								client/model/chromecast.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								client/model/chromecast.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,73 @@ | |||||||
|  | "use strict"; | ||||||
|  |  | ||||||
|  | import { Session } from "./session"; | ||||||
|  | import { currentShare, objectGet } from "../helpers/"; | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     origin() { | ||||||
|  |         return location.origin; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     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(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     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); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     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(); | ||||||
| @ -6,3 +6,4 @@ export { Log } from "./log"; | |||||||
| export { Admin } from "./admin"; | export { Admin } from "./admin"; | ||||||
| export { Audit } from "./audit"; | export { Audit } from "./audit"; | ||||||
| export { Tags } from "./tags"; | export { Tags } from "./tags"; | ||||||
|  | export { Chromecast } from "./chromecast"; | ||||||
|  | |||||||
| @ -4,7 +4,10 @@ class SessionManager { | |||||||
|     currentUser() { |     currentUser() { | ||||||
|         const shareID = currentShare(); |         const shareID = currentShare(); | ||||||
|         return http_get("/api/session" + (shareID && `?share=${shareID}`)) |         return http_get("/api/session" + (shareID && `?share=${shareID}`)) | ||||||
|             .then((data) => data.result) |             .then((data) => { | ||||||
|  |                 this.authorization = data.result.authorization; | ||||||
|  |                 return data.result; | ||||||
|  |             }) | ||||||
|             .catch((err) => { |             .catch((err) => { | ||||||
|                 if (err.code === "Unauthorized") { |                 if (err.code === "Unauthorized") { | ||||||
|                     if (location.pathname.indexOf("/files/") !== -1 || location.pathname.indexOf("/view/") !== -1) { |                     if (location.pathname.indexOf("/files/") !== -1 || location.pathname.indexOf("/view/") !== -1) { | ||||||
| @ -41,6 +44,7 @@ class SessionManager { | |||||||
|  |  | ||||||
|     logout() { |     logout() { | ||||||
|         const url = "/api/session"; |         const url = "/api/session"; | ||||||
|  |         this.authorization = null; | ||||||
|         return http_delete(url) |         return http_delete(url) | ||||||
|             .then((data) => data.result); |             .then((data) => data.result); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import Path from "path"; | |||||||
|  |  | ||||||
| import "./viewerpage.scss"; | import "./viewerpage.scss"; | ||||||
| import "./error.scss"; | import "./error.scss"; | ||||||
| import { Files } from "../model/"; | import { Files, Chromecast } from "../model/"; | ||||||
| import { | import { | ||||||
|     BreadCrumb, Bundle, NgIf, Loader, EventReceiver, LoggedInOnly, ErrorPage, |     BreadCrumb, Bundle, NgIf, Loader, EventReceiver, LoggedInOnly, ErrorPage, | ||||||
| } from "../components/"; | } from "../components/"; | ||||||
| @ -137,12 +137,11 @@ export function ViewerPageComponent({ error, subscribe, unsubscribe, match, loca | |||||||
|  |  | ||||||
|     useEffect(() => { |     useEffect(() => { | ||||||
|         return () => { |         return () => { | ||||||
|             if (!objectGet(window.chrome, ["cast", "isAvailable"])) { |             const context = Chromecast.context(); | ||||||
|                 return |             if (!context) return; | ||||||
|             } |             context.endCurrentSession(); | ||||||
|             cast.framework.CastContext.getInstance().endCurrentSession(); |  | ||||||
|         }; |         }; | ||||||
|     }, []) |     }, []); | ||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
|         <div className="component_page_viewerpage"> |         <div className="component_page_viewerpage"> | ||||||
|  | |||||||
| @ -1,9 +1,12 @@ | |||||||
| import React, { useState, useEffect, useRef } from "react"; | import React, { useState, useEffect, useRef } from "react"; | ||||||
| import WaveSurfer from "wavesurfer.js"; | import WaveSurfer from "wavesurfer.js"; | ||||||
|  | import filepath from "path"; | ||||||
|  |  | ||||||
| import { MenuBar } from "./menubar"; | import { MenuBar } from "./menubar"; | ||||||
| import { NgIf, Icon } from "../../components/"; | import { NgIf, Icon } from "../../components/"; | ||||||
| import { settings_get, settings_put } from "../../helpers/"; | import { settings_get, settings_put, notify, getMimeType, basename } from "../../helpers/"; | ||||||
|  | import { Chromecast } from "../../model/"; | ||||||
|  | import { t } from "../../locales/"; | ||||||
| import "./audioplayer.scss"; | import "./audioplayer.scss"; | ||||||
|  |  | ||||||
| export function AudioPlayer({ filename, data }) { | export function AudioPlayer({ filename, data }) { | ||||||
| @ -11,6 +14,7 @@ export function AudioPlayer({ filename, data }) { | |||||||
|     const [isLoading, setIsLoading] = useState(true); |     const [isLoading, setIsLoading] = useState(true); | ||||||
|     const [purcentLoading, setPurcentLoading] = useState(0); |     const [purcentLoading, setPurcentLoading] = useState(0); | ||||||
|     const [volume, setVolume] = useState(settings_get("volume") === null ? 50 : settings_get("volume")); |     const [volume, setVolume] = useState(settings_get("volume") === null ? 50 : settings_get("volume")); | ||||||
|  |     const [isChromecast, setIsChromecast] = useState(false); | ||||||
|     const [error, setError] = useState(null); |     const [error, setError] = useState(null); | ||||||
|     const wavesurfer = useRef(null); |     const wavesurfer = useRef(null); | ||||||
|  |  | ||||||
| @ -29,13 +33,14 @@ export function AudioPlayer({ filename, data }) { | |||||||
|         let $currentTime = document.getElementById("currentTime"); |         let $currentTime = document.getElementById("currentTime"); | ||||||
|         let $totalDuration = document.getElementById("totalDuration"); |         let $totalDuration = document.getElementById("totalDuration"); | ||||||
|         wavesurfer.current.on("ready", () => { |         wavesurfer.current.on("ready", () => { | ||||||
|  |             setPurcentLoading(100); | ||||||
|             setIsLoading(false); |             setIsLoading(false); | ||||||
|             wavesurfer.current.setVolume(volume / 100); |             wavesurfer.current.setVolume(volume / 100); | ||||||
|             $totalDuration.innerHTML = formatTimecode(wavesurfer.current.getDuration()); |             $totalDuration.innerHTML = formatTimecode(wavesurfer.current.getDuration()); | ||||||
|         }); |         }); | ||||||
|         wavesurfer.current.on("audioprocess", () => { |         wavesurfer.current.on("audioprocess", () => { | ||||||
|             $currentTime.innerHTML = formatTimecode(wavesurfer.current.getCurrentTime()); |             $currentTime.innerHTML = formatTimecode(wavesurfer.current.getCurrentTime()); | ||||||
|         }) |         }); | ||||||
|         wavesurfer.current.on("loading", (n) => { |         wavesurfer.current.on("loading", (n) => { | ||||||
|             setPurcentLoading(n); |             setPurcentLoading(n); | ||||||
|         }); |         }); | ||||||
| @ -43,15 +48,113 @@ export function AudioPlayer({ filename, data }) { | |||||||
|             setIsLoading(false); |             setIsLoading(false); | ||||||
|             setError(err); |             setError(err); | ||||||
|         }); |         }); | ||||||
|  |         wavesurfer.current.on("seek", (s) => { | ||||||
|  |             const media = Chromecast.media(); | ||||||
|  |             if (!media) return; | ||||||
|  |             const seekRequest = new chrome.cast.media.SeekRequest(); | ||||||
|  |             seekRequest.currentTime = parseInt(s*wavesurfer.current.getDuration()); | ||||||
|  |             media.seek(seekRequest); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|         return () => wavesurfer.current.destroy(); |         return () => wavesurfer.current.destroy(); | ||||||
|     }, []); |     }, []); | ||||||
|  |  | ||||||
|     useEffect(() => { |     useEffect(() => { | ||||||
|         if(wavesurfer.current === null) return; |  | ||||||
|         window.addEventListener("keypress", onKeyPressHandler); |         window.addEventListener("keypress", onKeyPressHandler); | ||||||
|         return () => window.removeEventListener("keypress", onKeyPressHandler); |         return () => window.removeEventListener("keypress", onKeyPressHandler); | ||||||
|     }, [isPlaying]) |     }, [isPlaying]) | ||||||
|  |  | ||||||
|  |     const chromecastSetup = (event) => { | ||||||
|  |         switch (event.sessionState) { | ||||||
|  |         case cast.framework.SessionState.SESSION_STARTING: | ||||||
|  |             setIsChromecast(true); | ||||||
|  |             setIsLoading(true); | ||||||
|  |             break; | ||||||
|  |         case cast.framework.SessionState.SESSION_START_FAILED: | ||||||
|  |             notify.send(t("Cannot establish a connection"), "error"); | ||||||
|  |             setIsChromecast(false); | ||||||
|  |             setIsLoading(false); | ||||||
|  |             break; | ||||||
|  |         case cast.framework.SessionState.SESSION_STARTED: | ||||||
|  |             chromecastHandler() | ||||||
|  |             break; | ||||||
|  |         case cast.framework.SessionState.SESSION_ENDING: | ||||||
|  |             wavesurfer.current.setMute(false); | ||||||
|  |             setIsChromecast(false); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const chromecastHandler = () => { | ||||||
|  |         setIsLoading(true); | ||||||
|  |         const link = Chromecast.createLink(data); | ||||||
|  |         const media = new chrome.cast.media.MediaInfo( | ||||||
|  |             link, | ||||||
|  |             getMimeType(data), | ||||||
|  |         ); | ||||||
|  |         media.metadata = new chrome.cast.media.MusicTrackMediaMetadata() | ||||||
|  |         media.metadata.title = filename.substr(0, filename.lastIndexOf(filepath.extname(filename))); | ||||||
|  |         media.metadata.subtitle = CONFIG.name; | ||||||
|  |         media.metadata.albumName = CONFIG.name; | ||||||
|  |         media.metadata.images = [ | ||||||
|  |             new chrome.cast.Image(origin + "/assets/icons/music.png"), | ||||||
|  |         ]; | ||||||
|  |         const session = Chromecast.session(); | ||||||
|  |         if (!session) return; | ||||||
|  |  | ||||||
|  |         Chromecast.createRequest(media) | ||||||
|  |             .then((req) => { | ||||||
|  |                 req.currentTime = parseInt(wavesurfer.current.getCurrentTime()); | ||||||
|  |                 return session.loadMedia(req) | ||||||
|  |             }) | ||||||
|  |             .then(() => { | ||||||
|  |                 setIsPlaying(true); | ||||||
|  |                 setIsLoading(false); | ||||||
|  |                 wavesurfer.current.play(); | ||||||
|  |                 wavesurfer.current.setMute(true); | ||||||
|  |  | ||||||
|  |                 const media = Chromecast.media(); | ||||||
|  |                 if (!media) return; | ||||||
|  |                 wavesurfer.current.seekTo(media.getEstimatedTime() / wavesurfer.current.getDuration()); | ||||||
|  |                 media.addUpdateListener(chromecastAlive); | ||||||
|  |             }).catch((err) => { | ||||||
|  |                 console.error(err); | ||||||
|  |                 notify.send(t("Cannot establish a connection"), "error"); | ||||||
|  |                 setIsChromecast(false); | ||||||
|  |                 setIsLoading(false); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const chromecastAlive = (isAlive) => { | ||||||
|  |         if (isAlive) return; | ||||||
|  |         const session = Chromecast.session(); | ||||||
|  |         if (session) { | ||||||
|  |             session.endSession(); | ||||||
|  |             wavesurfer.current.setMute(false); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     useEffect(() => { | ||||||
|  |         const context = Chromecast.context(); | ||||||
|  |         if (!context) return; | ||||||
|  |         chromecastAlive(false); | ||||||
|  |         document.getElementById("chromecast-target").append(document.createElement("google-cast-launcher"));         | ||||||
|  |         context.addEventListener( | ||||||
|  |             cast.framework.CastContextEventType.SESSION_STATE_CHANGED, | ||||||
|  |             chromecastSetup, | ||||||
|  |         ); | ||||||
|  |         return () => { | ||||||
|  |             context.removeEventListener( | ||||||
|  |                 cast.framework.CastContextEventType.SESSION_STATE_CHANGED, | ||||||
|  |                 chromecastSetup, | ||||||
|  |             ); | ||||||
|  |             const media = Chromecast.media(); | ||||||
|  |             if (!media) return | ||||||
|  |             media.removeUpdateListener(chromecastAlive); | ||||||
|  |             chromecastAlive(false); | ||||||
|  |         }; | ||||||
|  |     }, []); | ||||||
|  |  | ||||||
|     const onKeyPressHandler = (e) => { |     const onKeyPressHandler = (e) => { | ||||||
|         if(e.code !== "Space") { |         if(e.code !== "Space") { | ||||||
|             return |             return | ||||||
| @ -62,22 +165,33 @@ export function AudioPlayer({ filename, data }) { | |||||||
|     const onPlay = (e) => { |     const onPlay = (e) => { | ||||||
|         e.preventDefault(); |         e.preventDefault(); | ||||||
|         e.stopPropagation(); |         e.stopPropagation(); | ||||||
|         wavesurfer.current.play(); |  | ||||||
|         setIsPlaying(true); |         setIsPlaying(true); | ||||||
|  |         if (wavesurfer.current) wavesurfer.current.play(); | ||||||
|  |         if (isChromecast) { | ||||||
|  |             const media = Chromecast.media(); | ||||||
|  |             if (media) media.play(); | ||||||
|  |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     const onPause = (e) => { |     const onPause = (e) => { | ||||||
|         e.preventDefault(); |         e.preventDefault(); | ||||||
|         e.stopPropagation(); |         e.stopPropagation(); | ||||||
|         wavesurfer.current.pause(); |  | ||||||
|         setIsPlaying(false); |         setIsPlaying(false); | ||||||
|  |         if (wavesurfer.current) wavesurfer.current.pause(); | ||||||
|  |         if (isChromecast) { | ||||||
|  |             const media = Chromecast.media(); | ||||||
|  |             if (media) media.pause(); | ||||||
|  |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     const onVolumeChange = (e) => { |     const onVolumeChange = (e) => { | ||||||
|         const v = Number(e.target.value); |         const v = Number(e.target.value); | ||||||
|         settings_put("volume", v); |         settings_put("volume", v); | ||||||
|         setVolume(v); |         setVolume(v); | ||||||
|         wavesurfer.current.setVolume(v / 100); |         if (isChromecast) { | ||||||
|  |             const session = Chromecast.session() | ||||||
|  |             if (session) session.setVolume(v / 100); | ||||||
|  |         } else wavesurfer.current.setVolume(v / 100); | ||||||
|     }; |     }; | ||||||
|     const onVolumeClick = () => { |     const onVolumeClick = () => { | ||||||
|         onVolumeChange({ target: { value: 0 }}); |         onVolumeChange({ target: { value: 0 }}); | ||||||
| @ -95,13 +209,23 @@ export function AudioPlayer({ filename, data }) { | |||||||
|                 <NgIf cond={error === null}> |                 <NgIf cond={error === null}> | ||||||
|                     <div className="audioplayer_box"> |                     <div className="audioplayer_box"> | ||||||
|                         <NgIf cond={isLoading}> |                         <NgIf cond={isLoading}> | ||||||
|                             <div className="audioplayer_loader" style={{width: purcentLoading + "%"}}></div> |                             { | ||||||
|  |                                 isChromecast ? ( | ||||||
|  |                                     <div className="chromecast_loader"> | ||||||
|                                         <Icon name="loading" /> |                                         <Icon name="loading" /> | ||||||
|  |                                     </div> | ||||||
|  |                                 ) : ( | ||||||
|  |                                     <React.Fragment> | ||||||
|  |                                         <div className="audioplayer_loader" style={{width: purcentLoading + "%"}}></div> | ||||||
|                                         <span className="percent">{purcentLoading}%</span> |                                         <span className="percent">{purcentLoading}%</span> | ||||||
|  |                                         <Icon name="loading" /> | ||||||
|  |                                     </React.Fragment> | ||||||
|  |                                 ) | ||||||
|  |                             } | ||||||
|                         </NgIf> |                         </NgIf> | ||||||
|                         <div id="waveform"></div> |                         <div id="waveform"></div> | ||||||
|                         <div className="audioplayer_control" style={{ opacity: isLoading? 0 : 1 }}> |                         <div className="audioplayer_control" style={{ opacity: isLoading? 0 : 1 }}> | ||||||
|                             <div className="buttons"> |                             <div className="buttons no-select"> | ||||||
|                                 { |                                 { | ||||||
|                                     isPlaying ? ( |                                     isPlaying ? ( | ||||||
|                                         <span onClick={onPause}> |                                         <span onClick={onPause}> | ||||||
| @ -119,7 +243,7 @@ export function AudioPlayer({ filename, data }) { | |||||||
|  |  | ||||||
|                             <div className="timecode"> |                             <div className="timecode"> | ||||||
|                                 <span id="currentTime">00:00:00</span> |                                 <span id="currentTime">00:00:00</span> | ||||||
|                                 <span id="separator">/</span> |                                 <span id="separator" className="no-select">/</span> | ||||||
|                                 <span id="totalDuration">00:00:00</span> |                                 <span id="totalDuration">00:00:00</span> | ||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
|  | |||||||
| @ -90,16 +90,23 @@ | |||||||
|                 top: 0; |                 top: 0; | ||||||
|                 left: 0; |                 left: 0; | ||||||
|             } |             } | ||||||
|  |             .component_icon[alt="loading"] { | ||||||
|  |                 position: absolute; | ||||||
|  |                 margin: 50px 0px | ||||||
|  |             } | ||||||
|  |             .chromecast_loader .component_icon[alt="loading"] { | ||||||
|  |                 margin: 0; | ||||||
|  |                 right: 20px; | ||||||
|  |                 top: 20px; | ||||||
|  |                 width: 30px; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             .percent { |             .percent { | ||||||
|                 position: absolute; |                 position: absolute; | ||||||
|                 margin: 100px 0px; |                 margin: 100px 0px; | ||||||
|                 width: 120px; |                 width: 120px; | ||||||
|                 font-size: 1.4rem; |                 font-size: 1.4rem; | ||||||
|             } |             } | ||||||
|             .component_icon[alt="loading"] { |  | ||||||
|                 position: absolute; |  | ||||||
|                 margin: 50px 0px |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,8 +4,8 @@ import ReactCSSTransitionGroup from "react-addons-css-transition-group"; | |||||||
|  |  | ||||||
| import { MenuBar } from "./menubar"; | import { MenuBar } from "./menubar"; | ||||||
| import { Bundle, Icon, NgIf, Loader, EventEmitter, EventReceiver } from "../../components/"; | import { Bundle, Icon, NgIf, Loader, EventEmitter, EventReceiver } from "../../components/"; | ||||||
| import { alert, randomString, objectGet, notify, getMimeType, currentShare } from "../../helpers/"; | import { alert, randomString, notify, getMimeType, currentShare } from "../../helpers/"; | ||||||
| import { Session } from "../../model/"; | import { Chromecast } from "../../model/"; | ||||||
| import { Pager } from "./pager"; | import { Pager } from "./pager"; | ||||||
| import { t } from "../../locales/"; | import { t } from "../../locales/"; | ||||||
| import "./imageviewer.scss"; | import "./imageviewer.scss"; | ||||||
| @ -67,25 +67,10 @@ export function ImageViewerComponent({ filename, data, path, subscribe, unsubscr | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     const chromecastHandler = (event) => { |     const chromecastHandler = (event) => { | ||||||
|         const cSession = cast.framework.CastContext.getInstance().getCurrentSession() |         const session = Chromecast.session(); | ||||||
|         if (!cSession) return; |         if (!session) return; | ||||||
|  |  | ||||||
|         const createLink = () => { |         const link = Chromecast.createLink(data); | ||||||
|             const shareID = currentShare(); |  | ||||||
|             const origin = location.origin; |  | ||||||
|             if (shareID) { |  | ||||||
|                 const target = new URL(origin + data); |  | ||||||
|                 target.searchParams.append("share", shareID); |  | ||||||
|                 return Promise.resolve(target.toString()); |  | ||||||
|             } |  | ||||||
|             return Session.currentUser().then(({ authorization }) => { |  | ||||||
|                 const target = new URL(origin + data); |  | ||||||
|                 target.searchParams.append("authorization", authorization); |  | ||||||
|                 return target.toString() |  | ||||||
|             }); |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         return createLink().then((link) => { |  | ||||||
|         const media = new chrome.cast.media.MediaInfo( |         const media = new chrome.cast.media.MediaInfo( | ||||||
|             link, |             link, | ||||||
|             getMimeType(filename), |             getMimeType(filename), | ||||||
| @ -93,19 +78,19 @@ export function ImageViewerComponent({ filename, data, path, subscribe, unsubscr | |||||||
|         media.metadata = new chrome.cast.media.PhotoMediaMetadata(); |         media.metadata = new chrome.cast.media.PhotoMediaMetadata(); | ||||||
|         media.metadata.title = filename; |         media.metadata.title = filename; | ||||||
|         media.metadata.images = [ |         media.metadata.images = [ | ||||||
|                 new chrome.cast.Image(origin + "/assets/icons/photo.png"), |             new chrome.cast.Image(Chromecast.origin() + "/assets/icons/photo.png"), | ||||||
|         ]; |         ]; | ||||||
|             return cSession.loadMedia(new chrome.cast.media.LoadRequest(media)); |         Chromecast.createRequest(media) | ||||||
|         }).catch((err) => { |             .then((req) => session.loadMedia(req)) | ||||||
|             notify.send(err && err.message, "error"); |             .catch((err) => { | ||||||
|  |                 console.error(err) | ||||||
|  |                 notify.send(t("Cannot establish a connection"), "error"); | ||||||
|             }); |             }); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     useEffect(() => { |     useEffect(() => { | ||||||
|         if (!objectGet(window.chrome, ["cast", "isAvailable"])) { |         const context = Chromecast.context(); | ||||||
|             return; |         if (!context) return; | ||||||
|         } |  | ||||||
|         const context = cast.framework.CastContext.getInstance(); |  | ||||||
|         document.getElementById("chromecast-target").append(document.createElement("google-cast-launcher")); |         document.getElementById("chromecast-target").append(document.createElement("google-cast-launcher")); | ||||||
|         context.addEventListener( |         context.addEventListener( | ||||||
|             cast.framework.CastContextEventType.SESSION_STATE_CHANGED, |             cast.framework.CastContextEventType.SESSION_STATE_CHANGED, | ||||||
| @ -158,6 +143,7 @@ export function ImageViewerComponent({ filename, data, path, subscribe, unsubscr | |||||||
|                 ref={$container} |                 ref={$container} | ||||||
|                 className={ |                 className={ | ||||||
|                     "component_image_container" + |                     "component_image_container" + | ||||||
|  |                         (state.draggable ? "" : " component_image_no_pager") + | ||||||
|                         (document.webkitIsFullScreen || document.mozFullScreen ? " fullscreen" : "") |                         (document.webkitIsFullScreen || document.mozFullScreen ? " fullscreen" : "") | ||||||
|                 } |                 } | ||||||
|             > |             > | ||||||
|  | |||||||
| @ -26,8 +26,10 @@ | |||||||
|         background: #525659; |         background: #525659; | ||||||
|         overflow: hidden; |         overflow: hidden; | ||||||
|         padding: 15px 10px 65px 10px; |         padding: 15px 10px 65px 10px; | ||||||
|  |         &.component_image_no_pager { padding-bottom: 15px; } | ||||||
|         @media screen and (max-height: 410px) { |         @media screen and (max-height: 410px) { | ||||||
|             padding: 5px 0px 40px 10px; |             padding: 5px 0px 40px 10px; | ||||||
|  |             &.component_image_no_pager { padding-bottom: 5px; } | ||||||
|             .component_pager .wrapper{ |             .component_pager .wrapper{ | ||||||
|                 > span{padding: 2px 5px;} |                 > span{padding: 2px 5px;} | ||||||
|                 padding: 5px 0; |                 padding: 5px 0; | ||||||
|  | |||||||
| @ -34,7 +34,8 @@ | |||||||
|     max-height: 500px; |     max-height: 500px; | ||||||
|  |  | ||||||
|     .vjs-control-bar{ |     .vjs-control-bar{ | ||||||
|         background: rgba(255,255,255,0.2); |         background: black; | ||||||
|  |         background: linear-gradient(transparent 20%, #00000099); | ||||||
|     } |     } | ||||||
|     .vjs-load-progress div{ |     .vjs-load-progress div{ | ||||||
|         background: var(--primary); |         background: var(--primary); | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Mickael Kerjean
					Mickael Kerjean