add hooks for custom actions
All checks were successful
ci/woodpecker/push/tests Pipeline was successful

This commit is contained in:
Ivan Schaller 2022-08-13 18:52:32 +02:00
parent 30955369c8
commit c2d9ca9f72
5 changed files with 204 additions and 16 deletions

View file

@ -9,6 +9,8 @@ class YourAPI:
# get infos to initiate class # get infos to initiate class
def __init__(self, url_uuid, language, forcevol): def __init__(self, url_uuid, language, forcevol):
# static info # static info
self.api_name = "Your API Name"
self.url_uuid = url_uuid self.url_uuid = url_uuid
self.language = language self.language = language
self.forcevol = forcevol self.forcevol = forcevol

View file

@ -36,6 +36,8 @@ class Mangadex:
# get infos to initiate class # get infos to initiate class
def __init__(self, url_uuid: str, language: str, forcevol: bool): def __init__(self, url_uuid: str, language: str, forcevol: bool):
# static info # static info
self.api_name = "Mangadex"
self.url_uuid = url_uuid self.url_uuid = url_uuid
self.language = language self.language = language
self.forcevol = forcevol self.forcevol = forcevol

View file

@ -6,6 +6,7 @@ from typing import Any
from mangadlp import downloader, utils from mangadlp import downloader, utils
from mangadlp.api.mangadex import Mangadex from mangadlp.api.mangadex import Mangadex
from mangadlp.hooks import Hooks
from mangadlp.logger import Logger from mangadlp.logger import Logger
# prepare logger # prepare logger
@ -38,16 +39,28 @@ class MangaDLP:
forcevol: bool = False, forcevol: bool = False,
download_path: str = "downloads", download_path: str = "downloads",
download_wait: float = 0.5, download_wait: float = 0.5,
manga_pre_hook_cmd: str = "",
manga_post_hook_cmd: str = "",
chapter_pre_hook_cmd: str = "",
chapter_post_hook_cmd: str = "",
) -> None: ) -> None:
# init parameters # init parameters
self.url_uuid = url_uuid self.url_uuid: str = url_uuid
self.language = language self.language: str = language
self.chapters = chapters self.chapters: str = chapters
self.list_chapters = list_chapters self.list_chapters: bool = list_chapters
self.file_format = file_format self.file_format: str = file_format
self.forcevol = forcevol self.forcevol: bool = forcevol
self.download_path = download_path self.download_path: str = download_path
self.download_wait = download_wait self.download_wait: float = download_wait
# hooks
self.hook: Hooks = Hooks(
manga_pre_hook_cmd,
manga_post_hook_cmd,
chapter_pre_hook_cmd,
chapter_post_hook_cmd,
)
self.hook_infos: dict = {}
# prepare everything # prepare everything
self._prepare() self._prepare()
@ -147,15 +160,37 @@ class MangaDLP:
# create manga folder # create manga folder
self.manga_path.mkdir(parents=True, exist_ok=True) self.manga_path.mkdir(parents=True, exist_ok=True)
# create dict with all variables for the hooks
self.hook_infos.update(
{
"api": self.api.api_name,
"manga_url_uuid": self.url_uuid,
"manga_uuid": self.manga_uuid,
"manga_title": self.manga_title,
"language": self.language,
"total_chapters": len(self.manga_chapter_list),
"chapters_to_download": chapters_to_download,
"file_format": self.file_format,
"forcevol": self.forcevol,
"download_path": self.download_path,
"manga_path": self.manga_path,
}
)
# start manga pre hook
self.hook.run("manga_pre", {"status": "starting"}, self.hook_infos)
# get chapters # get chapters
for chapter in chapters_to_download: for chapter in chapters_to_download:
return_infos = self.get_chapter(chapter) return_infos = self.get_chapter(chapter)
error_chapters.append(return_infos.get("error")) error_chapters.append(return_infos.get("error"))
skipped_chapters.append(return_infos.get("skipped")) skipped_chapters.append(return_infos.get("skipped"))
if self.file_format and return_infos["chapter_path"]: if self.file_format and return_infos["chapter_path"]:
return_infos = self.archive_chapter(return_infos["chapter_path"]) return_infos = self.archive_chapter(return_infos["chapter_path"])
error_chapters.append(return_infos.get("error")) error_chapters.append(return_infos.get("error"))
skipped_chapters.append(return_infos.get("skipped")) skipped_chapters.append(return_infos.get("skipped"))
# check if chapter was skipped # check if chapter was skipped
try: try:
return_infos["skipped"] return_infos["skipped"]
@ -164,18 +199,26 @@ class MangaDLP:
# done with chapter # done with chapter
log.info(f"Done with chapter '{chapter}'\n") log.info(f"Done with chapter '{chapter}'\n")
# start chapter post hook
self.hook.run("chapter_post", {"status": "successful"}, self.hook_infos)
# done with manga # done with manga
log.info(f"{print_divider}") log.info(f"{print_divider}")
log.lean(f"Done with manga: {self.manga_title}") log.lean(f"Done with manga: {self.manga_title}")
# filter skipped list # filter skipped list
skipped_chapters = list(filter(None, skipped_chapters)) skipped_chapters = list(filter(None, skipped_chapters))
if len(skipped_chapters) >= 1: if len(skipped_chapters) >= 1:
log.lean(f"Skipped chapters: {', '.join(skipped_chapters)}") log.lean(f"Skipped chapters: {', '.join(skipped_chapters)}")
# filter error list # filter error list
error_chapters = list(filter(None, error_chapters)) error_chapters = list(filter(None, error_chapters))
if len(error_chapters) >= 1: if len(error_chapters) >= 1:
log.lean(f"Chapters with errors: {', '.join(error_chapters)}") log.lean(f"Chapters with errors: {', '.join(error_chapters)}")
# start manga post hook
self.hook.run("manga_post", {"status": "successful"}, self.hook_infos)
log.info(f"{print_divider}\n") log.info(f"{print_divider}\n")
# once called per chapter # once called per chapter
@ -197,6 +240,11 @@ class MangaDLP:
log.error( log.error(
f"No images: Skipping Vol. {chapter_infos['volume']} Ch.{chapter_infos['chapter']}" f"No images: Skipping Vol. {chapter_infos['volume']} Ch.{chapter_infos['chapter']}"
) )
self.hook.run(
"chapter_pre", {"status": "skipped", "reason": "No images"}, {}
)
# add to skipped chapters list # add to skipped chapters list
return ( return (
{ {
@ -221,6 +269,11 @@ class MangaDLP:
# check for folder, if file format is an empty string # check for folder, if file format is an empty string
if chapter_archive_path.exists(): if chapter_archive_path.exists():
log.warning(f"'{chapter_archive_path}' already exists. Skipping") log.warning(f"'{chapter_archive_path}' already exists. Skipping")
self.hook.run(
"chapter_pre", {"status": "skipped", "reason": "Existing"}, {}
)
# add to skipped chapters list # add to skipped chapters list
return ( return (
{ {
@ -240,6 +293,22 @@ class MangaDLP:
log.verbose(f"File path: '{chapter_archive_path}'") log.verbose(f"File path: '{chapter_archive_path}'")
log.verbose(f"Image URLS:\n{chapter_image_urls}") log.verbose(f"Image URLS:\n{chapter_image_urls}")
# create dict with all variables for the hooks
self.hook_infos.update(
{
"chapter_filename": chapter_filename,
"chapter_path": chapter_path,
"chapter_archive_path": chapter_archive_path,
"chapter_uuid": chapter_infos["uuid"],
"chapter_volume": chapter_infos["volume"],
"chapter_number": chapter_infos["chapter"],
"chapter_name": chapter_infos["name"],
}
)
# start chapter pre hook
self.hook.run("chapter_pre", {"status": "starting"}, self.hook_infos)
# log # log
log.lean(f"Downloading: '{chapter_filename}'") log.lean(f"Downloading: '{chapter_filename}'")
@ -253,6 +322,11 @@ class MangaDLP:
sys.exit(1) sys.exit(1)
except Exception: except Exception:
log.error(f"Cant download: '{chapter_filename}'. Skipping") log.error(f"Cant download: '{chapter_filename}'. Skipping")
self.hook.run(
"chapter_post", {"status": "error", "reason": "Download error"}, {}
)
# add to skipped chapters list # add to skipped chapters list
return ( return (
{ {
@ -266,6 +340,7 @@ class MangaDLP:
else: else:
# Done with chapter # Done with chapter
log.lean(f"Successfully downloaded: '{chapter_filename}'") log.lean(f"Successfully downloaded: '{chapter_filename}'")
return {"chapter_path": chapter_path} return {"chapter_path": chapter_path}
# create an archive of the chapter if needed # create an archive of the chapter if needed

71
mangadlp/hooks.py Normal file
View file

@ -0,0 +1,71 @@
import os
import subprocess
from mangadlp.logger import Logger
# prepare logger
log = Logger(__name__)
class Hooks:
"""Pre- and post-hooks for each download.
Args:
cmd_manga_pre (str): Commands to execute before the manga download starts
cmd_manga_post (str): Commands to execute after the manga download finished
cmd_chapter_pre (str): Commands to execute before the chapter download starts
cmd_chapter_post (str): Commands to execute after the chapter download finished
"""
def __init__(
self,
cmd_manga_pre: str,
cmd_manga_post: str,
cmd_chapter_pre: str,
cmd_chapter_post: str,
) -> None:
self.cmd_manga_pre = cmd_manga_pre
self.cmd_manga_post = cmd_manga_post
self.cmd_chapter_pre = cmd_chapter_pre
self.cmd_chapter_post = cmd_chapter_post
def run(self, hook_type: str, hook_status: dict, hook_info: dict) -> int:
if hook_type == "manga_pre":
hook_cmd_str = self.cmd_manga_pre
elif hook_type == "manga_post":
hook_cmd_str = self.cmd_manga_post
elif hook_type == "chapter_pre":
hook_cmd_str = self.cmd_chapter_pre
elif hook_type == "chapter_post":
hook_cmd_str = self.cmd_chapter_post
else:
log.error(f"Hook type '{hook_type}' is not valid. Not running")
return 1
# check if hook commands are empty
if not hook_cmd_str or hook_cmd_str == "None":
log.verbose(f"Hook '{hook_type}' empty. Not running")
return 2
hook_cmd_list = hook_cmd_str.split(" ")
# setting env vars
hook_info["hook_type"] = hook_type
hook_info["status"] = hook_status.get("status")
hook_info["reason"] = hook_status.get("reason")
for key, value in hook_info.items():
os.environ[f"MDLP_{key.upper()}"] = str(value)
# running command
log.info(f"Hook '{hook_type}' - running command: '{hook_cmd_str}'")
ecode = subprocess.call(hook_cmd_list)
if ecode == 0:
log.verbose("Hook returned status code 0. All good")
else:
log.warning(f"Hook returned status code {ecode}. Possible error")
# return exit code of command
return ecode

View file

@ -49,14 +49,18 @@ def readin_list(readlist: str) -> list:
def call_app(args): def call_app(args):
# call main function with all input arguments # call main function with all input arguments
mdlp = app.MangaDLP( mdlp = app.MangaDLP(
args.url_uuid, url_uuid=args.url_uuid,
args.lang, language=args.lang,
args.chapters, chapters=args.chapters,
args.list, list_chapters=args.list,
args.format, file_format=args.format,
args.forcevol, forcevol=args.forcevol,
args.path, download_path=args.path,
args.wait, download_wait=args.wait,
manga_pre_hook_cmd=args.hook_manga_pre,
manga_post_hook_cmd=args.hook_manga_post,
chapter_pre_hook_cmd=args.hook_chapter_pre,
chapter_post_hook_cmd=args.hook_chapter_post,
) )
mdlp.get_manga() mdlp.get_manga()
@ -105,6 +109,7 @@ def get_args():
action = parser.add_mutually_exclusive_group(required=True) action = parser.add_mutually_exclusive_group(required=True)
verbosity = parser.add_mutually_exclusive_group(required=False) verbosity = parser.add_mutually_exclusive_group(required=False)
# selection options
action.add_argument( action.add_argument(
"-u", "-u",
"--url", "--url",
@ -129,6 +134,8 @@ def get_args():
help="Show version of manga-dlp and exit", help="Show version of manga-dlp and exit",
action="store_true", action="store_true",
) )
# base options
parser.add_argument( parser.add_argument(
"-c", "-c",
"--chapters", "--chapters",
@ -185,6 +192,8 @@ def get_args():
default=0.5, default=0.5,
help="Time to wait for each picture to download in seconds(float). Defaults 0.5", help="Time to wait for each picture to download in seconds(float). Defaults 0.5",
) )
# logging options
verbosity.add_argument( verbosity.add_argument(
"--lean", "--lean",
dest="verbosity", dest="verbosity",
@ -212,6 +221,35 @@ def get_args():
const=10, const=10,
default=20, default=20,
) )
# hook options
parser.add_argument(
"--hook-manga-pre",
dest="hook_manga_pre",
required=False,
help="Commands to execute before the manga download starts",
action="store",
)
parser.add_argument(
"--hook-manga-post",
dest="hook_manga_post",
required=False,
help="Commands to execute after the manga download finished",
action="store",
)
parser.add_argument(
"--hook-chapter-pre",
dest="hook_chapter_pre",
required=False,
help="Commands to execute before the chapter download starts",
action="store",
)
parser.add_argument(
"--hook-chapter-post",
dest="hook_chapter_post",
required=False,
help="Commands to execute after the chapter download finished",
action="store",
)
# parser.print_help() # parser.print_help()
args = parser.parse_args() args = parser.parse_args()