Add viewer
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Jack Hadrill 2021-01-05 21:25:04 +00:00
parent 6d0250bbef
commit 9b967c2dde
4 changed files with 151 additions and 35 deletions

View File

@ -31,13 +31,9 @@ export default {
}
</script>
<style lang="scss">
<style>
.dropZone {
cursor: pointer;
i, h2 {
color: #aaaaaa
}
}
i.pi.pi-upload {

View File

@ -1,9 +1,14 @@
<template>
<div class="p-p-6">
<h1 class="p-my-0">Host</h1>
<template v-if="!state.active">
<FileSelect class="p-mb-4" v-if="!state.fileSelected" message="Drag a H.264 encoded MP4 here to start a screen." @selected="filesSelected" />
<Card class="p-mb-4" v-else>
<Card class="p-mb-4" v-show="state.active">
<template #content>
<video id="player" controls="true"></video>
</template>
</Card>
<div v-if="!state.active" key="host-pending">
<FileSelect class="p-mb-4" v-if="!state.fileSelected" key="file-select" message="Drag a H.264 encoded MP4 here to start a screen." @selected="onFilesSelected" />
<Card class="p-mb-4" v-else key="file-selected">
<template #content>
<div class="p-text-center">
<ProgressSpinner />
@ -11,26 +16,23 @@
</div>
</template>
</Card>
</template>
<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 v-else key="host-live">
<Card class="p-mb-4">
<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"/>
</div>
</div>
</template>
<script>
import { inject, onBeforeUnmount, reactive } from 'vue'
import { inject, onBeforeUnmount, onMounted, reactive } from 'vue'
import { useToast } from 'primevue/usetoast'
import prettyBytes from 'pretty-bytes'
import sha1 from 'crypto-js/sha1'
@ -49,14 +51,20 @@ export default {
uploadSpeed: 0,
wires: []
})
const webTorrent = new WebTorrent()
var webTorrent = null
const wires = reactive([])
onBeforeUnmount(() => {
webTorrent.destroy()
onMounted(() => {
webTorrent = new WebTorrent()
})
const filesSelected = (f) => {
onBeforeUnmount(() => {
if (webTorrent) {
webTorrent.destroy()
}
})
const onFilesSelected = (f) => {
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 })
} else {
@ -76,8 +84,13 @@ export default {
state.active = true
state.infoHash = torrent.infoHash
var fileRendered = false
file.createReadStream().on('data', () => {
file.renderTo('#player')
if (!fileRendered) {
file.renderTo('#player')
fileRendered = true
}
})
torrent.on('upload', bytes => {
@ -106,7 +119,7 @@ export default {
}, 500)
return {
filesSelected,
onFilesSelected,
state,
wires
}

View File

@ -1,14 +1,51 @@
<template>
<h1>Join</h1>
<InputText />
<div class="p-p-6">
<h1 class="p-my-0">Join</h1>
<Card>
<template #content>
<div class="p-fluid p-formgrid p-grid p-jc-center">
<div class="p-field p-col-12 p-lg-8">
<InputText :placeholder="defaultId" v-model="id" @keydown.enter="onIdSelected" />
</div>
<div class="p-field p-col-12 p-lg-2">
<Button label="Join" @click="onIdSelected" />
</div>
</div>
</template>
</Card>
</div>
</template>
<script>
export default {
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useToast } from 'primevue/usetoast'
export default {
setup () {
const router = useRouter()
const toast = useToast()
const id = ref()
const defaultId = '08ada5a7a6183aae1e09d831df6748d566095a10'
const onIdSelected = () => {
if (!id.value) {
id.value = defaultId
}
if (!/^([a-f0-9]{40})$/.test(id.value)) {
toast.add({ severity: 'error', summary: 'Bad ID', detail: 'Please enter a valid ID.', life: 3000 })
} else {
router.push(`/join/${id.value}`)
}
}
return {
id,
defaultId,
onIdSelected
}
}
}
</script>
<style>
</style>

View File

@ -1,14 +1,84 @@
<template>
<h1>Screen {{ id }}</h1>
<div class="p-p-6">
<h1 class="p-my-0">Watch</h1>
<Card class="p-mb-4" v-if="state.wires.length === 0">
<template #content>
<div class="p-text-center">
<ProgressSpinner />
<h2>Waiting for connections. Please wait...</h2>
</div>
</template>
</Card>
<Card class="p-mb-4" v-show="state.wires.length !== 0">
<template #content>
<video id="player" controls="true"></video>
</template>
</Card>
</div>
</template>
<script>
import { inject, onBeforeMount, onBeforeUnmount, onMounted, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { useToast } from 'primevue/usetoast'
import WebTorrent from 'webtorrent/webtorrent.min.js'
export default {
props: {
id: {
required: true,
type: String
}
},
setup (props) {
const router = useRouter()
const toast = useToast()
const trackers = inject('trackers')
const state = reactive({
wires: []
})
var webTorrent = null
onBeforeMount(() => {
if (!/^([a-f0-9]{40})$/.test(props.id)) {
toast.add({ severity: 'error', summary: 'Bad ID', detail: 'Please enter a valid ID.', life: 3000 })
router.push('/join')
}
})
onMounted(() => {
webTorrent = new WebTorrent()
webTorrent.add(props.id, { announce: trackers }, function (torrent) {
var file = torrent.files.find(function (file) {
return file.name.endsWith('.mp4')
})
var fileRendered = false
file.createReadStream().on('data', () => {
if (!fileRendered) {
file.renderTo('#player')
fileRendered = true
}
})
torrent.on('wire', wire => {
console.log(wire)
state.wires.push(wire)
toast.add({ severity: 'info', summary: 'New watcher', detail: 'Someone has joined your screen.', life: 3000 })
})
})
})
onBeforeUnmount(() => {
if (webTorrent) {
webTorrent.destroy()
}
})
return {
state
}
}
}
</script>