mirror of
https://gitlab.com/futo-org/fcast.git
synced 2025-08-03 15:57:01 +00:00
Electron: Initial support for most of protocol v3
This commit is contained in:
parent
a83f92d874
commit
72d5c10918
13 changed files with 764 additions and 216 deletions
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { PlaybackErrorMessage, PlaybackUpdateMessage, VolumeUpdateMessage, Opcode } from 'common/Packets';
|
||||
import { PlaybackErrorMessage, PlaybackUpdateMessage, VolumeUpdateMessage, Opcode, EventMessage } from 'common/Packets';
|
||||
import { Logger, LoggerType } from 'common/Logger';
|
||||
const logger = new Logger('PlayerWindow', LoggerType.FRONTEND);
|
||||
|
||||
|
@ -25,12 +25,22 @@ declare global {
|
|||
}
|
||||
|
||||
let preloadData: Record<string, any> = {};
|
||||
preloadData.subscribedKeys = {
|
||||
keyDown: new Set<string>(),
|
||||
keyUp: new Set<string>(),
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
if (TARGET === 'electron') {
|
||||
// @ts-ignore
|
||||
const electronAPI = __non_webpack_require__('electron');
|
||||
|
||||
electronAPI.ipcRenderer.on("event-subscribed-keys-update", (_event, value: { keyDown: Set<string>, keyUp: Set<string> }) => {
|
||||
logger.info('PLAYER Updated key subscriptions', value);
|
||||
preloadData.subscribedKeys.keyDown = value.keyDown;
|
||||
preloadData.subscribedKeys.keyUp = value.keyUp;
|
||||
})
|
||||
|
||||
electronAPI.contextBridge.exposeInMainWorld('targetAPI', {
|
||||
sendPlaybackError: (error: PlaybackErrorMessage) => electronAPI.ipcRenderer.send('send-playback-error', error),
|
||||
sendPlaybackUpdate: (update: PlaybackUpdateMessage) => electronAPI.ipcRenderer.send('send-playback-update', update),
|
||||
|
@ -41,9 +51,13 @@ if (TARGET === 'electron') {
|
|||
onSeek: (callback: any) => electronAPI.ipcRenderer.on("seek", callback),
|
||||
onSetVolume: (callback: any) => electronAPI.ipcRenderer.on("setvolume", callback),
|
||||
onSetSpeed: (callback: any) => electronAPI.ipcRenderer.on("setspeed", callback),
|
||||
getSessions: () => electronAPI.ipcRenderer.invoke('get-sessions'),
|
||||
onConnect: (callback: any) => electronAPI.ipcRenderer.on('connect', callback),
|
||||
onDisconnect: (callback: any) => electronAPI.ipcRenderer.on('disconnect', callback),
|
||||
onSetPlaylistItem: (callback: any) => electronAPI.ipcRenderer.on("setplaylistitem", callback),
|
||||
emitEvent: (message: EventMessage) => electronAPI.ipcRenderer.send('emit-event', message),
|
||||
|
||||
getSessions: () => electronAPI.ipcRenderer.invoke('get-sessions'),
|
||||
getSubscribedKeys: () => preloadData.subscribedKeys,
|
||||
logger: loggerInterface,
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import dashjs from 'modules/dashjs';
|
||||
import Hls, { LevelLoadedData } from 'modules/hls.js';
|
||||
import { PlaybackUpdateMessage, PlayMessage, SeekMessage, SetSpeedMessage, SetVolumeMessage } from 'common/Packets';
|
||||
import { EventMessage, EventType, KeyEvent, MediaItem, MediaItemEvent, PlaybackUpdateMessage, PlayMessage, SeekMessage, SetSpeedMessage, SetVolumeMessage } from 'common/Packets';
|
||||
import { Player, PlayerType } from './Player';
|
||||
import * as connectionMonitor from '../ConnectionMonitor';
|
||||
import { toast, ToastIcon } from '../components/Toast';
|
||||
|
@ -35,7 +35,7 @@ function formatDuration(duration: number) {
|
|||
}
|
||||
|
||||
function sendPlaybackUpdate(updateState: number) {
|
||||
const updateMessage = new PlaybackUpdateMessage(Date.now(), player.getCurrentTime(), player.getDuration(), updateState, player.getPlaybackRate());
|
||||
const updateMessage = new PlaybackUpdateMessage(Date.now(), updateState, player.getCurrentTime(), player.getDuration(), player.getPlaybackRate());
|
||||
|
||||
if (updateMessage.generationTime > lastPlayerUpdateGenerationTime) {
|
||||
lastPlayerUpdateGenerationTime = updateMessage.generationTime;
|
||||
|
@ -73,6 +73,7 @@ function onPlayerLoad(value: PlayMessage, currentPlaybackRate?: number, currentV
|
|||
window.targetAPI.sendVolumeUpdate({ generationTime: Date.now(), volume: 1.0 });
|
||||
}
|
||||
|
||||
window.targetAPI.emitEvent(new EventMessage(Date.now(), new MediaItemEvent(EventType.MediaItemStart, cachedPlayMediaItem)));
|
||||
player.play();
|
||||
}
|
||||
|
||||
|
@ -120,11 +121,18 @@ let isLive = false;
|
|||
let isLivePosition = false;
|
||||
let captionsBaseHeight = 0;
|
||||
let captionsContentHeight = 0;
|
||||
let cachedPlayMediaItem: MediaItem = null;
|
||||
|
||||
function onPlay(_event, value: PlayMessage) {
|
||||
logger.info("Handle play message renderer", JSON.stringify(value));
|
||||
const currentVolume = player ? player.getVolume() : null;
|
||||
const currentPlaybackRate = player ? player.getPlaybackRate() : null;
|
||||
cachedPlayMediaItem = new MediaItem(
|
||||
value.container, value.url, value.content,
|
||||
value.time, value.volume, value.speed,
|
||||
null, null, value.headers, value.metadata
|
||||
);
|
||||
window.targetAPI.emitEvent(new EventMessage(Date.now(), new MediaItemEvent(EventType.MediaItemChange, cachedPlayMediaItem)));
|
||||
|
||||
if (player) {
|
||||
if ((player.getSource() === value.url) || (player.getSource() === value.content)) {
|
||||
|
@ -167,7 +175,10 @@ function onPlay(_event, value: PlayMessage) {
|
|||
// Player event handlers
|
||||
dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_PLAYING, () => { sendPlaybackUpdate(1); playerCtrlStateUpdate(PlayerControlEvent.Play); });
|
||||
dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_PAUSED, () => { sendPlaybackUpdate(2); playerCtrlStateUpdate(PlayerControlEvent.Pause); });
|
||||
dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_ENDED, () => { sendPlaybackUpdate(0) });
|
||||
dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_ENDED, () => {
|
||||
sendPlaybackUpdate(0);
|
||||
window.targetAPI.emitEvent(new EventMessage(Date.now(), new MediaItemEvent(EventType.MediaItemEnd, cachedPlayMediaItem)));
|
||||
});
|
||||
dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_TIME_UPDATED, () => {
|
||||
playerCtrlStateUpdate(PlayerControlEvent.TimeUpdate);
|
||||
|
||||
|
@ -290,7 +301,10 @@ function onPlay(_event, value: PlayMessage) {
|
|||
if (player.playerType === PlayerType.Hls || player.playerType === PlayerType.Html) {
|
||||
videoElement.onplay = () => { sendPlaybackUpdate(1); playerCtrlStateUpdate(PlayerControlEvent.Play); };
|
||||
videoElement.onpause = () => { sendPlaybackUpdate(2); playerCtrlStateUpdate(PlayerControlEvent.Pause); };
|
||||
videoElement.onended = () => { sendPlaybackUpdate(0) };
|
||||
videoElement.onended = () => {
|
||||
sendPlaybackUpdate(0);
|
||||
window.targetAPI.emitEvent(new EventMessage(Date.now(), new MediaItemEvent(EventType.MediaItemEnd, cachedPlayMediaItem)));
|
||||
};
|
||||
videoElement.ontimeupdate = () => {
|
||||
playerCtrlStateUpdate(PlayerControlEvent.TimeUpdate);
|
||||
|
||||
|
@ -737,69 +751,82 @@ document.addEventListener('click', (event: MouseEvent) => {
|
|||
const skipInterval = 10;
|
||||
const volumeIncrement = 0.1;
|
||||
|
||||
function keyDownEventListener(event: any) {
|
||||
function keyDownEventListener(event: KeyboardEvent) {
|
||||
// logger.info("KeyDown", event);
|
||||
const handledCase = targetKeyDownEventListener(event);
|
||||
if (handledCase) {
|
||||
return;
|
||||
let handledCase = targetKeyDownEventListener(event);
|
||||
|
||||
if (!handledCase) {
|
||||
switch (event.code) {
|
||||
case 'KeyF':
|
||||
case 'F11':
|
||||
playerCtrlStateUpdate(PlayerControlEvent.ToggleFullscreen);
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case 'Escape':
|
||||
playerCtrlStateUpdate(PlayerControlEvent.ExitFullscreen);
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case 'ArrowLeft':
|
||||
skipBack();
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
skipForward();
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case "Home":
|
||||
player?.setCurrentTime(0);
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case "End":
|
||||
if (isLive) {
|
||||
setLivePosition();
|
||||
}
|
||||
else {
|
||||
player?.setCurrentTime(player?.getDuration());
|
||||
}
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case 'KeyK':
|
||||
case 'Space':
|
||||
case 'Enter':
|
||||
// Play/pause toggle
|
||||
if (player?.isPaused()) {
|
||||
player?.play();
|
||||
} else {
|
||||
player?.pause();
|
||||
}
|
||||
event.preventDefault();
|
||||
handledCase = true;
|
||||
break;
|
||||
case 'KeyM':
|
||||
// Mute toggle
|
||||
player?.setMute(!player?.isMuted());
|
||||
handledCase = true;
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
// Volume up
|
||||
volumeChangeHandler(Math.min(player?.getVolume() + volumeIncrement, 1));
|
||||
handledCase = true;
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
// Volume down
|
||||
volumeChangeHandler(Math.max(player?.getVolume() - volumeIncrement, 0));
|
||||
handledCase = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (event.code) {
|
||||
case 'KeyF':
|
||||
case 'F11':
|
||||
playerCtrlStateUpdate(PlayerControlEvent.ToggleFullscreen);
|
||||
event.preventDefault();
|
||||
break;
|
||||
case 'Escape':
|
||||
playerCtrlStateUpdate(PlayerControlEvent.ExitFullscreen);
|
||||
event.preventDefault();
|
||||
break;
|
||||
case 'ArrowLeft':
|
||||
skipBack();
|
||||
event.preventDefault();
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
skipForward();
|
||||
event.preventDefault();
|
||||
break;
|
||||
case "Home":
|
||||
player?.setCurrentTime(0);
|
||||
event.preventDefault();
|
||||
break;
|
||||
case "End":
|
||||
if (isLive) {
|
||||
setLivePosition();
|
||||
}
|
||||
else {
|
||||
player?.setCurrentTime(player?.getDuration());
|
||||
}
|
||||
event.preventDefault();
|
||||
break;
|
||||
case 'KeyK':
|
||||
case 'Space':
|
||||
case 'Enter':
|
||||
// Play/pause toggle
|
||||
if (player?.isPaused()) {
|
||||
player?.play();
|
||||
} else {
|
||||
player?.pause();
|
||||
}
|
||||
event.preventDefault();
|
||||
break;
|
||||
case 'KeyM':
|
||||
// Mute toggle
|
||||
player?.setMute(!player?.isMuted());
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
// Volume up
|
||||
volumeChangeHandler(Math.min(player?.getVolume() + volumeIncrement, 1));
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
// Volume down
|
||||
volumeChangeHandler(Math.max(player?.getVolume() - volumeIncrement, 0));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (window.targetAPI.getSubscribedKeys().keyDown.has(event.key)) {
|
||||
window.targetAPI.emitEvent(new EventMessage(Date.now(), new KeyEvent(EventType.KeyDown, event.key, event.repeat, handledCase)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -814,6 +841,11 @@ function skipForward() {
|
|||
}
|
||||
|
||||
document.addEventListener('keydown', keyDownEventListener);
|
||||
document.addEventListener('keyup', (event: KeyboardEvent) => {
|
||||
if (window.targetAPI.getSubscribedKeys().keyUp.has(event.key)) {
|
||||
window.targetAPI.emitEvent(new EventMessage(Date.now(), new KeyEvent(EventType.KeyUp, event.key, event.repeat, false)));
|
||||
}
|
||||
});
|
||||
|
||||
export {
|
||||
PlayerControlEvent,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue