Merge pull request #567 from arabcoders/dev

fix: forcibly register the NFOMaker PP
This commit is contained in:
Abdulmohsen 2026-02-14 20:32:56 +03:00 committed by GitHub
commit 0c7ebb66ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 48 additions and 20 deletions

View file

@ -1,4 +1,4 @@
# flake8: noqa: F401 # flake8: noqa: F401, RUF100, W291, I001
import sys import sys
from typing import Any from typing import Any
@ -49,6 +49,7 @@ class _ArchiveProxy:
class YTDLP(yt_dlp.YoutubeDL): class YTDLP(yt_dlp.YoutubeDL):
_interrupted = False _interrupted = False
_registered = False
def __init__(self, params=None, auto_init=True): def __init__(self, params=None, auto_init=True):
# Avoid yt-dlp preloading the archive file by stripping the param first # Avoid yt-dlp preloading the archive file by stripping the param first
@ -73,6 +74,15 @@ class YTDLP(yt_dlp.YoutubeDL):
pass pass
self.archive = _ArchiveProxy(orig_file) self.archive = _ArchiveProxy(orig_file)
if not YTDLP._registered:
try:
from app.yt_dlp_plugins.postprocessor.nfo_maker import NFOMakerPP
from yt_dlp.postprocessor import postprocessors
postprocessors.value.update({"NFOMakerPP": NFOMakerPP})
YTDLP._registered = True
except Exception:
pass
def _delete_downloaded_files(self, *args, **kwargs) -> None: def _delete_downloaded_files(self, *args, **kwargs) -> None:
if self._interrupted: if self._interrupted:

View file

@ -85,6 +85,7 @@ async def add(
""" """
_preset: Preset | None = Presets.get_instance().get(item.preset) _preset: Preset | None = Presets.get_instance().get(item.preset)
logs = []
if item.has_cli(): if item.has_cli():
try: try:

View file

@ -66,9 +66,17 @@ class StatusTracker:
""" """
self.info.datetime = str(formatdate(time.time())) self.info.datetime = str(formatdate(time.time()))
self.info.filename = safe_relative_path(filepath, Path(self.download_dir), self.temp_path) self.info.filename = safe_relative_path(filepath, Path(self.download_dir))
self.final_update = True self.final_update = True
self.logger.debug(f"Final file name: '{filepath}'.") self.logger.debug(f"Final file name: '{filepath}'.")
try:
filepath.relative_to(self.download_dir)
except ValueError:
self.logger.warning(
f"Final file '{filepath}' is outside of the intended download directory '{self.download_dir}'."
)
self.info.filename = None
return
if filepath.is_file() and filepath.exists(): if filepath.is_file() and filepath.exists():
try: try:

View file

@ -120,6 +120,10 @@ class NFOMakerPP(PostProcessor):
return "NFOMaker" return "NFOMaker"
def run(self, info: dict | None = None) -> tuple[list, dict]: def run(self, info: dict | None = None) -> tuple[list, dict]:
if "fail" == self.mode:
msg = "Intentionally failing due to mode=fail."
raise Exception(msg)
if not info: if not info:
self.report_warning("No info provided to NFO Maker.") self.report_warning("No info provided to NFO Maker.")
return [], {} return [], {}

View file

@ -121,7 +121,7 @@
</td> </td>
<td> <td>
<div class="progress-bar is-unselectable"> <div class="progress-bar is-unselectable">
<div class="progress-percentage">{{ updateProgress(item) }}</div> <div class="progress-percentage" v-html="updateProgress(item)" />
<div class="progress" :style="{ width: percentPipe(item.percent as number) + '%' }"></div> <div class="progress" :style="{ width: percentPipe(item.percent as number) + '%' }"></div>
</div> </div>
</td> </td>
@ -247,7 +247,7 @@
<div class="columns is-multiline is-mobile"> <div class="columns is-multiline is-mobile">
<div class="column is-12"> <div class="column is-12">
<div class="progress-bar is-unselectable"> <div class="progress-bar is-unselectable">
<div class="progress-percentage">{{ updateProgress(item) }}</div> <div class="progress-percentage" v-html="updateProgress(item)" />
<div class="progress" :style="{ width: percentPipe(item.percent as number) + '%' }"></div> <div class="progress" :style="{ width: percentPipe(item.percent as number) + '%' }"></div>
</div> </div>
</div> </div>
@ -600,7 +600,7 @@ const updateProgress = (item: StoreItem): string => {
if ('postprocessing' === item.status) { if ('postprocessing' === item.status) {
if (item.postprocessor) { if (item.postprocessor) {
return `PP Running: ${item.postprocessor}` return `<i class="fa fa-cog fa-spin"></i> PP: ${item.postprocessor}`
} }
return 'Post-processors are running.' return 'Post-processors are running.'
} }

View file

@ -75,22 +75,31 @@ const sources: EmbedSource[] = [
url: "https://drive.google.com/file/d/{id}/preview", url: "https://drive.google.com/file/d/{id}/preview",
regex: /https?:\/\/(?:www\.)?drive\.google\.com\/file\/d\/(?<id>[^/?#&]+)/, regex: /https?:\/\/(?:www\.)?drive\.google\.com\/file\/d\/(?<id>[^/?#&]+)/,
}, },
{
name: "fbc_sites",
url: "{domain}/e/{id}",
regex: /(?<domain>(.+?))\/(?:api\/tokens|f)\/(?<id>fbc_[A-Za-z0-9_-]{22})\/?/,
},
] ]
const isEmbedable = (url: string): boolean => sources.some(source => source.regex.test(url)) const isEmbedable = (url: string): boolean => sources.some(source => source.regex.test(url))
const getEmbedable = (url: string): string | null => { const getEmbedable = (url: string): string | null => {
const source = sources.find(source => source.regex.test(url)) for (const source of sources) {
if (!source) { const match = source.regex.exec(url)
return null if (!match?.groups) {
continue
}
const replacements: Record<string, string> = {
...match.groups,
origin: window.location.origin,
}
return source.url.replace(/\{(\w+)\}/g, (_, key) => replacements[key] ?? `{${key}}`)
} }
const match = source.regex.exec(url) return null
if (!match || !match.groups?.id) {
return null
}
return source.url.replace(/\{origin\}/g, window.location.origin).replace(/\{id\}/g, match.groups.id)
} }
export { isEmbedable, getEmbedable } export { isEmbedable, getEmbedable }

View file

@ -213,11 +213,7 @@ const encodePath = (item: string): string => {
processed = encodeURIComponent(processed) processed = encodeURIComponent(processed)
const placeholderRegex = new RegExp(`${_PREFIX.replace(/_/g, '_')}(\\d+)${_SUFFIX.replace(/_/g, '_')}`, 'g') const placeholderRegex = new RegExp(`${_PREFIX.replace(/_/g, '_')}(\\d+)${_SUFFIX.replace(/_/g, '_')}`, 'g')
processed = processed.replace(placeholderRegex, (_match, index: string) => { return processed.replace(placeholderRegex, (_match, index: string) => placeholders[parseInt(index)] || '')
return placeholders[parseInt(index)] || ''
})
return processed
}).join('/') }).join('/')
} }
@ -255,7 +251,7 @@ const request = (url: string, options: RequestInit & { timeout?: number } = {}):
if (typeof timeout === 'number' && timeout > 0) { if (typeof timeout === 'number' && timeout > 0) {
controller = new AbortController() controller = new AbortController()
fetchOptions.signal = controller.signal fetchOptions.signal = controller.signal
timer = setTimeout(() => controller!.abort(`Request timed out.`), timeout*1000) timer = setTimeout(() => controller!.abort(`Request timed out.`), timeout * 1000)
} }
return fetch(url.startsWith('/') ? uri(url) : url, fetchOptions).finally(() => { return fetch(url.startsWith('/') ? uri(url) : url, fetchOptions).finally(() => {