mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2024-10-23 03:06:43 +03:00
feat(rss): Update rule form to include enabled
and torrentParams
(#1501)
This commit is contained in:
parent
01ac1bb577
commit
aefa996a6c
8 changed files with 450 additions and 70 deletions
296
src/components/Dialogs/AddTorrentParamsDialog.vue
Normal file
296
src/components/Dialogs/AddTorrentParamsDialog.vue
Normal file
|
@ -0,0 +1,296 @@
|
|||
<script lang="ts" setup>
|
||||
import HistoryField from '@/components/Core/HistoryField.vue'
|
||||
import { AppPreferences } from '@/constants/qbit'
|
||||
import { HistoryKey } from '@/constants/vuetorrent'
|
||||
import { useMaindataStore, usePreferenceStore } from '@/stores'
|
||||
import { AddTorrentParams } from '@/types/qbit/models'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const form = defineModel<AddTorrentParams>({ required: true })
|
||||
const isOpened = defineModel<boolean>('isOpened')
|
||||
|
||||
const { t } = useI18n()
|
||||
const maindataStore = useMaindataStore()
|
||||
const preferenceStore = usePreferenceStore()
|
||||
|
||||
const contentLayoutOptions = [
|
||||
{ title: t('common.useGlobalSettings'), value: null },
|
||||
{ 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 = [
|
||||
{ title: t('common.useGlobalSettings'), value: null },
|
||||
{ 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 downloadPathField = ref<typeof HistoryField>()
|
||||
const savePathField = ref<typeof HistoryField>()
|
||||
|
||||
const tagSearch = ref('')
|
||||
|
||||
const categorySearch = ref('')
|
||||
const categoryNames = 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<string | undefined>({
|
||||
get: () => form.value.download_path || undefined,
|
||||
set: value => {
|
||||
form.value.use_download_path = !!value || false
|
||||
form.value.download_path = value || undefined
|
||||
}
|
||||
})
|
||||
|
||||
function getLimit(value?: number) {
|
||||
return !value || value === -1 ? '' : (value / 1024).toString()
|
||||
}
|
||||
|
||||
const downloadLimit = computed({
|
||||
get: () => getLimit(form.value.download_limit),
|
||||
set: value => {
|
||||
if (!value) {
|
||||
form.value.download_limit = undefined
|
||||
} else {
|
||||
const parsedValue = parseInt(value)
|
||||
if (parsedValue > 0) {
|
||||
form.value.download_limit = parsedValue * 1024
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const uploadLimit = computed({
|
||||
get: () => getLimit(form.value.upload_limit),
|
||||
set: value => {
|
||||
if (!value) {
|
||||
form.value.upload_limit = undefined
|
||||
} else {
|
||||
const parsedValue = parseInt(value)
|
||||
if (parsedValue > 0) {
|
||||
form.value.upload_limit = parsedValue * 1024
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const ratioLimit = computed({
|
||||
get: () => form.value.ratio_limit,
|
||||
set: val => (form.value.ratio_limit = val || undefined)
|
||||
})
|
||||
|
||||
const seedingTimeLimit = computed({
|
||||
get: () => form.value.seeding_time_limit,
|
||||
set: val => (form.value.seeding_time_limit = val || undefined)
|
||||
})
|
||||
|
||||
const inactiveSeedingTimeLimit = computed({
|
||||
get: () => form.value.inactive_seeding_time_limit,
|
||||
set: val => (form.value.inactive_seeding_time_limit = val || undefined)
|
||||
})
|
||||
|
||||
function close() {
|
||||
downloadPathField.value?.saveValueToHistory()
|
||||
savePathField.value?.saveValueToHistory()
|
||||
|
||||
isOpened.value = false
|
||||
}
|
||||
|
||||
const onCategoryChanged = () => {
|
||||
form.value.save_path = maindataStore.getCategoryFromName(form.value.category)?.savePath ?? preferenceStore.preferences!.save_path
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-dialog v-model="isOpened" :class="$vuetify.display.mobile ? '' : 'w-75'" :fullscreen="$vuetify.display.mobile" scrollable>
|
||||
<v-card>
|
||||
<v-card-title class="ios-margin">
|
||||
<v-toolbar color="transparent">
|
||||
<v-toolbar-title>{{ t('dialogs.add.params.title') }}</v-toolbar-title>
|
||||
<v-btn icon="mdi-close" @click="close" />
|
||||
</v-toolbar>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<v-combobox
|
||||
v-model="form.tags"
|
||||
v-model:search="tagSearch"
|
||||
:hide-no-data="false"
|
||||
:items="maindataStore.tags"
|
||||
:label="t('dialogs.add.params.tags')"
|
||||
chips
|
||||
clearable
|
||||
hide-details
|
||||
multiple
|
||||
autocomplete="tags">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-tag</v-icon>
|
||||
</template>
|
||||
<template v-slot:no-data>
|
||||
<v-list-item>
|
||||
<v-list-item-title v-if="tagSearch?.length > 0">
|
||||
{{ t('dialogs.add.params.noTagMatch', { query: tagSearch }) }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-title v-else>
|
||||
{{ t('dialogs.add.params.noTags') }}
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-combobox>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-combobox
|
||||
v-model="category"
|
||||
v-model:search="categorySearch"
|
||||
:hide-no-data="false"
|
||||
:items="categoryNames"
|
||||
:label="$t('dialogs.add.params.category')"
|
||||
clearable
|
||||
hide-details
|
||||
autocomplete="categories"
|
||||
@update:modelValue="onCategoryChanged">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-label</v-icon>
|
||||
</template>
|
||||
<template v-slot:no-data>
|
||||
<v-list-item>
|
||||
<v-list-item-title v-if="categorySearch?.length > 0">
|
||||
{{ t('dialogs.add.params.noCategoryMatch', { query: categorySearch }) }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-title v-else>
|
||||
{{ t('dialogs.add.params.noCategories') }}
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-combobox>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<HistoryField
|
||||
v-model="downloadPath"
|
||||
:history-key="HistoryKey.TORRENT_PATH"
|
||||
ref="downloadPathField"
|
||||
:disabled="form.use_auto_tmm"
|
||||
:label="t('dialogs.add.params.downloadPath')"
|
||||
hide-details>
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-tray-arrow-down</v-icon>
|
||||
</template>
|
||||
</HistoryField>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<HistoryField
|
||||
v-model="form.save_path"
|
||||
:history-key="HistoryKey.TORRENT_PATH"
|
||||
ref="savePathField"
|
||||
:disabled="form.use_auto_tmm"
|
||||
:label="t('dialogs.add.params.savePath')"
|
||||
hide-details>
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-content-save</v-icon>
|
||||
</template>
|
||||
</HistoryField>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-select
|
||||
v-model="form.content_layout"
|
||||
:items="contentLayoutOptions"
|
||||
:label="t('constants.contentLayout.title')"
|
||||
color="accent"
|
||||
hide-details
|
||||
rounded="xl"
|
||||
variant="solo-filled" />
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-select
|
||||
v-model="form.stop_condition"
|
||||
: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="form.stopped" :label="t('dialogs.add.params.stopped')" color="accent" density="compact" hide-details />
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-checkbox v-model="form.add_to_top_of_queue" :label="t('dialogs.add.params.add_to_top_of_queue')" 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.params.skip_checking')" color="accent" density="compact" hide-details />
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-checkbox v-model="form.use_auto_tmm" :label="t('dialogs.add.params.use_auto_tmm')" color="accent" density="compact" hide-details />
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-expansion-panels>
|
||||
<v-expansion-panel color="primary" :title="$t('dialogs.add.params.limit_collapse')">
|
||||
<v-expansion-panel-text>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field v-model="downloadLimit" :label="$t('dialogs.add.params.download_limit')" 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="uploadLimit" :label="$t('dialogs.add.params.upload_limit')" 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.params.limit_hint')" :label="$t('dialogs.add.params.ratio_limit')" type="number" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field
|
||||
v-model="seedingTimeLimit"
|
||||
:label="$t('dialogs.add.params.seeding_time_limit')"
|
||||
:hint="$t('dialogs.add.params.limit_hint')"
|
||||
:suffix="$t('units.minutes')"
|
||||
type="number" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field
|
||||
v-model="inactiveSeedingTimeLimit"
|
||||
:label="$t('dialogs.add.params.inactive_seeding_time_limit')"
|
||||
:hint="$t('dialogs.add.params.limit_hint')"
|
||||
: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="mb-2">
|
||||
<v-spacer />
|
||||
<v-btn :text="$t('common.close')" color="" variant="flat" @click="close" />
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
|
@ -1,8 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import AddTorrentParamsDialog from '@/components/Dialogs/AddTorrentParamsDialog.vue'
|
||||
import { useDialog } from '@/composables'
|
||||
import { ContentLayout } from '@/constants/qbit/AppPreferences'
|
||||
import { useMaindataStore, useRssStore } from '@/stores'
|
||||
import { FeedRule } from '@/types/qbit/models'
|
||||
import { useMaindataStore, usePreferenceStore, useRssStore } from '@/stores'
|
||||
import { FeedRule, getEmptyParams } from '@/types/qbit/models'
|
||||
import { computed, onBeforeMount, reactive, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { VForm } from 'vuetify/components'
|
||||
|
@ -12,62 +12,46 @@ const props = defineProps<{
|
|||
initialRule?: FeedRule
|
||||
}>()
|
||||
|
||||
const hasInitialRule = computed(() => {
|
||||
return !!(props.initialRule && props.initialRule.name)
|
||||
})
|
||||
|
||||
const { isOpened } = useDialog(props.guid)
|
||||
const { t } = useI18n()
|
||||
const maindataStore = useMaindataStore()
|
||||
const preferenceStore = usePreferenceStore()
|
||||
const rssStore = useRssStore()
|
||||
|
||||
const form = ref<VForm>()
|
||||
const isFormValid = ref(false)
|
||||
const formData = reactive({
|
||||
addPaused: null,
|
||||
affectedFeeds: [] as string[],
|
||||
assignedCategory: '',
|
||||
enabled: true,
|
||||
episodeFilter: '',
|
||||
ignoreDays: 0,
|
||||
lastMatch: '',
|
||||
mustContain: '',
|
||||
mustNotContain: '',
|
||||
name: '',
|
||||
savePath: '',
|
||||
smartFilter: false,
|
||||
torrentContentLayout: null,
|
||||
useRegex: false
|
||||
})
|
||||
const formData = reactive<FeedRule>(getEmptyRule())
|
||||
const lastSavedName = ref('')
|
||||
const matchingArticles = ref<{ type: string; value?: string }[]>([])
|
||||
|
||||
const addPausedOptions = [
|
||||
{ title: t('common.useGlobalSettings'), value: null },
|
||||
{ title: t('constants.addPaused.always'), value: true },
|
||||
{ title: t('constants.addPaused.never'), value: false }
|
||||
]
|
||||
const contentLayoutOptions = [
|
||||
{ title: t('common.useGlobalSettings'), value: null },
|
||||
{ title: t('constants.contentLayout.original'), value: ContentLayout.ORIGINAL },
|
||||
{ title: t('constants.contentLayout.subfolder'), value: ContentLayout.SUBFOLDER },
|
||||
{ title: t('constants.contentLayout.nosubfolder'), value: ContentLayout.NO_SUBFOLDER }
|
||||
]
|
||||
const categories = computed(() => {
|
||||
return [
|
||||
{ title: t('common.none'), value: '' },
|
||||
...maindataStore.categories.map(category => ({
|
||||
title: category.name,
|
||||
value: category.name
|
||||
}))
|
||||
]
|
||||
})
|
||||
|
||||
const lastMatch = computed(() => {
|
||||
if (formData.lastMatch === '') return t('dialogs.rss.rule.lastMatch.unknownValue').toString()
|
||||
|
||||
const delta = new Date().getTime() - new Date(formData.lastMatch).getTime()
|
||||
return t('dialogs.rss.rule.lastMatch.knownValue', Math.floor(delta / (1000 * 60 * 60 * 24)).toString())
|
||||
})
|
||||
const hasInitialRule = computed(() => {
|
||||
return !!(props.initialRule && props.initialRule.name)
|
||||
})
|
||||
|
||||
function getEmptyRule(): FeedRule {
|
||||
return {
|
||||
affectedFeeds: [] as string[],
|
||||
enabled: true,
|
||||
episodeFilter: '',
|
||||
ignoreDays: 0,
|
||||
lastMatch: '',
|
||||
mustContain: '',
|
||||
mustNotContain: '',
|
||||
name: '',
|
||||
priority: 0,
|
||||
smartFilter: false,
|
||||
useRegex: false,
|
||||
previouslyMatchedEpisodes: hasInitialRule.value ? props.initialRule!.previouslyMatchedEpisodes : [],
|
||||
torrentParams: getEmptyParams(preferenceStore.preferences)
|
||||
}
|
||||
}
|
||||
|
||||
async function updateArticles() {
|
||||
if (lastSavedName.value === '') return
|
||||
|
@ -120,8 +104,6 @@ onBeforeMount(async () => {
|
|||
if (hasInitialRule.value) {
|
||||
lastSavedName.value = props.initialRule!.name!
|
||||
Object.assign(formData, props.initialRule!)
|
||||
} else {
|
||||
form.value?.reset()
|
||||
}
|
||||
|
||||
await updateArticles()
|
||||
|
@ -142,6 +124,19 @@ onBeforeMount(async () => {
|
|||
<v-col cols="12" sm="6" class="scrollable-col">
|
||||
<v-text-field v-model="formData.name" autofocus required :label="$t('dialogs.rss.rule.name')" />
|
||||
|
||||
<div class="d-flex">
|
||||
<v-switch v-model="formData.enabled" color="accent" inset hide-details :label="$t('dialogs.rss.rule.enabled')" />
|
||||
|
||||
<v-spacer />
|
||||
|
||||
<div class="d-flex align-center">
|
||||
<v-btn class="d-flex align-center justify-center" color="accent">
|
||||
{{ $t('dialogs.add.params.title') }}
|
||||
<AddTorrentParamsDialog v-model="formData.torrentParams" activator="parent" />
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<v-checkbox v-model="formData.useRegex" hide-details :label="$t('dialogs.rss.rule.useRegex')" />
|
||||
|
@ -152,16 +147,11 @@ onBeforeMount(async () => {
|
|||
|
||||
<v-divider class="mb-4" />
|
||||
|
||||
<v-select v-model="formData.assignedCategory" :items="categories" :label="$t('dialogs.rss.rule.assignedCategory')" />
|
||||
<v-text-field v-model="formData.savePath" :placeholder="$t('dialogs.rss.rule.savePathPlaceholder')" :label="$t('dialogs.rss.rule.savePath')" />
|
||||
<v-text-field v-model.number="formData.ignoreDays" type="number" :hint="$t('dialogs.rss.rule.ignoreDaysHint')" :label="$t('dialogs.rss.rule.ignoreDays')" />
|
||||
<v-text-field v-model="lastMatch" disabled :label="$t('dialogs.rss.rule.lastMatch.label')" />
|
||||
|
||||
<v-divider />
|
||||
|
||||
<v-select v-model="formData.addPaused" :items="addPausedOptions" :label="$t('constants.addPaused.title')" />
|
||||
<v-select v-model="formData.torrentContentLayout" :items="contentLayoutOptions" :label="$t('constants.contentLayout.title')" />
|
||||
|
||||
<v-list-subheader>{{ $t('dialogs.rss.rule.affectedFeedsSubheader') }}</v-list-subheader>
|
||||
|
||||
<v-row>
|
||||
|
|
|
@ -11,6 +11,11 @@ const rssStore = useRssStore()
|
|||
const loading = ref(false)
|
||||
const ruleDialog = ref('')
|
||||
|
||||
async function toggleRule(rule: FeedRule) {
|
||||
await rssStore.setRule(rule.name, { ...rule, enabled: !rule.enabled })
|
||||
await rssStore.fetchRules()
|
||||
}
|
||||
|
||||
async function deleteRule(rule: FeedRule) {
|
||||
await rssStore.deleteRule(rule.name!)
|
||||
await rssStore.fetchRules()
|
||||
|
@ -50,8 +55,11 @@ watch(
|
|||
<div class="pl-4">{{ rule.name }}</div>
|
||||
<v-spacer />
|
||||
<div>
|
||||
<v-btn icon="mdi-pencil" variant="plain" density="compact" @click="openRuleDialog(rule)" />
|
||||
<v-btn icon="mdi-delete" color="red" variant="plain" @click="deleteRule(rule)" />
|
||||
<v-btn v-if="rule.enabled" class="my-2 mr-2" icon="mdi-check" color="accent" variant="plain" density="compact" @click="toggleRule(rule)" />
|
||||
<v-btn v-if="!rule.enabled" class="my-2 mr-2" icon="mdi-cancel" color="red" variant="plain" density="compact" @click="toggleRule(rule)" />
|
||||
|
||||
<v-btn class="my-2 mr-2" icon="mdi-pencil" variant="plain" density="compact" @click="openRuleDialog(rule)" />
|
||||
<v-btn class="my-2 mr-2" icon="mdi-delete" color="red" variant="plain" density="compact" @click="deleteRule(rule)" />
|
||||
</div>
|
||||
</v-sheet>
|
||||
</v-col>
|
||||
|
|
|
@ -272,6 +272,28 @@
|
|||
"noCategoryMatch": "No categories matching \"{query}\". It will be created automatically.",
|
||||
"noTagMatch": "No tags matching \"{query}\". Press Enter to create it.",
|
||||
"noTags": "No tags yet. Type a name to create one.",
|
||||
"params": {
|
||||
"title": "Torrent parameters",
|
||||
"add_to_top_of_queue": "Add to top of queue",
|
||||
"use_auto_tmm": "Automatic Torrent Management",
|
||||
"downloadPath": "Download path (when incomplete)",
|
||||
"download_limit": "Download limit",
|
||||
"category": "Category",
|
||||
"limit_collapse": "Configure limits",
|
||||
"noCategories": "No categories yet. Type a name to create one.",
|
||||
"noCategoryMatch": "No categories matching \"{query}\". It will be created automatically.",
|
||||
"tags": "Tags",
|
||||
"noTagMatch": "No tags matching \"{query}\". Press Enter to create it.",
|
||||
"noTags": "No tags yet. Type a name to create one.",
|
||||
"savePath": "Save path (when completed)",
|
||||
"skip_checking": "Skip hash checking",
|
||||
"stopped": "Don't start torrent",
|
||||
"upload_limit": "Upload limit",
|
||||
"ratio_limit": "Ratio limit",
|
||||
"limit_hint": "-1 to disable, -2 or empty to use global value",
|
||||
"seeding_time_limit": "Seeding time limit",
|
||||
"inactive_seeding_time_limit": "Inactive seeding time limit"
|
||||
},
|
||||
"pending": "Sending torrents...",
|
||||
"ratioLimit": "Ratio limit",
|
||||
"rename": "Rename torrent",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ConnectionStatus, FilePriority, LogType, PieceState, TorrentState } from '@/constants/qbit'
|
||||
import { ConnectionStatus, FilePriority, LogType, PieceState, TorrentOperatingMode, TorrentState } from '@/constants/qbit'
|
||||
import { ContentLayout, ProxyType, ResumeDataStorageType, StopCondition } from '@/constants/qbit/AppPreferences'
|
||||
import type {
|
||||
ApplicationVersion,
|
||||
|
@ -458,9 +458,7 @@ export default class MockProvider implements IProvider {
|
|||
return this.generateResponse({
|
||||
result: [
|
||||
{
|
||||
addPaused: null,
|
||||
affectedFeeds: ['https://www.example.com/feed'],
|
||||
assignedCategory: '',
|
||||
enabled: true,
|
||||
episodeFilter: '',
|
||||
ignoreDays: 0,
|
||||
|
@ -470,15 +468,13 @@ export default class MockProvider implements IProvider {
|
|||
name: 'rule1',
|
||||
previouslyMatchedEpisodes: [],
|
||||
priority: 0,
|
||||
savePath: '',
|
||||
smartFilter: false,
|
||||
torrentContentLayout: null,
|
||||
torrentParams: {
|
||||
category: '',
|
||||
download_limit: -1,
|
||||
download_path: '',
|
||||
inactive_seeding_time_limit: -2,
|
||||
operating_mode: 'AutoManaged',
|
||||
operating_mode: TorrentOperatingMode.AUTO_MANAGED,
|
||||
ratio_limit: -2,
|
||||
save_path: '',
|
||||
seeding_time_limit: -2,
|
||||
|
|
59
src/types/qbit/models/AddTorrentParams.ts
Normal file
59
src/types/qbit/models/AddTorrentParams.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { ContentLayout, StopCondition } from '@/constants/qbit/AppPreferences'
|
||||
import { AppPreferences } from '@/types/qbit/models'
|
||||
import { TorrentOperatingMode } from '@/constants/qbit'
|
||||
|
||||
export default interface AddTorrentParams {
|
||||
/** Whether this torrent should be added at the top of the waiting queue */
|
||||
add_to_top_of_queue?: boolean
|
||||
/** Torrent category */
|
||||
category?: string
|
||||
/** Overrides the default value of the torrent content layout */
|
||||
content_layout?: ContentLayout
|
||||
/** Torrent download limit (in kb/s), set to -1 to disable (default) */
|
||||
download_limit?: number
|
||||
/** Torrent download path */
|
||||
download_path?: string
|
||||
/** Inactive upload seeding time limit (in minutes), -1 to disable, -2 to use global value (default) */
|
||||
inactive_seeding_time_limit?: number
|
||||
/** Torrent operating mode (used for forced state) */
|
||||
operating_mode?: TorrentOperatingMode
|
||||
/** Ratio limit, -1 to disable, -2 to use global value (default) */
|
||||
ratio_limit?: number
|
||||
/** Torrent save path */
|
||||
save_path: string
|
||||
/** Upload seeding time limit (in minutes), -1 to disable, -2 to use global value (default) */
|
||||
seeding_time_limit?: number
|
||||
/** Skip hash checking */
|
||||
skip_checking: boolean
|
||||
/** Overrides the default value of the torrent stop condition */
|
||||
stop_condition?: StopCondition
|
||||
/** Whether this torrent should be added in paused state */
|
||||
stopped?: boolean
|
||||
/** List of torrent tags */
|
||||
tags?: string[]
|
||||
/** Torrent upload limit (in kb/s), set to -1 to disable (default) */
|
||||
upload_limit?: number
|
||||
/** Overrides the default value of the TMM attribute */
|
||||
use_auto_tmm?: boolean
|
||||
/** Whether the download_path attribute should be used */
|
||||
use_download_path?: boolean
|
||||
}
|
||||
|
||||
export function getEmptyParams(prefs?: AppPreferences): AddTorrentParams {
|
||||
return {
|
||||
save_path: prefs?.save_path ?? '',
|
||||
skip_checking: false,
|
||||
add_to_top_of_queue: prefs?.add_to_top_of_queue ?? false,
|
||||
content_layout: prefs?.torrent_content_layout,
|
||||
stop_condition: prefs?.torrent_stop_condition,
|
||||
download_limit: prefs?.dl_limit,
|
||||
upload_limit: prefs?.up_limit,
|
||||
use_download_path: !!prefs?.temp_path,
|
||||
download_path: !!prefs?.temp_path ? prefs?.temp_path : '',
|
||||
stopped: prefs?.start_paused_enabled,
|
||||
use_auto_tmm: prefs?.auto_tmm_enabled,
|
||||
ratio_limit: -2,
|
||||
seeding_time_limit: -2,
|
||||
inactive_seeding_time_limit: -2
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
import { AddTorrentParams } from '@/types/qbit/models'
|
||||
|
||||
export default interface FeedRule {
|
||||
/** The feed URLs the rule applies to */
|
||||
affectedFeeds?: string[]
|
||||
affectedFeeds: string[]
|
||||
/** Whether the rule is enabled */
|
||||
enabled?: boolean
|
||||
enabled: boolean
|
||||
/**
|
||||
* Matches articles based on episode filter.
|
||||
*
|
||||
|
@ -18,18 +20,18 @@ export default interface FeedRule {
|
|||
* - * 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
|
||||
episodeFilter: string
|
||||
/**
|
||||
* Ignore articles where its date is within n days
|
||||
* Values less than 1 will be ignored
|
||||
*/
|
||||
ignoreDays?: number
|
||||
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
|
||||
lastMatch: string
|
||||
/**
|
||||
* Wildcard mode: you can use
|
||||
*
|
||||
|
@ -42,7 +44,7 @@ export default interface FeedRule {
|
|||
*
|
||||
* An expression with an empty | clause (e.g. expr|) will match all articles.
|
||||
*/
|
||||
mustContain?: string
|
||||
mustContain: string
|
||||
/**
|
||||
* Wildcard mode: you can use
|
||||
*
|
||||
|
@ -55,18 +57,20 @@ export default interface FeedRule {
|
|||
*
|
||||
* An expression with an empty | clause (e.g. expr|) will exclude all articles.
|
||||
*/
|
||||
mustNotContain?: string
|
||||
mustNotContain: string
|
||||
/** The rule name */
|
||||
name?: string
|
||||
name: string
|
||||
/** The list of episodes already matched by smart filter */
|
||||
previouslyMatchedEpisodes?: string[]
|
||||
previouslyMatchedEpisodes: string[]
|
||||
/** The rule priority */
|
||||
priority?: number
|
||||
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
|
||||
smartFilter: boolean
|
||||
/** Parameters to apply to torrents added using that rule */
|
||||
torrentParams: AddTorrentParams
|
||||
/** Enable regex mode in "mustContain" and "mustNotContain" */
|
||||
useRegex?: boolean
|
||||
useRegex: boolean
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import type AddTorrentParams from './AddTorrentParams'
|
||||
import { getEmptyParams } from './AddTorrentParams'
|
||||
import type AppPreferences from './AppPreferences'
|
||||
import type Category from './Category'
|
||||
import type ServerState from './ServerState'
|
||||
|
@ -17,7 +19,10 @@ import type Log from './Log'
|
|||
|
||||
type ApplicationVersion = string
|
||||
|
||||
export { getEmptyParams }
|
||||
|
||||
export type {
|
||||
AddTorrentParams,
|
||||
ApplicationVersion,
|
||||
AppPreferences,
|
||||
Category,
|
||||
|
|
Loading…
Reference in a new issue