diff options
| author | 2025-07-31 01:22:01 -0400 | |
|---|---|---|
| committer | 2025-07-31 01:22:01 -0400 | |
| commit | a6e995c093de8aae2e91a0787281bb34c0b871eb (patch) | |
| tree | 2d79821b05300d34d8871eb6c9662b359a2de85d /gallery_dl/postprocessor | |
| parent | 7672a750cb74bf31e21d76aad2776367fd476155 (diff) | |
New upstream version 1.30.2.upstream/1.30.2
Diffstat (limited to 'gallery_dl/postprocessor')
| -rw-r--r-- | gallery_dl/postprocessor/__init__.py | 2 | ||||
| -rw-r--r-- | gallery_dl/postprocessor/common.py | 3 | ||||
| -rw-r--r-- | gallery_dl/postprocessor/compare.py | 11 | ||||
| -rw-r--r-- | gallery_dl/postprocessor/exec.py | 76 | ||||
| -rw-r--r-- | gallery_dl/postprocessor/metadata.py | 18 | ||||
| -rw-r--r-- | gallery_dl/postprocessor/mtime.py | 5 | ||||
| -rw-r--r-- | gallery_dl/postprocessor/ugoira.py | 53 |
7 files changed, 91 insertions, 77 deletions
diff --git a/gallery_dl/postprocessor/__init__.py b/gallery_dl/postprocessor/__init__.py index dd44a8a..1a4ce56 100644 --- a/gallery_dl/postprocessor/__init__.py +++ b/gallery_dl/postprocessor/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright 2018-2023 Mike Fährmann +# Copyright 2018-2025 Mike Fährmann # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as diff --git a/gallery_dl/postprocessor/common.py b/gallery_dl/postprocessor/common.py index 3099547..8da8417 100644 --- a/gallery_dl/postprocessor/common.py +++ b/gallery_dl/postprocessor/common.py @@ -22,8 +22,7 @@ class PostProcessor(): return self.__class__.__name__ def _init_archive(self, job, options, prefix=None): - archive_path = options.get("archive") - if archive_path: + if archive_path := options.get("archive"): extr = job.extractor archive_table = options.get("archive-table") diff --git a/gallery_dl/postprocessor/compare.py b/gallery_dl/postprocessor/compare.py index c6bc54d..c3d328d 100644 --- a/gallery_dl/postprocessor/compare.py +++ b/gallery_dl/postprocessor/compare.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright 2020-2023 Mike Fährmann +# Copyright 2020-2025 Mike Fährmann # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as @@ -21,8 +21,7 @@ class ComparePP(PostProcessor): self._compare = self._compare_size self._equal_exc = self._equal_cnt = 0 - equal = options.get("equal") - if equal: + if equal := options.get("equal"): equal, _, emax = equal.partition(":") self._equal_max = text.parse_int(emax) if equal == "abort": @@ -62,12 +61,10 @@ class ComparePP(PostProcessor): def _compare(self, f1, f2): return self._compare_size(f1, f2) and self._compare_content(f1, f2) - @staticmethod - def _compare_size(f1, f2): + def _compare_size(self, f1, f2): return os.stat(f1).st_size == os.stat(f2).st_size - @staticmethod - def _compare_content(f1, f2): + def _compare_content(self, f1, f2): size = 16384 with open(f1, "rb") as fp1, open(f2, "rb") as fp2: while True: diff --git a/gallery_dl/postprocessor/exec.py b/gallery_dl/postprocessor/exec.py index 7d2be2b..0bfe1a2 100644 --- a/gallery_dl/postprocessor/exec.py +++ b/gallery_dl/postprocessor/exec.py @@ -10,13 +10,14 @@ from .common import PostProcessor from .. import util, formatter +import subprocess import os -import re if util.WINDOWS: def quote(s): - return '"' + s.replace('"', '\\"') + '"' + s = s.replace('"', '\\"') + return f'"{s}"' else: from shlex import quote @@ -26,17 +27,21 @@ class ExecPP(PostProcessor): def __init__(self, job, options): PostProcessor.__init__(self, job) - if options.get("async", False): - self._exec = self._exec_async - - args = options["command"] - if isinstance(args, str): - self.args = args - self._sub = re.compile(r"\{(_directory|_filename|_path|)\}").sub - execute = self.exec_string + if cmds := options.get("commands"): + self.cmds = [self._prepare_cmd(c) for c in cmds] + execute = self.exec_many else: - self.args = [formatter.parse(arg) for arg in args] - execute = self.exec_list + execute, self.args = self._prepare_cmd(options["command"]) + if options.get("async", False): + self._exec = self._popen + + self.session = False + self.creationflags = 0 + if options.get("session"): + if util.WINDOWS: + self.creationflags = subprocess.CREATE_NEW_PROCESS_GROUP + else: + self.session = True events = options.get("event") if events is None: @@ -47,6 +52,13 @@ class ExecPP(PostProcessor): self._init_archive(job, options) + def _prepare_cmd(self, cmd): + if isinstance(cmd, str): + self._sub = util.re(r"\{(_directory|_filename|_path|)\}").sub + return self.exec_string, cmd + else: + return self.exec_list, [formatter.parse(arg) for arg in cmd] + def exec_list(self, pathfmt): archive = self.archive kwdict = pathfmt.kwdict @@ -60,10 +72,11 @@ class ExecPP(PostProcessor): args = [arg.format_map(kwdict) for arg in self.args] args[0] = os.path.expanduser(args[0]) - self._exec(args, False) + retcode = self._exec(args, False) if archive: archive.add(kwdict) + return retcode def exec_string(self, pathfmt): archive = self.archive @@ -72,24 +85,47 @@ class ExecPP(PostProcessor): self.pathfmt = pathfmt args = self._sub(self._replace, self.args) - self._exec(args, True) + retcode = self._exec(args, True) if archive: archive.add(pathfmt.kwdict) + return retcode + + def exec_many(self, pathfmt): + if archive := self.archive: + if archive.check(pathfmt.kwdict): + return + self.archive = False + + retcode = 0 + for execute, args in self.cmds: + self.args = args + if retcode := execute(pathfmt): + # non-zero exit status + break + + if archive: + self.archive = archive + archive.add(pathfmt.kwdict) + return retcode def _exec(self, args, shell): - self.log.debug("Running '%s'", args) - retcode = util.Popen(args, shell=shell).wait() - if retcode: + if retcode := self._popen(args, shell).wait(): self.log.warning("'%s' returned with non-zero exit status (%d)", args, retcode) + return retcode - def _exec_async(self, args, shell): + def _popen(self, args, shell): self.log.debug("Running '%s'", args) - util.Popen(args, shell=shell) + return util.Popen( + args, + shell=shell, + creationflags=self.creationflags, + start_new_session=self.session, + ) def _replace(self, match): - name = match.group(1) + name = match[1] if name == "_directory": return quote(self.pathfmt.realdirectory) if name == "_filename": diff --git a/gallery_dl/postprocessor/metadata.py b/gallery_dl/postprocessor/metadata.py index fbb3fb8..c74f92f 100644 --- a/gallery_dl/postprocessor/metadata.py +++ b/gallery_dl/postprocessor/metadata.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright 2019-2023 Mike Fährmann +# Copyright 2019-2025 Mike Fährmann # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as @@ -55,8 +55,7 @@ class MetadataPP(PostProcessor): self._json_encode = self._make_encoder(options, 4).encode ext = "json" - base_directory = options.get("base-directory") - if base_directory: + if base_directory := options.get("base-directory"): if base_directory is True: self._base = lambda p: p.basedirectory else: @@ -139,9 +138,7 @@ class MetadataPP(PostProcessor): archive.add(pathfmt.kwdict) if self.mtime: - mtime = pathfmt.kwdict.get("_mtime") - if mtime: - util.set_mtime(path, mtime) + pathfmt.set_mtime(path) def _run_stdout(self, pathfmt): self.write(sys.stdout, pathfmt.kwdict) @@ -183,8 +180,7 @@ class MetadataPP(PostProcessor): try: pathfmt.directory_formatters = self._directory_formatters pathfmt.directory_conditions = () - segments = pathfmt.build_directory(pathfmt.kwdict) - if segments: + if segments := pathfmt.build_directory(pathfmt.kwdict): directory = pathfmt.clean_path(os.sep.join(segments) + os.sep) else: directory = "." + os.sep @@ -246,8 +242,7 @@ class MetadataPP(PostProcessor): fp.write(self._json_encode(kwdict) + "\n") def _make_filter(self, options): - include = options.get("include") - if include: + if include := options.get("include"): if isinstance(include, str): include = include.split(",") return lambda d: {k: d[k] for k in include if k in d} @@ -268,8 +263,7 @@ class MetadataPP(PostProcessor): if not private: return util.filter_dict - @staticmethod - def _make_encoder(options, indent=None): + def _make_encoder(self, options, indent=None): return json.JSONEncoder( ensure_ascii=options.get("ascii", False), sort_keys=options.get("sort", False), diff --git a/gallery_dl/postprocessor/mtime.py b/gallery_dl/postprocessor/mtime.py index 6ded1e2..b1269dd 100644 --- a/gallery_dl/postprocessor/mtime.py +++ b/gallery_dl/postprocessor/mtime.py @@ -17,8 +17,7 @@ class MtimePP(PostProcessor): def __init__(self, job, options): PostProcessor.__init__(self, job) - value = options.get("value") - if value: + if value := options.get("value"): self._get = formatter.parse(value, None, util.identity).format_map else: key = options.get("key", "date") @@ -36,7 +35,7 @@ class MtimePP(PostProcessor): if mtime is None: return - pathfmt.kwdict["_mtime"] = ( + pathfmt.kwdict["_mtime_meta"] = ( util.datetime_to_timestamp(mtime) if isinstance(mtime, datetime) else text.parse_int(mtime) diff --git a/gallery_dl/postprocessor/ugoira.py b/gallery_dl/postprocessor/ugoira.py index 5340335..33ebb75 100644 --- a/gallery_dl/postprocessor/ugoira.py +++ b/gallery_dl/postprocessor/ugoira.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright 2018-2023 Mike Fährmann +# Copyright 2018-2025 Mike Fährmann # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as @@ -170,8 +170,8 @@ class UgoiraPP(PostProcessor): for frame in self._files: # update frame filename extension - frame["file"] = name = "{}.{}".format( - frame["file"].partition(".")[0], frame["ext"]) + frame["file"] = name = \ + f"{frame['file'].partition('.')[0]}.{frame['ext']}" if tempdir: # move frame into tempdir @@ -236,9 +236,7 @@ class UgoiraPP(PostProcessor): pathfmt.realpath = pathfmt.temppath else: if self.mtime: - mtime = pathfmt.kwdict.get("_mtime") - if mtime: - util.set_mtime(pathfmt.realpath, mtime) + pathfmt.set_mtime() return True def convert_to_archive(self, pathfmt, tempdir): @@ -298,8 +296,7 @@ class UgoiraPP(PostProcessor): def _exec(self, args): self.log.debug(args) out = None if self.output else subprocess.DEVNULL - retcode = util.Popen(args, stdout=out, stderr=out).wait() - if retcode: + if retcode := util.Popen(args, stdout=out, stderr=out).wait(): output.stderr_write("\n") self.log.error("Non-zero exit status when running %s (%s)", args, retcode) @@ -334,7 +331,7 @@ class UgoiraPP(PostProcessor): last_copy = last.copy() frames.append(last_copy) name, _, ext = last_copy["file"].rpartition(".") - last_copy["file"] = "{:>06}.{}".format(int(name)+1, ext) + last_copy["file"] = f"{int(name) + 1:>06}.{ext}" shutil.copyfile(tempdir + last["file"], tempdir + last_copy["file"]) @@ -349,10 +346,8 @@ class UgoiraPP(PostProcessor): "-f", "image2", "-ts_from_file", "2", "-pattern_type", "sequence", - "-i", "{}%06d.{}".format( - tempdir.replace("%", "%%"), - frame["file"].rpartition(".")[2] - ), + "-i", (f"{tempdir.replace('%', '%%')}%06d." + f"{frame['file'].rpartition('.')[2]}"), ] def _process_mkvmerge(self, pathfmt, tempdir): @@ -363,10 +358,8 @@ class UgoiraPP(PostProcessor): self.ffmpeg, "-f", "image2", "-pattern_type", "sequence", - "-i", "{}/%06d.{}".format( - tempdir.replace("%", "%%"), - self._frames[0]["file"].rpartition(".")[2] - ), + "-i", (f"{tempdir.replace('%', '%%')}/%06d." + f"{self._frames[0]['file'].rpartition('.')[2]}"), ] def _finalize_mkvmerge(self, pathfmt, tempdir): @@ -384,14 +377,13 @@ class UgoiraPP(PostProcessor): def _write_ffmpeg_concat(self, tempdir): content = ["ffconcat version 1.0"] - append = content.append for frame in self._frames: - append("file '{}'\nduration {}".format( - frame["file"], frame["delay"] / 1000)) + content.append(f"file '{frame['file']}'\n" + f"duration {frame['delay'] / 1000}") if self.repeat: - append("file '{}'".format(frame["file"])) - append("") + content.append(f"file '{frame['file']}'") + content.append("") ffconcat = tempdir + "/ffconcat.txt" with open(ffconcat, "w") as fp: @@ -400,14 +392,13 @@ class UgoiraPP(PostProcessor): def _write_mkvmerge_timecodes(self, tempdir): content = ["# timecode format v2"] - append = content.append delay_sum = 0 for frame in self._frames: - append(str(delay_sum)) + content.append(str(delay_sum)) delay_sum += frame["delay"] - append(str(delay_sum)) - append("") + content.append(str(delay_sum)) + content.append("") timecodes = tempdir + "/timecodes.tc" with open(timecodes, "w") as fp: @@ -416,24 +407,22 @@ class UgoiraPP(PostProcessor): def calculate_framerate(self, frames): if self._delay_is_uniform(frames): - return ("1000/{}".format(frames[0]["delay"]), None) + return (f"1000/{frames[0]['delay']}", None) if not self.uniform: gcd = self._delay_gcd(frames) if gcd >= 10: - return (None, "1000/{}".format(gcd)) + return (None, f"1000/{gcd}") return (None, None) - @staticmethod - def _delay_gcd(frames): + def _delay_gcd(self, frames): result = frames[0]["delay"] for f in frames: result = gcd(result, f["delay"]) return result - @staticmethod - def _delay_is_uniform(frames): + def _delay_is_uniform(self, frames): delay = frames[0]["delay"] for f in frames: if f["delay"] != delay: |
