extend '-A / --abort' & '"skip": "abort"' functionality (#7891)

implement ascending by more than 1 level or
up to an extractor with a specific subcategory
This commit is contained in:
Mike Fährmann
2025-07-30 00:01:49 +02:00
parent 64de6605ce
commit 2eb5e52055
5 changed files with 70 additions and 23 deletions

View File

@@ -313,28 +313,51 @@ Type
* ``string`` * ``string``
Default Default
``true`` ``true``
Example
* ``"abort:5"``
* ``"abort:5:2"``
* ``"abort:5:manga"``
* ``"terminate:3"``
Description Description
Controls the behavior when downloading files that have been Controls the behavior when downloading files that have been
downloaded before, i.e. a file with the same filename already downloaded before, i.e. a file with the same filename already
exists or its ID is in a `download archive <extractor.*.archive_>`__. exists or its ID is in a `download archive <extractor.*.archive_>`__.
* ``true``: Skip downloads ``true``
* ``false``: Overwrite already existing files Skip downloads
``false``
Overwrite already existing files
* ``"abort"``: Stop the current extractor run ``"abort"``
* ``"abort:N"``: Skip downloads and stop the current extractor run Stop the current extractor
after ``N`` consecutive skips ``"abort:N"``
Skip downloads and
stop the current extractor after ``N`` consecutive skips
``"abort:N:L"``
| Skip downloads and
stop the current extractor after ``N`` consecutive skips
| Ascend ``L`` levels in the extractor hierarchy
``"abort:N:SC"``
| Skip downloads and
stop the current extractor after ``N`` consecutive skips
| Ascend to an extractor with subcategory ``SC`` in the extractor hierarchy
* ``"terminate"``: Stop the current extractor run, including parent extractors ``"terminate"``
* ``"terminate:N"``: Skip downloads and stop the current extractor run, Stop the current extractor, including parent extractors
including parent extractors, after ``N`` consecutive skips ``"terminate:N"``
Skip downloads and
stop the current extractor, including parent extractors,
after ``N`` consecutive skips
* ``"exit"``: Exit the program altogether ``"exit"``
* ``"exit:N"``: Skip downloads and exit the program Exit the program altogether
after ``N`` consecutive skips ``"exit:N"``
Skip downloads and
exit the program after ``N`` consecutive skips
* ``"enumerate"``: Add an enumeration index to the beginning of the ``"enumerate"``
filename extension (``file.1.ext``, ``file.2.ext``, etc.) Add an enumeration index to the beginning of the
filename extension (``file.1.ext``, ``file.2.ext``, etc.)
extractor.*.skip-filter extractor.*.skip-filter

View File

@@ -48,7 +48,7 @@ def main():
if filename == "/O": if filename == "/O":
filename = "{filename}.{extension}" filename = "{filename}.{extension}"
elif filename.startswith("\\f"): elif filename.startswith("\\f"):
filename = "\f" + filename[2:] filename = f"\f{filename[2:]}"
config.set((), "filename", filename) config.set((), "filename", filename)
if args.directory is not None: if args.directory is not None:
config.set((), "base-directory", args.directory) config.set((), "base-directory", args.directory)
@@ -56,9 +56,9 @@ def main():
if args.postprocessors: if args.postprocessors:
config.set((), "postprocessors", args.postprocessors) config.set((), "postprocessors", args.postprocessors)
if args.abort: if args.abort:
config.set((), "skip", "abort:" + str(args.abort)) config.set((), "skip", f"abort:{args.abort}")
if args.terminate: if args.terminate:
config.set((), "skip", "terminate:" + str(args.terminate)) config.set((), "skip", f"terminate:{args.terminate}")
if args.cookies_from_browser: if args.cookies_from_browser:
browser, _, profile = args.cookies_from_browser.partition(":") browser, _, profile = args.cookies_from_browser.partition(":")
browser, _, keyring = browser.partition("+") browser, _, keyring = browser.partition("+")

View File

@@ -160,6 +160,22 @@ class ControlException(GalleryDLException):
class StopExtraction(ControlException): class StopExtraction(ControlException):
"""Stop data extraction""" """Stop data extraction"""
def __init__(self, target=None):
ControlException.__init__(self)
if target is None:
self.target = None
self.depth = 1
elif isinstance(target, int):
self.target = None
self.depth = target
elif target.isdecimal():
self.target = None
self.depth = int(target)
else:
self.target = target
self.depth = 128
class AbortExtraction(ExtractionError, ControlException): class AbortExtraction(ExtractionError, ControlException):
"""Abort data extraction due to an error""" """Abort data extraction due to an error"""

View File

@@ -151,7 +151,10 @@ class Job():
try: try:
for msg in extractor: for msg in extractor:
self.dispatch(msg) self.dispatch(msg)
except exception.StopExtraction: except exception.StopExtraction as exc:
if exc.depth > 1 and exc.target != extractor.__class__.subcategory:
exc.depth -= 1
raise
pass pass
except exception.AbortExtraction as exc: except exception.AbortExtraction as exc:
log.error(exc.message) log.error(exc.message)
@@ -509,7 +512,7 @@ class DownloadJob(Job):
if not self._skipftr or self._skipftr(pathfmt.kwdict): if not self._skipftr or self._skipftr(pathfmt.kwdict):
self._skipcnt += 1 self._skipcnt += 1
if self._skipcnt >= self._skipmax: if self._skipcnt >= self._skipmax:
raise self._skipexc() raise self._skipexc
def download(self, url): def download(self, url):
"""Download 'url'""" """Download 'url'"""
@@ -603,7 +606,8 @@ class DownloadJob(Job):
elif isinstance(skip, str): elif isinstance(skip, str):
skip, _, smax = skip.partition(":") skip, _, smax = skip.partition(":")
if skip == "abort": if skip == "abort":
self._skipexc = exception.StopExtraction smax, _, sarg = smax.partition(":")
self._skipexc = exception.StopExtraction(sarg or None)
elif skip == "terminate": elif skip == "terminate":
self._skipexc = exception.TerminateExtraction self._skipexc = exception.TerminateExtraction
elif skip == "exit": elif skip == "exit":

View File

@@ -664,14 +664,18 @@ def build_parser():
selection = parser.add_argument_group("Selection Options") selection = parser.add_argument_group("Selection Options")
selection.add_argument( selection.add_argument(
"-A", "--abort", "-A", "--abort",
dest="abort", metavar="N", type=int, dest="abort", metavar="N[:TARGET]",
help=("Stop current extractor run " help=("Stop current extractor(s) "
"after N consecutive file downloads were skipped"), "after N consecutive file downloads were skipped. "
"Specify a TARGET to set how many levels to ascend or "
"to which subcategory to jump to. "
"Examples: '-A 3', '-A 3:2', '-A 3:manga'"),
) )
selection.add_argument( selection.add_argument(
"-T", "--terminate", "-T", "--terminate",
dest="terminate", metavar="N", type=int, dest="terminate", metavar="N", type=int,
help=("Stop current and parent extractor runs " help=("Stop current & parent extractors "
"and proceed with the next input URL "
"after N consecutive file downloads were skipped"), "after N consecutive file downloads were skipped"),
) )
selection.add_argument( selection.add_argument(