mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
update states.
This commit is contained in:
parent
a98866e5cb
commit
d6c3c4b2aa
197
src/app.vue
197
src/app.vue
@ -1,48 +1,146 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<button @click="connect()">Connect</button>
|
<div style="float: right; max-width: 500px">
|
||||||
<button @click="disconnect()">Disonnect</button>
|
<h3>State</h3>
|
||||||
|
<table class="states" v-if="loaded">
|
||||||
<template v-if="loaded && neko.connected">
|
<tr class="ok">
|
||||||
<button v-if="!is_controlling" @click="neko.control.request()">request control</button>
|
<th>connection.websocket</th>
|
||||||
<button v-else @click="neko.control.release()">release control</button>
|
<td>{{ neko.state.connection.websocket }}</td>
|
||||||
|
</tr>
|
||||||
<button @click="neko.video.pause()">pause stream</button>
|
<tr class="ok">
|
||||||
<button @click="neko.video.play()">play stream</button><br />
|
<th>connection.webrtc</th>
|
||||||
</template>
|
<td>{{ neko.state.connection.webrtc }}</td>
|
||||||
|
</tr>
|
||||||
<table class="states" v-if="loaded">
|
<tr>
|
||||||
<tr>
|
<th>connection.type</th>
|
||||||
<th>is connected</th>
|
<td>{{ neko.state.connection.type }}</td>
|
||||||
<td>{{ neko.connected ? 'yes' : 'no' }}</td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
<tr>
|
<th>connection.can_watch</th>
|
||||||
<th>is contolling</th>
|
<td>{{ neko.state.connection.can_watch }}</td>
|
||||||
<td>{{ is_controlling ? 'yes' : 'no' }}</td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
<tr>
|
<th>connection.can_control</th>
|
||||||
<th>websocket state</th>
|
<td>{{ neko.state.connection.can_control }}</td>
|
||||||
<td>{{ neko.state.connection.websocket }}</td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
<tr>
|
<th>connection.clipboard_access</th>
|
||||||
<th>webrtc state</th>
|
<td>{{ neko.state.connection.clipboard_access }}</td>
|
||||||
<td>{{ neko.state.connection.webrtc }}</td>
|
</tr>
|
||||||
</tr>
|
<tr class="ok">
|
||||||
</table>
|
<th>video.playable</th>
|
||||||
|
<td>{{ neko.state.video.playable }}</td>
|
||||||
<div ref="container" style="width: 1280px; height: 720px; border: 2px solid red">
|
</tr>
|
||||||
<neko-canvas ref="neko" />
|
<tr class="ok">
|
||||||
|
<th>video.playing</th>
|
||||||
|
<td>{{ neko.state.video.playing }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>video.volume</th>
|
||||||
|
<td>{{ neko.state.video.volume }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="ok">
|
||||||
|
<th>control.scroll.inverse</th>
|
||||||
|
<td><input type="checkbox" v-model="neko.state.control.scroll.inverse" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr class="ok">
|
||||||
|
<th>control.scroll.sensitivity</th>
|
||||||
|
<td><input type="number" v-model="neko.state.control.scroll.sensitivity" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>control.host</th>
|
||||||
|
<td>{{ neko.state.control.host }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="ok">
|
||||||
|
<th>screen.size.width</th>
|
||||||
|
<td>{{ neko.state.screen.size.width }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="ok">
|
||||||
|
<th>screen.size.height</th>
|
||||||
|
<td>{{ neko.state.screen.size.height }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="ok">
|
||||||
|
<th>screen.size.rate</th>
|
||||||
|
<td>{{ neko.state.screen.size.rate }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="ok">
|
||||||
|
<th>screen.configurations</th>
|
||||||
|
<td>
|
||||||
|
<select
|
||||||
|
:value="Object.values(neko.state.screen.size).join()"
|
||||||
|
@input="
|
||||||
|
a = String($event.target.value).split(',')
|
||||||
|
neko.screen.size(parseInt(a[0]), parseInt(a[1]), parseInt(a[2]))
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="{ width, height, rate } in neko.state.screen.configurations"
|
||||||
|
:key="width + height + rate"
|
||||||
|
:value="[width, height, rate].join()"
|
||||||
|
>
|
||||||
|
{{ width }}x{{ height }}@{{ rate }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>screen.is_fullscreen</th>
|
||||||
|
<td>{{ neko.state.screen.is_fullscreen }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="ok">
|
||||||
|
<th>member.id</th>
|
||||||
|
<td>{{ neko.state.member.id }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="ok">
|
||||||
|
<th>member.name</th>
|
||||||
|
<td>{{ neko.state.member.name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>member.is_admin</th>
|
||||||
|
<td>{{ neko.state.member.is_admin }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>member.is_watching</th>
|
||||||
|
<td>{{ neko.state.member.is_watching }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="ok">
|
||||||
|
<th>member.is_controlling</th>
|
||||||
|
<td>{{ neko.state.member.is_controlling }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>member.can_watch</th>
|
||||||
|
<td>{{ neko.state.member.can_watch }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>member.can_control</th>
|
||||||
|
<td>{{ neko.state.member.can_control }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>member.clipboard_access</th>
|
||||||
|
<td>{{ neko.state.member.clipboard_access }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>members</th>
|
||||||
|
<td>{{ neko.state.members }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<button @click="connect()">Connect</button>
|
||||||
|
<button @click="disconnect()">Disonnect</button>
|
||||||
|
|
||||||
<template v-if="loaded">
|
<template v-if="loaded && neko.connected">
|
||||||
<button
|
<button v-if="!is_controlling" @click="neko.control.request()">request control</button>
|
||||||
v-for="{ width, height, rate } in available_screen_sizes"
|
<button v-else @click="neko.control.release()">release control</button>
|
||||||
:key="width + height + rate"
|
|
||||||
@click="neko.screen.size(width, height, rate)"
|
<button @click="neko.video.pause()">pause stream</button>
|
||||||
>
|
<button @click="neko.video.play()">play stream</button><br />
|
||||||
{{ width }}x{{ height }}@{{ rate }}
|
</template>
|
||||||
</button>
|
|
||||||
</template>
|
<div ref="container" style="width: 1280px; height: 720px; border: 2px solid red">
|
||||||
|
<neko-canvas ref="neko" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -55,7 +153,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
text-align: right;
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ok {
|
||||||
|
background: #97f197;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -80,10 +182,6 @@
|
|||||||
return this.neko.state.member.is_controlling
|
return this.neko.state.member.is_controlling
|
||||||
}
|
}
|
||||||
|
|
||||||
get available_screen_sizes() {
|
|
||||||
return this.neko.state.screen.configurations
|
|
||||||
}
|
|
||||||
|
|
||||||
connect() {
|
connect() {
|
||||||
this.neko.connect('ws://192.168.1.20:3000/', 'admin', 'test')
|
this.neko.connect('ws://192.168.1.20:3000/', 'admin', 'test')
|
||||||
}
|
}
|
||||||
@ -128,11 +226,8 @@
|
|||||||
this.neko.events.on('clipboard.update', (text) => {
|
this.neko.events.on('clipboard.update', (text) => {
|
||||||
console.log('clipboard.update', text)
|
console.log('clipboard.update', text)
|
||||||
})
|
})
|
||||||
this.neko.events.on('screen.configuration', (configurations) => {
|
this.neko.events.on('screen.size', (id) => {
|
||||||
console.log('screen.configuration', configurations)
|
console.log('screen.size', id)
|
||||||
})
|
|
||||||
this.neko.events.on('screen.size', (width, height, rate) => {
|
|
||||||
console.log('screen.size', width, height, rate)
|
|
||||||
})
|
})
|
||||||
this.neko.events.on('broadcast.status', (payload) => {
|
this.neko.events.on('broadcast.status', (payload) => {
|
||||||
console.log('broadcast.status', payload)
|
console.log('broadcast.status', payload)
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
:screenHeight="state.screen.size.height"
|
:screenHeight="state.screen.size.height"
|
||||||
:isControling="state.member.is_controlling"
|
:isControling="state.member.is_controlling"
|
||||||
:scrollSensitivity="state.control.scroll.sensitivity"
|
:scrollSensitivity="state.control.scroll.sensitivity"
|
||||||
:scrollInvert="state.control.scroll.invert"
|
:scrollInvert="state.control.scroll.inverse"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -51,6 +51,7 @@
|
|||||||
import { NekoWebSocket } from '~/internal/websocket'
|
import { NekoWebSocket } from '~/internal/websocket'
|
||||||
import { NekoWebRTC } from '~/internal/webrtc'
|
import { NekoWebRTC } from '~/internal/webrtc'
|
||||||
import { NekoMessages } from '~/internal/messages'
|
import { NekoMessages } from '~/internal/messages'
|
||||||
|
import { register as VideoRegister } from '~/internal/video'
|
||||||
|
|
||||||
import NekoState from '~/types/state'
|
import NekoState from '~/types/state'
|
||||||
import Overlay from './overlay.vue'
|
import Overlay from './overlay.vue'
|
||||||
@ -93,7 +94,7 @@
|
|||||||
control: {
|
control: {
|
||||||
scroll: {
|
scroll: {
|
||||||
inverse: true,
|
inverse: true,
|
||||||
sensitivity: 10,
|
sensitivity: 1,
|
||||||
},
|
},
|
||||||
host: null,
|
host: null,
|
||||||
},
|
},
|
||||||
@ -125,6 +126,11 @@
|
|||||||
return this.state.connection.websocket == 'connected' && this.state.connection.webrtc == 'connected'
|
return this.state.connection.websocket == 'connected' && this.state.connection.webrtc == 'connected'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Watch('state.screen.size')
|
||||||
|
onScreenSizeChanged() {
|
||||||
|
this.onResize()
|
||||||
|
}
|
||||||
|
|
||||||
public control = {
|
public control = {
|
||||||
request: () => {
|
request: () => {
|
||||||
this.websocket.send('control/request')
|
this.websocket.send('control/request')
|
||||||
@ -174,6 +180,9 @@
|
|||||||
Vue.set(this.state.member, 'is_controlling', id != null && id === this.state.member.id)
|
Vue.set(this.state.member, 'is_controlling', id != null && id === this.state.member.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Video
|
||||||
|
VideoRegister(this.video, this.state.video)
|
||||||
|
|
||||||
// WebSocket
|
// WebSocket
|
||||||
this.websocket.on('message', async (event: string, payload: any) => {
|
this.websocket.on('message', async (event: string, payload: any) => {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
@ -185,40 +194,6 @@
|
|||||||
this.websocket.send('signal/answer', { sdp, displayname: this.state.member.name })
|
this.websocket.send('signal/answer', { sdp, displayname: this.state.member.name })
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
break
|
break
|
||||||
case 'screen/resolution':
|
|
||||||
Vue.set(this.state.screen, 'size', payload)
|
|
||||||
this.onResize()
|
|
||||||
break
|
|
||||||
case 'screen/configurations':
|
|
||||||
let data = []
|
|
||||||
for (const i of Object.keys(payload.configurations)) {
|
|
||||||
const { width, height, rates } = payload.configurations[i]
|
|
||||||
if (width >= 600 && height >= 300) {
|
|
||||||
for (const j of Object.keys(rates)) {
|
|
||||||
const rate = rates[j]
|
|
||||||
if (rate === 30 || rate === 60) {
|
|
||||||
data.push({
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
rate,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let conf = data.sort((a, b) => {
|
|
||||||
if (b.width === a.width && b.height == a.height) {
|
|
||||||
return b.rate - a.rate
|
|
||||||
} else if (b.width === a.width) {
|
|
||||||
return b.height - a.height
|
|
||||||
}
|
|
||||||
return b.width - a.width
|
|
||||||
})
|
|
||||||
|
|
||||||
Vue.set(this.state.screen, 'configurations', conf)
|
|
||||||
this.onResize()
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.websocket.on('connecting', () => {
|
this.websocket.on('connecting', () => {
|
||||||
@ -261,6 +236,8 @@
|
|||||||
this.webrtc.on('disconnected', () => {
|
this.webrtc.on('disconnected', () => {
|
||||||
Vue.set(this.state.connection, 'webrtc', 'disconnected')
|
Vue.set(this.state.connection, 'webrtc', 'disconnected')
|
||||||
this.events.emit('system.webrtc', 'disconnected')
|
this.events.emit('system.webrtc', 'disconnected')
|
||||||
|
// @ts-ignore
|
||||||
|
this.video.src = null
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
import { Member, ScreenConfigurations } from '../types/structs'
|
import { Member, ScreenConfigurations } from '../types/structs'
|
||||||
import { EVENT } from '../types/events'
|
import { EVENT } from '../types/events'
|
||||||
import {
|
import {
|
||||||
@ -31,8 +32,7 @@ export interface NekoEvents {
|
|||||||
['control.request']: (id: string) => void
|
['control.request']: (id: string) => void
|
||||||
['control.requesting']: (id: string) => void
|
['control.requesting']: (id: string) => void
|
||||||
['clipboard.update']: (text: string) => void
|
['clipboard.update']: (text: string) => void
|
||||||
['screen.configuration']: (configurations: ScreenConfigurations) => void
|
['screen.size']: (id: string) => void
|
||||||
['screen.size']: (width: number, height: number, rate: number) => void
|
|
||||||
['broadcast.status']: (url: string, isActive: boolean) => void
|
['broadcast.status']: (url: string, isActive: boolean) => void
|
||||||
['member.ban']: (id: string, target: string) => void
|
['member.ban']: (id: string, target: string) => void
|
||||||
['member.kick']: (id: string, target: string) => void
|
['member.kick']: (id: string, target: string) => void
|
||||||
@ -132,15 +132,38 @@ export class NekoMessages extends EventEmitter<NekoEvents> {
|
|||||||
// Screen Events
|
// Screen Events
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
protected [EVENT.SCREEN.CONFIGURATIONS]({ configurations }: ScreenConfigurationsPayload) {
|
protected [EVENT.SCREEN.CONFIGURATIONS]({ configurations }: ScreenConfigurationsPayload) {
|
||||||
console.log('EVENT.SCREEN.CONFIGURATIONS')
|
let data = []
|
||||||
this.emit('screen.configuration', configurations)
|
for (const i of Object.keys(configurations)) {
|
||||||
//video.setConfigurations(configurations)
|
const { width, height, rates } = configurations[i]
|
||||||
|
if (width >= 600 && height >= 300) {
|
||||||
|
for (const j of Object.keys(rates)) {
|
||||||
|
const rate = rates[j]
|
||||||
|
if (rate === 30 || rate === 60) {
|
||||||
|
data.push({
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
rate,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let conf = data.sort((a, b) => {
|
||||||
|
if (b.width === a.width && b.height == a.height) {
|
||||||
|
return b.rate - a.rate
|
||||||
|
} else if (b.width === a.width) {
|
||||||
|
return b.height - a.height
|
||||||
|
}
|
||||||
|
return b.width - a.width
|
||||||
|
})
|
||||||
|
|
||||||
|
Vue.set(this.state.screen, 'configurations', conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected [EVENT.SCREEN.RESOLUTION]({ id, width, height, rate }: ScreenResolutionPayload) {
|
protected [EVENT.SCREEN.RESOLUTION]({ id, width, height, rate }: ScreenResolutionPayload) {
|
||||||
console.log('EVENT.SCREEN.RESOLUTION')
|
Vue.set(this.state.screen, 'size', { width, height, rate })
|
||||||
this.emit('screen.size', width, height, rate)
|
if (id) this.emit('screen.size', id)
|
||||||
//video.setResolution({ width, height, rate })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
25
src/internal/video.ts
Normal file
25
src/internal/video.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import { Video } from '~/types/state'
|
||||||
|
|
||||||
|
export function register(el: HTMLVideoElement, state: Video) {
|
||||||
|
el.addEventListener('canplaythrough', () => {
|
||||||
|
Vue.set(state, 'playable', true)
|
||||||
|
})
|
||||||
|
el.addEventListener('playing', () => {
|
||||||
|
Vue.set(state, 'playing', true)
|
||||||
|
})
|
||||||
|
el.addEventListener('pause', () => {
|
||||||
|
Vue.set(state, 'playing', false)
|
||||||
|
})
|
||||||
|
el.addEventListener('emptied', () => {
|
||||||
|
Vue.set(state, 'playable', false)
|
||||||
|
Vue.set(state, 'playing', false)
|
||||||
|
})
|
||||||
|
el.addEventListener('error', () => {
|
||||||
|
Vue.set(state, 'playable', false)
|
||||||
|
Vue.set(state, 'playing', false)
|
||||||
|
})
|
||||||
|
el.addEventListener('volumechange', (value) => {
|
||||||
|
Vue.set(state, 'volume', value)
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user