mirror of
https://github.com/streamwall/streamwall.git
synced 2025-12-06 01:45:37 -05:00
202 lines
5.1 KiB
JavaScript
202 lines
5.1 KiB
JavaScript
import { Machine, assign } from 'xstate'
|
|
|
|
const viewStateMachine = Machine(
|
|
{
|
|
id: 'view',
|
|
initial: 'empty',
|
|
context: {
|
|
view: null,
|
|
pos: null,
|
|
url: null,
|
|
info: {},
|
|
},
|
|
on: {
|
|
CLEAR: 'empty',
|
|
DISPLAY: 'displaying',
|
|
},
|
|
states: {
|
|
empty: {
|
|
entry: [
|
|
assign({
|
|
pos: { url: null },
|
|
info: {},
|
|
}),
|
|
'hideView',
|
|
],
|
|
invoke: {
|
|
src: 'clearView',
|
|
onError: {
|
|
target: '#view.error',
|
|
},
|
|
},
|
|
},
|
|
displaying: {
|
|
id: 'displaying',
|
|
initial: 'loading',
|
|
entry: assign({
|
|
pos: (context, event) => event.pos,
|
|
url: (context, event) => event.url,
|
|
}),
|
|
on: {
|
|
DISPLAY: {
|
|
actions: assign({
|
|
pos: (context, event) => event.pos,
|
|
}),
|
|
cond: 'urlUnchanged',
|
|
},
|
|
},
|
|
states: {
|
|
loading: {
|
|
initial: 'page',
|
|
states: {
|
|
page: {
|
|
invoke: {
|
|
src: 'loadURL',
|
|
onDone: {
|
|
target: 'video',
|
|
},
|
|
onError: {
|
|
target: '#view.error',
|
|
},
|
|
},
|
|
},
|
|
video: {
|
|
invoke: {
|
|
src: 'startVideo',
|
|
onDone: {
|
|
target: '#view.displaying.running',
|
|
actions: assign({
|
|
info: (context, event) => event.data,
|
|
}),
|
|
},
|
|
onError: {
|
|
target: '#view.error',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
running: {
|
|
initial: 'muted',
|
|
entry: 'positionView',
|
|
on: {
|
|
DISPLAY: {
|
|
actions: [
|
|
assign({
|
|
pos: (context, event) => event.pos,
|
|
}),
|
|
'positionView',
|
|
],
|
|
cond: 'urlUnchanged',
|
|
},
|
|
MUTE: '.muted',
|
|
UNMUTE: '.listening',
|
|
},
|
|
states: {
|
|
muted: {
|
|
entry: 'muteAudio',
|
|
},
|
|
listening: {
|
|
entry: 'unmuteAudio',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
error: {
|
|
entry: 'logError',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
actions: {
|
|
logError: (context, event) => {
|
|
console.warn(event)
|
|
},
|
|
muteAudio: (context, event) => {
|
|
context.view.webContents.audioMuted = true
|
|
},
|
|
unmuteAudio: (context, event) => {
|
|
context.view.webContents.audioMuted = false
|
|
},
|
|
},
|
|
guards: {
|
|
urlUnchanged: (context, event) => {
|
|
return context.url === event.url
|
|
},
|
|
},
|
|
services: {
|
|
clearView: async (context, event) => {
|
|
await context.view.webContents.loadURL('about:blank')
|
|
},
|
|
loadURL: async (context, event) => {
|
|
const { url, view } = context
|
|
const wc = view.webContents
|
|
wc.audioMuted = true
|
|
await wc.loadURL(url)
|
|
wc.insertCSS(
|
|
`
|
|
* {
|
|
display: none !important;
|
|
pointer-events: none;
|
|
}
|
|
html, body, video {
|
|
display: block !important;
|
|
background: black !important;
|
|
}
|
|
html, body {
|
|
overflow: hidden !important;
|
|
background: black !important;
|
|
}
|
|
video {
|
|
display: block !important;
|
|
position: fixed !important;
|
|
left: 0 !important;
|
|
right: 0 !important;
|
|
top: 0 !important;
|
|
bottom: 0 !important;
|
|
width: 100% !important;
|
|
height: 100% !important;
|
|
object-fit: cover !important;
|
|
z-index: 999999 !important;
|
|
}
|
|
`,
|
|
{ cssOrigin: 'user' },
|
|
)
|
|
},
|
|
startVideo: async (context, event) => {
|
|
const wc = context.view.webContents
|
|
const info = await wc.executeJavaScript(`
|
|
const sleep = ms => new Promise((resolve) => setTimeout(resolve, ms))
|
|
async function waitForVideo() {
|
|
// Give the client side a little time to load. In particular, YouTube seems to need a delay.
|
|
await sleep(1000)
|
|
|
|
let tries = 0
|
|
let video
|
|
while (!video && tries < 20) {
|
|
video = document.querySelector('video')
|
|
tries++
|
|
await sleep(200)
|
|
}
|
|
if (!video) {
|
|
throw new Error('could not find video')
|
|
}
|
|
document.body.appendChild(video)
|
|
video.muted = false
|
|
video.autoPlay = true
|
|
video.play()
|
|
setInterval(() => video.play(), 1000)
|
|
const info = {title: document.title}
|
|
return info
|
|
}
|
|
waitForVideo()
|
|
`)
|
|
return info
|
|
},
|
|
},
|
|
},
|
|
)
|
|
|
|
export default viewStateMachine
|