Some minor W2G and general changes
This commit is contained in:
parent
516bcefc36
commit
6b623a4d11
13 changed files with 127 additions and 39 deletions
|
@ -1,6 +1,9 @@
|
||||||
# Changelog:
|
# Changelog:
|
||||||
|
* **09.08.20**
|
||||||
|
- Added a "watch to gather" context menu entry for clients
|
||||||
|
|
||||||
* **08.08.20**
|
* **08.08.20**
|
||||||
- Added a watch to gether mode
|
- Added a watch to gather mode
|
||||||
- Added API support for the popout able browsers for the native client
|
- Added API support for the popout able browsers for the native client
|
||||||
|
|
||||||
* **05.08.20**
|
* **05.08.20**
|
||||||
|
|
4
shared/img/icon_w2g.svg
Normal file
4
shared/img/icon_w2g.svg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="100%" version="1.1" viewBox="0 0 68 48" width="100%">
|
||||||
|
<path d="M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z" fill="#f00"></path>
|
||||||
|
<path d="M 45,24 27,14 27,34" fill="#fff"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 506 B |
|
@ -36,7 +36,7 @@ import {guid} from "tc-shared/crypto/uid";
|
||||||
import {ServerEventLog} from "tc-shared/ui/frames/log/ServerEventLog";
|
import {ServerEventLog} from "tc-shared/ui/frames/log/ServerEventLog";
|
||||||
import {EventType} from "tc-shared/ui/frames/log/Definitions";
|
import {EventType} from "tc-shared/ui/frames/log/Definitions";
|
||||||
import {PluginCmdRegistry} from "tc-shared/connection/PluginCmdHandler";
|
import {PluginCmdRegistry} from "tc-shared/connection/PluginCmdHandler";
|
||||||
import {W2GPluginCmdHandler} from "tc-shared/video-viewer/W2GPluginHandler";
|
import {W2GPluginCmdHandler} from "tc-shared/video-viewer/W2GPlugin";
|
||||||
|
|
||||||
export enum DisconnectReason {
|
export enum DisconnectReason {
|
||||||
HANDLER_DESTROYED,
|
HANDLER_DESTROYED,
|
||||||
|
|
|
@ -16,6 +16,14 @@ export interface ClientGlobalControlEvents {
|
||||||
connection?: ConnectionHandler
|
connection?: ConnectionHandler
|
||||||
},
|
},
|
||||||
|
|
||||||
|
action_w2g: {
|
||||||
|
following: number,
|
||||||
|
handlerId: string
|
||||||
|
} | {
|
||||||
|
videoUrl: string,
|
||||||
|
handlerId: string
|
||||||
|
}
|
||||||
|
|
||||||
/* some more specific window openings */
|
/* some more specific window openings */
|
||||||
action_open_window_connect: {
|
action_open_window_connect: {
|
||||||
new_tab: boolean
|
new_tab: boolean
|
||||||
|
|
|
@ -41,7 +41,7 @@ import "./ui/elements/ContextDivider";
|
||||||
import "./ui/elements/Tab";
|
import "./ui/elements/Tab";
|
||||||
import "./connection/CommandHandler";
|
import "./connection/CommandHandler";
|
||||||
import {ConnectRequestData} from "tc-shared/ipc/ConnectHandler";
|
import {ConnectRequestData} from "tc-shared/ipc/ConnectHandler";
|
||||||
import {openVideoViewer} from "tc-shared/video-viewer/Controller";
|
import "./video-viewer/Controller";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
@ -497,8 +497,6 @@ function main() {
|
||||||
modal.close_listener.push(() => settings.changeGlobal(Settings.KEY_USER_IS_NEW, false));
|
modal.close_listener.push(() => settings.changeGlobal(Settings.KEY_USER_IS_NEW, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
(window as any).spawnVideoPopout = openVideoViewer;
|
|
||||||
|
|
||||||
//spawnVideoPopout(server_connections.active_connection(), "https://www.youtube.com/watch?v=9683D18fyvs");
|
//spawnVideoPopout(server_connections.active_connection(), "https://www.youtube.com/watch?v=9683D18fyvs");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ import {HTMLRenderer} from "tc-shared/ui/react-elements/HTMLRenderer";
|
||||||
import * as contextmenu from "tc-shared/ui/elements/ContextMenu";
|
import * as contextmenu from "tc-shared/ui/elements/ContextMenu";
|
||||||
import {spawn_context_menu} from "tc-shared/ui/elements/ContextMenu";
|
import {spawn_context_menu} from "tc-shared/ui/elements/ContextMenu";
|
||||||
import {copy_to_clipboard} from "tc-shared/utils/helpers";
|
import {copy_to_clipboard} from "tc-shared/utils/helpers";
|
||||||
import {openVideoViewer} from "tc-shared/video-viewer/Controller";
|
|
||||||
import {server_connections} from "tc-shared/ui/frames/connection_handlers";
|
import {server_connections} from "tc-shared/ui/frames/connection_handlers";
|
||||||
|
import {global_client_actions} from "tc-shared/events/GlobalEvents";
|
||||||
|
|
||||||
const playIcon = require("./yt-play-button.svg");
|
const playIcon = require("./yt-play-button.svg");
|
||||||
const cssStyle = require("./youtube.scss");
|
const cssStyle = require("./youtube.scss");
|
||||||
|
@ -36,7 +36,10 @@ loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, {
|
||||||
|
|
||||||
spawn_context_menu(event.pageX, event.pageY, {
|
spawn_context_menu(event.pageX, event.pageY, {
|
||||||
callback: () => {
|
callback: () => {
|
||||||
openVideoViewer(server_connections.active_connection(), text);
|
global_client_actions.fire("action_w2g", {
|
||||||
|
videoUrl: text,
|
||||||
|
handlerId: server_connections.active_connection().handlerId
|
||||||
|
});
|
||||||
},
|
},
|
||||||
name: tr("Watch video"),
|
name: tr("Watch video"),
|
||||||
type: contextmenu.MenuEntryType.ENTRY,
|
type: contextmenu.MenuEntryType.ENTRY,
|
||||||
|
@ -59,7 +62,10 @@ loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, {
|
||||||
>
|
>
|
||||||
<img draggable={false} src={"https://img.youtube.com/vi/" + result[1] + "/hqdefault.jpg"} alt={"Video thumbnail"} title={tra("Youtube video {}", result[1])} />
|
<img draggable={false} src={"https://img.youtube.com/vi/" + result[1] + "/hqdefault.jpg"} alt={"Video thumbnail"} title={tra("Youtube video {}", result[1])} />
|
||||||
<button className={cssStyle.playButton} onClick={() => {
|
<button className={cssStyle.playButton} onClick={() => {
|
||||||
openVideoViewer(server_connections.active_connection(), text);
|
global_client_actions.fire("action_w2g", {
|
||||||
|
videoUrl: text,
|
||||||
|
handlerId: server_connections.active_connection().handlerId
|
||||||
|
});
|
||||||
}}>
|
}}>
|
||||||
<HTMLRenderer purify={false}>{playIcon}</HTMLRenderer>
|
<HTMLRenderer purify={false}>{playIcon}</HTMLRenderer>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -27,6 +27,8 @@ import {ChannelTreeEntry, ChannelTreeEntryEvents} from "tc-shared/ui/TreeEntry";
|
||||||
import {spawnClientVolumeChange, spawnMusicBotVolumeChange} from "tc-shared/ui/modal/ModalChangeVolumeNew";
|
import {spawnClientVolumeChange, spawnMusicBotVolumeChange} from "tc-shared/ui/modal/ModalChangeVolumeNew";
|
||||||
import {spawnPermissionEditorModal} from "tc-shared/ui/modal/permission/ModalPermissionEditor";
|
import {spawnPermissionEditorModal} from "tc-shared/ui/modal/permission/ModalPermissionEditor";
|
||||||
import {EventClient, EventType} from "tc-shared/ui/frames/log/Definitions";
|
import {EventClient, EventType} from "tc-shared/ui/frames/log/Definitions";
|
||||||
|
import {W2GPluginCmdHandler} from "tc-shared/video-viewer/W2GPlugin";
|
||||||
|
import {global_client_actions} from "tc-shared/events/GlobalEvents";
|
||||||
|
|
||||||
export enum ClientType {
|
export enum ClientType {
|
||||||
CLIENT_VOICE,
|
CLIENT_VOICE,
|
||||||
|
@ -508,6 +510,8 @@ export class ClientEntry extends ChannelTreeEntry<ClientEvents> {
|
||||||
}
|
}
|
||||||
|
|
||||||
showContextMenu(x: number, y: number, on_close: () => void = undefined) {
|
showContextMenu(x: number, y: number, on_close: () => void = undefined) {
|
||||||
|
const w2gPlugin = this.channelTree.client.getPluginCmdRegistry().getPluginHandler<W2GPluginCmdHandler>(W2GPluginCmdHandler.kPluginChannel);
|
||||||
|
|
||||||
let trigger_close = true;
|
let trigger_close = true;
|
||||||
contextmenu.spawn_context_menu(x, y,
|
contextmenu.spawn_context_menu(x, y,
|
||||||
...this.contextmenu_info(), {
|
...this.contextmenu_info(), {
|
||||||
|
@ -519,6 +523,17 @@ export class ClientEntry extends ChannelTreeEntry<ClientEvents> {
|
||||||
callback: () => {
|
callback: () => {
|
||||||
this.open_text_chat();
|
this.open_text_chat();
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
type: contextmenu.MenuEntryType.ENTRY,
|
||||||
|
name: tr("Watch clients video"),
|
||||||
|
icon_path: "img/icon_w2g.svg",
|
||||||
|
visible: w2gPlugin?.getCurrentWatchers().findIndex(e => e.clientId === this.clientId()) !== -1,
|
||||||
|
callback: () => {
|
||||||
|
global_client_actions.fire("action_w2g", {
|
||||||
|
following: this.clientId(),
|
||||||
|
handlerId: this.channelTree.client.handlerId
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
contextmenu.Entry.HR(),
|
contextmenu.Entry.HR(),
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@ import {ClientEntry} from "tc-shared/ui/client";
|
||||||
import {ConnectionHandler, ConnectionState} from "tc-shared/ConnectionHandler";
|
import {ConnectionHandler, ConnectionState} from "tc-shared/ConnectionHandler";
|
||||||
import {EventHandler, Registry} from "tc-shared/events";
|
import {EventHandler, Registry} from "tc-shared/events";
|
||||||
import {
|
import {
|
||||||
|
PrivateConversationManagerEvents,
|
||||||
PrivateConversationInfo,
|
PrivateConversationInfo,
|
||||||
PrivateConversationUIEvents
|
PrivateConversationUIEvents
|
||||||
} from "tc-shared/ui/frames/side/PrivateConversationDefinitions";
|
} from "tc-shared/ui/frames/side/PrivateConversationDefinitions";
|
||||||
|
@ -252,6 +253,9 @@ export class PrivateConversation extends AbstractChat<PrivateConversationUIEvent
|
||||||
/* TODO: Move this somehow to the client itself? */
|
/* TODO: Move this somehow to the client itself? */
|
||||||
if(this.activeClient instanceof ClientEntry)
|
if(this.activeClient instanceof ClientEntry)
|
||||||
this.activeClient.setUnread(timestamp !== undefined);
|
this.activeClient.setUnread(timestamp !== undefined);
|
||||||
|
|
||||||
|
/* TODO: Eliminate this cross reference? */
|
||||||
|
this.connection.side_bar.info_frame().update_chat_counter();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected canClientAccessChat(): boolean {
|
protected canClientAccessChat(): boolean {
|
||||||
|
@ -311,6 +315,7 @@ export class PrivateConversation extends AbstractChat<PrivateConversationUIEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PrivateConversationManager extends AbstractChatManager<PrivateConversationUIEvents> {
|
export class PrivateConversationManager extends AbstractChatManager<PrivateConversationUIEvents> {
|
||||||
|
public readonly events: Registry<PrivateConversationManagerEvents>;
|
||||||
public readonly htmlTag: HTMLDivElement;
|
public readonly htmlTag: HTMLDivElement;
|
||||||
public readonly connection: ConnectionHandler;
|
public readonly connection: ConnectionHandler;
|
||||||
|
|
||||||
|
@ -322,6 +327,7 @@ export class PrivateConversationManager extends AbstractChatManager<PrivateConve
|
||||||
constructor(connection: ConnectionHandler) {
|
constructor(connection: ConnectionHandler) {
|
||||||
super();
|
super();
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
|
this.events = new Registry<PrivateConversationManagerEvents>();
|
||||||
|
|
||||||
this.htmlTag = document.createElement("div");
|
this.htmlTag = document.createElement("div");
|
||||||
this.htmlTag.style.display = "flex";
|
this.htmlTag.style.display = "flex";
|
||||||
|
|
|
@ -10,6 +10,8 @@ export type ModalType = "error" | "warning" | "info" | "none";
|
||||||
|
|
||||||
export interface ModalOptions {
|
export interface ModalOptions {
|
||||||
destroyOnClose?: boolean;
|
destroyOnClose?: boolean;
|
||||||
|
|
||||||
|
defaultSize?: { width: number, height: number };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModalEvents {
|
export interface ModalEvents {
|
||||||
|
|
|
@ -4,9 +4,12 @@ import {spawnExternalModal} from "tc-shared/ui/react-elements/external-modal";
|
||||||
import {EventHandler, Registry} from "tc-shared/events";
|
import {EventHandler, Registry} from "tc-shared/events";
|
||||||
import {VideoViewerEvents} from "./Definitions";
|
import {VideoViewerEvents} from "./Definitions";
|
||||||
import {ConnectionHandler} from "tc-shared/ConnectionHandler";
|
import {ConnectionHandler} from "tc-shared/ConnectionHandler";
|
||||||
import {W2GPluginCmdHandler, W2GWatcher, W2GWatcherFollower} from "tc-shared/video-viewer/W2GPluginHandler";
|
import {W2GPluginCmdHandler, W2GWatcher, W2GWatcherFollower} from "tc-shared/video-viewer/W2GPlugin";
|
||||||
import {ModalController} from "tc-shared/ui/react-elements/Modal";
|
import {ModalController} from "tc-shared/ui/react-elements/Modal";
|
||||||
import {settings, Settings} from "tc-shared/settings";
|
import {settings, Settings} from "tc-shared/settings";
|
||||||
|
import {global_client_actions} from "tc-shared/events/GlobalEvents";
|
||||||
|
import {server_connections} from "tc-shared/ui/frames/connection_handlers";
|
||||||
|
import {createErrorModal} from "tc-shared/ui/elements/Modal";
|
||||||
|
|
||||||
const parseWatcherId = (id: string): { clientId: number, clientUniqueId: string} => {
|
const parseWatcherId = (id: string): { clientId: number, clientUniqueId: string} => {
|
||||||
const [ clientIdString, clientUniqueId ] = id.split(" - ");
|
const [ clientIdString, clientUniqueId ] = id.split(" - ");
|
||||||
|
@ -26,7 +29,7 @@ class VideoViewer {
|
||||||
private unregisterCallbacks = [];
|
private unregisterCallbacks = [];
|
||||||
private destroyCalled = false;
|
private destroyCalled = false;
|
||||||
|
|
||||||
constructor(connection: ConnectionHandler, initialUrl: string) {
|
constructor(connection: ConnectionHandler) {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
|
|
||||||
this.events = new Registry<VideoViewerEvents>();
|
this.events = new Registry<VideoViewerEvents>();
|
||||||
|
@ -37,8 +40,7 @@ class VideoViewer {
|
||||||
throw tr("Missing video viewer plugin");
|
throw tr("Missing video viewer plugin");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modal = spawnExternalModal("video-viewer", this.events, { handlerId: connection.handlerId, url: initialUrl });
|
this.modal = spawnExternalModal("video-viewer", this.events, { handlerId: connection.handlerId });
|
||||||
this.setWatchingVideo(initialUrl);
|
|
||||||
|
|
||||||
this.registerPluginListeners();
|
this.registerPluginListeners();
|
||||||
this.plugin.getCurrentWatchers().forEach(watcher => this.registerWatcherEvents(watcher));
|
this.plugin.getCurrentWatchers().forEach(watcher => this.registerWatcherEvents(watcher));
|
||||||
|
@ -64,8 +66,16 @@ class VideoViewer {
|
||||||
if(this.currentVideoUrl === url)
|
if(this.currentVideoUrl === url)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.events.fire_async("notify_following", { watcherId: undefined });
|
this.plugin.setLocalWatcherStatus(url, { status: "paused" });
|
||||||
this.events.fire_async("notify_video", { url: url });
|
this.events.fire_async("notify_video", { url: url }); /* notify the new url */
|
||||||
|
}
|
||||||
|
|
||||||
|
setFollowing(target: W2GWatcher) {
|
||||||
|
if(this.plugin.getLocalFollowingWatcher() === target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.plugin.setLocalFollowing(target, { status: "paused" });
|
||||||
|
this.events.fire_async("notify_video", { url: target.getCurrentVideo() }); /* notify the new url */
|
||||||
}
|
}
|
||||||
|
|
||||||
async open() {
|
async open() {
|
||||||
|
@ -291,45 +301,57 @@ class VideoViewer {
|
||||||
settings.changeGlobal(Settings.KEY_W2G_SIDEBAR_COLLAPSED, !event.shown);
|
settings.changeGlobal(Settings.KEY_W2G_SIDEBAR_COLLAPSED, !event.shown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@EventHandler<VideoViewerEvents>("notify_video")
|
@EventHandler<VideoViewerEvents>("notify_video")
|
||||||
private handleVideo(event: VideoViewerEvents["notify_video"]) {
|
private handleVideo(event: VideoViewerEvents["notify_video"]) {
|
||||||
if(this.currentVideoUrl === event.url)
|
if(this.currentVideoUrl === event.url)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.currentVideoUrl = event.url;
|
this.currentVideoUrl = event.url;
|
||||||
const following = this.plugin.getLocalFollowingWatcher();
|
|
||||||
if(following)
|
|
||||||
this.plugin.setLocalFollowing(following, { status: "paused" });
|
|
||||||
else
|
|
||||||
this.plugin.setLocalWatcherStatus(this.currentVideoUrl, { status: "paused" });
|
|
||||||
this.notifyWatcherList();
|
this.notifyWatcherList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentVideoViewer: VideoViewer;
|
let currentVideoViewer: VideoViewer;
|
||||||
|
|
||||||
export function openVideoViewer(connection: ConnectionHandler, url: string) {
|
global_client_actions.on("action_w2g", event => {
|
||||||
if(currentVideoViewer?.connection === connection) {
|
const connection = server_connections.findConnection(event.handlerId);
|
||||||
currentVideoViewer.setWatchingVideo(url);
|
if(connection === undefined) return;
|
||||||
currentVideoViewer.open(); /* draw focus */
|
|
||||||
return;
|
const plugin = connection.getPluginCmdRegistry().getPluginHandler<W2GPluginCmdHandler>(W2GPluginCmdHandler.kPluginChannel);
|
||||||
} else if(currentVideoViewer) {
|
|
||||||
|
let watcher: W2GWatcher;
|
||||||
|
if('following' in event) {
|
||||||
|
watcher = plugin.getCurrentWatchers().find(e => e.clientId === event.following);
|
||||||
|
if(!watcher) {
|
||||||
|
createErrorModal(tr("Target client isn't watching anything"), tr("The target client isn't watching anything.")).open();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentVideoViewer && currentVideoViewer.connection !== connection) {
|
||||||
currentVideoViewer.destroy();
|
currentVideoViewer.destroy();
|
||||||
currentVideoViewer = undefined;
|
currentVideoViewer = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentVideoViewer = new VideoViewer(connection, url);
|
if(!currentVideoViewer) {
|
||||||
currentVideoViewer.events.on("notify_destroy", () => {
|
currentVideoViewer = new VideoViewer(connection);
|
||||||
currentVideoViewer = undefined;
|
currentVideoViewer.events.on("notify_destroy", () => {
|
||||||
});
|
currentVideoViewer = undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if('following' in event) {
|
||||||
|
currentVideoViewer.setFollowing(watcher);
|
||||||
|
} else {
|
||||||
|
currentVideoViewer.setWatchingVideo(event.videoUrl);
|
||||||
|
}
|
||||||
|
|
||||||
currentVideoViewer.open().catch(error => {
|
currentVideoViewer.open().catch(error => {
|
||||||
logError(LogCategory.GENERAL, tr("Failed to open video viewer: %o"), error);
|
logError(LogCategory.GENERAL, tr("Failed to open video viewer: %o"), error);
|
||||||
currentVideoViewer.destroy();
|
currentVideoViewer.destroy();
|
||||||
currentVideoViewer = undefined;
|
currentVideoViewer = undefined;
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
window.onbeforeunload = () => {
|
window.onbeforeunload = () => {
|
||||||
currentVideoViewer?.destroy();
|
currentVideoViewer?.destroy();
|
||||||
|
|
|
@ -127,7 +127,7 @@ const WatcherInfo = React.memo((props: { events: Registry<VideoViewerEvents>, wa
|
||||||
if(Math.abs(expectedPlaytime - currentPlaytime) > 2) {
|
if(Math.abs(expectedPlaytime - currentPlaytime) > 2) {
|
||||||
setStatus(Object.assign({ timestamp: Date.now() }, event.status));
|
setStatus(Object.assign({ timestamp: Date.now() }, event.status));
|
||||||
} else {
|
} else {
|
||||||
/* keep the last value, its still close enought */
|
/* keep the last value, its still close enough */
|
||||||
setStatus({
|
setStatus({
|
||||||
status: "playing",
|
status: "playing",
|
||||||
timestamp: status.timestamp,
|
timestamp: status.timestamp,
|
||||||
|
@ -305,6 +305,8 @@ const PlayerController = React.memo((props: { events: Registry<VideoViewerEvents
|
||||||
const [ masterPlayerState, setWatcherPlayerState ] = useState<"playing" | "buffering" | "paused" | "stopped">("stopped");
|
const [ masterPlayerState, setWatcherPlayerState ] = useState<"playing" | "buffering" | "paused" | "stopped">("stopped");
|
||||||
const watcherTimestamp = useRef<number>();
|
const watcherTimestamp = useRef<number>();
|
||||||
|
|
||||||
|
const videoEnded = useRef(false);
|
||||||
|
|
||||||
const [ forcePause, setForcePause ] = useState(false);
|
const [ forcePause, setForcePause ] = useState(false);
|
||||||
|
|
||||||
props.events.reactUse("notify_following", event => setMode(event.watcherId === undefined ? "watcher" : "follower"));
|
props.events.reactUse("notify_following", event => setMode(event.watcherId === undefined ? "watcher" : "follower"));
|
||||||
|
@ -375,10 +377,19 @@ const PlayerController = React.memo((props: { events: Registry<VideoViewerEvents
|
||||||
kLogPlayerEvents && log.trace(LogCategory.GENERAL, tr("ReactPlayer::onEnded()"));
|
kLogPlayerEvents && log.trace(LogCategory.GENERAL, tr("ReactPlayer::onEnded()"));
|
||||||
playerState.current = "stopped";
|
playerState.current = "stopped";
|
||||||
props.events.fire("notify_local_status", { status: { status: "stopped" } });
|
props.events.fire("notify_local_status", { status: { status: "stopped" } });
|
||||||
|
|
||||||
|
videoEnded.current = true;
|
||||||
|
player.current.seekTo(0, "seconds");
|
||||||
}}
|
}}
|
||||||
|
|
||||||
onPause={() => {
|
onPause={() => {
|
||||||
kLogPlayerEvents && log.trace(LogCategory.GENERAL, tr("ReactPlayer::onPause()"));
|
kLogPlayerEvents && log.trace(LogCategory.GENERAL, tr("ReactPlayer::onPause()"));
|
||||||
|
|
||||||
|
if(videoEnded.current) {
|
||||||
|
videoEnded.current = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
playerState.current = "paused";
|
playerState.current = "paused";
|
||||||
props.events.fire("notify_local_status", { status: { status: "paused" } });
|
props.events.fire("notify_local_status", { status: { status: "paused" } });
|
||||||
}}
|
}}
|
||||||
|
@ -386,6 +397,11 @@ const PlayerController = React.memo((props: { events: Registry<VideoViewerEvents
|
||||||
onPlay={() => {
|
onPlay={() => {
|
||||||
kLogPlayerEvents && log.trace(LogCategory.GENERAL, tr("ReactPlayer::onPlay()"));
|
kLogPlayerEvents && log.trace(LogCategory.GENERAL, tr("ReactPlayer::onPlay()"));
|
||||||
|
|
||||||
|
if(videoEnded.current) {
|
||||||
|
/* it's just the seek to the beginning */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(mode === "follower") {
|
if(mode === "follower") {
|
||||||
if(masterPlayerState !== "playing") {
|
if(masterPlayerState !== "playing") {
|
||||||
setForcePause(true);
|
setForcePause(true);
|
||||||
|
@ -399,6 +415,7 @@ const PlayerController = React.memo((props: { events: Registry<VideoViewerEvents
|
||||||
log.debug(LogCategory.GENERAL, tr("Player started, at second %d. Watcher is at %s. So sync: %o"), currentSeconds, expectedSeconds, doSync);
|
log.debug(LogCategory.GENERAL, tr("Player started, at second %d. Watcher is at %s. So sync: %o"), currentSeconds, expectedSeconds, doSync);
|
||||||
doSync && player.current.seekTo(expectedSeconds, "seconds");
|
doSync && player.current.seekTo(expectedSeconds, "seconds");
|
||||||
}
|
}
|
||||||
|
|
||||||
playerState.current = "playing";
|
playerState.current = "playing";
|
||||||
props.events.fire("notify_local_status", { status: { status: "playing", timestampBuffer: currentTime.current.buffer, timestampPlay: currentTime.current.play } });
|
props.events.fire("notify_local_status", { status: { status: "playing", timestampBuffer: currentTime.current.buffer, timestampPlay: currentTime.current.play } });
|
||||||
}}
|
}}
|
||||||
|
@ -436,6 +453,13 @@ const PlayerController = React.memo((props: { events: Registry<VideoViewerEvents
|
||||||
loop={false}
|
loop={false}
|
||||||
light={false}
|
light={false}
|
||||||
|
|
||||||
|
config={{
|
||||||
|
youtube: {
|
||||||
|
playerVars: {
|
||||||
|
rel: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
playing={mode === "watcher" ? undefined : masterPlayerState === "playing" || forcePause}
|
playing={mode === "watcher" ? undefined : masterPlayerState === "playing" || forcePause}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -195,6 +195,8 @@ export class W2GPluginCmdHandler extends PluginCmdHandler {
|
||||||
static readonly kStatusUpdateTimeout = 10000;
|
static readonly kStatusUpdateTimeout = 10000;
|
||||||
|
|
||||||
readonly events: Registry<W2GEvents>;
|
readonly events: Registry<W2GEvents>;
|
||||||
|
private readonly callbackWatcherEvents;
|
||||||
|
|
||||||
private currentWatchers: InternalW2GWatcher[] = [];
|
private currentWatchers: InternalW2GWatcher[] = [];
|
||||||
|
|
||||||
private localPlayerStatus: PlayerStatus;
|
private localPlayerStatus: PlayerStatus;
|
||||||
|
@ -202,8 +204,6 @@ export class W2GPluginCmdHandler extends PluginCmdHandler {
|
||||||
private localFollowing: InternalW2GWatcher | undefined;
|
private localFollowing: InternalW2GWatcher | undefined;
|
||||||
private localStatusUpdateTimer: number;
|
private localStatusUpdateTimer: number;
|
||||||
|
|
||||||
private callbackWatcherEvents;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(W2GPluginCmdHandler.kPluginChannel);
|
super(W2GPluginCmdHandler.kPluginChannel);
|
||||||
this.events = new Registry<W2GEvents>();
|
this.events = new Registry<W2GEvents>();
|
|
@ -89,15 +89,15 @@ class ExternalModalController extends AbstractExternalModalController {
|
||||||
"loader-abort": __build.mode === "debug" ? 1 : 0,
|
"loader-abort": __build.mode === "debug" ? 1 : 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const options = this.getOptions();
|
||||||
const features = {
|
const features = {
|
||||||
status: "no",
|
status: "no",
|
||||||
location: "no",
|
location: "no",
|
||||||
toolbar: "no",
|
toolbar: "no",
|
||||||
menubar: "no",
|
menubar: "no",
|
||||||
/*
|
resizable: "yes",
|
||||||
width: 600,
|
width: options.defaultSize?.width,
|
||||||
height: 400
|
height: options.defaultSize?.height
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let baseUrl = location.origin + location.pathname + "?";
|
let baseUrl = location.origin + location.pathname + "?";
|
||||||
|
|
Loading…
Add table
Reference in a new issue