Add video output to host view
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Jack Hadrill 2021-01-05 01:59:52 +00:00
parent 87959d0f3b
commit a30db82afe
4 changed files with 49 additions and 27 deletions

View File

@ -5,9 +5,9 @@
<i class="pi pi-upload"></i> <i class="pi pi-upload"></i>
<h2>{{ message }}</h2> <h2>{{ message }}</h2>
</div> </div>
<input type="file" hidden="true" ref="fileInput" @change="selected" />
</template> </template>
</Card> </Card>
<input type="file" hidden="true" ref="fileInput" @change="selected" />
</template> </template>
<script> <script>

View File

@ -4,7 +4,7 @@
Wire statistics Wire statistics
</template> </template>
<template #content> <template #content>
<DataTable :value="wires" autoLayout=true> <DataTable :value="wires" :autoLayout="true">
<Column field="peerId" header="Wire ID"></Column> <Column field="peerId" header="Wire ID"></Column>
<Column field="remoteAddress" header="Remote address"></Column> <Column field="remoteAddress" header="Remote address"></Column>
<Column field="uploadSpeed" header="Upload speed"></Column> <Column field="uploadSpeed" header="Upload speed"></Column>

View File

@ -15,6 +15,7 @@ import DataTable from 'primevue/datatable'
import InputText from 'primevue/inputtext' import InputText from 'primevue/inputtext'
import MenuBar from 'primevue/menubar' import MenuBar from 'primevue/menubar'
import ProgressBar from 'primevue/progressbar' import ProgressBar from 'primevue/progressbar'
import ProgressSpinner from 'primevue/progressspinner'
import Toast from 'primevue/toast' import Toast from 'primevue/toast'
import ToastService from 'primevue/toastservice' import ToastService from 'primevue/toastservice'
import 'primeflex/primeflex.css' import 'primeflex/primeflex.css'
@ -36,6 +37,7 @@ app.component('DataTable', DataTable)
app.component('InputText', InputText) app.component('InputText', InputText)
app.component('MenuBar', MenuBar) app.component('MenuBar', MenuBar)
app.component('ProgressBar', ProgressBar) app.component('ProgressBar', ProgressBar)
app.component('ProgressSpinner', ProgressSpinner)
app.component('Toast', Toast) app.component('Toast', Toast)
// Register VCinemaApp components. // Register VCinemaApp components.

View File

@ -1,23 +1,36 @@
<template> <template>
<div class="p-p-6"> <div class="p-p-6">
<h1 class="p-my-0">Host</h1> <h1 class="p-my-0">Host</h1>
<FileSelect v-if="!state.active" message="Drag a H.264 encoded MP4 here to start a screen." @selected="filesSelected" /> <template v-if="!state.active">
<div v-else> <FileSelect class="p-mb-4" v-if="!state.fileSelected" message="Drag a H.264 encoded MP4 here to start a screen." @selected="filesSelected" />
<Card> <Card class="p-mb-4" v-else>
<template #title>
Info hash
</template>
<template #content> <template #content>
<InputText id="infoHash" type="text" v-model="state.infoHash" disabled /> <div class="p-text-center">
<ProgressSpinner />
<h2>Generating hash. Please wait...</h2>
</div>
</template> </template>
</Card> </Card>
<HostWires class="p-mt-4" :wires="wires" /> </template>
</div> <Card class="p-mb-4" v-show="state.active">
<template #content>
<video id="player" controls="true"></video>
</template>
</Card>
<Card class="p-mb-4" v-show="state.active">
<template #title>
Info hash
</template>
<template #content>
<InputText id="infoHash" type="text" v-model="state.infoHash" disabled />
</template>
</Card>
<HostWires class="p-mb-4" :wires="wires" v-show="state.active" />
</div> </div>
</template> </template>
<script> <script>
import { inject, onBeforeUnmount, onMounted, reactive } from 'vue' import { inject, onBeforeUnmount, reactive } from 'vue'
import { useToast } from 'primevue/usetoast' import { useToast } from 'primevue/usetoast'
import prettyBytes from 'pretty-bytes' import prettyBytes from 'pretty-bytes'
import sha1 from 'crypto-js/sha1' import sha1 from 'crypto-js/sha1'
@ -29,52 +42,59 @@ export default {
const trackers = inject('trackers') const trackers = inject('trackers')
const state = reactive({ const state = reactive({
active: false, active: false,
fileSelected: false,
infoHash: '', infoHash: '',
size: 0, size: 0,
uploaded: 0, uploaded: 0,
uploadSpeed: 0, uploadSpeed: 0,
wires: [] wires: []
}) })
const webTorrent = new WebTorrent()
const wires = reactive([]) const wires = reactive([])
var webTorrent
onMounted(() => {
webTorrent = new WebTorrent()
})
onBeforeUnmount(() => { onBeforeUnmount(() => {
webTorrent.destroy() webTorrent.destroy()
}) })
const filesSelected = (files) => { const filesSelected = (f) => {
if (files?.length !== 1 || !files[0].name.endsWith('.mp4') || files[0].type !== 'video/mp4') { if (f?.length !== 1 || !f[0].name.endsWith('.mp4') || f[0].type !== 'video/mp4') {
toast.add({ severity: 'error', summary: 'Bad file input', detail: 'You must select a single H.264 encoded MP4.', life: 3000 }) toast.add({ severity: 'error', summary: 'Bad file input', detail: 'You must select a single H.264 encoded MP4.', life: 3000 })
return } else {
state.fileSelected = true
} }
seedFile(files[0]) seedFile(f[0])
} }
const seedFile = (file) => { const seedFile = (file) => {
webTorrent.seed(file, { announce: trackers }, (torrent) => { webTorrent.seed(file, { announce: trackers }, (torrent) => {
toast.add({ severity: 'success', summary: 'File added', detail: `You are now sharing ${file.name}`, life: 5000 }) var file = torrent.files.find(file => {
return file.name.endsWith('.mp4')
})
state.size = file.size
state.active = true state.active = true
state.infoHash = torrent.infoHash state.infoHash = torrent.infoHash
state.size = file.size
torrent.on('upload', (bytes) => { file.createReadStream().on('data', () => {
file.renderTo('#player')
})
torrent.on('upload', bytes => {
state.uploaded += bytes state.uploaded += bytes
}) })
torrent.on('wire', (wire) => { torrent.on('wire', wire => {
state.wires.push(wire) state.wires.push(wire)
toast.add({ severity: 'info', summary: 'New watcher', detail: 'Someone has joined your screen.', life: 3000 }) toast.add({ severity: 'info', summary: 'New watcher', detail: 'Someone has joined your screen.', life: 3000 })
}) })
toast.add({ severity: 'success', summary: 'File added', detail: `You are now sharing ${file.name}`, life: 5000 })
}) })
} }
setInterval(() => { setInterval(() => {
const newWires = state.wires.map((wire) => ({ const newWires = state.wires.map(wire => ({
peerId: sha1(wire.peerId).toString().substring(0, 100), peerId: sha1(wire.peerId).toString().substring(0, 100),
remoteAddress: wire.remoteAddress, remoteAddress: wire.remoteAddress,
uploadSpeed: prettyBytes(wire.uploadSpeed()) + 'ps', uploadSpeed: prettyBytes(wire.uploadSpeed()) + 'ps',
@ -95,7 +115,7 @@ export default {
</script> </script>
<style> <style>
#infoHash { #infoHash, video#player {
width: 100%; width: 100%;
} }
</style> </style>