perf: Add download path management (#1359)

This commit is contained in:
Rémi Marseault 2023-11-26 16:39:06 +01:00 committed by GitHub
parent fdad814b1f
commit 988ecaaa03
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 24 deletions

View file

@ -52,8 +52,12 @@ function deleteTorrents() {
dialogStore.createDialog(ConfirmDeleteDialog, { hashes: [...dashboardStore.selectedTorrents] }) dialogStore.createDialog(ConfirmDeleteDialog, { hashes: [...dashboardStore.selectedTorrents] })
} }
function moveTorrents() { function setDownloadPath() {
dialogStore.createDialog(MoveTorrentDialog, { hashes: [...dashboardStore.selectedTorrents] }) dialogStore.createDialog(MoveTorrentDialog, { hashes: [...dashboardStore.selectedTorrents], mode: 'dl' })
}
function setSavePath() {
dialogStore.createDialog(MoveTorrentDialog, { hashes: [...dashboardStore.selectedTorrents], mode: 'save' })
} }
function renameTorrents() { function renameTorrents() {
@ -126,9 +130,14 @@ const menuData = computed<TRCMenuEntry[]>(() => [
icon: 'mdi-head-cog', icon: 'mdi-head-cog',
children: [ children: [
{ {
text: t('dashboard.right_click.advanced.change_location'), text: t('dashboard.right_click.advanced.download_path'),
icon: 'mdi-folder', icon: 'mdi-tray-arrow-down',
action: moveTorrents action: setDownloadPath
},
{
text: t('dashboard.right_click.advanced.save_path'),
icon: 'mdi-content-save',
action: setSavePath
}, },
{ {
text: t('dashboard.right_click.advanced.rename'), text: t('dashboard.right_click.advanced.rename'),

View file

@ -1,17 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
import { useDialog } from '@/composables' import { useDialog } from '@/composables'
import { useTorrentStore } from '@/stores' import { useMaindataStore, useTorrentStore } from '@/stores'
import { computed, onBeforeMount, reactive, ref } from 'vue' import { computed, onBeforeMount, reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { VForm } from 'vuetify/components' import { VForm } from 'vuetify/components'
const props = defineProps<{ const props = defineProps<{
guid: string guid: string
hashes: string[] hashes: string[],
mode: 'dl' | 'save'
}>() }>()
const { isOpened } = useDialog(props.guid) const { isOpened } = useDialog(props.guid)
const { t } = useI18n() const { t } = useI18n()
const maindataStore = useMaindataStore()
const torrentStore = useTorrentStore() const torrentStore = useTorrentStore()
const form = ref<VForm>() const form = ref<VForm>()
@ -20,16 +22,24 @@ const formData = reactive({
newPath: '' newPath: ''
}) })
const rules = [(v: string) => !!v || t('dialogs.moveTorrent.required'), (v: string) => v !== oldPath.value || t('dialogs.moveTorrent.samePath')] const rules = [(v: string) => !!v || t('dialogs.moveTorrent.required')]
const torrents = computed(() => props.hashes.map(torrentStore.getTorrentByHash)) const torrents = computed(() => props.hashes.map(torrentStore.getTorrentByHash))
const oldPath = computed(() => torrents.value[0]?.savePath) const oldPath = computed(() => {
switch (props.mode) {
case 'dl':
return torrents.value[0]?.download_path
case 'save':
return torrents.value[0]?.savePath
}
})
async function submit() { async function submit() {
await form.value?.validate() await form.value?.validate()
if (!isFormValid.value) return if (!isFormValid.value) return
await torrentStore.moveTorrents(props.hashes, formData.newPath) await maindataStore.toggleAutoTmm(props.hashes, false)
await torrentStore.moveTorrents(props.mode, props.hashes, formData.newPath)
close() close()
} }
@ -39,14 +49,14 @@ const close = () => {
} }
onBeforeMount(() => { onBeforeMount(() => {
formData.newPath = torrents.value[0]?.savePath || '' formData.newPath = oldPath.value || ''
}) })
</script> </script>
<template> <template>
<v-dialog v-model="isOpened"> <v-dialog v-model="isOpened">
<v-card> <v-card>
<v-card-title>{{ $t('dialogs.moveTorrent.title') }}</v-card-title> <v-card-title>{{ $t(`dialogs.moveTorrent.${mode}.title`) }}</v-card-title>
<v-card-text> <v-card-text>
<v-form v-model="isFormValid" ref="form" @submit.prevent> <v-form v-model="isFormValid" ref="form" @submit.prevent>
<v-text-field v-if="oldPath" :model-value="oldPath" disabled :label="$t('dialogs.moveTorrent.oldPath')" /> <v-text-field v-if="oldPath" :model-value="oldPath" disabled :label="$t('dialogs.moveTorrent.oldPath')" />

View file

@ -126,8 +126,8 @@ async function copyHash() {
await navigator.clipboard.writeText(props.torrent.hash) await navigator.clipboard.writeText(props.torrent.hash)
} }
function openMoveTorrentDialog() { function openMoveTorrentDialog(mode: 'dl' | 'save') {
dialogStore.createDialog(MoveTorrentDialog, { hashes: [props.torrent.hash] }) dialogStore.createDialog(MoveTorrentDialog, { hashes: [props.torrent.hash], mode })
} }
function openMoveTorrentFileDialog() { function openMoveTorrentFileDialog() {
@ -169,9 +169,15 @@ watch(
function handleKeyboardShortcuts(e: KeyboardEvent) { function handleKeyboardShortcuts(e: KeyboardEvent) {
if (dialogStore.hasActiveDialog) return false if (dialogStore.hasActiveDialog) return false
if (e.key === 'd') {
e.preventDefault()
openMoveTorrentDialog('dl')
return true
}
if (e.key === 's') { if (e.key === 's') {
e.preventDefault() e.preventDefault()
openMoveTorrentDialog() openMoveTorrentDialog('save')
return true return true
} }
@ -210,7 +216,7 @@ onUnmounted(() => {
<v-row> <v-row>
<v-col cols="12" md="6"> <v-col cols="12" md="6">
<v-row> <v-row>
<v-col cols="4" md="4"> <v-col cols="4">
<v-progress-circular :color="torrentStateColor" :indeterminate="isFetchingMetadata" :size="100" <v-progress-circular :color="torrentStateColor" :indeterminate="isFetchingMetadata" :size="100"
:model-value="torrent?.progress * 100 ?? 0" :width="15"> :model-value="torrent?.progress * 100 ?? 0" :width="15">
<template v-slot> <template v-slot>
@ -220,7 +226,7 @@ onUnmounted(() => {
</template> </template>
</v-progress-circular> </v-progress-circular>
</v-col> </v-col>
<v-col cols="8" md="8" class="d-flex flex-column align-center justify-center"> <v-col cols="8" class="d-flex flex-column align-center justify-center">
<div v-if="isFetchingMetadata"> <div v-if="isFetchingMetadata">
<span>{{ $t('torrentDetail.overview.waitingForMetadata') }}</span> <span>{{ $t('torrentDetail.overview.waitingForMetadata') }}</span>
</div> </div>
@ -259,9 +265,9 @@ onUnmounted(() => {
<v-row> <v-row>
<v-col cols="6"> <v-col cols="6">
<div>{{ $t('torrent.properties.save_path') }}:</div> <div>{{ $t('torrent.properties.download_path') }}:</div>
<div>{{ torrent.savePath }}</div> <div>{{ torrent.download_path }}</div>
<v-btn icon="mdi-pencil" color="accent" size="x-small" @click="openMoveTorrentDialog" /> <v-btn icon="mdi-pencil" color="accent" size="x-small" @click="openMoveTorrentDialog('dl')" />
</v-col> </v-col>
<v-col cols="6"> <v-col cols="6">
<div>{{ $t('torrentDetail.overview.fileCount') }}:</div> <div>{{ $t('torrentDetail.overview.fileCount') }}:</div>
@ -271,7 +277,20 @@ onUnmounted(() => {
@click="openMoveTorrentFileDialog" /> @click="openMoveTorrentFileDialog" />
</v-col> </v-col>
</v-row> </v-row>
<v-row>
<v-col cols="6">
<div>{{ $t('torrent.properties.save_path') }}:</div>
<div>{{ torrent.savePath }}</div>
<v-btn icon="mdi-pencil" color="accent" size="x-small" @click="openMoveTorrentDialog('save')" />
</v-col>
<v-col cols="6">
<div>{{ $t('torrent.properties.content_path') }}:</div>
<div>{{ torrent.content_path }}</div>
</v-col>
</v-row>
</v-col> </v-col>
<v-col cols="12" md="6"> <v-col cols="12" md="6">
<v-row> <v-row>
<v-col cols="6"> <v-col cols="6">

View file

@ -354,8 +354,22 @@ export class QBitApi {
return this.torrentAction('recheck', hashes) return this.torrentAction('recheck', hashes)
} }
async setTorrentLocation(hashes: string[], location: string): Promise<void> { async setTorrentDownloadPath(hashes: string[], path: string): Promise<void> {
return this.torrentAction('setLocation', hashes, { location }) const params = {
id: hashes.length ? hashes.join('|') : 'all',
path
}
return this.execute(`/torrents/setDownloadPath`, params)
}
async setTorrentSavePath(hashes: string[], path: string): Promise<void> {
const params = {
id: hashes.length ? hashes.join('|') : 'all',
path
}
return this.execute(`/torrents/setSavePath`, params)
} }
async addTorrentTrackers(hash: string, trackers: string): Promise<void> { async addTorrentTrackers(hash: string, trackers: string): Promise<void> {

View file

@ -95,8 +95,13 @@ export const useTorrentStore = defineStore('torrents', () => {
await qbit.deleteTorrents(hashes, deleteWithFiles) await qbit.deleteTorrents(hashes, deleteWithFiles)
} }
async function moveTorrents(hashes: string[], newPath: string) { async function moveTorrents(mode: 'dl' | 'save', hashes: string[], newPath: string) {
await qbit.setTorrentLocation(hashes, newPath) switch (mode) {
case 'dl':
return await qbit.setTorrentDownloadPath(hashes, newPath)
case 'save':
return await qbit.setTorrentSavePath(hashes, newPath)
}
} }
async function addTorrents(torrents: File[], urls: string, payload: AddTorrentPayload) { async function addTorrents(torrents: File[], urls: string, payload: AddTorrentPayload) {