mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2025-02-26 04:10:52 +03:00
feat(AddTorrentDialog): Rework dialog to add missing parameters (#1323)
This commit is contained in:
parent
153268f30d
commit
f69851cc39
17 changed files with 506 additions and 226 deletions
|
@ -2,23 +2,23 @@
|
|||
import AddPanel from '@/components/AddPanel.vue'
|
||||
import DnDZone from '@/components/DnDZone.vue'
|
||||
import Navbar from '@/components/Navbar/Navbar.vue'
|
||||
import { useAddTorrentStore } from '@/stores/addTorrents'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useDialogStore } from '@/stores/dialog'
|
||||
import { useLogStore } from '@/stores/logs'
|
||||
import { useMaindataStore } from '@/stores/maindata'
|
||||
import { useNavbarStore } from '@/stores/navbar.ts'
|
||||
import { usePreferenceStore } from '@/stores/preferences'
|
||||
import { useVueTorrentStore } from '@/stores/vuetorrent'
|
||||
|
||||
import { onBeforeMount, watch } from 'vue'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const addTorrentStore = useAddTorrentStore()
|
||||
const appStore = useAppStore()
|
||||
const authStore = useAuthStore()
|
||||
const dialogStore = useDialogStore()
|
||||
const logStore = useLogStore()
|
||||
const maindataStore = useMaindataStore()
|
||||
const navbarStore = useNavbarStore()
|
||||
const preferencesStore = usePreferenceStore()
|
||||
const vuetorrentStore = useVueTorrentStore()
|
||||
|
||||
|
@ -63,7 +63,7 @@ watch(
|
|||
await logStore.fetchLogs()
|
||||
await maindataStore.fetchCategories()
|
||||
await maindataStore.fetchTags()
|
||||
navbarStore.initAddTorrentDialogForm()
|
||||
addTorrentStore.initForm()
|
||||
} else {
|
||||
appStore.clearIntervals()
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import AddTorrentDialog from '@/components/Dialogs/AddTorrentDialog.vue'
|
||||
import { useAddTorrentStore } from '@/stores/addTorrents'
|
||||
import { useDialogStore } from '@/stores/dialog'
|
||||
import { useNavbarStore } from '@/stores/navbar'
|
||||
|
||||
const addTorrentStore = useAddTorrentStore()
|
||||
const dialogStore = useDialogStore()
|
||||
const navbarStore = useNavbarStore()
|
||||
|
||||
function openAddTorrentDialog() {
|
||||
dialogStore.createDialog(AddTorrentDialog)
|
||||
|
@ -12,8 +12,8 @@ function openAddTorrentDialog() {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<v-bottom-navigation :active="navbarStore.pendingTorrentsCount > 0" class="pointer" v-touch="{ up: openAddTorrentDialog }" @click="openAddTorrentDialog">
|
||||
<v-list-item :title="$t('navbar.addPanel.torrentsPendingCount', navbarStore.pendingTorrentsCount)" />
|
||||
<v-bottom-navigation :active="addTorrentStore.pendingTorrentsCount > 0" class="pointer" v-touch="{ up: openAddTorrentDialog }" @click="openAddTorrentDialog">
|
||||
<v-list-item :title="$t('navbar.addPanel.torrentsPendingCount', addTorrentStore.pendingTorrentsCount)" />
|
||||
<v-spacer />
|
||||
<v-list-item>
|
||||
<v-icon icon="mdi-chevron-up" />
|
||||
|
|
|
@ -22,7 +22,7 @@ defineProps<{
|
|||
<span v-if="disabled && disabledText">{{ disabledText }}</span>
|
||||
<span v-else>{{ text }}</span>
|
||||
<v-spacer />
|
||||
<v-icon v-if="children">mdi-chevron-right</v-icon>
|
||||
<v-icon v-if="!disabled && children">mdi-chevron-right</v-icon>
|
||||
</div>
|
||||
<v-menu v-if="children" activator="parent" :open-on-hover="true" :open-on-click="true" close-delay="0" open-delay="0" location="right">
|
||||
<v-list>
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
<script lang="ts" setup>
|
||||
import { useDialog } from '@/composables'
|
||||
import { AppPreferences } from '@/constants/qbit'
|
||||
import { useAddTorrentStore } from '@/stores/addTorrents'
|
||||
import { useMaindataStore } from '@/stores/maindata'
|
||||
import { useNavbarStore } from '@/stores/navbar'
|
||||
import { usePreferenceStore } from '@/stores/preferences'
|
||||
import { useVueTorrentStore } from '@/stores/vuetorrent'
|
||||
import { AddTorrentPayload } from '@/types/qbit/payloads'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { toast } from 'vue3-toastify'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
guid: string
|
||||
|
@ -18,65 +19,152 @@ const props = withDefaults(defineProps<{
|
|||
|
||||
const { isOpened } = useDialog(props.guid)
|
||||
const { t } = useI18n()
|
||||
const addTorrentStore = useAddTorrentStore()
|
||||
const maindataStore = useMaindataStore()
|
||||
const navbarStore = useNavbarStore()
|
||||
const { urls, files, form } = storeToRefs(addTorrentStore)
|
||||
const preferenceStore = usePreferenceStore()
|
||||
const vueTorrentStore = useVueTorrentStore()
|
||||
|
||||
const fileOverflowDisplayLimit = 2
|
||||
|
||||
const isFormValid = computed(() => navbarStore.addTorrentDialogUrls.length > 0 || navbarStore.addTorrentDialogFiles.length > 0)
|
||||
const tagSearch = ref('')
|
||||
const categorySearch = ref('')
|
||||
const isLoading = ref(false)
|
||||
|
||||
const contentLayoutOptions = ref([
|
||||
const contentLayoutOptions = [
|
||||
{ title: t('constants.contentLayout.original'), value: AppPreferences.ContentLayout.ORIGINAL },
|
||||
{ title: t('constants.contentLayout.subfolder'), value: AppPreferences.ContentLayout.SUBFOLDER },
|
||||
{ title: t('constants.contentLayout.nosubfolder'), value: AppPreferences.ContentLayout.NO_SUBFOLDER }
|
||||
])
|
||||
const stopConditionOptions = ref([
|
||||
]
|
||||
const stopConditionOptions = [
|
||||
{ title: t('constants.stopCondition.none'), value: AppPreferences.StopCondition.NONE },
|
||||
{ title: t('constants.stopCondition.metadataReceived'), value: AppPreferences.StopCondition.METADATA_RECEIVED },
|
||||
{ title: t('constants.stopCondition.filesChecked'), value: AppPreferences.StopCondition.FILES_CHECKED }
|
||||
])
|
||||
]
|
||||
|
||||
const submit = async () => {
|
||||
const isFormValid = computed(() => urls.value.length > 0 || files.value.length > 0)
|
||||
|
||||
const cookie = computed({
|
||||
get: () => form.value.cookie,
|
||||
set: value => form.value.cookie = value || undefined
|
||||
})
|
||||
|
||||
const rename = computed({
|
||||
get: () => form.value.rename,
|
||||
set: value => form.value.rename = value || undefined
|
||||
})
|
||||
|
||||
const tagSearch = ref('')
|
||||
const tags = computed({
|
||||
get: () => {
|
||||
if (form.value.tags) {
|
||||
return form.value.tags.split(',').map(tag => tag.trim())
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
},
|
||||
set: (value: string[]) => form.value.tags = value.join(',')
|
||||
})
|
||||
|
||||
const categorySearch = ref('')
|
||||
const categories = computed(() => maindataStore.categories.map(c => c.name))
|
||||
const category = computed<string | undefined>({
|
||||
get: () => form.value.category || categorySearch.value || undefined,
|
||||
set: value => form.value.category = value || undefined
|
||||
})
|
||||
|
||||
const downloadPath = computed({
|
||||
get: () => form.value.downloadPath,
|
||||
set: value => {
|
||||
form.value.useDownloadPath = !!value || undefined
|
||||
form.value.downloadPath = value || undefined
|
||||
}
|
||||
})
|
||||
|
||||
const startNow = computed({
|
||||
get: () => !form.value.paused,
|
||||
set: value => form.value.paused = !value
|
||||
})
|
||||
|
||||
const dlLimit = computed({
|
||||
get: () => {
|
||||
if (!form.value.dlLimit || form.value.dlLimit === -1) {
|
||||
return ''
|
||||
} else {
|
||||
return (form.value.dlLimit / 1024).toString()
|
||||
}
|
||||
},
|
||||
set: value => {
|
||||
if (!value) {
|
||||
form.value.dlLimit = undefined
|
||||
} else {
|
||||
const parsedValue = parseInt(value)
|
||||
if (parsedValue > 0) {
|
||||
form.value.dlLimit = parsedValue * 1024
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const upLimit = computed({
|
||||
get: () => {
|
||||
if (!form.value.upLimit || form.value.upLimit === -1) {
|
||||
return ''
|
||||
} else {
|
||||
return (form.value.upLimit / 1024).toString()
|
||||
}
|
||||
},
|
||||
set: value => {
|
||||
if (!value) {
|
||||
form.value.upLimit = undefined
|
||||
} else {
|
||||
const parsedValue = parseInt(value)
|
||||
if (parsedValue > 0) {
|
||||
form.value.upLimit = parsedValue * 1024
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const ratioLimit = computed({
|
||||
get: () => form.value.ratioLimit,
|
||||
set: val => form.value.ratioLimit = val || undefined
|
||||
})
|
||||
|
||||
const seedingTimeLimit = computed({
|
||||
get: () => form.value.seedingTimeLimit,
|
||||
set: val => form.value.seedingTimeLimit = val || undefined
|
||||
})
|
||||
|
||||
const inactiveSeedingTimeLimit = computed({
|
||||
get: () => form.value.inactiveSeedingTimeLimit,
|
||||
set: val => form.value.inactiveSeedingTimeLimit = val || undefined
|
||||
})
|
||||
|
||||
function submit() {
|
||||
if (!isFormValid.value) return
|
||||
|
||||
const params: AddTorrentPayload = {
|
||||
savepath: navbarStore.addTorrentDialogForm.savepath,
|
||||
paused: !navbarStore.addTorrentDialogForm.startNow,
|
||||
skip_checking: navbarStore.addTorrentDialogForm.skipChecking,
|
||||
autoTMM: navbarStore.addTorrentDialogForm.autoTMM,
|
||||
sequentialDownload: navbarStore.addTorrentDialogForm.sequentialDownload,
|
||||
firstLastPiecePrio: navbarStore.addTorrentDialogForm.firstLastPiecePrio,
|
||||
contentLayout: navbarStore.addTorrentDialogForm.contentLayout,
|
||||
stopCondition: navbarStore.addTorrentDialogForm.stopCondition
|
||||
}
|
||||
const promise = maindataStore.addTorrents(form.value, files.value)
|
||||
.then(() => {
|
||||
addTorrentStore.resetForm()
|
||||
close()
|
||||
})
|
||||
|
||||
if (navbarStore.addTorrentDialogUrls.length > 0) params.urls = navbarStore.addTorrentDialogUrls
|
||||
if (navbarStore.addTorrentDialogForm.category && navbarStore.addTorrentDialogForm.category.name) params.category = navbarStore.addTorrentDialogForm.category.name
|
||||
if (navbarStore.addTorrentDialogForm.tags.length > 0) params.tags = navbarStore.addTorrentDialogForm.tags.join(',')
|
||||
|
||||
isLoading.value = true
|
||||
await maindataStore.addTorrents(params, navbarStore.addTorrentDialogFiles)
|
||||
isLoading.value = false
|
||||
|
||||
navbarStore.resetAddTorrentDialogForm()
|
||||
close()
|
||||
toast.promise(promise, {
|
||||
pending: t('dialogs.add.pending'),
|
||||
error: t('dialogs.add.error', addTorrentStore.pendingTorrentsCount),
|
||||
success: t('dialogs.add.success', addTorrentStore.pendingTorrentsCount)
|
||||
}, {
|
||||
autoClose: 1500
|
||||
})
|
||||
}
|
||||
const close = () => {
|
||||
|
||||
function close() {
|
||||
isOpened.value = false
|
||||
}
|
||||
|
||||
const onCategoryChanged = () => {
|
||||
navbarStore.addTorrentDialogForm.savepath = navbarStore.addTorrentDialogForm.category && navbarStore.addTorrentDialogForm.category.savePath ? navbarStore.addTorrentDialogForm.category.savePath : preferenceStore.preferences!.save_path
|
||||
form.value.savepath = maindataStore.getCategoryFromName(form.value.category)?.savePath ?? preferenceStore.preferences!.save_path
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-dialog v-model="isOpened" :class="$vuetify.display.mobile ? '' : 'w-50'"
|
||||
<v-dialog v-model="isOpened" :class="$vuetify.display.mobile ? '' : 'w-75'"
|
||||
:fullscreen="$vuetify.display.mobile" :transition="openSuddenly ? 'none' : 'dialog-bottom-transition'">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
|
@ -88,8 +176,8 @@ const onCategoryChanged = () => {
|
|||
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-file-input v-model="navbarStore.addTorrentDialogFiles" :label="t('dialogs.add.files')"
|
||||
<v-col cols="12">
|
||||
<v-file-input v-model="files" :label="t('dialogs.add.files')"
|
||||
:show-size="vueTorrentStore.useBinarySize ? 1024 : 1000"
|
||||
accept=".torrent" counter multiple
|
||||
persistent-clear persistent-hint prepend-icon="" variant="outlined">
|
||||
|
@ -102,24 +190,33 @@ const onCategoryChanged = () => {
|
|||
{{ filename }}
|
||||
</v-chip>
|
||||
</template>
|
||||
<span v-if="fileNames.length == fileOverflowDisplayLimit" class="text-overline text-grey-darken-2 ml-2">
|
||||
<span v-if="fileNames.length === fileOverflowDisplayLimit + 1"
|
||||
class="text-overline text-grey-darken-2 ml-2">
|
||||
{{ t('dialogs.add.fileOverflow', fileNames.length - fileOverflowDisplayLimit) }}
|
||||
</span>
|
||||
</template>
|
||||
</v-file-input>
|
||||
<v-textarea v-model="navbarStore.addTorrentDialogUrls" :label="t('dialogs.add.links')" clearable>
|
||||
<v-textarea v-model="urls" :label="t('dialogs.add.links')" clearable>
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-link</v-icon>
|
||||
</template>
|
||||
</v-textarea>
|
||||
<v-text-field v-if="!!urls" v-model="cookie" :label="$t('dialogs.add.cookie')" :placeholder="$t('dialogs.add.cookiePlaceholder')"
|
||||
clearable>
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-cookie</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<v-text-field v-model="rename" :label="$t('dialogs.add.rename')" clearable hide-details>
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-rename</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-combobox v-model="navbarStore.addTorrentDialogForm.tags" v-model:search="tagSearch"
|
||||
:hide-no-data="false" :items="maindataStore.tags" :label="t('dialogs.add.tags')" chips clearable
|
||||
multiple>
|
||||
<v-col cols="12" md="6">
|
||||
<v-combobox v-model="tags" v-model:search="tagSearch" :hide-no-data="false" :items="maindataStore.tags" :label="t('dialogs.add.tags')" chips
|
||||
clearable hide-details multiple>
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-tag</v-icon>
|
||||
</template>
|
||||
|
@ -134,9 +231,12 @@ const onCategoryChanged = () => {
|
|||
</v-list-item>
|
||||
</template>
|
||||
</v-combobox>
|
||||
<v-combobox v-model="navbarStore.addTorrentDialogForm.category" v-model:search="categorySearch"
|
||||
:hide-no-data="false" :items="maindataStore.categories" chips clearable
|
||||
item-title="name" label="Category" return-object @update:modelValue="onCategoryChanged">
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-combobox v-model="category" v-model:search="categorySearch" :hide-no-data="false" :items="categories"
|
||||
:label="$t('dialogs.add.category')" clearable hide-details
|
||||
@update:modelValue="onCategoryChanged">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-label</v-icon>
|
||||
</template>
|
||||
|
@ -152,72 +252,115 @@ const onCategoryChanged = () => {
|
|||
</template>
|
||||
</v-combobox>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field v-model="navbarStore.addTorrentDialogForm.savepath"
|
||||
:disabled="navbarStore.addTorrentDialogForm.autoTMM" :label="t('dialogs.add.savePath')">
|
||||
<v-col cols="12">
|
||||
<v-text-field v-model="downloadPath" :disabled="form.autoTMM"
|
||||
:label="t('dialogs.add.downloadPath')" hide-details>
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-folder</v-icon>
|
||||
<v-icon color="accent">mdi-tray-arrow-down</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-select v-model="navbarStore.addTorrentDialogForm.contentLayout" :items="contentLayoutOptions"
|
||||
<v-col cols="12">
|
||||
<v-text-field v-model="form.savepath" :disabled="form.autoTMM"
|
||||
:label="t('dialogs.add.savePath')" hide-details>
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-content-save</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-select v-model="form.contentLayout" :items="contentLayoutOptions"
|
||||
:label="t('constants.contentLayout.title')" color="accent" hide-details rounded="xl"
|
||||
variant="solo-filled" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-select v-model="navbarStore.addTorrentDialogForm.stopCondition" :items="stopConditionOptions"
|
||||
<v-col cols="12" md="6">
|
||||
<v-select v-model="form.stopCondition" :items="stopConditionOptions"
|
||||
:label="t('constants.stopCondition.title')" color="accent" hide-details rounded="xl"
|
||||
variant="solo-filled" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row class="mx-3">
|
||||
<v-col cols="12" md="6">
|
||||
<v-checkbox v-model="startNow" :label="t('dialogs.add.startNow')" color="accent"
|
||||
density="compact" hide-details />
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-checkbox v-model="form.addToTopOfQueue" :label="t('dialogs.add.addToTopOfQueue')" color="accent"
|
||||
density="compact" hide-details />
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-checkbox v-model="form.skip_checking" :label="t('dialogs.add.skipChecking')" color="accent"
|
||||
density="compact" hide-details />
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-checkbox v-model="form.autoTMM" :label="t('dialogs.add.autoTMM')" color="accent"
|
||||
density="compact" hide-details />
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-checkbox v-model="form.sequentialDownload" :label="t('dialogs.add.sequentialDownload')" color="accent"
|
||||
density="compact" hide-details />
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-checkbox v-model="form.firstLastPiecePrio" :label="t('dialogs.add.firstLastPiecePrio')" color="accent"
|
||||
density="compact" hide-details />
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<v-checkbox v-model="navbarStore.addTorrentDialogForm.startNow" :label="t('dialogs.add.startNow')"
|
||||
density="compact"
|
||||
hide-details />
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-checkbox v-model="navbarStore.addTorrentDialogForm.skipChecking"
|
||||
:label="t('dialogs.add.skipChecking')" density="compact"
|
||||
hide-details />
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-checkbox v-model="navbarStore.addTorrentDialogForm.autoTMM" :label="t('dialogs.add.autoTMM')"
|
||||
density="compact"
|
||||
hide-details />
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-checkbox v-model="navbarStore.addTorrentDialogForm.sequentialDownload"
|
||||
:label="t('dialogs.add.sequentialDownload')" density="compact"
|
||||
hide-details />
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-checkbox v-model="navbarStore.addTorrentDialogForm.firstLastPiecePrio"
|
||||
:label="t('dialogs.add.firstLastPiecePrio')" density="compact"
|
||||
hide-details />
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-col cols="12">
|
||||
<v-expansion-panels>
|
||||
<v-expansion-panel color="primary" :title="$t('dialogs.add.limitCollapse')">
|
||||
<v-expansion-panel-text>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field v-model="dlLimit" :label="$t('dialogs.add.dlLimit')"
|
||||
hide-details suffix="KiB/s">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-download</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field v-model="upLimit" :label="$t('dialogs.add.upLimit')"
|
||||
hide-details suffix="KiB/s">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-upload</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field v-model="ratioLimit" :hint="$t('dialogs.add.limitHint')"
|
||||
:label="$t('dialogs.add.ratioLimit')" type="number" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field v-model="seedingTimeLimit" :hint="$t('dialogs.add.limitHint')" :label="$t('dialogs.add.seedingTimeLimit')"
|
||||
:suffix="$t('units.minutes')" type="number" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field v-model="inactiveSeedingTimeLimit" :hint="$t('dialogs.add.limitHint')"
|
||||
:label="$t('dialogs.add.inactiveSeedingTimeLimit')"
|
||||
:suffix="$t('units.minutes')" type="number" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-expansion-panel-text>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions class="justify-center">
|
||||
<v-btn :disabled="!isFormValid" :loading="isLoading" color="accent" variant="elevated"
|
||||
:text="$t('dialogs.add.submit')" @click="submit" />
|
||||
<v-btn color="error" variant="flat" :text="$t('common.close')" @click="close" />
|
||||
<v-btn :text="$t('dialogs.add.resetForm')" color="error" variant="flat" @click="addTorrentStore.resetForm()" />
|
||||
<v-spacer />
|
||||
<v-btn :disabled="!isFormValid" :text="$t('dialogs.add.submit')" color="accent"
|
||||
variant="elevated" @click="submit" />
|
||||
<v-btn :text="$t('common.close')" color="" variant="flat" @click="close" />
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
<script lang="ts" setup>
|
||||
import { useAddTorrentStore } from '@/stores/addTorrents'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useNavbarStore } from '@/stores/navbar'
|
||||
import { useDropZone } from '@vueuse/core'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const addTorrentStore = useAddTorrentStore()
|
||||
const authStore = useAuthStore()
|
||||
const navbarStore = useNavbarStore()
|
||||
|
||||
const dndZoneRef = ref<HTMLDivElement>()
|
||||
|
||||
function onDragEnter() {
|
||||
|
@ -26,8 +27,8 @@ function onDrop(files: File[] | null, event: DragEvent) {
|
|||
const links = event.dataTransfer.getData('text/plain').split('\n')
|
||||
.filter(link => link.startsWith('magnet:') || link.startsWith('http'))
|
||||
|
||||
torrentFiles.forEach(navbarStore.pushTorrentToQueue)
|
||||
links.forEach(navbarStore.pushTorrentToQueue)
|
||||
torrentFiles.forEach(addTorrentStore.pushTorrentToQueue)
|
||||
links.forEach(addTorrentStore.pushTorrentToQueue)
|
||||
}
|
||||
|
||||
const { isOverDropZone } = useDropZone(dndZoneRef, { onDrop })
|
||||
|
|
|
@ -19,7 +19,7 @@ const isOnTorrentDetail = computed(() => route.name === 'torrentDetail')
|
|||
const hashes = computed(() => (isOnTorrentDetail.value ? [route.params.hash as string] : dashboardStore.selectedTorrents))
|
||||
|
||||
function openAddTorrentDialog() {
|
||||
dialogStore.createDialog(AddTorrentDialog, { openSuddenly: true })
|
||||
dialogStore.createDialog(AddTorrentDialog)
|
||||
}
|
||||
|
||||
async function resumeTorrents() {
|
||||
|
|
4
src/constants/qbit/TorrentOperatingMode.ts
Normal file
4
src/constants/qbit/TorrentOperatingMode.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export enum TorrentOperatingMode {
|
||||
AUTO_MANAGED = 'AutoManaged',
|
||||
FORCED = 'Forced'
|
||||
}
|
|
@ -4,7 +4,8 @@ import { FilterState } from './FilterState'
|
|||
import { LogType } from './LogType'
|
||||
import { PieceState } from './PieceState'
|
||||
import { FilePriority } from './FilePriority'
|
||||
import { TorrentOperatingMode } from './TorrentOperatingMode'
|
||||
import { TorrentState } from './TorrentState'
|
||||
import { TrackerStatus } from './TrackerStatus'
|
||||
|
||||
export { AppPreferences, ConnectionStatus, FilterState, LogType, PieceState, FilePriority, TrackerStatus, TorrentState }
|
||||
export { AppPreferences, ConnectionStatus, FilterState, LogType, PieceState, FilePriority, TrackerStatus, TorrentOperatingMode, TorrentState }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import AddTorrentDialog from '@/components/Dialogs/AddTorrentDialog.vue'
|
||||
import { useDialogStore } from '@/stores/dialog'
|
||||
import { useNavbarStore } from '@/stores/navbar'
|
||||
import { useAddTorrentStore } from '@/stores/addTorrents'
|
||||
import { onBeforeMount } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
|
@ -11,9 +11,9 @@ const router = useRouter()
|
|||
onBeforeMount(async () => {
|
||||
const magnetLink = decodeURIComponent(route.params.url as string)
|
||||
if (magnetLink.startsWith('magnet:')) {
|
||||
const navbarStore = useNavbarStore()
|
||||
navbarStore.isAddTorrentDialogFirstInit = false
|
||||
navbarStore.pushTorrentToQueue(magnetLink)
|
||||
const addTorrentStore = useAddTorrentStore()
|
||||
addTorrentStore.isFirstInit = false
|
||||
addTorrentStore.pushTorrentToQueue(magnetLink)
|
||||
useDialogStore().createDialog(AddTorrentDialog, {})
|
||||
}
|
||||
await router.push({ name: 'dashboard' })
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts" setup>
|
||||
import { useArrayPagination, useSearchQuery } from '@/composables'
|
||||
import { useAddTorrentStore } from '@/stores/addTorrents'
|
||||
import { useDialogStore } from '@/stores/dialog'
|
||||
import { useNavbarStore } from '@/stores/navbar'
|
||||
import { useRssStore } from '@/stores/rss'
|
||||
import { RssArticle } from '@/types/vuetorrent'
|
||||
import debounce from 'lodash.debounce'
|
||||
|
@ -11,8 +11,8 @@ import { useRouter } from 'vue-router'
|
|||
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
const addTorrentStore = useAddTorrentStore()
|
||||
const dialogStore = useDialogStore()
|
||||
const navbarStore = useNavbarStore()
|
||||
const rssStore = useRssStore()
|
||||
|
||||
const descriptionDialogVisible = ref(false)
|
||||
|
@ -48,7 +48,7 @@ function showDescription(article: RssArticle) {
|
|||
}
|
||||
|
||||
function downloadArticle(item: RssArticle) {
|
||||
navbarStore.pushTorrentToQueue(item.torrentURL)
|
||||
addTorrentStore.pushTorrentToQueue(item.torrentURL)
|
||||
}
|
||||
|
||||
async function markAsRead(item: RssArticle) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import PluginManagerDialog from '@/components/Dialogs/PluginManagerDialog.vue'
|
||||
import { useSearchQuery } from '@/composables'
|
||||
import { useAddTorrentStore } from '@/stores/addTorrents'
|
||||
import { useDialogStore } from '@/stores/dialog'
|
||||
import { useNavbarStore } from '@/stores/navbar'
|
||||
import { useSearchEngineStore } from '@/stores/searchEngine'
|
||||
import { useVueTorrentStore } from '@/stores/vuetorrent'
|
||||
import { SearchPlugin, SearchResult } from '@/types/qbit/models'
|
||||
|
@ -15,8 +15,8 @@ import { useRouter } from 'vue-router'
|
|||
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
const addTorrentStore = useAddTorrentStore()
|
||||
const dialogStore = useDialogStore()
|
||||
const navbarStore = useNavbarStore()
|
||||
const searchEngineStore = useSearchEngineStore()
|
||||
const vuetorrentStore = useVueTorrentStore()
|
||||
|
||||
|
@ -82,7 +82,7 @@ function deleteTab() {
|
|||
}
|
||||
|
||||
function downloadTorrent(result: SearchResult) {
|
||||
navbarStore.pushTorrentToQueue(result.fileUrl)
|
||||
addTorrentStore.pushTorrentToQueue(result.fileUrl)
|
||||
}
|
||||
|
||||
async function runNewSearch() {
|
||||
|
|
83
src/stores/addTorrents.ts
Normal file
83
src/stores/addTorrents.ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
import { usePreferenceStore } from '@/stores/preferences'
|
||||
import { AddTorrentPayload } from '@/types/qbit/payloads'
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
|
||||
export const useAddTorrentStore = defineStore('addTorrents', () => {
|
||||
const preferenceStore = usePreferenceStore()
|
||||
|
||||
const isFirstInit = ref(true)
|
||||
|
||||
const files = ref<File[]>([])
|
||||
const urls = ref<string>('')
|
||||
|
||||
const form = reactive<AddTorrentPayload>({})
|
||||
|
||||
const pendingTorrentsCount = computed(() => files.value.length + urls.value.split('\n').filter(url => url.trim() !== '').length)
|
||||
|
||||
function pushTorrentToQueue(torrentDescriptor: File | string) {
|
||||
if (torrentDescriptor instanceof File) {
|
||||
files.value.push(torrentDescriptor)
|
||||
} else {
|
||||
if (urls.value !== '') {
|
||||
urls.value += '\n'
|
||||
}
|
||||
urls.value += torrentDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
function initForm() {
|
||||
if (isFirstInit.value) {
|
||||
isFirstInit.value = false
|
||||
resetForm()
|
||||
}
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
urls.value = ''
|
||||
files.value = []
|
||||
|
||||
form.addToTopOfQueue = preferenceStore.preferences!.add_to_top_of_queue
|
||||
form.autoTMM = preferenceStore.preferences!.auto_tmm_enabled
|
||||
form.category = undefined
|
||||
form.contentLayout = preferenceStore.preferences!.torrent_content_layout
|
||||
form.cookie = undefined
|
||||
form.dlLimit = preferenceStore.preferences!.dl_limit
|
||||
form.downloadPath = preferenceStore.preferences!.temp_path
|
||||
form.firstLastPiecePrio = false
|
||||
form.inactiveSeedingTimeLimit = undefined
|
||||
form.paused = preferenceStore.preferences!.start_paused_enabled
|
||||
form.ratioLimit = undefined
|
||||
form.rename = undefined
|
||||
form.savepath = preferenceStore.preferences!.save_path
|
||||
form.seedingTimeLimit = undefined
|
||||
form.sequentialDownload = false
|
||||
form.skip_checking = false
|
||||
form.stopCondition = preferenceStore.preferences!.torrent_stop_condition
|
||||
form.tags = undefined
|
||||
form.upLimit = preferenceStore.preferences!.up_limit
|
||||
form.useDownloadPath = preferenceStore.preferences!.temp_path_enabled
|
||||
}
|
||||
|
||||
return {
|
||||
isFirstInit,
|
||||
files,
|
||||
urls,
|
||||
form,
|
||||
pendingTorrentsCount,
|
||||
pushTorrentToQueue,
|
||||
initForm,
|
||||
resetForm
|
||||
}
|
||||
},
|
||||
{
|
||||
persist: {
|
||||
enabled: true,
|
||||
strategies: [
|
||||
{
|
||||
storage: sessionStorage,
|
||||
key: 'vuetorrent_addTorrents'
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
|
@ -82,6 +82,10 @@ export const useMaindataStore = defineStore('maindata', () => {
|
|||
categories.value = await qbit.getCategories()
|
||||
}
|
||||
|
||||
function getCategoryFromName(categoryName?: string) {
|
||||
return categories.value.find(c => c.name === categoryName)
|
||||
}
|
||||
|
||||
async function createCategory(category: Category) {
|
||||
await qbit.createCategory(category)
|
||||
}
|
||||
|
@ -369,6 +373,7 @@ export const useMaindataStore = defineStore('maindata', () => {
|
|||
getTorrentIndexByHash,
|
||||
deleteTorrents,
|
||||
fetchCategories,
|
||||
getCategoryFromName,
|
||||
createCategory,
|
||||
setTorrentCategory,
|
||||
editCategory,
|
||||
|
|
|
@ -1,37 +1,12 @@
|
|||
import { ContentLayout, StopCondition } from '@/constants/qbit/AppPreferences.ts'
|
||||
import { usePreferenceStore } from '@/stores/preferences.ts'
|
||||
import { Category } from '@/types/qbit/models'
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useNavbarStore = defineStore(
|
||||
'navbar',
|
||||
() => {
|
||||
const preferenceStore = usePreferenceStore()
|
||||
|
||||
const downloadData = ref<number[]>(new Array(15).fill(0))
|
||||
const uploadData = ref<number[]>(new Array(15).fill(0))
|
||||
|
||||
const isAddTorrentDialogFirstInit = ref(true)
|
||||
|
||||
const addTorrentDialogFiles = ref<File[]>([])
|
||||
const addTorrentDialogUrls = ref('')
|
||||
|
||||
const addTorrentDialogForm = reactive({
|
||||
autoTMM: false,
|
||||
skipChecking: false,
|
||||
sequentialDownload: false,
|
||||
firstLastPiecePrio: false,
|
||||
startNow: true,
|
||||
contentLayout: ContentLayout.ORIGINAL,
|
||||
stopCondition: StopCondition.NONE,
|
||||
savepath: '',
|
||||
category: null as Category | null,
|
||||
tags: [] as string[]
|
||||
})
|
||||
|
||||
const pendingTorrentsCount = computed(() => addTorrentDialogFiles.value.length + addTorrentDialogUrls.value.split('\n').filter(url => url.trim() !== '').length)
|
||||
|
||||
function pushDownloadData(data: number) {
|
||||
downloadData.value.shift()
|
||||
downloadData.value.push(data)
|
||||
|
@ -42,53 +17,11 @@ export const useNavbarStore = defineStore(
|
|||
uploadData.value.push(data)
|
||||
}
|
||||
|
||||
function pushTorrentToQueue(torrentDescriptor: File | string) {
|
||||
if (torrentDescriptor instanceof File) {
|
||||
addTorrentDialogFiles.value.push(torrentDescriptor)
|
||||
} else {
|
||||
if (addTorrentDialogUrls.value !== '') {
|
||||
addTorrentDialogUrls.value += '\n'
|
||||
}
|
||||
addTorrentDialogUrls.value += torrentDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
function initAddTorrentDialogForm() {
|
||||
if (isAddTorrentDialogFirstInit.value) {
|
||||
isAddTorrentDialogFirstInit.value = false
|
||||
resetAddTorrentDialogForm()
|
||||
}
|
||||
}
|
||||
|
||||
function resetAddTorrentDialogForm() {
|
||||
addTorrentDialogUrls.value = ''
|
||||
addTorrentDialogFiles.value = []
|
||||
|
||||
addTorrentDialogForm.autoTMM = preferenceStore.preferences!.auto_tmm_enabled
|
||||
addTorrentDialogForm.category = null
|
||||
addTorrentDialogForm.contentLayout = preferenceStore.preferences!.torrent_content_layout
|
||||
addTorrentDialogForm.firstLastPiecePrio = false
|
||||
addTorrentDialogForm.savepath = preferenceStore.preferences!.save_path
|
||||
addTorrentDialogForm.sequentialDownload = false
|
||||
addTorrentDialogForm.skipChecking = false
|
||||
addTorrentDialogForm.startNow = !preferenceStore.preferences!.start_paused_enabled
|
||||
addTorrentDialogForm.stopCondition = preferenceStore.preferences!.torrent_stop_condition
|
||||
addTorrentDialogForm.tags = []
|
||||
}
|
||||
|
||||
return {
|
||||
downloadData,
|
||||
uploadData,
|
||||
isAddTorrentDialogFirstInit,
|
||||
addTorrentDialogFiles,
|
||||
addTorrentDialogUrls,
|
||||
addTorrentDialogForm,
|
||||
pendingTorrentsCount,
|
||||
pushDownloadData,
|
||||
pushUploadData,
|
||||
pushTorrentToQueue,
|
||||
initAddTorrentDialogForm,
|
||||
resetAddTorrentDialogForm
|
||||
pushUploadData
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@ export interface NetworkInterface {
|
|||
}
|
||||
|
||||
export default interface AppPreferences {
|
||||
/** Whether torrents should be placed at the top of the queue when added */
|
||||
add_to_top_of_queue: boolean
|
||||
/** List of trackers to add to new torrent */
|
||||
add_trackers: string
|
||||
|
@ -35,6 +36,7 @@ export default interface AppPreferences {
|
|||
alternative_webui_enabled: boolean
|
||||
/** File path to the alternative WebUI */
|
||||
alternative_webui_path: string
|
||||
/** IP address reported to trackers */
|
||||
announce_ip: string
|
||||
/** True always announce to all tiers */
|
||||
announce_to_all_tiers: boolean
|
||||
|
@ -58,10 +60,13 @@ export default interface AppPreferences {
|
|||
autorun_program: string
|
||||
/** List of banned IPs */
|
||||
banned_IPs: string
|
||||
/** depth limit used when decoding bencoded torrent files */
|
||||
bdecode_depth_limit: number
|
||||
/** token limit used when decoding bencoded torrent files */
|
||||
bdecode_token_limit: number
|
||||
/** Bittorrent Protocol to use (see list of possible values below) */
|
||||
/** Bittorrent Protocol to use */
|
||||
bittorrent_protocol: BitTorrentProtocol
|
||||
/** Whether peers connection should be blocked on privileged ports (< 1024) */
|
||||
block_peers_on_privileged_ports: boolean
|
||||
/** (White)list of ipv4/ipv6 subnets for which webui authentication should be bypassed; list entries are separated by commas */
|
||||
bypass_auth_subnet_whitelist: string
|
||||
|
@ -73,6 +78,7 @@ export default interface AppPreferences {
|
|||
category_changed_tmm_enabled: boolean
|
||||
/** Outstanding memory when checking torrents in MiB */
|
||||
checking_memory_use: number
|
||||
/** Outgoing connections per second */
|
||||
connection_speed: number
|
||||
/** IP Address to bind to. Empty String means All addresses */
|
||||
current_interface_address: string
|
||||
|
@ -86,9 +92,13 @@ export default interface AppPreferences {
|
|||
disk_cache: number
|
||||
/** Disk cache expiry interval in seconds */
|
||||
disk_cache_ttl: number
|
||||
/** Disk IO read mode */
|
||||
disk_io_read_mode: DiskIOMode
|
||||
/** Disk IO type */
|
||||
disk_io_type: DiskIOType
|
||||
/** Disk IO write mode */
|
||||
disk_io_write_mode: DiskIOMode
|
||||
/** Disk queue size */
|
||||
disk_queue_size: number
|
||||
/** Global download speed limit in KiB/s; -1 means no limit is applied */
|
||||
dl_limit: number
|
||||
|
@ -106,6 +116,7 @@ export default interface AppPreferences {
|
|||
dyndns_username: string
|
||||
/** Port used for embedded tracker */
|
||||
embedded_tracker_port: number
|
||||
/** Enable port forwarding for embedded tracker */
|
||||
embedded_tracker_port_forwarding: boolean
|
||||
/** True enables coalesce reads & writes */
|
||||
enable_coalesce_read_write: boolean
|
||||
|
@ -119,22 +130,39 @@ export default interface AppPreferences {
|
|||
enable_upload_suggestions: boolean
|
||||
/** See list of possible values here below */
|
||||
encryption: Encryption
|
||||
/** File name patterns to automatically exclude on added torrents */
|
||||
excluded_file_names: string
|
||||
/** Whether to use the `excluded_file_names` patterns */
|
||||
excluded_file_names_enabled: boolean
|
||||
/** Path to directory to copy .torrent files to. Slashes are used as path separators */
|
||||
export_dir: string
|
||||
/** Path to directory to copy .torrent files of completed downloads to. Slashes are used as path separators */
|
||||
export_dir_fin: string
|
||||
/** Max backup log files retention time */
|
||||
file_log_age: number
|
||||
/** File log age unit */
|
||||
file_log_age_type: FileLogAgeType
|
||||
/** Enable log file backup */
|
||||
file_log_backup_enabled: boolean
|
||||
/** Enable log file auto-delete after a certain period of time */
|
||||
file_log_delete_old: boolean
|
||||
/** Enable log files */
|
||||
file_log_enabled: boolean
|
||||
/** Log file max size before backing up */
|
||||
file_log_max_size: number
|
||||
/** Log files save path */
|
||||
file_log_path: string
|
||||
/** File pool size */
|
||||
file_pool_size: number
|
||||
/**
|
||||
* Number of disk I/O threads to use for piece hash verification
|
||||
* These threads are in addition to the regular disk I/O threads.
|
||||
*
|
||||
* These are only used when force rechecking torrent.
|
||||
* The hash checking done while downloading are done by the regular disk I/O threads
|
||||
*/
|
||||
hashing_threads: number
|
||||
/** Support internationalized domain name (IDN) */
|
||||
idn_support_enabled: boolean
|
||||
/** True if ".!qB" should be appended to incomplete files */
|
||||
incomplete_files_ext: boolean
|
||||
|
@ -172,6 +200,7 @@ export default interface AppPreferences {
|
|||
mail_notification_ssl_enabled: boolean
|
||||
/** Username for smtp authentication */
|
||||
mail_notification_username: string
|
||||
/** Max active checking torrents */
|
||||
max_active_checking_torrents: number
|
||||
/** Maximum number of active simultaneous downloads */
|
||||
max_active_downloads: number
|
||||
|
@ -179,12 +208,15 @@ export default interface AppPreferences {
|
|||
max_active_torrents: number
|
||||
/** Maximum number of active simultaneous uploads */
|
||||
max_active_uploads: number
|
||||
/** Limits the number of concurrent HTTP tracker announces */
|
||||
max_concurrent_http_announces: number
|
||||
/** Maximum global number of simultaneous connections */
|
||||
max_connec: number
|
||||
/** Maximum number of simultaneous connections per torrent */
|
||||
max_connec_per_torrent: number
|
||||
/** Number of minutes to keep seeding a torrent while inactive */
|
||||
max_inactive_seeding_time: number
|
||||
/** True enables max inactive seeding time */
|
||||
max_inactive_seeding_time_enabled: boolean
|
||||
/** Get the global share ratio limit */
|
||||
max_ratio: number
|
||||
|
@ -200,16 +232,23 @@ export default interface AppPreferences {
|
|||
max_uploads: number
|
||||
/** Maximum number of upload slots per torrent */
|
||||
max_uploads_per_torrent: number
|
||||
/** Physical memory (RAM) usage limit */
|
||||
memory_working_set_limit: number
|
||||
/** Whether trackers should be merged when adding a duplicate torrent */
|
||||
merge_trackers: boolean
|
||||
/** Maximal outgoing port (0: Disabled) */
|
||||
outgoing_ports_max: number
|
||||
/** Minimal outgoing port (0: Disabled) */
|
||||
outgoing_ports_min: number
|
||||
/** Type of service (ToS) for connections to peers */
|
||||
peer_tos: number
|
||||
/** Peer turnover disconnect percentage */
|
||||
peer_turnover: number
|
||||
/** Peer turnover threshold percentage */
|
||||
peer_turnover_cutoff: number
|
||||
/** Peer turnover disconnect interval */
|
||||
peer_turnover_interval: number
|
||||
/** Whether to log performance warnings */
|
||||
performance_warning: boolean
|
||||
/** True if PeX is enabled */
|
||||
pex: boolean
|
||||
|
@ -217,17 +256,21 @@ export default interface AppPreferences {
|
|||
preallocate_all: boolean
|
||||
/** True proxy requires authentication; doesn't apply to SOCKS4 proxies */
|
||||
proxy_auth_enabled: boolean
|
||||
/** Whether to use proxy for BitTorrent purposes */
|
||||
proxy_bittorrent: boolean
|
||||
/** Perform hostname lookup via proxy */
|
||||
proxy_hostname_lookup: boolean
|
||||
/** Proxy IP address or domain name */
|
||||
proxy_ip: string
|
||||
/** Whether to use proxy for general purposes */
|
||||
proxy_misc: boolean
|
||||
/** Password for proxy authentication */
|
||||
proxy_password: string
|
||||
/** True if peer and web seed connections should be proxified; this option will have any effect only in qBittorent built against libtorrent version 0.16.X and higher */
|
||||
/** Whether to use proxy for peer connections */
|
||||
proxy_peer_connections: boolean
|
||||
/** Proxy port */
|
||||
proxy_port: number
|
||||
/** Whether to use proxy for RSS purposes */
|
||||
proxy_rss: boolean
|
||||
/** See list of possible values here below */
|
||||
proxy_type: ProxyType
|
||||
|
@ -237,13 +280,17 @@ export default interface AppPreferences {
|
|||
queueing_enabled: boolean
|
||||
/** True if the port is randomly selected */
|
||||
random_port: boolean
|
||||
/** Reannounce to all trackers when IP or port changed */
|
||||
reannounce_when_address_changed: boolean
|
||||
/** True rechecks torrents on completion */
|
||||
recheck_completed_torrents: boolean
|
||||
/** Refresh interval (in ms) */
|
||||
refresh_interval: number
|
||||
/** Maximum outstanding requests to a single peer */
|
||||
request_queue_size: number
|
||||
/** True resolves peer countries */
|
||||
resolve_peer_countries: boolean
|
||||
/** Resume data storage type */
|
||||
resume_data_storage_type: ResumeDataStorageType
|
||||
/** Enable auto-downloading of torrents from the RSS feeds */
|
||||
rss_auto_downloading_enabled: boolean
|
||||
|
@ -291,8 +338,11 @@ export default interface AppPreferences {
|
|||
slow_torrent_ul_rate_threshold: number
|
||||
/** Socket backlog size */
|
||||
socket_backlog_size: number
|
||||
/** Socket receive buffer size */
|
||||
socket_receive_buffer_size: number
|
||||
/** Socket send buffer size */
|
||||
socket_send_buffer_size: number
|
||||
/** Server-side request forgery (SSRF) mitigation **/
|
||||
ssrf_mitigation: boolean
|
||||
/** True if torrents should be added in a Paused state */
|
||||
start_paused_enabled: boolean
|
||||
|
@ -306,6 +356,7 @@ export default interface AppPreferences {
|
|||
torrent_changed_tmm_enabled: boolean
|
||||
/** Default content layout to select when adding a new torrent */
|
||||
torrent_content_layout: ContentLayout
|
||||
/** .torrent file size limit */
|
||||
torrent_file_size_limit: number
|
||||
/** Default stop condition to select when adding a new torrent */
|
||||
torrent_stop_condition: StopCondition
|
||||
|
@ -319,12 +370,15 @@ export default interface AppPreferences {
|
|||
upnp: boolean
|
||||
/** UPnP lease duration (0: Permanent lease) */
|
||||
upnp_lease_duration: number
|
||||
/** Whether to use category save path when autoTMM isn't enabled */
|
||||
use_category_paths_in_manual_mode: boolean
|
||||
/** True if WebUI HTTPS access is enabled */
|
||||
use_https: boolean
|
||||
/** Whether to use subcategories */
|
||||
use_subcategories: boolean
|
||||
/** μTP-TCP mixed mode algorithm (see list of possible values below) */
|
||||
utp_tcp_mixed_mode: UtpTcpMixedMode
|
||||
/** Validate HTTPS tracker certificates */
|
||||
validate_https_tracker_certificate: boolean
|
||||
/** IP address to use for the WebUI */
|
||||
web_ui_address: string
|
||||
|
@ -350,7 +404,9 @@ export default interface AppPreferences {
|
|||
web_ui_password?: string
|
||||
/** WebUI port */
|
||||
web_ui_port: number
|
||||
/** Trusted proxies list */
|
||||
web_ui_reverse_proxies_list: string
|
||||
/** Enable reverse proxy support */
|
||||
web_ui_reverse_proxy_enabled: boolean
|
||||
/** True if WebUI cookie Secure flag is enabled */
|
||||
web_ui_secure_cookie_enabled: boolean
|
||||
|
|
|
@ -1,34 +1,72 @@
|
|||
import { AppPreferences } from '@/constants/qbit'
|
||||
|
||||
export default interface FeedRule {
|
||||
/** Add matched torrent in paused mode */
|
||||
addPaused: boolean | null
|
||||
/** The feed URLs the rule applied to */
|
||||
affectedFeeds: string[]
|
||||
/** Assign category to the torrent */
|
||||
assignedCategory: string
|
||||
/** The feed URLs the rule applies to */
|
||||
affectedFeeds?: string[]
|
||||
/** Whether the rule is enabled */
|
||||
enabled: boolean
|
||||
/** Episode filter definition */
|
||||
episodeFilter: string
|
||||
/** Ignore subsequent rule matches */
|
||||
ignoreDays: number
|
||||
/** The rule last match time */
|
||||
lastMatch: string
|
||||
/** The substring that the torrent name must contain */
|
||||
mustContain: string
|
||||
/** The substring that the torrent name must not contain */
|
||||
mustNotContain: string
|
||||
/** The rule name, !! injected by VueTorrent !! */
|
||||
enabled?: boolean
|
||||
/**
|
||||
* Matches articles based on episode filter.
|
||||
*
|
||||
* Example: 1x2;8-15;5;30-; will match 2, 5, 8 through 15, 30 and onward episodes of season one
|
||||
*
|
||||
* Episode filter rules:
|
||||
*
|
||||
* - Season number is a mandatory non-zero value
|
||||
* - Episode number is a mandatory positive value
|
||||
* - Filter must end with semicolon
|
||||
* - Three range types for episodes are supported:
|
||||
* - * Single number: 1x25; matches episode 25 of season one
|
||||
* - * Normal range: 1x25-40; matches episodes 25 through 40 of season one
|
||||
* - * Infinite range: 1x25-; matches episodes 25 and upward of season one, and all episodes of later seasons
|
||||
*/
|
||||
episodeFilter?: string
|
||||
/**
|
||||
* Ignore articles where its date is within n days
|
||||
* Values less than 1 will be ignored
|
||||
*/
|
||||
ignoreDays?: number
|
||||
/**
|
||||
* The rule last match time
|
||||
* Must match RFC-2822 or ISO-8601 date format
|
||||
* source: https://www.rfc-editor.org/rfc/rfc2822#page-14
|
||||
*/
|
||||
lastMatch?: string
|
||||
/**
|
||||
* Wildcard mode: you can use
|
||||
*
|
||||
* - ? to match any single character
|
||||
* - \* to match zero or more of any characters
|
||||
* - Whitespaces count as AND operators (all words, any order)
|
||||
* - | is used as OR operator
|
||||
*
|
||||
* If word order is important use * instead of whitespace.
|
||||
*
|
||||
* An expression with an empty | clause (e.g. expr|) will match all articles.
|
||||
*/
|
||||
mustContain?: string
|
||||
/**
|
||||
* Wildcard mode: you can use
|
||||
*
|
||||
* - ? to match any single character
|
||||
* - \* to match zero or more of any characters
|
||||
* - Whitespaces count as AND operators (all words, any order)
|
||||
* - | is used as OR operator
|
||||
*
|
||||
* If word order is important use * instead of whitespace.
|
||||
*
|
||||
* An expression with an empty | clause (e.g. expr|) will exclude all articles.
|
||||
*/
|
||||
mustNotContain?: string
|
||||
/** The rule name */
|
||||
name?: string
|
||||
/** The list of episode IDs already matched by smart filter */
|
||||
previouslyMatchedEpisodes?: unknown[]
|
||||
/** Save torrent to the given directory */
|
||||
savePath: string
|
||||
/** Enable smart episode filter */
|
||||
smartFilter: boolean
|
||||
/** Torrent content layout to use with matched torrent */
|
||||
torrentContentLayout: AppPreferences.ContentLayout | null
|
||||
/** The list of episodes already matched by smart filter */
|
||||
previouslyMatchedEpisodes?: string[]
|
||||
/** The rule priority */
|
||||
priority?: number
|
||||
/**
|
||||
* Smart Episode Filter will check the episode number to prevent downloading of duplicates.
|
||||
* Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also support - as a separator)
|
||||
*/
|
||||
smartFilter?: boolean
|
||||
/** Enable regex mode in "mustContain" and "mustNotContain" */
|
||||
useRegex: boolean
|
||||
useRegex?: boolean
|
||||
}
|
||||
|
|
|
@ -1,34 +1,49 @@
|
|||
import { ContentLayout, StopCondition } from '@/constants/qbit/AppPreferences'
|
||||
|
||||
export default interface AddTorrentPayload {
|
||||
/** Whether to add the torrent at the top of the queue */
|
||||
addToTopOfQueue?: boolean
|
||||
/** Whether Automatic Torrent Management should be used */
|
||||
autoTMM?: boolean
|
||||
/** Category for the torrent */
|
||||
category?: string
|
||||
/** Content layout used when creating the torrent */
|
||||
contentLayout?: ContentLayout
|
||||
/** Cookie sent to download the .torrent file */
|
||||
/** Cookie sent to download the files using HTTP(S) */
|
||||
cookie?: string
|
||||
/** Set torrent download speed limit. Unit in bytes/second */
|
||||
dlLimit?: number
|
||||
/**
|
||||
* If enabled and set, will use this location to save torrent content when downloading
|
||||
* Otherwise, use `savepath` or default save path
|
||||
*/
|
||||
downloadPath?: string
|
||||
/** Prioritize download first last piece. Possible values are true, false (default) */
|
||||
/** Prioritize download first last piece */
|
||||
firstLastPiecePrio?: boolean
|
||||
/**
|
||||
* Set inactive torrent seeding time limit. Unit in minutes
|
||||
* - -1 to disable
|
||||
* - -2 to use global value
|
||||
*/
|
||||
inactiveSeedingTimeLimit?: number
|
||||
/** Add torrents in the paused state. Possible values are true, false (default) */
|
||||
/** Add torrents in the paused state */
|
||||
paused?: boolean
|
||||
/** Set torrent share ratio limit */
|
||||
ratioLimit?: number
|
||||
/** Rename torrent */
|
||||
rename?: string
|
||||
/** Download folder */
|
||||
/**
|
||||
* Will use this location to save torrent content when download is complete
|
||||
* It will also be used when `downloadPath` is disabled or not set
|
||||
*/
|
||||
savepath?: string
|
||||
/** Set torrent seeding time limit. Unit in minutes */
|
||||
seedingTimeLimit?: number
|
||||
/** Enable sequential download. Possible values are true, false (default) */
|
||||
/** Enable sequential download */
|
||||
sequentialDownload?: boolean
|
||||
/** Skip hash checking. Possible values are true, false (default) */
|
||||
/** Skip hash checking */
|
||||
skip_checking?: boolean
|
||||
/** Torrent stop condition */
|
||||
stopCondition?: StopCondition
|
||||
/** Tags for the torrent, split by ',' */
|
||||
tags?: string
|
||||
|
@ -36,5 +51,6 @@ export default interface AddTorrentPayload {
|
|||
upLimit?: number
|
||||
/** URLs separated with newlines */
|
||||
urls?: string
|
||||
/** Whether to enable use of `downloadPath` */
|
||||
useDownloadPath?: boolean
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue