2020-03-21 13:34:37 +03:00
|
|
|
// common variables
|
2020-03-25 02:29:08 +03:00
|
|
|
let iBytesUploaded = 0
|
|
|
|
let iBytesTotal = 0
|
|
|
|
let iPreviousBytesLoaded = 0
|
|
|
|
let iMaxFilesize = 104857600 // 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')
|
2020-03-27 14:04:10 +03:00
|
|
|
const videoTitle = document.getElementById('video-title')
|
|
|
|
const videoDescription = document.getElementById('video-description')
|
2020-03-25 02:29:08 +03:00
|
|
|
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) => {
|
2020-03-27 14:26:13 +03:00
|
|
|
if (uploadInProgress === true || file != null) {
|
2020-03-25 02:29:08 +03:00
|
|
|
e.preventDefault()
|
|
|
|
return false
|
2020-03-21 13:34:37 +03:00
|
|
|
}
|
2020-03-25 02:29:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const fileSelected = (_file) => {
|
2020-03-25 02:48:43 +03:00
|
|
|
const fileObj = _file || videoInput.files[0]
|
2020-03-25 02:29:08 +03:00
|
|
|
if (_file) videoInput.value = ''
|
2020-03-25 02:48:43 +03:00
|
|
|
|
|
|
|
if (fileObj) file = fileObj
|
2020-03-25 02:29:08 +03:00
|
|
|
if (!file) return
|
|
|
|
|
|
|
|
if (file.size > iMaxFilesize) {
|
|
|
|
setMessage('Your file is very big. We can\'t accept it. Please select more small file.', true)
|
|
|
|
return
|
2020-03-21 13:34:37 +03:00
|
|
|
}
|
2020-03-25 02:29:08 +03:00
|
|
|
|
|
|
|
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)
|
2020-03-21 13:34:37 +03:00
|
|
|
}
|
2020-03-25 02:29:08 +03:00
|
|
|
|
|
|
|
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
|
2020-03-21 13:34:37 +03:00
|
|
|
}
|
2020-03-25 02:29:08 +03:00
|
|
|
|
|
|
|
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)
|
2020-03-27 14:04:10 +03:00
|
|
|
formData.append('video_title', videoTitle.value)
|
|
|
|
formData.append('video_description', videoDescription.value)
|
2020-03-25 02:29:08 +03:00
|
|
|
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
|
2020-03-21 13:34:37 +03:00
|
|
|
// if nothing new loaded - exit
|
|
|
|
if (iDiff == 0)
|
2020-03-25 02:29:08 +03:00
|
|
|
return
|
|
|
|
iPreviousBytesLoaded = iBytesUploaded
|
|
|
|
iDiff = iDiff * 2
|
|
|
|
const iBytesRem = iBytesTotal - iPreviousBytesLoaded
|
|
|
|
const secondsRemaining = iBytesRem / iDiff
|
2020-03-21 13:34:37 +03:00
|
|
|
// update speed info
|
2020-03-25 02:29:08 +03:00
|
|
|
let iSpeed = iDiff.toString() + 'B/s'
|
2020-03-21 13:34:37 +03:00
|
|
|
if (iDiff > 1024 * 1024) {
|
2020-03-25 02:29:08 +03:00
|
|
|
iSpeed = (Math.round(iDiff * 100/(1024*1024))/100).toString() + 'MB/s'
|
2020-03-21 13:34:37 +03:00
|
|
|
} else if (iDiff > 1024) {
|
2020-03-25 02:29:08 +03:00
|
|
|
iSpeed = (Math.round(iDiff * 100/1024)/100).toString() + 'KB/s'
|
2020-03-21 13:34:37 +03:00
|
|
|
}
|
2020-03-25 02:29:08 +03:00
|
|
|
|
|
|
|
const speedMessage = `${iSpeed} | ${secondsToTime(secondsRemaining)}`
|
|
|
|
setMessage(speedMessage)
|
2020-03-21 13:34:37 +03:00
|
|
|
}
|
2020-03-25 02:29:08 +03:00
|
|
|
|
2020-03-21 13:34:37 +03:00
|
|
|
function uploadProgress(e) { // upload process in progress
|
|
|
|
if (e.lengthComputable) {
|
2020-03-25 02:29:08 +03:00
|
|
|
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')
|
2020-03-21 13:34:37 +03:00
|
|
|
}
|
|
|
|
} else {
|
2020-03-25 02:29:08 +03:00
|
|
|
setMessage('Unable to compute progress.')
|
2020-03-21 13:34:37 +03:00
|
|
|
}
|
|
|
|
}
|
2020-03-25 02:29:08 +03:00
|
|
|
|
|
|
|
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)
|
2020-03-21 13:34:37 +03:00
|
|
|
}
|
2020-03-25 02:29:08 +03:00
|
|
|
|
|
|
|
const uploadError = () => { // upload error
|
|
|
|
setMessage('An error occurred while uploading the file.', true)
|
|
|
|
setProgress(0)
|
|
|
|
setUploadState(false)
|
2020-03-21 13:34:37 +03:00
|
|
|
}
|
2020-03-25 02:29:08 +03:00
|
|
|
|
|
|
|
const uploadAbort = () => { // upload abort
|
|
|
|
setMessage('The upload has been canceled by the user or the browser dropped the connection.', true)
|
|
|
|
setProgress(0)
|
|
|
|
setUploadState(false)
|
2020-03-27 14:04:10 +03:00
|
|
|
}
|