From 27def1f67039abbbec9b931b13ddf5e05e59656c Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 19 Aug 2023 21:01:45 +0000 Subject: [PATCH] separated YTDL_OPTIONS_FILE --- README.md | 3 ++- app/main.py | 35 +++++++++++++++++++---------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 9255477..b089a46 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,8 @@ Certain values can be set via environment variables, using the `-e` parameter on * __URL_PREFIX__: base path for the web server (for use when hosting behind a reverse proxy). Defaults to `/`. * __OUTPUT_TEMPLATE__: the template for the filenames of the downloaded videos, formatted according to [this spec](https://github.com/yt-dlp/yt-dlp/blob/master/README.md#output-template). Defaults to `%(title)s.%(ext)s`. * __OUTPUT_TEMPLATE_CHAPTER__: the template for the filenames of the downloaded videos, when split into chapters via postprocessors. Defaults to `%(title)s - %(section_number)s %(section_title)s.%(ext)s`. -* __YTDL_OPTIONS__: Additional options to pass to youtube-dl, This can be path to a file or JSON formatted string. [See available options here](https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/YoutubeDL.py#L183). They roughly correspond to command-line options, though some do not have exact equivalents here, for example `--recode-video` has to be specified via `postprocessors`. Also note that dashes are replaced with underscores. +* __YTDL_OPTIONS__: Additional options to pass to youtube-dl, in JSON format. [See available options here](https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/YoutubeDL.py#L183). They roughly correspond to command-line options, though some do not have exact equivalents here, for example `--recode-video` has to be specified via `postprocessors`. Also note that dashes are replaced with underscores. +* __YTDL_OPTIONS_FILE__: A path to a JSON file that will be loaded and used for populating `YTDL_OPTIONS` above. Please note that if both `YTDL_OPTIONS_FILE` and `YTDL_OPTIONS` are specified, the options in `YTDL_OPTIONS` take precedence. The following example value for `YTDL_OPTIONS` embeds English subtitles and chapter markers (for videos that have them), and also changes the permissions on the downloaded video and sets the file modification timestamp to the date of when it was downloaded: diff --git a/app/main.py b/app/main.py index 8d526a8..88b3d5b 100644 --- a/app/main.py +++ b/app/main.py @@ -12,8 +12,6 @@ import pathlib from ytdl import DownloadQueueNotifier, DownloadQueue log = logging.getLogger('main') -if __name__ == '__main__': - logging.basicConfig(level=logging.DEBUG) class Config: _DEFAULTS = { @@ -29,6 +27,7 @@ class Config: 'OUTPUT_TEMPLATE': '%(title)s.%(ext)s', 'OUTPUT_TEMPLATE_CHAPTER': '%(title)s - %(section_number)s %(section_title)s.%(ext)s', 'YTDL_OPTIONS': '{}', + 'YTDL_OPTIONS_FILE': '', 'HOST': '0.0.0.0', 'PORT': '8081', 'BASE_DIR': '', @@ -39,8 +38,6 @@ class Config: def __init__(self): for k, v in self._DEFAULTS.items(): - if k in os.environ: - log.debug(f"ENV override for {k} = {os.environ[k]}") setattr(self, k, os.environ[k] if k in os.environ else v) for k, v in self.__dict__.items(): @@ -56,21 +53,26 @@ class Config: self.URL_PREFIX += '/' try: - if isinstance(self.YTDL_OPTIONS, str) and os.path.exists(self.YTDL_OPTIONS): - log.info(f"Loading yt-dlp custom options from {self.YTDL_OPTIONS}") - with open(self.YTDL_OPTIONS) as json_data: - self.YTDL_OPTIONS = json.load(json_data) - else: - log.info(f"Loading yt-dlp custom options from Environment variable.") - self.YTDL_OPTIONS = json.loads(self.YTDL_OPTIONS) - + self.YTDL_OPTIONS = json.loads(self.YTDL_OPTIONS) assert isinstance(self.YTDL_OPTIONS, dict) - if len(self.YTDL_OPTIONS) != 0: - log.debug(f"Using custom yt-dlp options:\n{json.dumps(self.YTDL_OPTIONS, indent=2, ensure_ascii=False)}") - except (json.decoder.JSONDecodeError, AssertionError) as e: - log.error(f"Unable to parse YTDL_OPTIONS value. {str(e)}") + except (json.decoder.JSONDecodeError, AssertionError): + log.error('YTDL_OPTIONS is invalid') sys.exit(1) + if self.YTDL_OPTIONS_FILE: + log.info(f'Loading yt-dlp custom options from "{self.YTDL_OPTIONS_FILE}"') + if not os.path.exists(self.YTDL_OPTIONS_FILE): + log.error(f'File "{self.YTDL_OPTIONS_FILE}" not found') + sys.exit(1) + try: + with open(self.YTDL_OPTIONS_FILE) as json_data: + opts = json.load(json_data) + assert isinstance(opts, dict) + except (json.decoder.JSONDecodeError, AssertionError): + log.error('YTDL_OPTIONS_FILE contents is invalid') + sys.exit(1) + self.YTDL_OPTIONS.update(opts) + config = Config() class ObjectSerializer(json.JSONEncoder): @@ -211,5 +213,6 @@ app.on_response_prepare.append(on_prepare) if __name__ == '__main__': + logging.basicConfig(level=logging.DEBUG) log.info(f"Listening on {config.HOST}:{config.PORT}") web.run_app(app, host=config.HOST, port=config.PORT, reuse_port=True)