make it possible to ignore item download via conditions
This commit is contained in:
parent
0d6532df5d
commit
d0a11cbcd6
4 changed files with 77 additions and 35 deletions
|
|
@ -24,6 +24,7 @@ from .Presets import Presets
|
|||
from .Scheduler import Scheduler
|
||||
from .Singleton import Singleton
|
||||
from .Utils import (
|
||||
archive_add,
|
||||
arg_converter,
|
||||
calc_download_path,
|
||||
dt_delta,
|
||||
|
|
@ -675,8 +676,10 @@ class DownloadQueue(metaclass=Singleton):
|
|||
LOG.warning(f"Using external downloader '{yt_conf.get('external_downloader')}' for '{item.url}'.")
|
||||
item.extras.update({"external_downloader": True})
|
||||
|
||||
archive_id = item.get_archive_id()
|
||||
|
||||
if item.is_archived():
|
||||
if archive_id := item.get_archive_id():
|
||||
if archive_id:
|
||||
store_type, _ = self.get_item(archive_id=archive_id)
|
||||
if not store_type:
|
||||
dlInfo = Download(
|
||||
|
|
@ -750,7 +753,55 @@ class DownloadQueue(metaclass=Singleton):
|
|||
|
||||
if not item.requeued and (condition := Conditions.get_instance().match(info=entry)):
|
||||
already.pop()
|
||||
LOG.info(f"Matched '{condition.name}' for '{item.url}' Adding '{condition.cli}' to request.")
|
||||
|
||||
item_title = entry.get("title") or entry.get("id") or item.url
|
||||
message = f"Condition '{condition.name}' matched for '{item_title}'."
|
||||
|
||||
if condition.cli:
|
||||
message += f" Re-queuing with '{condition.cli}'."
|
||||
|
||||
LOG.info(message)
|
||||
|
||||
if condition.extras.get("ignore_download", False):
|
||||
extra_msg: str = ""
|
||||
if yt_conf.get("download_archive") and not condition.extras.get("no_archive", False):
|
||||
archive_add(yt_conf.get("download_archive"), [archive_id])
|
||||
extra_msg = f" and added to archive '{yt_conf.get('download_archive')}'"
|
||||
|
||||
log_message = f"Ignoring download of '{item_title}' as per condition '{condition.name}'{extra_msg}."
|
||||
|
||||
store_type, _ = self.get_item(archive_id=archive_id)
|
||||
if not store_type:
|
||||
dlInfo = Download(
|
||||
info=ItemDTO(
|
||||
id=entry.get("id"),
|
||||
title=item_title,
|
||||
url=item.url,
|
||||
preset=item.preset,
|
||||
folder=item.folder,
|
||||
status="skip",
|
||||
cookies=item.cookies,
|
||||
template=item.template,
|
||||
msg=log_message,
|
||||
extras=item.extras,
|
||||
)
|
||||
)
|
||||
self.done.put(dlInfo)
|
||||
|
||||
LOG.info(log_message)
|
||||
await asyncio.gather(
|
||||
*[
|
||||
self._notify.emit(Events.LOG_INFO, data={}, title="Ignored Download", message=log_message),
|
||||
self._notify.emit(
|
||||
Events.ITEM_MOVED,
|
||||
data={"to": "history", "preset": dlInfo.info.preset, "item": dlInfo.info},
|
||||
title="Download History Update",
|
||||
message=f"Download history updated with '{item.url}'.",
|
||||
),
|
||||
]
|
||||
)
|
||||
return {"status": "ok"}
|
||||
|
||||
return await self.add(item=item.new_with(requeued=True, cli=condition.cli), already=already)
|
||||
|
||||
_status, _msg = ytdlp_reject(entry=entry, yt_params=yt_conf)
|
||||
|
|
|
|||
|
|
@ -210,15 +210,12 @@ class Conditions(metaclass=Singleton):
|
|||
msg = f"Invalid filter. '{e!s}'."
|
||||
raise ValueError(msg) from e
|
||||
|
||||
if not item.get("cli"):
|
||||
msg = "No command options for yt-dlp were found."
|
||||
raise ValueError(msg)
|
||||
|
||||
try:
|
||||
arg_converter(args=item.get("cli"))
|
||||
except Exception as e:
|
||||
msg = f"Invalid command options for yt-dlp. '{e!s}'."
|
||||
raise ValueError(msg) from e
|
||||
if item.get("cli"):
|
||||
try:
|
||||
arg_converter(args=item.get("cli"))
|
||||
except Exception as e:
|
||||
msg = f"Invalid command options for yt-dlp. '{e!s}'."
|
||||
raise ValueError(msg) from e
|
||||
|
||||
if not isinstance(item.get("extras"), dict):
|
||||
msg = "Extras must be a dictionary."
|
||||
|
|
|
|||
|
|
@ -304,8 +304,7 @@ if (!form.extras) {
|
|||
|
||||
watch(() => config.ytdlp_options, newOptions => ytDlpOpt.value = newOptions
|
||||
.filter(opt => !opt.ignored)
|
||||
.flatMap(opt => opt.flags
|
||||
.filter(flag => flag.startsWith('--'))
|
||||
.flatMap(opt => opt.flags.filter(flag => flag.startsWith('--'))
|
||||
.map(flag => ({ value: flag, description: opt.description || '' }))),
|
||||
{ immediate: true }
|
||||
)
|
||||
|
|
@ -313,7 +312,7 @@ watch(() => config.ytdlp_options, newOptions => ytDlpOpt.value = newOptions
|
|||
watch(() => form.filter, () => test_data.value.changed = true)
|
||||
|
||||
const checkInfo = async (): Promise<void> => {
|
||||
const required: (keyof ConditionItem)[] = ['name', 'filter', 'cli']
|
||||
const required: (keyof ConditionItem)[] = ['name', 'filter']
|
||||
|
||||
for (const key of required) {
|
||||
if (!form[key]) {
|
||||
|
|
@ -457,27 +456,20 @@ const logic_test = computed(() => {
|
|||
}
|
||||
})
|
||||
|
||||
// Extras management functions
|
||||
const validateKey = (key: string): boolean => {
|
||||
// Key must be lowercase with underscores only
|
||||
return /^[a-z][a-z0-9_]*$/.test(key)
|
||||
}
|
||||
const validateKey = (key: string): boolean => /^[a-z][a-z0-9_]*$/.test(key)
|
||||
|
||||
const parseValue = (value: string): string | number | boolean => {
|
||||
// Try to parse as number
|
||||
if (!isNaN(Number(value)) && !isNaN(parseFloat(value))) {
|
||||
return Number(value)
|
||||
}
|
||||
|
||||
// Try to parse as boolean
|
||||
if (value.toLowerCase() === 'true') {
|
||||
if ('true' === value.toLowerCase()) {
|
||||
return true
|
||||
}
|
||||
if (value.toLowerCase() === 'false') {
|
||||
if ('false' === value.toLowerCase()) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Return as string
|
||||
return value
|
||||
}
|
||||
|
||||
|
|
@ -491,7 +483,7 @@ const addExtra = (): void => {
|
|||
}
|
||||
|
||||
if (!validateKey(key)) {
|
||||
toast.error('Key must be lowercase and contain only letters, numbers, and underscores (e.g., custom_field).')
|
||||
toast.error('Key must be lower_case.')
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -519,18 +511,17 @@ const updateExtraKey = (event: Event, oldKey: string): void => {
|
|||
|
||||
if (!validateKey(newKey)) {
|
||||
toast.error('Key must be lowercase and contain only letters, numbers, and underscores.')
|
||||
target.value = oldKey // Reset to old value
|
||||
target.value = oldKey
|
||||
return
|
||||
}
|
||||
|
||||
if (newKey !== oldKey) {
|
||||
if (form.extras[newKey]) {
|
||||
toast.error(`Key '${newKey}' already exists.`)
|
||||
target.value = oldKey // Reset to old value
|
||||
target.value = oldKey
|
||||
return
|
||||
}
|
||||
|
||||
// Move the value to the new key
|
||||
const value = form.extras[oldKey]
|
||||
delete form.extras[oldKey]
|
||||
form.extras[newKey] = value
|
||||
|
|
@ -540,11 +531,6 @@ const updateExtraKey = (event: Event, oldKey: string): void => {
|
|||
const updateExtraValue = (key: string, event: Event): void => {
|
||||
const target = event.target as HTMLInputElement
|
||||
const value = target.value.trim()
|
||||
|
||||
if (value) {
|
||||
form.extras[key] = parseValue(value)
|
||||
} else {
|
||||
form.extras[key] = ''
|
||||
}
|
||||
form.extras[key] = value ? parseValue(value) : ''
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -64,6 +64,14 @@
|
|||
<span class="icon"><i class="fa-solid fa-terminal" /></span>
|
||||
<span>{{ cond.cli }}</span>
|
||||
</p>
|
||||
<p class="is-text-overflow" v-if="cond.extras && Object.keys(cond.extras).length > 0">
|
||||
<span class="icon"><i class="fa-solid fa-list" /></span>
|
||||
<span>Extras:
|
||||
<span v-for="(value, key) in cond.extras" :key="key" class="tag is-info mr-2">
|
||||
<strong>{{ key }}</strong>: {{ value }}
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content" v-if="cond?.raw">
|
||||
|
|
@ -278,7 +286,7 @@ const exportItem = (cond: ConditionItem): void => {
|
|||
const userData: ImportedConditionItem = {
|
||||
...Object.fromEntries(Object.entries(clone).filter(([_, v]) => !!v)),
|
||||
_type: 'condition',
|
||||
_version: '1.0',
|
||||
_version: '1.1',
|
||||
} as ImportedConditionItem
|
||||
|
||||
copyText(encode(userData))
|
||||
|
|
|
|||
Loading…
Reference in a new issue