From 36dfb7849d8892bfb2cbd968905635a623f2450d Mon Sep 17 00:00:00 2001 From: PrestonN Date: Tue, 1 Feb 2022 22:11:38 -0500 Subject: [PATCH] Refactor video download logic --- .../ft-icon-button/ft-icon-button.js | 31 +--- src/renderer/components/ft-toast/ft-toast.js | 8 +- .../watch-video-info/watch-video-info.js | 21 +++ .../watch-video-info/watch-video-info.vue | 4 +- src/renderer/store/modules/utils.js | 144 ++++++++---------- static/locales/en-US.yaml | 8 +- 6 files changed, 95 insertions(+), 121 deletions(-) diff --git a/src/renderer/components/ft-icon-button/ft-icon-button.js b/src/renderer/components/ft-icon-button/ft-icon-button.js index d26ffede..02e3bcdb 100644 --- a/src/renderer/components/ft-icon-button/ft-icon-button.js +++ b/src/renderer/components/ft-icon-button/ft-icon-button.js @@ -32,6 +32,10 @@ export default Vue.extend({ type: Boolean, default: false }, + returnIndex: { + type: Boolean, + default: false + }, dropdownPositionX: { type: String, default: 'center' @@ -47,11 +51,6 @@ export default Vue.extend({ dropdownValues: { type: Array, default: () => { return [] } - }, - relatedVideoTitle: { - type: String, - default: () => { return '' }, - require: false } }, data: function () { @@ -60,18 +59,6 @@ export default Vue.extend({ id: '' } }, - computed: { - filesExtensions: function() { - const regex = /\/(\w*)/i - return this.dropdownNames.slice().map((el) => { - const group = el.match(regex) - if (group === null || group.length === 0) { - return '' - } - return group[1] - }) - } - }, mounted: function () { this.id = `iconButton${this._uid}` }, @@ -128,16 +115,12 @@ export default Vue.extend({ }, handleDropdownClick: function (index) { - if (this.relatedVideoTitle !== '') { - this.$emit('click', { - url: this.dropdownValues[index], - title: this.relatedVideoTitle, - extension: this.filesExtensions[index], - folderPath: this.$store.getters.getDownloadFolderPath - }) + if (this.returnIndex) { + this.$emit('click', index) } else { this.$emit('click', this.dropdownValues[index]) } + this.focusOut() } } diff --git a/src/renderer/components/ft-toast/ft-toast.js b/src/renderer/components/ft-toast/ft-toast.js index df557a5e..be0b4e3e 100644 --- a/src/renderer/components/ft-toast/ft-toast.js +++ b/src/renderer/components/ft-toast/ft-toast.js @@ -25,13 +25,7 @@ export default Vue.extend({ toast.isOpen = false }, - open: function (message, action, time, translate = false, formatArgs = []) { - if (translate) { - message = this.$t(message) - for (const arg of formatArgs) { - message = message.replace('$', arg) - } - } + open: function (message, action, time) { const toast = { message: message, action: action || (() => { }), isOpen: false, timeout: null } toast.timeout = setTimeout(this.close, time || 3000, toast) setImmediate(() => { toast.isOpen = true }) diff --git a/src/renderer/components/watch-video-info/watch-video-info.js b/src/renderer/components/watch-video-info/watch-video-info.js index 995fc08d..07ff0442 100644 --- a/src/renderer/components/watch-video-info/watch-video-info.js +++ b/src/renderer/components/watch-video-info/watch-video-info.js @@ -408,6 +408,27 @@ export default Vue.extend({ } }, + handleDownload: function (index) { + const url = this.downloadLinkValues[index] + const linkName = this.downloadLinkNames[index] + const extension = this.grabExtensionFromUrl(linkName) + + this.downloadMedia({ + url: url, + title: this.title, + extension: extension + }) + }, + + grabExtensionFromUrl: function (url) { + const regex = /\/(\w*)/i + const group = url.match(regex) + if (group.length === 0) { + return '' + } + return group[1] + }, + addToPlaylist: function () { const videoData = { videoId: this.id, diff --git a/src/renderer/components/watch-video-info/watch-video-info.vue b/src/renderer/components/watch-video-info/watch-video-info.vue index 673fe808..1d21d801 100644 --- a/src/renderer/components/watch-video-info/watch-video-info.vue +++ b/src/renderer/components/watch-video-info/watch-video-info.vue @@ -99,10 +99,10 @@ class="option" theme="secondary" icon="download" + :return-index="true" :dropdown-names="downloadLinkNames" :dropdown-values="downloadLinkValues" - :related-video-title="title" - @click="downloadMedia" + @click="handleDownload" /> { + console.log(error) + dispatch('showToast', { + message: errorMessage + }) }) - const response = await fetch(url) - // mechanism to show the download progress reference https://javascript.info/fetch-progress const reader = response.body.getReader() - const contentLength = response.headers.get('Content-Length') - let receivedLength = 0 const chunks = [] - // manage frequency notifications to the user - const intervalPercentageNotification = 0.2 - let lastPercentageNotification = 0 - while (true) { - const { done, value } = await reader.read() + const handleError = (err) => { + console.log(err) + dispatch('showToast', { + message: errorMessage + }) + } + const processText = async ({ done, value }) => { if (done) { - break + return } chunks.push(value) receivedLength += value.length + // Can be used in the future to determine download percentage const percentage = receivedLength / contentLength - if (percentage > (lastPercentageNotification + intervalPercentageNotification)) { - // mechanism kept for an upcoming download page - lastPercentageNotification = percentage - } + await reader.read().then(processText).catch(handleError) } - const chunksAll = new Uint8Array(receivedLength) - let position = 0 - for (const chunk of chunks) { - chunksAll.set(chunk, position) - position += chunk.length - } + await reader.read().then(processText).catch(handleError) - // write the file into the hardrive - if (!response.ok) { - console.error(`"Unable to download ${title}, return status code ${response.status}`) - dispatch('showToast', { - message: 'Downloading failed', translate: true, formatArgs: [title, response.status] - }) - return - } const blobFile = new Blob(chunks) const buffer = await blobFile.arrayBuffer() - if (usingElectron && !askFolderPath) { - fs.writeFile(`${folderPath}/${title}.${extension}`, new DataView(buffer), (err) => { - if (err) { - console.error(err) - dispatch('updateDownloadFolderPath', '') - dispatch('downloadMedia', { url: url, title: title, extension: extension, folderPath: '', fallingBackPath: folderPath }) - } else { - dispatch('showToast', { - message: successMsg, translate: true, formatArgs: [title] - }) - } - }) - } else if (usingElectron) { - fs.writeFile(filePathSelected, new DataView(buffer), (err) => { - if (err) { - console.error(err) - if (filePathSelected === '') { - dispatch('showToast', { - message: 'Downloading canceled', - translate: true - }) - } else { - dispatch('showToast', { - message: err - }) - } - } else { - dispatch('showToast', { - message: successMsg, translate: true, formatArgs: [title] - }) - } - }) - } else { - // Web placeholder - } + fs.writeFile(folderPath, new DataView(buffer), (err) => { + if (err) { + console.error(err) + dispatch('showToast', { + message: errorMessage + }) + } else { + dispatch('showToast', { + message: completedMessage + }) + } + }) }, async getSystemLocale (context) { @@ -790,9 +770,7 @@ const actions = { }, showToast (_, payload) { - const formatArgs = 'formatArgs' in payload ? payload.formatArgs : [] - const translate = 'translate' in payload ? payload.translate : false - FtToastEvents.$emit('toast-open', payload.message, payload.action, payload.time, translate, formatArgs) + FtToastEvents.$emit('toast-open', payload.message, payload.action, payload.time) }, showExternalPlayerUnsupportedActionToast: function ({ dispatch }, payload) { diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml index f4e090b5..0841c8f6 100644 --- a/static/locales/en-US.yaml +++ b/static/locales/en-US.yaml @@ -713,11 +713,9 @@ Default Invidious instance has been cleared: Default Invidious instance has been 'The playlist has ended. Enable loop to continue playing': 'The playlist has ended. Enable loop to continue playing' External link opening has been disabled in the general settings: 'External link opening has been disabled in the general settings' -Downloading has completed: 'Downloading "$" has completed' -Starting download: 'Downloading "$" has started' -Downloading failed: 'Unable to download "$", return http request status code $' -Downloading canceled: The dowload is canceled by the user -Download folder does not exist: The download directory "$" doesn't exist. Falling back to "ask folder" mode. +Downloading has completed: '"$" has finished downloading' +Starting download: 'Starting download of "$"' +Downloading failed: 'There was an issue downloading "$"' Yes: Yes No: No