-
-
Save BlueBazze/4f05a44d5e5712b3fdfa7e50aed2ac8d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<v-card> | |
<v-card-title>{{ | |
$t('pages.mediaSources.components.UploadMediaSourceCard.title') | |
}}</v-card-title> | |
<v-card-subtitle></v-card-subtitle> | |
<v-card-text> | |
<p> | |
{{ $t('pages.mediaSources.components.UploadMediaSourceCard.subTitle') }} | |
</p> | |
<p> | |
{{ $t('pages.mediaSources.components.UploadMediaSourceCard.text') }} | |
</p> | |
</v-card-text> | |
<v-form ref="form" v-model="valid" class="mx-4" @submit.prevent="submit"> | |
<v-text-field v-model="form.title" outlined :error="!form.title" :rules="$rules.for($t('title'), ['required'])" | |
:error-messages="errors.title || errors.name" :label="$t('title')" :disabled="busy" required class="mt-2" | |
@input="clearErrors" /> | |
<v-file-input autofocus prepend-icon="" outlined type="file" accept="video/mp4" show-size :error="!form.video" | |
:value="form.video" :rules="$rules.for($t('video'), ['required'])" :error-messages="errors.video" | |
:label="$t('video')" :loading="uploading" :disabled="busy" | |
:suffix="upload.progress > 0 ? `${upload.progress}%` : ''" required class="mt-2" @change="setFormVideo" | |
@input="clearErrors"> | |
</v-file-input> | |
</v-form> | |
<!-- Show progress bar for upload progress when uploading --> | |
<v-progress-linear v-if="uploading" :value="upload.progress" /> | |
<v-card-actions class="justify-end"> | |
<v-btn text color="primary" @click="cancel"> | |
{{ $t('cancel') }} | |
</v-btn> | |
<v-btn text color="primary" type="submit" :loading="busy" :disabled="!valid || busy" @click="submit"> | |
{{ $t('upload') }} | |
</v-btn> | |
</v-card-actions> | |
</v-card> | |
</template> | |
<script> | |
import * as UpChunk from '@mux/upchunk/dist/upchunk' | |
import { extractErrorsFromLaravelResponse, humanize } from '~/helpers.ts' | |
export default { | |
props: { | |
publisher: Object, | |
}, | |
data: () => ({ | |
busy: false, | |
valid: false, | |
upload: { | |
progress: 0, | |
}, | |
uploader: null, | |
source: undefined, | |
errors: {}, | |
form: { | |
title: '', | |
video: null, | |
}, | |
videoMetadata: { | |
video_duration: 0, | |
height: 0, | |
width: 0, | |
}, | |
}), | |
computed: { | |
uploading() { | |
if (!this.upload || !this.upload.progress) { | |
return false | |
} | |
return this.upload.progress > 0 && this.upload.progress < 100 | |
}, | |
}, | |
methods: { | |
async setFormVideo(file) { | |
this.form.video = file | |
if (!this.form.title) { | |
this.form.title = humanize( | |
file.name.substring(0, file.name.lastIndexOf('.')) || file.name | |
) | |
} | |
const video = await this.loadVideo(file) | |
this.videoMetadata.video_duration = Math.round(video.duration) | |
this.videoMetadata.height = video.videoHeight | |
this.videoMetadata.width = video.videoWidth | |
}, | |
cancel() { | |
if (!this.upload || !this.upload.progress) { | |
this.upload.abort() | |
return; | |
} | |
this.reset() | |
this.$emit('cancel') | |
}, | |
clearErrors() { | |
this.errors = {} | |
}, | |
reset() { | |
this.busy = false | |
this.valid = false | |
this.upload.progress = 0 | |
this.form = { | |
title: '', | |
video: null, | |
} | |
this.videoMetadata = { | |
video_duration: 0, | |
height: 0, | |
width: 0, | |
} | |
this.errors = {} | |
if (this.uploader) { | |
this.uploader.abort() | |
this.uploader = null | |
} | |
if (this.source) { | |
this.source = null | |
} | |
this.valid = this.$refs.form.validate() | |
}, | |
loadVideo(file) { | |
return new Promise((resolve, reject) => { | |
try { | |
const video = document.createElement('video') | |
video.preload = 'metadata' | |
video.onloadedmetadata = function () { | |
resolve(this) | |
} | |
video.onerror = function () { | |
reject(new Error('Invalid video. Please select a video file.')) | |
} | |
video.src = window.URL.createObjectURL(file) | |
} catch (e) { | |
reject(e) | |
} | |
}) | |
}, | |
async submit() { | |
try { | |
await this.$refs.form.validate() | |
this.busy = true | |
if (!this.source) { | |
this.source = await this.createSource() | |
} | |
await this.uploadToMux() | |
this.$emit('success', this.source) | |
this.$api.$patch(`/broadcast-sources/${this.source.id}`, { | |
uploaded_at: new Date(), | |
}) | |
this.reset() | |
} catch (error) { | |
this.$emit('error', error) | |
this.errors = error | |
} finally { | |
this.busy = false | |
} | |
}, | |
createSource() { | |
// eslint-disable-next-line no-async-promise-executor | |
return new Promise(async (resolve, reject) => { | |
try { | |
await this.$refs.form.validate() | |
const source = await this.$api.$post( | |
`publishers/${this.publisher.id}/broadcast-sources`, | |
{ | |
name: this.form.title, | |
filename: this.form.video.name, | |
mimetype: this.form.video.type, | |
video_width: this.videoMetadata.width, | |
video_height: this.videoMetadata.height, | |
video_duration: this.videoMetadata.video_duration, | |
} | |
) | |
resolve(source) | |
} catch (error) { | |
if (error.response?.status === 422) { | |
const validationErrors = { | |
title: [], | |
video: [], | |
} | |
Object.entries( | |
extractErrorsFromLaravelResponse(error.response) | |
).forEach(([key, message]) => { | |
if (key === 'name') { | |
validationErrors.title.push(...message) | |
} else { | |
validationErrors.video.push(...message) | |
} | |
}) | |
reject(validationErrors) | |
} else { | |
reject(error) | |
} | |
} | |
}) | |
}, | |
uploadToMux() { | |
return new Promise((resolve, reject) => { | |
this.uploader = UpChunk.createUpload({ | |
endpoint: this.source.upload_url, | |
file: this.form.video, | |
chunkSize: 5120, // Uploads the file in ~5mb chunks | |
}) | |
// subscribe to events | |
/** | |
type EventName = | |
| 'attempt' | |
| 'attemptFailure' | |
| 'chunkSuccess' | |
| 'error' | |
| 'offline' | |
| 'online' | |
| 'progress' | |
| 'success'; | |
*/ | |
this.uploader.on('error', (error) => { | |
console.error(error) | |
this.$rollbar.error(error) | |
reject(error) | |
}) | |
this.uploader.on('progress', (progress) => { | |
console.log(JSON.stringify(progress)) | |
this.upload.progress = progress | |
}) | |
this.uploader.on('success', () => { | |
resolve() | |
}) | |
}) | |
}, | |
}, | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment