mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-11-01 02:43:35 +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}>
|
||||||
|
{
|
||||||
|
isChromecast ? (
|
||||||
|
<div className="chromecast_loader">
|
||||||
|
<Icon name="loading" />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<React.Fragment>
|
||||||
<div className="audioplayer_loader" style={{width: purcentLoading + "%"}}></div>
|
<div className="audioplayer_loader" style={{width: purcentLoading + "%"}}></div>
|
||||||
<Icon name="loading"/>
|
|
||||||
<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,
|
||||||
@ -157,8 +142,9 @@ export function ImageViewerComponent({ filename, data, path, subscribe, unsubscr
|
|||||||
<div
|
<div
|
||||||
ref={$container}
|
ref={$container}
|
||||||
className={
|
className={
|
||||||
"component_image_container " +
|
"component_image_container" +
|
||||||
(document.webkitIsFullScreen || document.mozFullScreen ? "fullscreen" : "")
|
(state.draggable ? "" : " component_image_no_pager") +
|
||||||
|
(document.webkitIsFullScreen || document.mozFullScreen ? " fullscreen" : "")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="images_wrapper">
|
<div className="images_wrapper">
|
||||||
|
|||||||
@ -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