From 4e203eb773d83e8c0c7cbcdf1c98b9e3b57e4bcb Mon Sep 17 00:00:00 2001 From: James Mills Date: Wed, 1 Apr 2020 22:13:02 +1000 Subject: [PATCH] Improve video id handling in import to be more user friendly --- app/rice-box.go | 8 ++++---- importers/importer.go | 4 ++-- importers/vimeo_importer.go | 4 ++-- importers/youtube_importer.go | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/rice-box.go b/app/rice-box.go index 29e5485..2c6df7d 100644 --- a/app/rice-box.go +++ b/app/rice-box.go @@ -119,15 +119,15 @@ func init() { } filef := &embedded.EmbeddedFile{ Filename: "upload.js", - FileModTime: time.Unix(1585653781, 0), + FileModTime: time.Unix(1585653972, 0), - Content: string("// common variables\nlet iBytesUploaded = 0\nlet iBytesTotal = 0\nlet iPreviousBytesLoaded = 0\nlet iMaxFilesize = 104857600 // 100MB\nlet timer = 0\nlet uploadInProgress = 'n/a'\nlet isProcessing = false\nlet file = null\n\n/* CACHED ELEMENTS */\n\nconst uploadForm = document.getElementById('upload-form')\nconst videoInput = document.getElementById('video-input')\nconst videoTitle = document.getElementById('video-title')\nconst videoDescription = document.getElementById('video-description')\nconst uploadMessageLabel = document.getElementById('upload-message')\nconst uploadFileContainer = document.getElementById('upload-file')\nconst uploadFilenameLabel = document.getElementById('upload-filename')\nconst uploadButtonWrapper = document.getElementById('upload-button-wrapper')\nconst uploadButton = document.getElementById('upload-button')\nconst uploadProgressContainer = document.getElementById('upload-progress-container')\nconst uploadProgressBar = document.getElementById('upload-progress')\nconst uploadProgressLabel = document.getElementById('upload-progress-label')\nconst uploadStopped = document.getElementById('upload-stopped')\nconst uploadStarted = document.getElementById('upload-started')\n\n/* HELPERS */\n\nconst setProgress = (_progress) => {\n uploadProgressContainer.style.display = _progress > 0 ? 'flex' : 'none'\n uploadProgressBar.style.width = `${_progress}%`\n uploadProgressLabel.innerText = _progress >= 15 ? `${_progress}%` : ''\n}\n\nconst setMessage = (_message, isError) => {\n uploadMessageLabel.style.display = _message ? 'block' : 'none'\n uploadMessageLabel.innerHTML = _message\n if (isError) {\n uploadMessageLabel.classList.add('error')\n } else {\n uploadMessageLabel.classList.remove('error')\n }\n}\n\nconst setUploadState = (_uploadInProgress) => {\n uploadInProgress = _uploadInProgress\n\n uploadStarted.style.display = _uploadInProgress ? 'inline-block' : 'none'\n uploadStopped.style.display = _uploadInProgress ? 'none' : 'block'\n\n if (_uploadInProgress) {\n uploadButton.classList.add('transparent')\n timer = setInterval(doInnerUpdates, 300)\n } else {\n uploadButton.classList.remove('transparent')\n clearInterval(timer)\n }\n}\n\nconst secondsToTime = (secs) => {\n let hr = Math.floor(secs / 3600)\n let min = Math.floor((secs - (hr * 3600)) / 60)\n let sec = Math.floor(secs - (hr * 3600) - (min * 60))\n if (hr < 10) hr = `0${hr}`\n if (min < 10) min = `0${min}`\n if (sec < 10) sec = `0${sec}`\n if (hr) hr = '00'\n return `${hr}:${min}:${sec}`\n}\n\nconst bytesToSize = (bytes) => {\n const sizes = ['Bytes', 'KB', 'MB']\n if (bytes == 0) return 'n/a'\n const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))\n return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]\n}\n\nconst determineDragAndDropCapable = () => {\n const div = document.createElement('div')\n return (('draggable' in div)\n || ('ondragstart' in div && 'ondrop' in div))\n && 'FormData' in window\n && 'FileReader' in window\n}\n\n/* MAIN */\n\ndocument.addEventListener('DOMContentLoaded', () => {\n console.log(\"adding event listeners...\");\n videoTitle.addEventListener(\"keypress\", (e) => {\n console.log(\"keypress[1]: \" + e);\n if (e.keyCode == 9 || keyCode == 13 || keyCode == 10) {\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n });\n\n videoDescription.addEventListener(\"keypress\", (e) => {\n console.log(\"keypress[2]: \" + e);\n if (e.keyCode == 9 || keyCode == 13 || keyCode == 10) {\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n });\n\n ['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave']\n .forEach((evt) => {\n uploadForm.addEventListener(evt, (e) => {\n e.preventDefault()\n e.stopPropagation()\n })\n })\n\n uploadForm.addEventListener('drop', (e) => {\n console.log(111)\n e.preventDefault()\n e.stopPropagation()\n\n const _file = e.dataTransfer.files[0]\n if (!_file) return false\n fileSelected(_file)\n\n return false\n })\n}, false)\n\nconst labelClicked = (e) => {\n if (uploadInProgress === true || file != null) {\n e.preventDefault()\n return false\n }\n}\n\nconst fileSelected = (_file) => {\n const fileObj = _file || videoInput.files[0]\n if (_file) videoInput.value = ''\n\n if (fileObj) file = fileObj\n if (!file) return\n\n if (file.size > iMaxFilesize) {\n setMessage('Your file is very big. We can\\'t accept it. Please select more small file.', true)\n return\n }\n\n setMessage('')\n setProgress(0)\n \n const filename = file.name.length <= 20 ? file.name : `${file.name.substring(0, 14)}...${file.name.substring(file.name.length - 3)}`\n uploadFilenameLabel.innerText = filename\n uploadFileContainer.style.display = 'flex'\n \n uploadButtonWrapper.style.display = 'block'\n setUploadState(false)\n}\n\nconst removeFile = (e, keepMessage) => {\n if (e) e.preventDefault()\n if (uploadInProgress === true) return\n\n uploadFileContainer.style.display = 'none'\n uploadButtonWrapper.style.display = 'none'\n videoInput.value = ''\n file = null\n if (!keepMessage) setMessage('No file selected')\n\n return false\n}\n\nconst startUploading = () => {\n if (uploadInProgress === true) return\n if (!file) return\n\n isProcessing = false\n iPreviousBytesLoaded = 0\n setMessage('')\n setProgress(0)\n setUploadState(true)\n\n const formData = new FormData()\n formData.append('video_file', file)\n formData.append('video_title', videoTitle.value)\n formData.append('video_description', videoDescription.value)\n const xhr = new XMLHttpRequest()\n\n xhr.upload.addEventListener('progress', uploadProgress, false)\n xhr.addEventListener('load', uploadFinish, false)\n xhr.addEventListener('error', uploadError, false)\n xhr.addEventListener('abort', uploadAbort, false)\n\n xhr.open('POST', '/upload')\n xhr.send(formData)\n\n timer = setInterval(doInnerUpdates, 300)\n}\n\nconst doInnerUpdates = () => { // we will use this function to display upload speed\n if (isProcessing) {\n clearInterval(timer)\n return\n }\n\n let iDiff = iBytesUploaded - iPreviousBytesLoaded\n // if nothing new loaded - exit\n if (iDiff == 0)\n return\n iPreviousBytesLoaded = iBytesUploaded\n iDiff = iDiff * 2\n const iBytesRem = iBytesTotal - iPreviousBytesLoaded\n const secondsRemaining = iBytesRem / iDiff\n // update speed info\n let iSpeed = iDiff.toString() + 'B/s'\n if (iDiff > 1024 * 1024) {\n iSpeed = (Math.round(iDiff * 100/(1024*1024))/100).toString() + 'MB/s'\n } else if (iDiff > 1024) {\n iSpeed = (Math.round(iDiff * 100/1024)/100).toString() + 'KB/s'\n }\n\n const speedMessage = `${iSpeed} | ${secondsToTime(secondsRemaining)}`\n setMessage(speedMessage)\n}\n\nfunction uploadProgress(e) { // upload process in progress\n if (e.lengthComputable) {\n iBytesUploaded = e.loaded\n iBytesTotal = e.total\n\n const iPercentComplete = Math.round(iBytesUploaded / iBytesTotal * 100)\n setProgress(iPercentComplete)\n if (iPercentComplete === 100) {\n isProcessing = true\n setMessage('Processing video... please wait')\n }\n } else {\n setMessage('Unable to compute progress.')\n }\n}\n\nconst uploadFinish = (e) => { // upload successfully finished\n const message = e.target.responseText\n const isSuccess = e.target.status < 400\n\n setProgress(isSuccess ? 100 : 0)\n setMessage(message, !isSuccess)\n setUploadState(false)\n if (isSuccess) removeFile(null, true)\n}\n\nconst uploadError = () => { // upload error\n setMessage('An error occurred while uploading the file.', true)\n setProgress(0)\n setUploadState(false)\n}\n\nconst uploadAbort = () => { // upload abort\n setMessage('The upload has been canceled by the user or the browser dropped the connection.', true)\n setProgress(0)\n setUploadState(false)\n}\n"), + Content: string("// common variables\nlet iBytesUploaded = 0\nlet iBytesTotal = 0\nlet iPreviousBytesLoaded = 0\nlet iMaxFilesize = 104857600 // 100MB\nlet timer = 0\nlet uploadInProgress = 'n/a'\nlet isProcessing = false\nlet file = null\n\n/* CACHED ELEMENTS */\n\nconst uploadForm = document.getElementById('upload-form')\nconst videoInput = document.getElementById('video-input')\nconst videoTitle = document.getElementById('video-title')\nconst videoDescription = document.getElementById('video-description')\nconst uploadMessageLabel = document.getElementById('upload-message')\nconst uploadFileContainer = document.getElementById('upload-file')\nconst uploadFilenameLabel = document.getElementById('upload-filename')\nconst uploadButtonWrapper = document.getElementById('upload-button-wrapper')\nconst uploadButton = document.getElementById('upload-button')\nconst uploadProgressContainer = document.getElementById('upload-progress-container')\nconst uploadProgressBar = document.getElementById('upload-progress')\nconst uploadProgressLabel = document.getElementById('upload-progress-label')\nconst uploadStopped = document.getElementById('upload-stopped')\nconst uploadStarted = document.getElementById('upload-started')\n\n/* HELPERS */\n\nconst setProgress = (_progress) => {\n uploadProgressContainer.style.display = _progress > 0 ? 'flex' : 'none'\n uploadProgressBar.style.width = `${_progress}%`\n uploadProgressLabel.innerText = _progress >= 15 ? `${_progress}%` : ''\n}\n\nconst setMessage = (_message, isError) => {\n uploadMessageLabel.style.display = _message ? 'block' : 'none'\n uploadMessageLabel.innerHTML = _message\n if (isError) {\n uploadMessageLabel.classList.add('error')\n } else {\n uploadMessageLabel.classList.remove('error')\n }\n}\n\nconst setUploadState = (_uploadInProgress) => {\n uploadInProgress = _uploadInProgress\n\n uploadStarted.style.display = _uploadInProgress ? 'inline-block' : 'none'\n uploadStopped.style.display = _uploadInProgress ? 'none' : 'block'\n\n if (_uploadInProgress) {\n uploadButton.classList.add('transparent')\n timer = setInterval(doInnerUpdates, 300)\n } else {\n uploadButton.classList.remove('transparent')\n clearInterval(timer)\n }\n}\n\nconst secondsToTime = (secs) => {\n let hr = Math.floor(secs / 3600)\n let min = Math.floor((secs - (hr * 3600)) / 60)\n let sec = Math.floor(secs - (hr * 3600) - (min * 60))\n if (hr < 10) hr = `0${hr}`\n if (min < 10) min = `0${min}`\n if (sec < 10) sec = `0${sec}`\n if (hr) hr = '00'\n return `${hr}:${min}:${sec}`\n}\n\nconst bytesToSize = (bytes) => {\n const sizes = ['Bytes', 'KB', 'MB']\n if (bytes == 0) return 'n/a'\n const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))\n return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]\n}\n\nconst determineDragAndDropCapable = () => {\n const div = document.createElement('div')\n return (('draggable' in div)\n || ('ondragstart' in div && 'ondrop' in div))\n && 'FormData' in window\n && 'FileReader' in window\n}\n\n/* MAIN */\n\ndocument.addEventListener('DOMContentLoaded', () => {\n ['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave']\n .forEach((evt) => {\n uploadForm.addEventListener(evt, (e) => {\n e.preventDefault()\n e.stopPropagation()\n })\n })\n\n uploadForm.addEventListener('drop', (e) => {\n console.log(111)\n e.preventDefault()\n e.stopPropagation()\n\n const _file = e.dataTransfer.files[0]\n if (!_file) return false\n fileSelected(_file)\n\n return false\n })\n}, false)\n\nconst labelClicked = (e) => {\n if (uploadInProgress === true || file != null) {\n e.preventDefault()\n return false\n }\n}\n\nconst fileSelected = (_file) => {\n const fileObj = _file || videoInput.files[0]\n if (_file) videoInput.value = ''\n\n if (fileObj) file = fileObj\n if (!file) return\n\n if (file.size > iMaxFilesize) {\n setMessage('Your file is very big. We can\\'t accept it. Please select more small file.', true)\n return\n }\n\n setMessage('')\n setProgress(0)\n \n const filename = file.name.length <= 20 ? file.name : `${file.name.substring(0, 14)}...${file.name.substring(file.name.length - 3)}`\n uploadFilenameLabel.innerText = filename\n uploadFileContainer.style.display = 'flex'\n \n uploadButtonWrapper.style.display = 'block'\n setUploadState(false)\n}\n\nconst removeFile = (e, keepMessage) => {\n if (e) e.preventDefault()\n if (uploadInProgress === true) return\n\n uploadFileContainer.style.display = 'none'\n uploadButtonWrapper.style.display = 'none'\n videoInput.value = ''\n file = null\n if (!keepMessage) setMessage('No file selected')\n\n return false\n}\n\nconst startUploading = () => {\n if (uploadInProgress === true) return\n if (!file) return\n\n isProcessing = false\n iPreviousBytesLoaded = 0\n setMessage('')\n setProgress(0)\n setUploadState(true)\n\n const formData = new FormData()\n formData.append('video_file', file)\n formData.append('video_title', videoTitle.value)\n formData.append('video_description', videoDescription.value)\n const xhr = new XMLHttpRequest()\n\n xhr.upload.addEventListener('progress', uploadProgress, false)\n xhr.addEventListener('load', uploadFinish, false)\n xhr.addEventListener('error', uploadError, false)\n xhr.addEventListener('abort', uploadAbort, false)\n\n xhr.open('POST', '/upload')\n xhr.send(formData)\n\n timer = setInterval(doInnerUpdates, 300)\n}\n\nconst doInnerUpdates = () => { // we will use this function to display upload speed\n if (isProcessing) {\n clearInterval(timer)\n return\n }\n\n let iDiff = iBytesUploaded - iPreviousBytesLoaded\n // if nothing new loaded - exit\n if (iDiff == 0)\n return\n iPreviousBytesLoaded = iBytesUploaded\n iDiff = iDiff * 2\n const iBytesRem = iBytesTotal - iPreviousBytesLoaded\n const secondsRemaining = iBytesRem / iDiff\n // update speed info\n let iSpeed = iDiff.toString() + 'B/s'\n if (iDiff > 1024 * 1024) {\n iSpeed = (Math.round(iDiff * 100/(1024*1024))/100).toString() + 'MB/s'\n } else if (iDiff > 1024) {\n iSpeed = (Math.round(iDiff * 100/1024)/100).toString() + 'KB/s'\n }\n\n const speedMessage = `${iSpeed} | ${secondsToTime(secondsRemaining)}`\n setMessage(speedMessage)\n}\n\nfunction uploadProgress(e) { // upload process in progress\n if (e.lengthComputable) {\n iBytesUploaded = e.loaded\n iBytesTotal = e.total\n\n const iPercentComplete = Math.round(iBytesUploaded / iBytesTotal * 100)\n setProgress(iPercentComplete)\n if (iPercentComplete === 100) {\n isProcessing = true\n setMessage('Processing video... please wait')\n }\n } else {\n setMessage('Unable to compute progress.')\n }\n}\n\nconst uploadFinish = (e) => { // upload successfully finished\n const message = e.target.responseText\n const isSuccess = e.target.status < 400\n\n setProgress(isSuccess ? 100 : 0)\n setMessage(message, !isSuccess)\n setUploadState(false)\n if (isSuccess) removeFile(null, true)\n}\n\nconst uploadError = () => { // upload error\n setMessage('An error occurred while uploading the file.', true)\n setProgress(0)\n setUploadState(false)\n}\n\nconst uploadAbort = () => { // upload abort\n setMessage('The upload has been canceled by the user or the browser dropped the connection.', true)\n setProgress(0)\n setUploadState(false)\n}\n"), } // define dirs dir6 := &embedded.EmbeddedDir{ Filename: "", - DirModTime: time.Unix(1585653781, 0), + DirModTime: time.Unix(1585653972, 0), ChildFiles: []*embedded.EmbeddedFile{ file7, // "close-icon.png" file8, // "defaulticon.jpg" @@ -148,7 +148,7 @@ func init() { // register embeddedBox embedded.RegisterEmbeddedBox(`../static`, &embedded.EmbeddedBox{ Name: `../static`, - Time: time.Unix(1585653781, 0), + Time: time.Unix(1585653972, 0), Dirs: map[string]*embedded.EmbeddedDir{ "": dir6, }, diff --git a/importers/importer.go b/importers/importer.go index f5d4b36..eab5b24 100644 --- a/importers/importer.go +++ b/importers/importer.go @@ -23,9 +23,9 @@ type Importer interface { } func NewImporter(url string) (Importer, error) { - if strings.Contains(url, "youtube.com") || strings.HasPrefix(url, "youtube:") { + if strings.Contains(url, "youtube.com") || strings.HasPrefix(strings.ToLower(url), "youtube:") { return &YoutubeImporter{}, nil - } else if strings.Contains(url, "vimeo.com") || strings.HasPrefix(url, "vimeo:") { + } else if strings.Contains(url, "vimeo.com") || strings.HasPrefix(strings.ToLower(url), "vimeo:") { return &VimeoImporter{}, nil } else { return nil, ErrUnsupportedVideoURL diff --git a/importers/vimeo_importer.go b/importers/vimeo_importer.go index 9983a69..ad21bcc 100644 --- a/importers/vimeo_importer.go +++ b/importers/vimeo_importer.go @@ -10,8 +10,8 @@ import ( type VimeoImporter struct{} func (i *VimeoImporter) GetVideoInfo(url string) (videoInfo VideoInfo, err error) { - if strings.HasPrefix(url, "vimeo:") { - url = strings.TrimPrefix(url, "vimeo:") + if strings.HasPrefix(strings.ToLower(url), "vimeo:") { + url = strings.TrimSpace(strings.SplitN(url, ":", 2)[1]) } if !strings.HasPrefix(url, "http") { diff --git a/importers/youtube_importer.go b/importers/youtube_importer.go index 5702b05..c309850 100644 --- a/importers/youtube_importer.go +++ b/importers/youtube_importer.go @@ -10,8 +10,8 @@ import ( type YoutubeImporter struct{} func (i *YoutubeImporter) GetVideoInfo(url string) (videoInfo VideoInfo, err error) { - if strings.HasPrefix(url, "youtube:") { - url = strings.TrimPrefix(url, "youtube:") + if strings.HasPrefix(strings.ToLower(url), "youtube:") { + url = strings.TrimSpace(strings.SplitN(url, ":", 2)[1]) } info, err := ytdl.GetVideoInfo(url)