initial 'signals-actions' implementation (#6582)
https://github.com/mikf/gallery-dl/issues/6582#issuecomment-2973285775 To stop gracefully after the current file finishes processing when Ctrl+C was pressed, or after the current post finishes processing when SIGUSR1 was received: { "signals-actions": { "SIGINT" : "file", "SIGUSR1": "post" } }
This commit is contained in:
@@ -11,7 +11,7 @@ import logging
|
|||||||
from . import version, config, option, output, extractor, job, util, exception
|
from . import version, config, option, output, extractor, job, util, exception
|
||||||
|
|
||||||
__author__ = "Mike Fährmann"
|
__author__ = "Mike Fährmann"
|
||||||
__copyright__ = "Copyright 2014-2023 Mike Fährmann"
|
__copyright__ = "Copyright 2014-2025 Mike Fährmann"
|
||||||
__license__ = "GPLv2"
|
__license__ = "GPLv2"
|
||||||
__maintainer__ = "Mike Fährmann"
|
__maintainer__ = "Mike Fährmann"
|
||||||
__email__ = "mike_faehrmann@web.de"
|
__email__ = "mike_faehrmann@web.de"
|
||||||
@@ -78,8 +78,7 @@ def main():
|
|||||||
output.configure_standard_streams()
|
output.configure_standard_streams()
|
||||||
|
|
||||||
# signals
|
# signals
|
||||||
signals = config.get((), "signals-ignore")
|
if signals := config.get((), "signals-ignore"):
|
||||||
if signals:
|
|
||||||
import signal
|
import signal
|
||||||
if isinstance(signals, str):
|
if isinstance(signals, str):
|
||||||
signals = signals.split(",")
|
signals = signals.split(",")
|
||||||
@@ -90,6 +89,19 @@ def main():
|
|||||||
else:
|
else:
|
||||||
signal.signal(signal_num, signal.SIG_IGN)
|
signal.signal(signal_num, signal.SIG_IGN)
|
||||||
|
|
||||||
|
if signals := config.get((), "signals-actions"):
|
||||||
|
import signal
|
||||||
|
for signal_name, action in signals.items():
|
||||||
|
signal_num = getattr(signal, signal_name, None)
|
||||||
|
if signal_num is None:
|
||||||
|
log.warning("signal '%s' is not defined", signal_name)
|
||||||
|
else:
|
||||||
|
def handler(signal_num, frame):
|
||||||
|
signal_name = signal.Signals(signal_num).name
|
||||||
|
output.stderr_write(f"{signal_name} received\n")
|
||||||
|
util.FLAGS.__dict__[action.upper()] = "stop"
|
||||||
|
signal.signal(signal_num, handler)
|
||||||
|
|
||||||
# enable ANSI escape sequences on Windows
|
# enable ANSI escape sequences on Windows
|
||||||
if util.WINDOWS and config.get(("output",), "ansi", output.COLORS):
|
if util.WINDOWS and config.get(("output",), "ansi", output.COLORS):
|
||||||
from ctypes import windll, wintypes, byref
|
from ctypes import windll, wintypes, byref
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ from . import (
|
|||||||
)
|
)
|
||||||
from .extractor.message import Message
|
from .extractor.message import Message
|
||||||
stdout_write = output.stdout_write
|
stdout_write = output.stdout_write
|
||||||
|
FLAGS = util.FLAGS
|
||||||
|
|
||||||
|
|
||||||
class Job():
|
class Job():
|
||||||
@@ -200,6 +201,8 @@ class Job():
|
|||||||
if self.pred_url(url, kwdict):
|
if self.pred_url(url, kwdict):
|
||||||
self.update_kwdict(kwdict)
|
self.update_kwdict(kwdict)
|
||||||
self.handle_url(url, kwdict)
|
self.handle_url(url, kwdict)
|
||||||
|
if FLAGS.FILE is not None:
|
||||||
|
FLAGS.FILE = FLAGS.process(FLAGS.FILE)
|
||||||
|
|
||||||
elif msg[0] == Message.Directory:
|
elif msg[0] == Message.Directory:
|
||||||
self.update_kwdict(msg[1])
|
self.update_kwdict(msg[1])
|
||||||
@@ -212,6 +215,8 @@ class Job():
|
|||||||
if self.pred_queue(url, kwdict):
|
if self.pred_queue(url, kwdict):
|
||||||
self.update_kwdict(kwdict)
|
self.update_kwdict(kwdict)
|
||||||
self.handle_queue(url, kwdict)
|
self.handle_queue(url, kwdict)
|
||||||
|
if FLAGS.CHILD is not None:
|
||||||
|
FLAGS.CHILD = FLAGS.process(FLAGS.CHILD)
|
||||||
|
|
||||||
def handle_url(self, url, kwdict):
|
def handle_url(self, url, kwdict):
|
||||||
"""Handle Message.Url"""
|
"""Handle Message.Url"""
|
||||||
@@ -390,6 +395,8 @@ class DownloadJob(Job):
|
|||||||
if "post-after" in self.hooks:
|
if "post-after" in self.hooks:
|
||||||
for callback in self.hooks["post-after"]:
|
for callback in self.hooks["post-after"]:
|
||||||
callback(self.pathfmt)
|
callback(self.pathfmt)
|
||||||
|
if FLAGS.POST is not None:
|
||||||
|
FLAGS.POST = FLAGS.process(FLAGS.POST)
|
||||||
self.pathfmt.set_directory(kwdict)
|
self.pathfmt.set_directory(kwdict)
|
||||||
if "post" in self.hooks:
|
if "post" in self.hooks:
|
||||||
for callback in self.hooks["post"]:
|
for callback in self.hooks["post"]:
|
||||||
|
|||||||
@@ -722,6 +722,17 @@ class CustomNone():
|
|||||||
__repr__ = __str__
|
__repr__ = __str__
|
||||||
|
|
||||||
|
|
||||||
|
class Flags():
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.FILE = self.POST = self.CHILD = self.DOWNLOAD = None
|
||||||
|
|
||||||
|
def process(self, flag):
|
||||||
|
if flag == "terminate":
|
||||||
|
raise exception.TerminateExtraction()
|
||||||
|
raise exception.StopExtraction()
|
||||||
|
|
||||||
|
|
||||||
# v137.0 release of Firefox on 2025-04-01 has ordinal 739342
|
# v137.0 release of Firefox on 2025-04-01 has ordinal 739342
|
||||||
# 735506 == 739342 - 137 * 28
|
# 735506 == 739342 - 137 * 28
|
||||||
# v135.0 release of Chrome on 2025-04-01 has ordinal 739342
|
# v135.0 release of Chrome on 2025-04-01 has ordinal 739342
|
||||||
@@ -737,6 +748,7 @@ re = text.re
|
|||||||
re_compile = text.re_compile
|
re_compile = text.re_compile
|
||||||
|
|
||||||
NONE = CustomNone()
|
NONE = CustomNone()
|
||||||
|
FLAGS = Flags()
|
||||||
EPOCH = datetime.datetime(1970, 1, 1)
|
EPOCH = datetime.datetime(1970, 1, 1)
|
||||||
SECOND = datetime.timedelta(0, 1)
|
SECOND = datetime.timedelta(0, 1)
|
||||||
WINDOWS = (os.name == "nt")
|
WINDOWS = (os.name == "nt")
|
||||||
|
|||||||
Reference in New Issue
Block a user