0a793f7d3f
This works for me, but for a more public site, I think I'll also add a boolean attribute named "upload_allowed" and "writable" to Config.Library.. Something to allow you to configure which directories can receive new uploads, and which directories we consider writable for other purposes (like editing meta data in yml, creating new thumbnails, ...) Co-authored-by: Heinrich Langos <gumbo2000@noreply@mills.io> Reviewed-on: https://git.mills.io/prologic/tube/pulls/39 Co-authored-by: Heinrich 'Henrik' Langos <gumbo2000@noreply@mills.io> Co-committed-by: Heinrich 'Henrik' Langos <gumbo2000@noreply@mills.io>
246 lines
7.6 KiB
JavaScript
246 lines
7.6 KiB
JavaScript
// common variables
|
|
let configMaxUploadSize = window['MAX_UPLOAD_SIZE'];
|
|
let iBytesUploaded = 0
|
|
let iBytesTotal = 0
|
|
let iPreviousBytesLoaded = 0
|
|
let iMaxFilesize = configMaxUploadSize ? (+configMaxUploadSize) : (100 * 1024 * 1024); // 100MB
|
|
let timer = 0
|
|
let uploadInProgress = 'n/a'
|
|
let isProcessing = false
|
|
let file = null
|
|
|
|
/* CACHED ELEMENTS */
|
|
|
|
const uploadForm = document.getElementById('upload-form')
|
|
const videoInput = document.getElementById('video-input')
|
|
const targetLibraryPath = document.getElementById('target-library-path')
|
|
const videoTitle = document.getElementById('video-title')
|
|
const videoDescription = document.getElementById('video-description')
|
|
const uploadMessageLabel = document.getElementById('upload-message')
|
|
const uploadFileContainer = document.getElementById('upload-file')
|
|
const uploadFilenameLabel = document.getElementById('upload-filename')
|
|
const uploadButtonWrapper = document.getElementById('upload-button-wrapper')
|
|
const uploadButton = document.getElementById('upload-button')
|
|
const uploadProgressContainer = document.getElementById('upload-progress-container')
|
|
const uploadProgressBar = document.getElementById('upload-progress')
|
|
const uploadProgressLabel = document.getElementById('upload-progress-label')
|
|
const uploadStopped = document.getElementById('upload-stopped')
|
|
const uploadStarted = document.getElementById('upload-started')
|
|
|
|
/* HELPERS */
|
|
|
|
const setProgress = (_progress) => {
|
|
uploadProgressContainer.style.display = _progress > 0 ? 'flex' : 'none'
|
|
uploadProgressBar.style.width = `${_progress}%`
|
|
uploadProgressLabel.innerText = _progress >= 15 ? `${_progress}%` : ''
|
|
}
|
|
|
|
const setMessage = (_message, isError) => {
|
|
uploadMessageLabel.style.display = _message ? 'block' : 'none'
|
|
uploadMessageLabel.innerHTML = _message
|
|
if (isError) {
|
|
uploadMessageLabel.classList.add('error')
|
|
} else {
|
|
uploadMessageLabel.classList.remove('error')
|
|
}
|
|
}
|
|
|
|
const setUploadState = (_uploadInProgress) => {
|
|
uploadInProgress = _uploadInProgress
|
|
|
|
uploadStarted.style.display = _uploadInProgress ? 'inline-block' : 'none'
|
|
uploadStopped.style.display = _uploadInProgress ? 'none' : 'block'
|
|
|
|
if (_uploadInProgress) {
|
|
uploadButton.classList.add('transparent')
|
|
timer = setInterval(doInnerUpdates, 300)
|
|
} else {
|
|
uploadButton.classList.remove('transparent')
|
|
clearInterval(timer)
|
|
}
|
|
}
|
|
|
|
const secondsToTime = (secs) => {
|
|
let hr = Math.floor(secs / 3600)
|
|
let min = Math.floor((secs - (hr * 3600)) / 60)
|
|
let sec = Math.floor(secs - (hr * 3600) - (min * 60))
|
|
if (hr < 10) hr = `0${hr}`
|
|
if (min < 10) min = `0${min}`
|
|
if (sec < 10) sec = `0${sec}`
|
|
if (hr) hr = '00'
|
|
return `${hr}:${min}:${sec}`
|
|
}
|
|
|
|
const bytesToSize = (bytes) => {
|
|
const sizes = ['Bytes', 'KB', 'MB']
|
|
if (bytes == 0) return 'n/a'
|
|
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))
|
|
return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]
|
|
}
|
|
|
|
const determineDragAndDropCapable = () => {
|
|
const div = document.createElement('div')
|
|
return (('draggable' in div)
|
|
|| ('ondragstart' in div && 'ondrop' in div))
|
|
&& 'FormData' in window
|
|
&& 'FileReader' in window
|
|
}
|
|
|
|
/* MAIN */
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave']
|
|
.forEach((evt) => {
|
|
uploadForm.addEventListener(evt, (e) => {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
})
|
|
})
|
|
|
|
uploadForm.addEventListener('drop', (e) => {
|
|
console.log(111)
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
|
|
const _file = e.dataTransfer.files[0]
|
|
if (!_file) return false
|
|
fileSelected(_file)
|
|
|
|
return false
|
|
})
|
|
}, false)
|
|
|
|
const labelClicked = (e) => {
|
|
if (uploadInProgress === true || file != null) {
|
|
e.preventDefault()
|
|
return false
|
|
}
|
|
}
|
|
|
|
const fileSelected = (_file) => {
|
|
const fileObj = _file || videoInput.files[0]
|
|
if (_file) videoInput.value = ''
|
|
|
|
if (fileObj) file = fileObj
|
|
if (!file) return
|
|
|
|
if (file.size > iMaxFilesize) {
|
|
setMessage('Your file is too big. It can\'t be accepted. Please select a smaller file.', true)
|
|
return
|
|
}
|
|
|
|
setMessage('')
|
|
setProgress(0)
|
|
|
|
const filename = file.name.length <= 20 ? file.name : `${file.name.substring(0, 14)}...${file.name.substring(file.name.length - 3)}`
|
|
uploadFilenameLabel.innerText = filename
|
|
uploadFileContainer.style.display = 'flex'
|
|
|
|
uploadButtonWrapper.style.display = 'block'
|
|
setUploadState(false)
|
|
}
|
|
|
|
const removeFile = (e, keepMessage) => {
|
|
if (e) e.preventDefault()
|
|
if (uploadInProgress === true) return
|
|
|
|
uploadFileContainer.style.display = 'none'
|
|
uploadButtonWrapper.style.display = 'none'
|
|
videoInput.value = ''
|
|
file = null
|
|
if (!keepMessage) setMessage('No file selected')
|
|
|
|
return false
|
|
}
|
|
|
|
const startUploading = () => {
|
|
if (uploadInProgress === true) return
|
|
if (!file) return
|
|
|
|
isProcessing = false
|
|
iPreviousBytesLoaded = 0
|
|
setMessage('')
|
|
setProgress(0)
|
|
setUploadState(true)
|
|
|
|
const formData = new FormData()
|
|
formData.append('video_file', file)
|
|
formData.append('target_library_path', targetLibraryPath.value)
|
|
formData.append('video_title', videoTitle.value)
|
|
formData.append('video_description', videoDescription.value)
|
|
const xhr = new XMLHttpRequest()
|
|
|
|
xhr.upload.addEventListener('progress', uploadProgress, false)
|
|
xhr.addEventListener('load', uploadFinish, false)
|
|
xhr.addEventListener('error', uploadError, false)
|
|
xhr.addEventListener('abort', uploadAbort, false)
|
|
|
|
xhr.open('POST', '/upload')
|
|
xhr.send(formData)
|
|
|
|
timer = setInterval(doInnerUpdates, 300)
|
|
}
|
|
|
|
const doInnerUpdates = () => { // we will use this function to display upload speed
|
|
if (isProcessing) {
|
|
clearInterval(timer)
|
|
return
|
|
}
|
|
|
|
let iDiff = iBytesUploaded - iPreviousBytesLoaded
|
|
// if nothing new loaded - exit
|
|
if (iDiff == 0)
|
|
return
|
|
iPreviousBytesLoaded = iBytesUploaded
|
|
iDiff = iDiff * 2
|
|
const iBytesRem = iBytesTotal - iPreviousBytesLoaded
|
|
const secondsRemaining = iBytesRem / iDiff
|
|
// update speed info
|
|
let iSpeed = iDiff.toString() + 'B/s'
|
|
if (iDiff > 1024 * 1024) {
|
|
iSpeed = (Math.round(iDiff * 100/(1024*1024))/100).toString() + 'MB/s'
|
|
} else if (iDiff > 1024) {
|
|
iSpeed = (Math.round(iDiff * 100/1024)/100).toString() + 'KB/s'
|
|
}
|
|
|
|
const speedMessage = `${iSpeed} | ${secondsToTime(secondsRemaining)}`
|
|
setMessage(speedMessage)
|
|
}
|
|
|
|
function uploadProgress(e) { // upload process in progress
|
|
if (e.lengthComputable) {
|
|
iBytesUploaded = e.loaded
|
|
iBytesTotal = e.total
|
|
|
|
const iPercentComplete = Math.round(iBytesUploaded / iBytesTotal * 100)
|
|
setProgress(iPercentComplete)
|
|
if (iPercentComplete === 100) {
|
|
isProcessing = true
|
|
setMessage('Processing video... please wait')
|
|
}
|
|
} else {
|
|
setMessage('Unable to compute progress.')
|
|
}
|
|
}
|
|
|
|
const uploadFinish = (e) => { // upload successfully finished
|
|
const message = e.target.responseText
|
|
const isSuccess = e.target.status < 400
|
|
|
|
setProgress(isSuccess ? 100 : 0)
|
|
setMessage(message, !isSuccess)
|
|
setUploadState(false)
|
|
if (isSuccess) removeFile(null, true)
|
|
}
|
|
|
|
const uploadError = () => { // upload error
|
|
setMessage('An error occurred while uploading the file.', true)
|
|
setProgress(0)
|
|
setUploadState(false)
|
|
}
|
|
|
|
const uploadAbort = () => { // upload abort
|
|
setMessage('The upload has been canceled by the user or the browser dropped the connection.', true)
|
|
setProgress(0)
|
|
setUploadState(false)
|
|
}
|