feat(export): Zip files when exporting several torrents (#1794)

This commit is contained in:
Rémi Marseault 2024-07-19 07:27:01 -05:00 committed by GitHub
parent 1599b0f5e7
commit 7236b23281
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 18 deletions

12
package-lock.json generated
View file

@ -16,6 +16,7 @@
"@mdi/font": "^7.4.47",
"@mdi/js": "^7.4.47",
"@vueuse/core": "^10.11.0",
"@zip.js/zip.js": "^2.7.45",
"apexcharts": "^3.50.0",
"axios": "^1.7.2",
"dayjs": "^1.11.11",
@ -1946,6 +1947,17 @@
"resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz",
"integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA=="
},
"node_modules/@zip.js/zip.js": {
"version": "2.7.45",
"resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.45.tgz",
"integrity": "sha512-Mm2EXF33DJQ/3GWWEWeP1UCqzpQ5+fiMvT3QWspsXY05DyqqxWu7a9awSzU4/spHMHVFrTjani1PR0vprgZpow==",
"license": "BSD-3-Clause",
"engines": {
"bun": ">=0.7.0",
"deno": ">=1.0.0",
"node": ">=16.5.0"
}
},
"node_modules/abbrev": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",

View file

@ -25,6 +25,7 @@
"@mdi/font": "^7.4.47",
"@mdi/js": "^7.4.47",
"@vueuse/core": "^10.11.0",
"@zip.js/zip.js": "^2.7.45",
"apexcharts": "^3.50.0",
"axios": "^1.7.2",
"dayjs": "^1.11.11",

View file

@ -7,6 +7,7 @@ import ShareLimitDialog from '@/components/Dialogs/ShareLimitDialog.vue'
import SpeedLimitDialog from '@/components/Dialogs/SpeedLimitDialog.vue'
import { useCategoryStore, useDashboardStore, useDialogStore, useMaindataStore, usePreferenceStore, useTagStore, useTorrentStore } from '@/stores'
import { RightClickMenuEntryType } from '@/types/vuetorrent'
import { BlobReader, BlobWriter, ZipWriter } from '@zip.js/zip.js'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
@ -117,19 +118,26 @@ function setShareLimit() {
dialogStore.createDialog(ShareLimitDialog, { hashes: hashes.value })
}
function downloadFile(filename: string, blob: Blob) {
const href = window.URL.createObjectURL(blob)
const el = Object.assign(document.createElement('a'), { href, download: filename, style: { opacity: '0' } })
document.body.appendChild(el)
el.click()
el.remove()
}
async function exportTorrents() {
hashes.value.forEach(hash => {
torrentStore.exportTorrent(hash).then(blob => {
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.style.opacity = '0'
link.setAttribute('download', `${hash}.torrent`)
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
})
})
const ts = [...torrents.value]
if (ts.length === 1) {
const t = ts[0]!
const blob = await torrentStore.exportTorrent(t.hash)
downloadFile(`${t.name}.torrent`, blob)
return
}
const zipWriter = new ZipWriter(new BlobWriter('application/zip'), { bufferedWrite: true })
await Promise.all(hashes.value.map(hash => torrentStore.exportTorrent(hash).then(blob => zipWriter.add(`${torrentStore.getTorrentByHash(hash)!.name}.torrent`, new BlobReader(blob)))))
downloadFile('torrents.zip', await zipWriter.close())
}
const menuData = computed<RightClickMenuEntryType[]>(() => [
@ -216,12 +224,12 @@ const menuData = computed<RightClickMenuEntryType[]>(() => [
children: [
...(torrent.value?.tags.length
? [
{
text: t('dashboard.right_click.tags.remove_all'),
action: () => removeAllTags().then(maindataStore.forceMaindataSync),
icon: 'mdi-playlist-remove'
}
]
{
text: t('dashboard.right_click.tags.remove_all'),
action: () => removeAllTags().then(maindataStore.forceMaindataSync),
icon: 'mdi-playlist-remove'
}
]
: []),
...tagStore.tags.map(tag => ({
text: tag,