Compare commits
No commits in common. "master" and "2026.02.23" have entirely different histories.
master
...
2026.02.23
208 changed files with 1442 additions and 1672 deletions
8
Makefile
8
Makefile
|
|
@ -36,12 +36,12 @@ endif
|
||||||
all: check_lint docs docker docker_ubuntu docker_gui
|
all: check_lint docs docker docker_ubuntu docker_gui
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
python3 -m ruff format .
|
python3 -m isort .
|
||||||
python3 -m ruff check --fix .
|
python3 -m black .
|
||||||
python3 -m pylint src
|
python3 -m pylint src
|
||||||
check_lint:
|
check_lint:
|
||||||
ruff format --check . \
|
isort . --check-only --diff \
|
||||||
&& ruff check . \
|
&& black . --check \
|
||||||
&& pylint src/
|
&& pylint src/
|
||||||
wheel: clean
|
wheel: clean
|
||||||
$(shell echo "__pypi_version__ = \"$(PYPI_VERSION)\"" > src/ytdl_sub/__init__.py)
|
$(shell echo "__pypi_version__ = \"$(PYPI_VERSION)\"" > src/ytdl_sub/__init__.py)
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ __preset__:
|
||||||
|
|
||||||
# Pass any arg directly to yt-dlp's Python API
|
# Pass any arg directly to yt-dlp's Python API
|
||||||
ytdl_options:
|
ytdl_options:
|
||||||
cookiefile: "/config/ytdl-sub-configs/cookie.txt"
|
cookiefile: "/config/cookie.txt"
|
||||||
|
|
||||||
###################################################################
|
###################################################################
|
||||||
# TV Show Presets. Can replace Plex with Plex/Jellyfin/Emby/Kodi
|
# TV Show Presets. Can replace Plex with Plex/Jellyfin/Emby/Kodi
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,6 @@ if [ "$CRON_SCHEDULE" != "" ] ; then
|
||||||
|
|
||||||
# create cron script wrapper
|
# create cron script wrapper
|
||||||
echo '#!/bin/bash' > "$CRON_WRAPPER_SCRIPT"
|
echo '#!/bin/bash' > "$CRON_WRAPPER_SCRIPT"
|
||||||
# Echo commands for easier user debugging:
|
|
||||||
echo "set -x" >> "$CRON_WRAPPER_SCRIPT"
|
|
||||||
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> "$CRON_WRAPPER_SCRIPT"
|
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> "$CRON_WRAPPER_SCRIPT"
|
||||||
echo "cd \"$DEFAULT_WORKSPACE\"" >> "$CRON_WRAPPER_SCRIPT"
|
echo "cd \"$DEFAULT_WORKSPACE\"" >> "$CRON_WRAPPER_SCRIPT"
|
||||||
echo ". \"$CRON_SCRIPT\" >> \"$LOGS_TO_STDOUT\" 2>&1" >> "$CRON_WRAPPER_SCRIPT"
|
echo ". \"$CRON_SCRIPT\" >> \"$LOGS_TO_STDOUT\" 2>&1" >> "$CRON_WRAPPER_SCRIPT"
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,4 @@
|
||||||
|
echo "Beginning cron job..."
|
||||||
|
|
||||||
# Place your ytdl-sub command(s) here.
|
# Place your ytdl-sub command(s) here.
|
||||||
#
|
# This script is executed in the same relative path as this file.
|
||||||
# This script is executed in the same directory as this file which also contains the
|
|
||||||
# default `./config.yaml` and `./subscriptions.yaml`, so you don't need to use the
|
|
||||||
# `--config` CLI option or pass a `SUBPATH` to the `$ ytdl-sub sub` sub-command.
|
|
||||||
#
|
|
||||||
# Test your configuration and subscriptions carefully before automating downloads to
|
|
||||||
# prevent triggering throttles or bans:
|
|
||||||
#
|
|
||||||
# https://ytdl-sub.readthedocs.io/en/latest/guides/getting_started/downloading.html
|
|
||||||
#
|
|
||||||
# Once you've tested your configuration and you're ready to download entries unattended,
|
|
||||||
# remove the next line and un-comment the following line:
|
|
||||||
echo "WARNING: Read /config/ytdl-sub-configs/cron and modify to automate downloads."
|
|
||||||
# ytdl-sub sub
|
|
||||||
|
|
@ -20,7 +20,7 @@ __preset__:
|
||||||
|
|
||||||
# Pass any arg directly to yt-dlp's Python API
|
# Pass any arg directly to yt-dlp's Python API
|
||||||
# ytdl_options:
|
# ytdl_options:
|
||||||
# cookiefile: "/config/ytdl-sub-configs/cookie.txt"
|
# cookiefile: "/config/cookie.txt"
|
||||||
|
|
||||||
###################################################################
|
###################################################################
|
||||||
# Subscriptions nested under this will use the
|
# Subscriptions nested under this will use the
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||||
|
|
||||||
project = "ytdl-sub"
|
project = "ytdl-sub"
|
||||||
copyright = "2026, Jesse Bannon"
|
copyright = "2024, Jesse Bannon"
|
||||||
author = "Jesse Bannon"
|
author = "Jesse Bannon"
|
||||||
release = ""
|
release = ""
|
||||||
|
|
||||||
|
|
@ -15,8 +15,10 @@ release = ""
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
||||||
extensions = [
|
extensions = [
|
||||||
|
"sphinx.ext.autodoc",
|
||||||
"sphinx.ext.autosectionlabel",
|
"sphinx.ext.autosectionlabel",
|
||||||
"sphinx.ext.extlinks",
|
"sphinx.ext.extlinks",
|
||||||
|
"sphinx.ext.napoleon",
|
||||||
"sphinx_copybutton",
|
"sphinx_copybutton",
|
||||||
"sphinx_design",
|
"sphinx_design",
|
||||||
]
|
]
|
||||||
|
|
@ -68,3 +70,19 @@ extlinks = {
|
||||||
"lsio-gh": ("https://github.com/linuxserver/%s", "%s image"),
|
"lsio-gh": ("https://github.com/linuxserver/%s", "%s image"),
|
||||||
"ytdl-sub-gh": ("https://github.com/jmbannon/ytdl-sub/%s", "src %s"),
|
"ytdl-sub-gh": ("https://github.com/jmbannon/ytdl-sub/%s", "src %s"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# -- Options for autodoc ----------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#configuration
|
||||||
|
|
||||||
|
# Automatically extract typehints when specified and place them in
|
||||||
|
# descriptions of the relevant function/method.
|
||||||
|
autodoc_default_options = {
|
||||||
|
"autodoc_typehints_format": "short",
|
||||||
|
"autodoc_class_signature": "separated",
|
||||||
|
"add_module_names": False,
|
||||||
|
# "add_class_names": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
python_use_unqualified_type_names = True
|
||||||
|
napoleon_numpy_docstring = True
|
||||||
|
napoleon_use_rtype = False
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,7 @@
|
||||||
..
|
==================
|
||||||
WARNING: This RST file is generated from docstrings in:
|
|
||||||
The respective function docstrings within ytdl_sub/config/config_validator.py
|
|
||||||
In order to make a change to this file, edit the respective docstring
|
|
||||||
and run `make docs`. This will automatically sync the Python RST-based
|
|
||||||
docstrings into this file. If the docstrings and RST file are out of sync,
|
|
||||||
it will fail TestDocGen tests in GitHub CI.
|
|
||||||
|
|
||||||
Configuration File
|
Configuration File
|
||||||
==================
|
==================
|
||||||
|
|
||||||
ytdl-sub is configured using a ``config.yaml`` file.
|
ytdl-sub is configured using a ``config.yaml`` file.
|
||||||
|
|
||||||
The ``config.yaml`` is made up of two sections:
|
The ``config.yaml`` is made up of two sections:
|
||||||
|
|
@ -17,118 +11,113 @@ The ``config.yaml`` is made up of two sections:
|
||||||
configuration:
|
configuration:
|
||||||
presets:
|
presets:
|
||||||
|
|
||||||
|
You can jump to any section and subsection of the config using the navigation section to
|
||||||
|
the left.
|
||||||
|
|
||||||
Note for Windows users, paths can be represented with ``C:/forward/slashes/like/linux``.
|
Note for Windows users, paths can be represented with ``C:/forward/slashes/like/linux``.
|
||||||
If you prefer to use a Windows backslash, note that it must have
|
If you wish to represent paths like Windows, you will need to
|
||||||
``C:\\double\\bashslash\\paths`` in order to escape the backslash character. This is due
|
``C:\\double\\bashslash\\paths`` in order to escape the backslash character.
|
||||||
to it being a YAML escape character.
|
|
||||||
|
|
||||||
|
configuration
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The ``configuration`` section contains app-wide configs applied to all presets and
|
||||||
|
subscriptions.
|
||||||
|
|
||||||
|
.. autoclass:: ytdl_sub.config.config_validator.ConfigOptions()
|
||||||
|
:members:
|
||||||
|
:member-order: bysource
|
||||||
|
:exclude-members: subscription_value, persist_logs, experimental
|
||||||
|
|
||||||
|
persist_logs
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Without this key, ``ytdl-sub`` only prints output to it's ``stdout`` and ``stderr``. If
|
||||||
|
your configuration includes the ``persist_logs:`` key, then ``ytdl-sub`` also writes log
|
||||||
|
files to disk.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
The log files grow rapidly if ``keep_successful_logs:`` is ``true``, the default, and
|
||||||
|
may fill up disk space. Set ``keep_successful_logs: false`` or prune the log files
|
||||||
|
regularly.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
configuration:
|
configuration:
|
||||||
dl_aliases:
|
|
||||||
mv: "--preset music_video"
|
|
||||||
u: "--download.url"
|
|
||||||
|
|
||||||
experimental:
|
|
||||||
enable_update_with_info_json: True
|
|
||||||
|
|
||||||
ffmpeg_path: "/usr/bin/ffmpeg"
|
|
||||||
ffprobe_path: "/usr/bin/ffprobe"
|
|
||||||
|
|
||||||
file_name_max_bytes: 255
|
|
||||||
lock_directory: "/tmp"
|
|
||||||
|
|
||||||
persist_logs:
|
persist_logs:
|
||||||
keep_successful_logs: True
|
logs_directory: "/path/to/log/directory"
|
||||||
logs_directory: "/var/log/ytdl-sub-logs"
|
|
||||||
|
|
||||||
umask: "022"
|
.. autoclass:: ytdl_sub.config.config_validator.PersistLogsValidator()
|
||||||
working_directory: ".ytdl-sub-working-directory"
|
:members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
dl_aliases
|
|
||||||
----------
|
|
||||||
.. _dl_aliases:
|
|
||||||
|
|
||||||
Alias definitions to shorten :ref:`dl arguments <usage:Download Options>`. For example,
|
presets
|
||||||
|
-------
|
||||||
|
|
||||||
|
Each key under ``presets:`` defines a `formula` for how to format downloaded media and
|
||||||
|
metadata. The key is the name of the preset and the value is a mapping that defines the
|
||||||
|
preset.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The ``presets:`` key at the top of the configuration file contains multiple
|
||||||
|
user-defined presets, but *each preset* itself may include a ``preset:`` key that
|
||||||
|
defines *that preset's* base presets. For example:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
presets:
|
||||||
|
Foo Preset:
|
||||||
|
preset:
|
||||||
|
- "Jellyfin TV Show by Date"
|
||||||
|
- "Only Recent"
|
||||||
|
|
||||||
|
preset
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
Presets support inheritance by defining one or more parent presets:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
configuration:
|
presets:
|
||||||
dl_aliases:
|
custom_preset:
|
||||||
mv: "--preset music_video"
|
...
|
||||||
u: "--download.url"
|
parent_preset:
|
||||||
|
...
|
||||||
|
child_preset:
|
||||||
|
preset:
|
||||||
|
- "parent_preset"
|
||||||
|
|
||||||
Simplifies
|
In the example above, ``child_preset`` inherits all fields defined in ``parent_preset``.
|
||||||
|
Use parent presets where possible to reduce duplicate yaml definitions.
|
||||||
|
|
||||||
.. code-block:: bash
|
Presets also support inheritance from multiple presets:
|
||||||
|
|
||||||
ytdl-sub dl --preset "Jellyfin Music Videos" --download.url "youtube.com/watch?v=a1b2c3"
|
.. code-block:: yaml
|
||||||
|
|
||||||
to
|
child_preset:
|
||||||
|
preset:
|
||||||
|
- "custom_preset"
|
||||||
|
- "parent_preset"
|
||||||
|
|
||||||
.. code-block:: bash
|
In this example, ``child_preset`` will inherit all fields from ``custom_preset`` and
|
||||||
|
``parent_preset`` in that order. The bottom-most preset has the highest priority. More
|
||||||
|
specifically, presets are merged using `mergedeep`_ via `a TYPESAFE_ADDITIVE merge`_,
|
||||||
|
which means:
|
||||||
|
|
||||||
ytdl-sub dl --mv --u "youtube.com/watch?v=a1b2c3"
|
- if two conflicting keys arent lists or mappings, overwrite the higher priority one
|
||||||
|
- otherwise, combine then re-evaluate
|
||||||
|
|
||||||
experimental
|
If you are only inheriting from one preset, using a single string instead of a list is
|
||||||
------------
|
valid, for example ``preset: "parent_preset"``, but we recommend always using a list for
|
||||||
Experimental flags reside under the ``experimental`` key.
|
consistent readability between presets.
|
||||||
|
|
||||||
``enable_update_with_info_json``
|
.. _`mergedeep`:
|
||||||
|
https://mergedeep.readthedocs.io/en/latest/
|
||||||
Enables modifying subscription files using info.json files using the argument
|
.. _`a TYPESAFE_ADDITIVE merge`:
|
||||||
``--update-with-info-json``. This feature is still being tested and has the ability to
|
https://mergedeep.readthedocs.io/en/latest/index.html#merge-strategies
|
||||||
destroy files. Ensure you have a full backup before usage. You have been warned!
|
|
||||||
|
|
||||||
ffmpeg_path
|
|
||||||
-----------
|
|
||||||
Path to ffmpeg executable. Defaults to ``/usr/bin/ffmpeg`` for Linux,
|
|
||||||
``./ffmpeg.exe`` in the same directory as ytdl-sub for Windows.
|
|
||||||
|
|
||||||
ffprobe_path
|
|
||||||
------------
|
|
||||||
Path to ffprobe executable. Defaults to ``/usr/bin/ffprobe`` for Linux,
|
|
||||||
``./ffprobe.exe`` in the same directory as ytdl-sub for Windows.
|
|
||||||
|
|
||||||
file_name_max_bytes
|
|
||||||
-------------------
|
|
||||||
Max file name size in bytes. Most OS's typically default to 255 bytes.
|
|
||||||
|
|
||||||
lock_directory
|
|
||||||
--------------
|
|
||||||
The directory to temporarily store file locks, which prevents multiple instances
|
|
||||||
of ``ytdl-sub`` from running. Note that file locks do not work on
|
|
||||||
network-mounted directories. Ensure that this directory resides on the host
|
|
||||||
machine. Defaults to ``/tmp``.
|
|
||||||
|
|
||||||
persist_logs
|
|
||||||
------------
|
|
||||||
By default, no logs are persisted. Specifying this key will enable persisted logs. The following
|
|
||||||
options are available.
|
|
||||||
|
|
||||||
``keep_successful_logs``
|
|
||||||
|
|
||||||
Defaults to ``True``. When this key is ``False``, only write log files for failed
|
|
||||||
subscriptions.
|
|
||||||
|
|
||||||
``logs_directory``
|
|
||||||
|
|
||||||
Required field. Write log files to this directory with names like
|
|
||||||
``YYYY-mm-dd-HHMMSS.subscription_name.(success|error).log``.
|
|
||||||
|
|
||||||
umask
|
|
||||||
-----
|
|
||||||
Umask in octal format to apply to every created file. Defaults to ``022``.
|
|
||||||
|
|
||||||
working_directory
|
|
||||||
-----------------
|
|
||||||
The directory to temporarily store downloaded files before moving them into their final
|
|
||||||
directory. Defaults to ``.ytdl-sub-working-directory``, created in the same directory
|
|
||||||
that ytdl-sub is invoked from.
|
|
||||||
|
|
||||||
Presets
|
|
||||||
=======
|
|
||||||
Custom presets are defined in this section. Refer to the
|
|
||||||
:ref:`Getting Started Guide<guides/getting_started/first_config:Basic Configuration>`
|
|
||||||
on how to configure.
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ Extracts audio from a video file.
|
||||||
The codec to output after extracting the audio. Supported codecs are aac, flac, mp3, m4a,
|
The codec to output after extracting the audio. Supported codecs are aac, flac, mp3, m4a,
|
||||||
opus, vorbis, wav, and best to grab the best possible format at runtime.
|
opus, vorbis, wav, and best to grab the best possible format at runtime.
|
||||||
|
|
||||||
|
|
||||||
``enable``
|
``enable``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -36,6 +37,7 @@ Extracts audio from a video file.
|
||||||
this field can be set using an override variable to easily toggle whether this plugin
|
this field can be set using an override variable to easily toggle whether this plugin
|
||||||
is enabled or not via Boolean.
|
is enabled or not via Boolean.
|
||||||
|
|
||||||
|
|
||||||
``quality``
|
``quality``
|
||||||
|
|
||||||
:expected type: Float
|
:expected type: Float
|
||||||
|
|
@ -43,6 +45,7 @@ Extracts audio from a video file.
|
||||||
Optional. Specify ffmpeg audio quality. Insert a value between ``0`` (better) and ``9``
|
Optional. Specify ffmpeg audio quality. Insert a value between ``0`` (better) and ``9``
|
||||||
(worse) for variable bitrate, or a specific bitrate like ``128`` for 128k.
|
(worse) for variable bitrate, or a specific bitrate like ``128`` for 128k.
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
chapters
|
chapters
|
||||||
|
|
@ -81,12 +84,14 @@ chapters and remove specific ones. Can also remove chapters using regex.
|
||||||
Defaults to False. If chapters do not exist in the video/description itself, attempt to
|
Defaults to False. If chapters do not exist in the video/description itself, attempt to
|
||||||
scrape comments to find the chapters.
|
scrape comments to find the chapters.
|
||||||
|
|
||||||
|
|
||||||
``embed_chapters``
|
``embed_chapters``
|
||||||
|
|
||||||
:expected type: Optional[Boolean]
|
:expected type: Optional[Boolean]
|
||||||
:description:
|
:description:
|
||||||
Defaults to True. Embed chapters into the file.
|
Defaults to True. Embed chapters into the file.
|
||||||
|
|
||||||
|
|
||||||
``enable``
|
``enable``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -95,6 +100,7 @@ chapters and remove specific ones. Can also remove chapters using regex.
|
||||||
this field can be set using an override variable to easily toggle whether this plugin
|
this field can be set using an override variable to easily toggle whether this plugin
|
||||||
is enabled or not via Boolean.
|
is enabled or not via Boolean.
|
||||||
|
|
||||||
|
|
||||||
``force_key_frames``
|
``force_key_frames``
|
||||||
|
|
||||||
:expected type: Optional[Boolean]
|
:expected type: Optional[Boolean]
|
||||||
|
|
@ -102,6 +108,7 @@ chapters and remove specific ones. Can also remove chapters using regex.
|
||||||
Defaults to False. Force keyframes at cuts when removing sections. This is slow due to
|
Defaults to False. Force keyframes at cuts when removing sections. This is slow due to
|
||||||
needing a re-encode, but the resulting video may have fewer artifacts around the cuts.
|
needing a re-encode, but the resulting video may have fewer artifacts around the cuts.
|
||||||
|
|
||||||
|
|
||||||
``remove_chapters_regex``
|
``remove_chapters_regex``
|
||||||
|
|
||||||
:expected type: Optional[List[RegexString]
|
:expected type: Optional[List[RegexString]
|
||||||
|
|
@ -109,6 +116,7 @@ chapters and remove specific ones. Can also remove chapters using regex.
|
||||||
List of regex patterns to match chapter titles against and remove them from the
|
List of regex patterns to match chapter titles against and remove them from the
|
||||||
entry.
|
entry.
|
||||||
|
|
||||||
|
|
||||||
``remove_sponsorblock_categories``
|
``remove_sponsorblock_categories``
|
||||||
|
|
||||||
:expected type: Optional[List[String]]
|
:expected type: Optional[List[String]]
|
||||||
|
|
@ -117,6 +125,7 @@ chapters and remove specific ones. Can also remove chapters using regex.
|
||||||
categories that are specified in ``sponsorblock_categories`` or "all", which removes
|
categories that are specified in ``sponsorblock_categories`` or "all", which removes
|
||||||
everything specified in ``sponsorblock_categories``.
|
everything specified in ``sponsorblock_categories``.
|
||||||
|
|
||||||
|
|
||||||
``sponsorblock_categories``
|
``sponsorblock_categories``
|
||||||
|
|
||||||
:expected type: Optional[List[String]]
|
:expected type: Optional[List[String]]
|
||||||
|
|
@ -125,6 +134,7 @@ chapters and remove specific ones. Can also remove chapters using regex.
|
||||||
"intro", "outro", "selfpromo", "preview", "filler", "interaction", "music_offtopic",
|
"intro", "outro", "selfpromo", "preview", "filler", "interaction", "music_offtopic",
|
||||||
"poi_highlight", or "all" to include all categories.
|
"poi_highlight", or "all" to include all categories.
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
date_range
|
date_range
|
||||||
|
|
@ -159,12 +169,14 @@ intended download files.
|
||||||
:description:
|
:description:
|
||||||
Only download videos after or on this datetime, inclusive.
|
Only download videos after or on this datetime, inclusive.
|
||||||
|
|
||||||
|
|
||||||
``before``
|
``before``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
:description:
|
:description:
|
||||||
Only download videos only before this datetime, not inclusive.
|
Only download videos only before this datetime, not inclusive.
|
||||||
|
|
||||||
|
|
||||||
``breaks``
|
``breaks``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -172,6 +184,7 @@ intended download files.
|
||||||
Toggle to enable breaking subsequent metadata downloads if an entry's upload date
|
Toggle to enable breaking subsequent metadata downloads if an entry's upload date
|
||||||
is out of range. Defaults to True.
|
is out of range. Defaults to True.
|
||||||
|
|
||||||
|
|
||||||
``enable``
|
``enable``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -180,6 +193,7 @@ intended download files.
|
||||||
this field can be set using an override variable to easily toggle whether this plugin
|
this field can be set using an override variable to easily toggle whether this plugin
|
||||||
is enabled or not via Boolean.
|
is enabled or not via Boolean.
|
||||||
|
|
||||||
|
|
||||||
``type``
|
``type``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -187,6 +201,7 @@ intended download files.
|
||||||
Which type of date to use. Must be either ``upload_date`` or ``release_date``.
|
Which type of date to use. Must be either ``upload_date`` or ``release_date``.
|
||||||
Defaults to ``upload_date``.
|
Defaults to ``upload_date``.
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
download
|
download
|
||||||
|
|
@ -290,6 +305,7 @@ Also supports custom ffmpeg conversions:
|
||||||
- Video: avi, flv, mkv, mov, mp4, webm
|
- Video: avi, flv, mkv, mov, mp4, webm
|
||||||
- Audio: aac, flac, mp3, m4a, opus, vorbis, wav
|
- Audio: aac, flac, mp3, m4a, opus, vorbis, wav
|
||||||
|
|
||||||
|
|
||||||
``convert_with``
|
``convert_with``
|
||||||
|
|
||||||
:expected type: Optional[String]
|
:expected type: Optional[String]
|
||||||
|
|
@ -298,6 +314,7 @@ Also supports custom ffmpeg conversions:
|
||||||
yt-dlp whereas ``ffmpeg`` specifies it will be converted using a custom command specified
|
yt-dlp whereas ``ffmpeg`` specifies it will be converted using a custom command specified
|
||||||
with ``ffmpeg_post_process_args``. Defaults to ``yt-dlp``.
|
with ``ffmpeg_post_process_args``. Defaults to ``yt-dlp``.
|
||||||
|
|
||||||
|
|
||||||
``enable``
|
``enable``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -306,6 +323,7 @@ Also supports custom ffmpeg conversions:
|
||||||
this field can be set using an override variable to easily toggle whether this plugin
|
this field can be set using an override variable to easily toggle whether this plugin
|
||||||
is enabled or not via Boolean.
|
is enabled or not via Boolean.
|
||||||
|
|
||||||
|
|
||||||
``ffmpeg_post_process_args``
|
``ffmpeg_post_process_args``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -318,6 +336,7 @@ Also supports custom ffmpeg conversions:
|
||||||
The output file will use the extension specified in ``convert_to``. Post-processing args
|
The output file will use the extension specified in ``convert_to``. Post-processing args
|
||||||
can still be set with ``convert_with`` set to ``yt-dlp``.
|
can still be set with ``convert_with`` set to ``yt-dlp``.
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
filter_exclude
|
filter_exclude
|
||||||
|
|
@ -453,6 +472,7 @@ with a ``.nfo`` extension. You can add any values into the NFO.
|
||||||
this field can be set using an override variable to easily toggle whether this plugin
|
this field can be set using an override variable to easily toggle whether this plugin
|
||||||
is enabled or not via Boolean.
|
is enabled or not via Boolean.
|
||||||
|
|
||||||
|
|
||||||
``kodi_safe``
|
``kodi_safe``
|
||||||
|
|
||||||
:expected type: OverridesBooleanFormatterValidator
|
:expected type: OverridesBooleanFormatterValidator
|
||||||
|
|
@ -461,12 +481,14 @@ with a ``.nfo`` extension. You can add any values into the NFO.
|
||||||
emojis and some foreign language characters. Setting this to True will replace those
|
emojis and some foreign language characters. Setting this to True will replace those
|
||||||
characters with '□'.
|
characters with '□'.
|
||||||
|
|
||||||
|
|
||||||
``nfo_name``
|
``nfo_name``
|
||||||
|
|
||||||
:expected type: EntryFormatter
|
:expected type: EntryFormatter
|
||||||
:description:
|
:description:
|
||||||
The NFO file name.
|
The NFO file name.
|
||||||
|
|
||||||
|
|
||||||
``nfo_root``
|
``nfo_root``
|
||||||
|
|
||||||
:expected type: EntryFormatter
|
:expected type: EntryFormatter
|
||||||
|
|
@ -479,6 +501,7 @@ with a ``.nfo`` extension. You can add any values into the NFO.
|
||||||
<episodedetails>
|
<episodedetails>
|
||||||
</episodedetails>
|
</episodedetails>
|
||||||
|
|
||||||
|
|
||||||
``tags``
|
``tags``
|
||||||
|
|
||||||
:expected type: NfoTags
|
:expected type: NfoTags
|
||||||
|
|
@ -515,6 +538,7 @@ with a ``.nfo`` extension. You can add any values into the NFO.
|
||||||
<genre>Comedy</genre>
|
<genre>Comedy</genre>
|
||||||
<genre>Drama</genre>
|
<genre>Drama</genre>
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
output_directory_nfo_tags
|
output_directory_nfo_tags
|
||||||
|
|
@ -546,6 +570,7 @@ Usage:
|
||||||
this field can be set using an override variable to easily toggle whether this plugin
|
this field can be set using an override variable to easily toggle whether this plugin
|
||||||
is enabled or not via Boolean.
|
is enabled or not via Boolean.
|
||||||
|
|
||||||
|
|
||||||
``kodi_safe``
|
``kodi_safe``
|
||||||
|
|
||||||
:expected type: OverridesBooleanFormatterValidator
|
:expected type: OverridesBooleanFormatterValidator
|
||||||
|
|
@ -554,12 +579,14 @@ Usage:
|
||||||
emojis and some foreign language characters. Setting this to True will replace those
|
emojis and some foreign language characters. Setting this to True will replace those
|
||||||
characters with '□'.
|
characters with '□'.
|
||||||
|
|
||||||
|
|
||||||
``nfo_name``
|
``nfo_name``
|
||||||
|
|
||||||
:expected type: EntryFormatter
|
:expected type: EntryFormatter
|
||||||
:description:
|
:description:
|
||||||
The NFO file name.
|
The NFO file name.
|
||||||
|
|
||||||
|
|
||||||
``nfo_root``
|
``nfo_root``
|
||||||
|
|
||||||
:expected type: EntryFormatter
|
:expected type: EntryFormatter
|
||||||
|
|
@ -572,6 +599,7 @@ Usage:
|
||||||
<tvshow>
|
<tvshow>
|
||||||
</tvshow>
|
</tvshow>
|
||||||
|
|
||||||
|
|
||||||
``tags``
|
``tags``
|
||||||
|
|
||||||
:expected type: NfoTags
|
:expected type: NfoTags
|
||||||
|
|
@ -606,6 +634,7 @@ Usage:
|
||||||
<genre>Comedy</genre>
|
<genre>Comedy</genre>
|
||||||
<genre>Drama</genre>
|
<genre>Drama</genre>
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
output_options
|
output_options
|
||||||
|
|
@ -640,6 +669,7 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
The file name to store a subscriptions download archive placed relative to
|
The file name to store a subscriptions download archive placed relative to
|
||||||
the output directory. Defaults to ``.ytdl-sub-{subscription_name}-download-archive.json``
|
the output directory. Defaults to ``.ytdl-sub-{subscription_name}-download-archive.json``
|
||||||
|
|
||||||
|
|
||||||
``file_name``
|
``file_name``
|
||||||
|
|
||||||
:expected type: EntryFormatter
|
:expected type: EntryFormatter
|
||||||
|
|
@ -647,6 +677,7 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
The file name for the media file. This can include directories such as
|
The file name for the media file. This can include directories such as
|
||||||
``"Season {upload_year}/{title}.{ext}"``, and will be placed in the output directory.
|
``"Season {upload_year}/{title}.{ext}"``, and will be placed in the output directory.
|
||||||
|
|
||||||
|
|
||||||
``info_json_name``
|
``info_json_name``
|
||||||
|
|
||||||
:expected type: Optional[EntryFormatter]
|
:expected type: Optional[EntryFormatter]
|
||||||
|
|
@ -655,6 +686,7 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
as ``"Season {upload_year}/{title}.{info_json_ext}"``, and will be placed in the output
|
as ``"Season {upload_year}/{title}.{info_json_ext}"``, and will be placed in the output
|
||||||
directory. Can be set to empty string or `null` to disable info json writes.
|
directory. Can be set to empty string or `null` to disable info json writes.
|
||||||
|
|
||||||
|
|
||||||
``keep_files_after``
|
``keep_files_after``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -666,6 +698,7 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
files after ``19000101``, which implies all files. Can be used in conjunction with
|
files after ``19000101``, which implies all files. Can be used in conjunction with
|
||||||
``keep_max_files``.
|
``keep_max_files``.
|
||||||
|
|
||||||
|
|
||||||
``keep_files_before``
|
``keep_files_before``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -677,6 +710,7 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
files before ``now``, which implies all files. Can be used in conjunction with
|
files before ``now``, which implies all files. Can be used in conjunction with
|
||||||
``keep_max_files``.
|
``keep_max_files``.
|
||||||
|
|
||||||
|
|
||||||
``keep_files_date_eval``
|
``keep_files_date_eval``
|
||||||
|
|
||||||
:expected type: str
|
:expected type: str
|
||||||
|
|
@ -686,6 +720,7 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
perform evaluation for keep_files_before/after and keep_max_files. Defaults
|
perform evaluation for keep_files_before/after and keep_max_files. Defaults
|
||||||
to the entry's upload_date_standardized variable.
|
to the entry's upload_date_standardized variable.
|
||||||
|
|
||||||
|
|
||||||
``keep_max_files``
|
``keep_max_files``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -695,6 +730,7 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
Only keeps N most recently uploaded videos. If set to <= 0, ``keep_max_files`` will not be
|
Only keeps N most recently uploaded videos. If set to <= 0, ``keep_max_files`` will not be
|
||||||
applied. Can be used in conjunction with ``keep_files_before`` and ``keep_files_after``.
|
applied. Can be used in conjunction with ``keep_files_before`` and ``keep_files_after``.
|
||||||
|
|
||||||
|
|
||||||
``maintain_download_archive``
|
``maintain_download_archive``
|
||||||
|
|
||||||
:expected type: Optional[Boolean]
|
:expected type: Optional[Boolean]
|
||||||
|
|
@ -709,6 +745,7 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
|
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
|
|
||||||
|
|
||||||
``migrated_download_archive_name``
|
``migrated_download_archive_name``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -718,12 +755,14 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
name first, and fallback to ``download_archive_name``. It will always save to this file
|
name first, and fallback to ``download_archive_name``. It will always save to this file
|
||||||
and remove the original ``download_archive_name``.
|
and remove the original ``download_archive_name``.
|
||||||
|
|
||||||
|
|
||||||
``output_directory``
|
``output_directory``
|
||||||
|
|
||||||
:expected type: OverridesFormatter
|
:expected type: OverridesFormatter
|
||||||
:description:
|
:description:
|
||||||
The output directory to store all media files downloaded.
|
The output directory to store all media files downloaded.
|
||||||
|
|
||||||
|
|
||||||
``preserve_mtime``
|
``preserve_mtime``
|
||||||
|
|
||||||
:expected type: Optional[Boolean]
|
:expected type: Optional[Boolean]
|
||||||
|
|
@ -732,6 +771,7 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
When True, sets the file's mtime to match the video's upload_date from
|
When True, sets the file's mtime to match the video's upload_date from
|
||||||
yt-dlp metadata. Defaults to False.
|
yt-dlp metadata. Defaults to False.
|
||||||
|
|
||||||
|
|
||||||
``thumbnail_name``
|
``thumbnail_name``
|
||||||
|
|
||||||
:expected type: Optional[EntryFormatter]
|
:expected type: Optional[EntryFormatter]
|
||||||
|
|
@ -740,6 +780,7 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
as ``"Season {upload_year}/{title}.{thumbnail_ext}"``, and will be placed in the output
|
as ``"Season {upload_year}/{title}.{thumbnail_ext}"``, and will be placed in the output
|
||||||
directory. Can be set to empty string or `null` to disable thumbnail writes.
|
directory. Can be set to empty string or `null` to disable thumbnail writes.
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
overrides
|
overrides
|
||||||
|
|
@ -804,6 +845,7 @@ used with no modifications.
|
||||||
If a file has no chapters and is set to "pass", then ``chapter_title`` is
|
If a file has no chapters and is set to "pass", then ``chapter_title`` is
|
||||||
set to the entry's title and ``chapter_index``, ``chapter_count`` are both set to 1.
|
set to the entry's title and ``chapter_index``, ``chapter_count`` are both set to 1.
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
square_thumbnail
|
square_thumbnail
|
||||||
|
|
@ -850,6 +892,7 @@ Usage:
|
||||||
this field can be set using an override variable to easily toggle whether this plugin
|
this field can be set using an override variable to easily toggle whether this plugin
|
||||||
is enabled or not via Boolean.
|
is enabled or not via Boolean.
|
||||||
|
|
||||||
|
|
||||||
``kodi_safe``
|
``kodi_safe``
|
||||||
|
|
||||||
:expected type: OverridesBooleanFormatterValidator
|
:expected type: OverridesBooleanFormatterValidator
|
||||||
|
|
@ -858,12 +901,14 @@ Usage:
|
||||||
emojis and some foreign language characters. Setting this to True will replace those
|
emojis and some foreign language characters. Setting this to True will replace those
|
||||||
characters with '□'.
|
characters with '□'.
|
||||||
|
|
||||||
|
|
||||||
``nfo_name``
|
``nfo_name``
|
||||||
|
|
||||||
:expected type: EntryFormatter
|
:expected type: EntryFormatter
|
||||||
:description:
|
:description:
|
||||||
The NFO file name.
|
The NFO file name.
|
||||||
|
|
||||||
|
|
||||||
``nfo_root``
|
``nfo_root``
|
||||||
|
|
||||||
:expected type: EntryFormatter
|
:expected type: EntryFormatter
|
||||||
|
|
@ -876,6 +921,7 @@ Usage:
|
||||||
<season>
|
<season>
|
||||||
</season>
|
</season>
|
||||||
|
|
||||||
|
|
||||||
``tags``
|
``tags``
|
||||||
|
|
||||||
:expected type: NfoTags
|
:expected type: NfoTags
|
||||||
|
|
@ -889,6 +935,7 @@ Usage:
|
||||||
<title>My custom season name!</title>
|
<title>My custom season name!</title>
|
||||||
</season>
|
</season>
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
subtitles
|
subtitles
|
||||||
|
|
@ -916,6 +963,7 @@ It will set the respective language to the correct subtitle file.
|
||||||
:description:
|
:description:
|
||||||
Defaults to False. Whether to allow auto generated subtitles.
|
Defaults to False. Whether to allow auto generated subtitles.
|
||||||
|
|
||||||
|
|
||||||
``embed_subtitles``
|
``embed_subtitles``
|
||||||
|
|
||||||
:expected type: Optional[Boolean]
|
:expected type: Optional[Boolean]
|
||||||
|
|
@ -923,6 +971,7 @@ It will set the respective language to the correct subtitle file.
|
||||||
Defaults to False. Whether to embed the subtitles into the video file. Note that
|
Defaults to False. Whether to embed the subtitles into the video file. Note that
|
||||||
webm files can only embed "vtt" subtitle types.
|
webm files can only embed "vtt" subtitle types.
|
||||||
|
|
||||||
|
|
||||||
``enable``
|
``enable``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -931,6 +980,7 @@ It will set the respective language to the correct subtitle file.
|
||||||
this field can be set using an override variable to easily toggle whether this plugin
|
this field can be set using an override variable to easily toggle whether this plugin
|
||||||
is enabled or not via Boolean.
|
is enabled or not via Boolean.
|
||||||
|
|
||||||
|
|
||||||
``languages``
|
``languages``
|
||||||
|
|
||||||
:expected type: Optional[List[String]]
|
:expected type: Optional[List[String]]
|
||||||
|
|
@ -938,6 +988,7 @@ It will set the respective language to the correct subtitle file.
|
||||||
Language code(s) to download for subtitles. Supports a single or list of multiple
|
Language code(s) to download for subtitles. Supports a single or list of multiple
|
||||||
language codes. Defaults to only "en".
|
language codes. Defaults to only "en".
|
||||||
|
|
||||||
|
|
||||||
``languages_required``
|
``languages_required``
|
||||||
|
|
||||||
:expected type: Optional[List[String]]
|
:expected type: Optional[List[String]]
|
||||||
|
|
@ -945,6 +996,7 @@ It will set the respective language to the correct subtitle file.
|
||||||
Language code(s) that are required to be present for downloads to continue. If missing,
|
Language code(s) that are required to be present for downloads to continue. If missing,
|
||||||
ytdl-sub will throw an error. NOTE: currently this only checks file-based subtitles.
|
ytdl-sub will throw an error. NOTE: currently this only checks file-based subtitles.
|
||||||
|
|
||||||
|
|
||||||
``subtitles_name``
|
``subtitles_name``
|
||||||
|
|
||||||
:expected type: Optional[EntryFormatter]
|
:expected type: Optional[EntryFormatter]
|
||||||
|
|
@ -954,12 +1006,14 @@ It will set the respective language to the correct subtitle file.
|
||||||
and will be placed in the output directory. ``lang`` is dynamic since you can download
|
and will be placed in the output directory. ``lang`` is dynamic since you can download
|
||||||
multiple subtitles. It will set the respective language to the correct subtitle file.
|
multiple subtitles. It will set the respective language to the correct subtitle file.
|
||||||
|
|
||||||
|
|
||||||
``subtitles_type``
|
``subtitles_type``
|
||||||
|
|
||||||
:expected type: Optional[String]
|
:expected type: Optional[String]
|
||||||
:description:
|
:description:
|
||||||
Defaults to "srt". One of the subtitle file types "srt", "vtt", "ass", "lrc".
|
Defaults to "srt". One of the subtitle file types "srt", "vtt", "ass", "lrc".
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
throttle_protection
|
throttle_protection
|
||||||
|
|
@ -1000,12 +1054,14 @@ Range min and max values support static override variables within their definiti
|
||||||
this field can be set using an override variable to easily toggle whether this plugin
|
this field can be set using an override variable to easily toggle whether this plugin
|
||||||
is enabled or not via Boolean.
|
is enabled or not via Boolean.
|
||||||
|
|
||||||
|
|
||||||
``max_downloads_per_subscription``
|
``max_downloads_per_subscription``
|
||||||
|
|
||||||
:expected type: Optional[Range]
|
:expected type: Optional[Range]
|
||||||
:description:
|
:description:
|
||||||
Number of downloads to perform per subscription.
|
Number of downloads to perform per subscription.
|
||||||
|
|
||||||
|
|
||||||
``sleep_per_download_s``
|
``sleep_per_download_s``
|
||||||
|
|
||||||
:expected type: Optional[Range]
|
:expected type: Optional[Range]
|
||||||
|
|
@ -1013,6 +1069,7 @@ Range min and max values support static override variables within their definiti
|
||||||
Number in seconds to sleep between each download. Does not include time it takes for
|
Number in seconds to sleep between each download. Does not include time it takes for
|
||||||
ytdl-sub to perform post-processing.
|
ytdl-sub to perform post-processing.
|
||||||
|
|
||||||
|
|
||||||
``sleep_per_request_s``
|
``sleep_per_request_s``
|
||||||
|
|
||||||
:expected type: Optional[Range]
|
:expected type: Optional[Range]
|
||||||
|
|
@ -1022,12 +1079,14 @@ Range min and max values support static override variables within their definiti
|
||||||
download for the entry. Also, yt-dlp only supports a single value at this time for this,
|
download for the entry. Also, yt-dlp only supports a single value at this time for this,
|
||||||
so will always use the max value.
|
so will always use the max value.
|
||||||
|
|
||||||
|
|
||||||
``sleep_per_subscription_s``
|
``sleep_per_subscription_s``
|
||||||
|
|
||||||
:expected type: Optional[Range]
|
:expected type: Optional[Range]
|
||||||
:description:
|
:description:
|
||||||
Number in seconds to sleep between each subscription.
|
Number in seconds to sleep between each subscription.
|
||||||
|
|
||||||
|
|
||||||
``subscription_download_probability``
|
``subscription_download_probability``
|
||||||
|
|
||||||
:expected type: Optional[Float]
|
:expected type: Optional[Float]
|
||||||
|
|
@ -1036,6 +1095,7 @@ Range min and max values support static override variables within their definiti
|
||||||
recommended to set if you run ytdl-sub in a cron-job, that way you are statistically
|
recommended to set if you run ytdl-sub in a cron-job, that way you are statistically
|
||||||
guaranteed over time to eventually download the subscription.
|
guaranteed over time to eventually download the subscription.
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
video_tags
|
video_tags
|
||||||
|
|
|
||||||
|
|
@ -837,7 +837,7 @@ behavior.
|
||||||
|
|
||||||
sanitize
|
sanitize
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
:spec: ``sanitize(value: AnyArgument, ...) -> String``
|
:spec: ``sanitize(value: AnyArgument) -> String``
|
||||||
|
|
||||||
Sanitize a string using yt-dlp's ``sanitize_filename`` method to ensure it's safe to use
|
Sanitize a string using yt-dlp's ``sanitize_filename`` method to ensure it's safe to use
|
||||||
for file/directory names on any OS.
|
for file/directory names on any OS.
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ supply a cookies file path.
|
||||||
|
|
||||||
# Directly set plugin options:
|
# Directly set plugin options:
|
||||||
ytdl_options:
|
ytdl_options:
|
||||||
cookiefile: "/config/ytdl-sub-configs/cookie.txt"
|
cookiefile: "/config/cookie.txt"
|
||||||
|
|
||||||
Layout
|
Layout
|
||||||
------
|
------
|
||||||
|
|
|
||||||
|
|
@ -1,80 +1,51 @@
|
||||||
Automating
|
Automating Downloads
|
||||||
==========
|
====================
|
||||||
|
|
||||||
Automate downloading your subscriptions by running the :ref:`'sub' sub-command
|
:ref:`Guide for Docker and Unraid Containers <guides/getting_started/automating_downloads:docker and unraid>`
|
||||||
<usage:subscriptions options>` periodically. There are various tools that can run
|
|
||||||
commands on a schedule you may use any of them that work with your installation
|
|
||||||
method. Most users use `cron`_ in `Docker containers <docker and unraid_>`_.
|
|
||||||
|
|
||||||
|
:ref:`Guide for Linux <guides/getting_started/automating_downloads:linux>`
|
||||||
|
|
||||||
|
:ref:`Guide for Windows <guides/getting_started/automating_downloads:windows>`
|
||||||
|
|
||||||
|
.. _cron scheduling syntax: https://crontab.guru/#0_*/6_*_*_*
|
||||||
|
|
||||||
|
|
||||||
|
.. _docker-unraid-setup:
|
||||||
|
|
||||||
Docker and Unraid
|
Docker and Unraid
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
:doc:`The 'ytdl-sub' Docker container images <../install/docker>` provide optional cron
|
Cron is preconfigured in every ytdl-sub docker container. Enable by adding the following
|
||||||
support. Enable cron support by setting `a cron schedule`_ in the ``CRON_SCHEDULE``
|
ENV variables to your docker setup.
|
||||||
environment variable:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
:caption: ./compose.yaml
|
|
||||||
:emphasize-lines: 4
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
ytdl-sub:
|
ytdl-sub:
|
||||||
environment:
|
environment:
|
||||||
CRON_SCHEDULE: "0 */6 * * *"
|
- CRON_SCHEDULE="0 */6 * * *"
|
||||||
# WARNING: See "Getting Started" -> "Automating" docs regarding throttles/bans:
|
- CRON_RUN_ON_START=false
|
||||||
# CRON_RUN_ON_START: false
|
|
||||||
|
|
||||||
Then recreate the container to apply the change and start it to generate the default
|
|
||||||
``/config/ytdl-sub-configs/cron`` script. Read the comments in that script and edit as
|
|
||||||
appropriate.
|
|
||||||
|
|
||||||
The container cron wrapper script will write output from the cron job to
|
- ``CRON_SCHEDULE`` follows the standard `cron scheduling syntax`_. The above value will
|
||||||
``/config/ytdl-sub-configs/.cron.log``. The default image ``ENTRYPOINT`` will ``$ tail
|
run the script once every 6 hours.
|
||||||
...`` that file so you can monitor the cron job in the container's output and thus also
|
- ``CRON_RUN_ON_START`` toggles whether to run your cron script on container start in
|
||||||
in the Docker logs.
|
addition to the cron schedule.
|
||||||
|
|
||||||
You may also set the ``CRON_RUN_ON_START`` environment variable to ``true`` to have the
|
The cron script will reside in the main directory with the file name ``cron``. Cron
|
||||||
image run your cron script whenever the container starts in addition to the cron
|
logs should show when viewing the Docker logs.
|
||||||
schedule.
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
Using ``CRON_RUN_ON_START`` may cause your cron script to run too often and may
|
|
||||||
trigger throttles and bans. When enabled, your cron script will run *whenever* the
|
|
||||||
container starts including when the host reboots, when ``# dockerd`` restarts such as
|
|
||||||
when upgrading Docker itself, when a new image is pulled, when something applies
|
|
||||||
Compose changes, etc.. This may result in running ``ytdl-sub`` right before or after
|
|
||||||
the next cron scheduled run.
|
|
||||||
|
|
||||||
|
|
||||||
.. _linux-setup:
|
.. _linux-setup:
|
||||||
|
|
||||||
Linux, Mac OS X, BSD, or other UNIX's
|
Linux
|
||||||
-------------------------------------
|
-----
|
||||||
|
Must configure crontab manually, like so:
|
||||||
For installations on systems already running ``# crond``, you can also use cron to run
|
|
||||||
``ytdl-sub`` periodically. Write a script to run ``ytdl-sub`` in the cron job. Be sure
|
|
||||||
the script changes to the same directory as your configuration and uses the full path to
|
|
||||||
``ytdl-sub``:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
:caption: ~/.local/bin/ytdl-sub-cron
|
|
||||||
:emphasize-lines: 2,3
|
|
||||||
|
|
||||||
#!/bin/bash
|
crontab -e
|
||||||
cd "~/.config/ytdl-sub/"
|
0 */6 * * * /config/run_cron
|
||||||
~/.local/bin/ytdl-sub --dry-run sub -o '--ytdl_options.max_downloads 3' |&
|
|
||||||
tee -a "~/.local/state/ytdl-sub/.cron.log"
|
|
||||||
|
|
||||||
Then tell ``# crond`` when to run the script:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
echo "0 */6 * * * ${HOME}/.local/bin/ytdl-sub-cron" | crontab "-"
|
|
||||||
|
|
||||||
Remove the ``--dry-run`` and ``-o ...`` CLI options from your cron script when you've
|
|
||||||
tested your configuration and you're ready to download entries unattended.
|
|
||||||
|
|
||||||
|
|
||||||
.. _windows-setup:
|
.. _windows-setup:
|
||||||
|
|
@ -82,51 +53,17 @@ tested your configuration and you're ready to download entries unattended.
|
||||||
Windows
|
Windows
|
||||||
-------
|
-------
|
||||||
|
|
||||||
For most Windows users, the best way to run commands periodically is `the Task
|
To be tested (please contact code owner or join the discord server if you can test this
|
||||||
Scheduler`_:
|
out for us)
|
||||||
|
|
||||||
.. attention::
|
.. code-block:: powershell
|
||||||
|
|
||||||
These instructions are untested. Use at your own risk. If you use them, whether they
|
ytdl-sub.exe --config \path\to\config\config.yaml sub \path\to\config\subscriptions.yaml
|
||||||
work or not, please let us know how it went in `a support post in Discord`_ or `a new
|
|
||||||
GitHub issue`_.
|
|
||||||
|
|
||||||
#. Open the Task Scheduler app.
|
|
||||||
|
|
||||||
#. Click ``Create Basic Task`` at the top of the right sidebar.
|
|
||||||
|
|
||||||
#. Set all the fields as appropriate until you get to the ``Action``...
|
|
||||||
|
|
||||||
#. For the ``Action``, select ``Start a program``...
|
|
||||||
|
|
||||||
#. Click ``Browse...`` to the installed ``ytdl-sub.exe`` executable...
|
|
||||||
|
|
||||||
#. Add CLI arguments to ``Add arguments (optional):``, for example ``--dry-run sub -o
|
|
||||||
'--ytdl_options.max_downloads 3'``...
|
|
||||||
|
|
||||||
#. Set ``Start in (optional):`` to the directory containing your configuration.
|
|
||||||
|
|
||||||
#. Finish the rest of the ``Create Basic Task`` wizard.
|
|
||||||
|
|
||||||
|
|
||||||
Next Steps
|
Next Steps
|
||||||
----------
|
----------
|
||||||
|
|
||||||
At this point, ``ytdl-sub`` should run periodically and keep your subscriptions current
|
Once you have a significant quantity of subscriptions or have use cases not served using
|
||||||
in your media library without your intervention. As your :doc:`subscriptions file
|
:doc:`YAML keys and the special characters <./subscriptions>`, it's time to start
|
||||||
<./subscriptions>` grows or you discover new use cases, it becomes worth while to
|
:doc:`defining your own custom presets <./first_config>`.
|
||||||
simplify things by :doc:`defining your own custom presets <./first_config>`.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. _`cron`:
|
|
||||||
https://en.wikipedia.org/wiki/Cron
|
|
||||||
.. _`a cron schedule`:
|
|
||||||
https://crontab.cronhub.io/
|
|
||||||
|
|
||||||
.. _`the Task Scheduler`:
|
|
||||||
https://learn.microsoft.com/en-us/windows/win32/taskschd/task-scheduler-start-page
|
|
||||||
.. _`a support post in Discord`:
|
|
||||||
https://discord.com/channels/994270357957648404/1084886228266127460
|
|
||||||
.. _`a new GitHub issue`:
|
|
||||||
https://github.com/jmbannon/ytdl-sub/issues/new
|
|
||||||
|
|
|
||||||
|
|
@ -3,33 +3,13 @@ Basic Configuration
|
||||||
|
|
||||||
A configuration file serves two purposes:
|
A configuration file serves two purposes:
|
||||||
|
|
||||||
1. Set application-level functionality that is not specifiable in a subscription file.
|
1. Set advanced functionality that is not specifiable in a subscription file, such as
|
||||||
|
working directory location. These are set underneath ``configuration``.
|
||||||
|
2. Create custom presets, which can drastically simplify your subscription file. These
|
||||||
|
are defined underneath ``presets``. Presets are intended to be applicable and
|
||||||
|
reusable across multiple subscriptions.
|
||||||
|
|
||||||
.. note::
|
Below is a common configuration:
|
||||||
|
|
||||||
ytdl-sub does not require a configuration file. However,
|
|
||||||
certain application settings may be desirable for tweak, such as setting
|
|
||||||
``working_directory`` to make ytdl-sub perform the initial download
|
|
||||||
to an SSD drive.
|
|
||||||
|
|
||||||
2. Create custom presets.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
In the prior Initial Subscription examples, we leveraged the prebuilt preset
|
|
||||||
``Jellyfin TV Show by Date``. This preset is entirely built using the same
|
|
||||||
YAML configuration system offered to users by using a configuration file.
|
|
||||||
|
|
||||||
The following section attempts to demystify and explain how to...
|
|
||||||
|
|
||||||
- Set an application setting
|
|
||||||
- Know whether or not custom presets are actually needed
|
|
||||||
- How to create a custom preset
|
|
||||||
- How to use a custom preset on subscriptions
|
|
||||||
|
|
||||||
-------------
|
|
||||||
|
|
||||||
how this works, and show-case how
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
:linenos:
|
:linenos:
|
||||||
|
|
@ -242,22 +222,3 @@ Be sure to tell ytdl-sub to use your config by using the argument ``--config
|
||||||
|
|
||||||
If you run ytdl-sub in the same directory, and the config file is named ``config.yaml``,
|
If you run ytdl-sub in the same directory, and the config file is named ``config.yaml``,
|
||||||
it will use it by default.
|
it will use it by default.
|
||||||
|
|
||||||
Visualizing a subscription in Preset form
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
Subscription file syntax is designed to minimize boiler-plate when authoring new subscriptions.
|
|
||||||
You can unpack any subscription using the ``inspect`` sub-command to see its boiler-plate *preset format*.
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
ytdl-sub inspect --match "BBC News" /path/to/subscriptions.yaml
|
|
||||||
|
|
||||||
This can be utilized for numerous purposes including:
|
|
||||||
|
|
||||||
* Ensuring your custom preset is getting applied correctly.
|
|
||||||
* Figuring out which variables set things like file names, metadata, etc.
|
|
||||||
* Understanding how subscription syntax translates to preset representation.
|
|
||||||
|
|
||||||
The default ``--level`` of inspect will fill in defined variables. Using ``--level original`` will
|
|
||||||
present the subscription's raw layout with no fill.
|
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ use no preset at all and will just run ``yt-dlp`` without any customization or p
|
||||||
processing. The subscriptions file has special support for :ref:`overriding the presets
|
processing. The subscriptions file has special support for :ref:`overriding the presets
|
||||||
of all subscriptions in the file <config_reference/subscription_yaml:file preset>`. The
|
of all subscriptions in the file <config_reference/subscription_yaml:file preset>`. The
|
||||||
configuration file supports :ref:`a few special options
|
configuration file supports :ref:`a few special options
|
||||||
<config_reference/config_yaml:Configuration File>` that are not about defining presets. See
|
<config_reference/config_yaml:configuration>` that are not about defining presets. See
|
||||||
:doc:`the reference documentation <../../config_reference/index>` for technically
|
:doc:`the reference documentation <../../config_reference/index>` for technically
|
||||||
complete details, but for almost all of the use cases served by ``ytdl-sub``, the above
|
complete details, but for almost all of the use cases served by ``ytdl-sub``, the above
|
||||||
is accurate and representative.
|
is accurate and representative.
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,6 @@ For example::
|
||||||
|
|
||||||
$ docker compose run --rm --user="${PUID}:${PGID}" --entrypoint="ytdl-sub" ytdl-sub sub
|
$ docker compose run --rm --user="${PUID}:${PGID}" --entrypoint="ytdl-sub" ytdl-sub sub
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
In `the recommended GUI image <gui image_>`_, the ``DEFAULT_WORKSPACE`` directory is
|
|
||||||
``/config/ytdl-sub-configs/`` which is used throughout the documentation and
|
|
||||||
examples. In the headless images, that directory is just ``/config/``, so substitute
|
|
||||||
that path if using a headless image.
|
|
||||||
|
|
||||||
|
|
||||||
Install with Docker Compose
|
Install with Docker Compose
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,8 @@ Using the command:
|
||||||
--overrides.tv_show_name "Rick A" \
|
--overrides.tv_show_name "Rick A" \
|
||||||
--overrides.url: "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
|
--overrides.url: "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
|
||||||
|
|
||||||
See how to shorten commands using :ref:`download aliases <config_reference/config_yaml:dl_aliases>`.
|
See how to shorten commands using `download aliases
|
||||||
|
<https://ytdl-sub.readthedocs.io/en/latest/config_reference/config_yaml.html#ytdl_sub.config.config_validator.ConfigOptions.dl_aliases>`_.
|
||||||
|
|
||||||
|
|
||||||
View Options
|
View Options
|
||||||
|
|
@ -112,35 +113,3 @@ Convert yt-dlp cli arguments to ytdl-sub `ytdl_options` arguments.
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
ytdl-sub cli-to-sub [YT-DLP ARGS]
|
ytdl-sub cli-to-sub [YT-DLP ARGS]
|
||||||
|
|
||||||
Inspect
|
|
||||||
-------
|
|
||||||
Inspect a single subscription's underlying preset representation.
|
|
||||||
This can be utilized for numerous purposes including:
|
|
||||||
|
|
||||||
* Ensuring your custom preset is getting applied correctly.
|
|
||||||
* Figuring out which variables set things like file names, metadata, etc.
|
|
||||||
* Understanding how subscription syntax translates to preset representation.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
ytdl-sub inspect --match "Game Chops" --mock 'title=Lets Play' examples/music_subscriptions.yaml
|
|
||||||
|
|
||||||
.. code-block:: text
|
|
||||||
:caption: Additional Options
|
|
||||||
|
|
||||||
-l 0,1,2,3, --level 0,1,2,3
|
|
||||||
level of inspection to perform:
|
|
||||||
0 - original present the subscription as-is
|
|
||||||
1 - fill fill in defined values
|
|
||||||
2 - resolve resolve all possible variables (default)
|
|
||||||
3 - internal resolve all variables to their internal representation
|
|
||||||
|
|
||||||
-m MATCH [MATCH ...], --match MATCH [MATCH ...]
|
|
||||||
match subscription names to one or more substrings, and only run those subscriptions
|
|
||||||
-o DL_OVERRIDE, --dl-override DL_OVERRIDE
|
|
||||||
override all subscription config values using `dl` syntax, i.e. --dl-override='--ytdl_options.max_downloads 3'
|
|
||||||
-k VAR=VALUE, --mock VAR=VALUE
|
|
||||||
ability to mock one or more variable values, i.e. --mock 'title=Lets Play'
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ presets:
|
||||||
# ytdl_options lets you pass any arg into yt-dlp's Python API
|
# ytdl_options lets you pass any arg into yt-dlp's Python API
|
||||||
ytdl_options:
|
ytdl_options:
|
||||||
# Set the cookie file
|
# Set the cookie file
|
||||||
# cookiefile: "/config/ytdl-sub-configs/youtube_cookies.txt"
|
# cookiefile: "/config/youtube_cookies.txt"
|
||||||
|
|
||||||
# For YouTube, get English metadata if multiple languages are present
|
# For YouTube, get English metadata if multiple languages are present
|
||||||
extractor_args:
|
extractor_args:
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ classifiers = [
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"yt-dlp[default]==2026.6.9",
|
"yt-dlp[default]==2026.2.21",
|
||||||
"colorama~=0.4",
|
"colorama~=0.4",
|
||||||
"mergedeep~=1.3",
|
"mergedeep~=1.3",
|
||||||
"mediafile~=0.12",
|
"mediafile~=0.12",
|
||||||
|
|
@ -43,12 +43,13 @@ where = ["src"]
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
test = [
|
test = [
|
||||||
"coverage[toml]>=6.3,<8.0",
|
"coverage[toml]>=6.3,<8.0",
|
||||||
"pytest>=7.2,<10.0",
|
"pytest>=7.2,<9.0",
|
||||||
"pytest-rerunfailures>=14,<17",
|
"pytest-rerunfailures>=14,<17",
|
||||||
]
|
]
|
||||||
lint = [
|
lint = [
|
||||||
"pylint==4.0.5",
|
"black==24.10.0",
|
||||||
"ruff==0.15.16",
|
"isort==7.0.0",
|
||||||
|
"pylint==4.0.1",
|
||||||
]
|
]
|
||||||
docs = [
|
docs = [
|
||||||
"sphinx>=7,<10",
|
"sphinx>=7,<10",
|
||||||
|
|
@ -65,6 +66,15 @@ build = [
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
ytdl-sub = "ytdl_sub.main:main"
|
ytdl-sub = "ytdl_sub.main:main"
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
profile = "black"
|
||||||
|
line_length = 100
|
||||||
|
force_single_line = true
|
||||||
|
|
||||||
|
[tool.black]
|
||||||
|
line_length = 100
|
||||||
|
target-version = ["py310"]
|
||||||
|
|
||||||
[tool.pylint.MASTER]
|
[tool.pylint.MASTER]
|
||||||
disable = [
|
disable = [
|
||||||
"C0115", # Missing class docstring
|
"C0115", # Missing class docstring
|
||||||
|
|
@ -90,27 +100,3 @@ include = [
|
||||||
exclude_also = [
|
exclude_also = [
|
||||||
"raise UNREACHABLE.*",
|
"raise UNREACHABLE.*",
|
||||||
]
|
]
|
||||||
|
|
||||||
# ruff
|
|
||||||
[tool.ruff]
|
|
||||||
line-length = 100
|
|
||||||
indent-width = 4
|
|
||||||
|
|
||||||
# Assume Python 3.10
|
|
||||||
target-version = "py310"
|
|
||||||
|
|
||||||
[tool.ruff.lint]
|
|
||||||
extend-select = ["I"]
|
|
||||||
|
|
||||||
[tool.ruff.format]
|
|
||||||
# Like Black, use double quotes for strings.
|
|
||||||
quote-style = "double"
|
|
||||||
|
|
||||||
# Like Black, indent with spaces, rather than tabs.
|
|
||||||
indent-style = "space"
|
|
||||||
|
|
||||||
# Like Black, respect magic trailing commas.
|
|
||||||
skip-magic-trailing-comma = false
|
|
||||||
|
|
||||||
# Like Black, automatically detect the appropriate line ending.
|
|
||||||
line-ending = "auto"
|
|
||||||
|
|
@ -4,28 +4,27 @@ import random
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from yt_dlp.utils import sanitize_filename
|
from yt_dlp.utils import sanitize_filename
|
||||||
|
|
||||||
from ytdl_sub.cli.output_summary import output_summary
|
from ytdl_sub.cli.output_summary import output_summary
|
||||||
from ytdl_sub.cli.output_transaction_log import (
|
from ytdl_sub.cli.output_transaction_log import _maybe_validate_transaction_log_file
|
||||||
_maybe_validate_transaction_log_file,
|
from ytdl_sub.cli.output_transaction_log import output_transaction_log
|
||||||
output_transaction_log,
|
|
||||||
)
|
|
||||||
from ytdl_sub.cli.parsers.cli_to_sub import print_cli_to_sub
|
from ytdl_sub.cli.parsers.cli_to_sub import print_cli_to_sub
|
||||||
from ytdl_sub.cli.parsers.dl import DownloadArgsParser
|
from ytdl_sub.cli.parsers.dl import DownloadArgsParser
|
||||||
from ytdl_sub.cli.parsers.main import DEFAULT_CONFIG_FILE_NAME, parser
|
from ytdl_sub.cli.parsers.main import DEFAULT_CONFIG_FILE_NAME
|
||||||
|
from ytdl_sub.cli.parsers.main import parser
|
||||||
from ytdl_sub.config.config_file import ConfigFile
|
from ytdl_sub.config.config_file import ConfigFile
|
||||||
from ytdl_sub.config.validators.variable_validation import ResolutionLevel
|
|
||||||
from ytdl_sub.subscriptions.subscription import Subscription
|
from ytdl_sub.subscriptions.subscription import Subscription
|
||||||
from ytdl_sub.utils.exceptions import ExperimentalFeatureNotEnabled, ValidationException
|
from ytdl_sub.utils.exceptions import ExperimentalFeatureNotEnabled
|
||||||
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
from ytdl_sub.utils.file_handler import FileHandler
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
from ytdl_sub.utils.file_lock import working_directory_lock
|
from ytdl_sub.utils.file_lock import working_directory_lock
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
|
|
||||||
# pylint: disable=too-many-branches
|
|
||||||
|
|
||||||
logger = Logger.get()
|
logger = Logger.get()
|
||||||
|
|
||||||
# View is a command to run a simple dry-run on a URL using the `_view` preset.
|
# View is a command to run a simple dry-run on a URL using the `_view` preset.
|
||||||
|
|
@ -205,44 +204,6 @@ def _view_url_from_cli(config: ConfigFile, url: str, split_chapters: bool) -> Su
|
||||||
return subscription
|
return subscription
|
||||||
|
|
||||||
|
|
||||||
def _parse_inspect_mocks(mocks: Optional[List[str]]) -> Dict[str, str]:
|
|
||||||
out: Dict[str, str] = {}
|
|
||||||
for mock in mocks or []:
|
|
||||||
spl = mock.split("=", 1)
|
|
||||||
if len(spl) == 1:
|
|
||||||
raise ValidationException("inspect mock must be in the form of VAR=VALUE")
|
|
||||||
out[spl[0].strip()] = spl[1]
|
|
||||||
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
def _inspect(
|
|
||||||
config: ConfigFile,
|
|
||||||
subscription_paths: List[str],
|
|
||||||
subscription_matches: List[str],
|
|
||||||
subscription_override_dict: Dict,
|
|
||||||
inspection_level: int,
|
|
||||||
mocks: Dict[str, str],
|
|
||||||
) -> None:
|
|
||||||
|
|
||||||
subscriptions: List[Subscription] = []
|
|
||||||
for path in subscription_paths:
|
|
||||||
subscriptions += Subscription.from_file_path(
|
|
||||||
config=config,
|
|
||||||
subscription_path=path,
|
|
||||||
subscription_matches=subscription_matches,
|
|
||||||
subscription_override_dict=subscription_override_dict,
|
|
||||||
)
|
|
||||||
|
|
||||||
if len(subscriptions) > 1:
|
|
||||||
print(
|
|
||||||
"inspect can only inspect a single subscription. Use --match to filter for a single one"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
print(subscriptions[0].resolved_yaml(resolution_level=inspection_level, mocks=mocks))
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> List[Subscription]:
|
def main() -> List[Subscription]:
|
||||||
"""
|
"""
|
||||||
Entrypoint for ytdl-sub, without the error handling
|
Entrypoint for ytdl-sub, without the error handling
|
||||||
|
|
@ -269,23 +230,6 @@ def main() -> List[Subscription]:
|
||||||
|
|
||||||
subscriptions: List[Subscription] = []
|
subscriptions: List[Subscription] = []
|
||||||
|
|
||||||
if args.subparser == "inspect":
|
|
||||||
subscription_override_dict = {}
|
|
||||||
if args.dl_override:
|
|
||||||
subscription_override_dict = DownloadArgsParser.from_dl_override(
|
|
||||||
override=args.dl_override, config=config
|
|
||||||
).to_subscription_dict()
|
|
||||||
|
|
||||||
_inspect(
|
|
||||||
config=config,
|
|
||||||
subscription_paths=args.subscription_paths,
|
|
||||||
subscription_matches=args.match,
|
|
||||||
subscription_override_dict=subscription_override_dict,
|
|
||||||
inspection_level=ResolutionLevel.level_number(args.inspection_level),
|
|
||||||
mocks=_parse_inspect_mocks(args.mock),
|
|
||||||
)
|
|
||||||
return []
|
|
||||||
|
|
||||||
# If transaction log file is specified, make sure we can open it
|
# If transaction log file is specified, make sure we can open it
|
||||||
_maybe_validate_transaction_log_file(transaction_log_file_path=args.transaction_log)
|
_maybe_validate_transaction_log_file(transaction_log_file_path=args.transaction_log)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import List, Optional
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.subscriptions.subscription import Subscription
|
from ytdl_sub.subscriptions.subscription import Subscription
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ create_parser = yt_dlp.options.create_parser
|
||||||
|
|
||||||
|
|
||||||
def parse_patched_options(opts):
|
def parse_patched_options(opts):
|
||||||
|
|
||||||
patched_parser = create_parser()
|
patched_parser = create_parser()
|
||||||
patched_parser.defaults.update(
|
patched_parser.defaults.update(
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
from typing import Any, Dict, List, Tuple
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from mergedeep import mergedeep
|
from mergedeep import mergedeep
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import argparse
|
import argparse
|
||||||
import dataclasses
|
import dataclasses
|
||||||
from typing import Dict, List
|
from typing import List
|
||||||
|
|
||||||
from ytdl_sub import __local_version__
|
from ytdl_sub import __local_version__
|
||||||
from ytdl_sub.utils.logger import LoggerLevels
|
from ytdl_sub.utils.logger import LoggerLevels
|
||||||
|
|
@ -236,77 +236,3 @@ view_parser.add_argument("url", help="URL to view source variables for")
|
||||||
###################################################################################################
|
###################################################################################################
|
||||||
# CLI-TO-SUB PARSER
|
# CLI-TO-SUB PARSER
|
||||||
cli_to_sub_parser = subparsers.add_parser("cli-to-sub")
|
cli_to_sub_parser = subparsers.add_parser("cli-to-sub")
|
||||||
|
|
||||||
###################################################################################################
|
|
||||||
# INSPECT PARSER
|
|
||||||
|
|
||||||
|
|
||||||
class InspectArguments:
|
|
||||||
LEVEL = CLIArgument(
|
|
||||||
short="-l",
|
|
||||||
long="--level",
|
|
||||||
)
|
|
||||||
LevelChoices: Dict[str, str] = {
|
|
||||||
"0": "original",
|
|
||||||
"1": "fill",
|
|
||||||
"2": "resolve",
|
|
||||||
"3": "internal",
|
|
||||||
}
|
|
||||||
|
|
||||||
MOCK = CLIArgument(
|
|
||||||
short="-k",
|
|
||||||
long="--mock",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
inspect_parser = subparsers.add_parser("inspect", formatter_class=argparse.RawTextHelpFormatter)
|
|
||||||
inspect_parser.add_argument(
|
|
||||||
InspectArguments.LEVEL.short,
|
|
||||||
InspectArguments.LEVEL.long,
|
|
||||||
metavar=",".join(str(i) for i in range(4)),
|
|
||||||
type=str,
|
|
||||||
help="""level of inspection to perform:
|
|
||||||
0 - original present the subscription as-is
|
|
||||||
1 - fill fill in defined values
|
|
||||||
2 - resolve resolve all possible variables (default)
|
|
||||||
3 - internal resolve all variables to their internal representation
|
|
||||||
""",
|
|
||||||
default="resolve",
|
|
||||||
choices=list(InspectArguments.LevelChoices.keys())
|
|
||||||
+ list(InspectArguments.LevelChoices.values()),
|
|
||||||
dest="inspection_level",
|
|
||||||
)
|
|
||||||
inspect_parser.add_argument(
|
|
||||||
MainArguments.MATCH.short,
|
|
||||||
MainArguments.MATCH.long,
|
|
||||||
dest="match",
|
|
||||||
nargs="+",
|
|
||||||
action="extend",
|
|
||||||
type=str,
|
|
||||||
help="match subscription names to one or more substrings, and only run those subscriptions",
|
|
||||||
default=[],
|
|
||||||
)
|
|
||||||
|
|
||||||
inspect_parser.add_argument(
|
|
||||||
"subscription_paths",
|
|
||||||
metavar="SUBPATH",
|
|
||||||
nargs="*",
|
|
||||||
help="path to subscription files, uses subscriptions.yaml if not provided",
|
|
||||||
default=["subscriptions.yaml"],
|
|
||||||
)
|
|
||||||
|
|
||||||
inspect_parser.add_argument(
|
|
||||||
SubArguments.OVERRIDE.short,
|
|
||||||
SubArguments.OVERRIDE.long,
|
|
||||||
type=str,
|
|
||||||
help="override all subscription config values using `dl` syntax, "
|
|
||||||
"i.e. --dl-override='--ytdl_options.max_downloads 3'",
|
|
||||||
)
|
|
||||||
|
|
||||||
inspect_parser.add_argument(
|
|
||||||
InspectArguments.MOCK.short,
|
|
||||||
InspectArguments.MOCK.long,
|
|
||||||
metavar="VAR=VALUE",
|
|
||||||
action="append",
|
|
||||||
help="ability to mock one or more variable values, i.e. --mock 'title=Lets Play'",
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
from typing import Any, Dict
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
from ytdl_sub.config.config_validator import ConfigValidator
|
from ytdl_sub.config.config_validator import ConfigValidator
|
||||||
from ytdl_sub.config.preset import Preset
|
from ytdl_sub.config.preset import Preset
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,29 @@
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from mergedeep import mergedeep
|
from mergedeep import mergedeep
|
||||||
from yt_dlp.utils import datetime_from_str
|
from yt_dlp.utils import datetime_from_str
|
||||||
|
|
||||||
from ytdl_sub.config.defaults import (
|
from ytdl_sub.config.defaults import DEFAULT_FFMPEG_PATH
|
||||||
DEFAULT_FFMPEG_PATH,
|
from ytdl_sub.config.defaults import DEFAULT_FFPROBE_PATH
|
||||||
DEFAULT_FFPROBE_PATH,
|
from ytdl_sub.config.defaults import DEFAULT_LOCK_DIRECTORY
|
||||||
DEFAULT_LOCK_DIRECTORY,
|
from ytdl_sub.config.defaults import MAX_FILE_NAME_BYTES
|
||||||
MAX_FILE_NAME_BYTES,
|
|
||||||
)
|
|
||||||
from ytdl_sub.prebuilt_presets import PREBUILT_PRESETS
|
from ytdl_sub.prebuilt_presets import PREBUILT_PRESETS
|
||||||
from ytdl_sub.utils.exceptions import SubscriptionPermissionError
|
from ytdl_sub.utils.exceptions import SubscriptionPermissionError
|
||||||
from ytdl_sub.utils.file_handler import FileHandler
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
from ytdl_sub.validators.file_path_validators import FFmpegFileValidator, FFprobeFileValidator
|
from ytdl_sub.validators.file_path_validators import FFmpegFileValidator
|
||||||
|
from ytdl_sub.validators.file_path_validators import FFprobeFileValidator
|
||||||
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
||||||
from ytdl_sub.validators.validators import (
|
from ytdl_sub.validators.validators import BoolValidator
|
||||||
BoolValidator,
|
from ytdl_sub.validators.validators import IntValidator
|
||||||
IntValidator,
|
from ytdl_sub.validators.validators import LiteralDictValidator
|
||||||
LiteralDictValidator,
|
from ytdl_sub.validators.validators import StringValidator
|
||||||
StringValidator,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ExperimentalValidator(StrictDictValidator):
|
class ExperimentalValidator(StrictDictValidator):
|
||||||
"""
|
|
||||||
Experimental flags reside under the ``experimental`` key.
|
|
||||||
"""
|
|
||||||
|
|
||||||
_optional_keys = {"enable_update_with_info_json"}
|
_optional_keys = {"enable_update_with_info_json"}
|
||||||
_allow_extra_keys = True
|
_allow_extra_keys = True
|
||||||
|
|
||||||
|
|
@ -50,11 +45,6 @@ class ExperimentalValidator(StrictDictValidator):
|
||||||
|
|
||||||
|
|
||||||
class PersistLogsValidator(StrictDictValidator):
|
class PersistLogsValidator(StrictDictValidator):
|
||||||
"""
|
|
||||||
By default, no logs are persisted. Specifying this key will enable persisted logs. The following
|
|
||||||
options are available.
|
|
||||||
"""
|
|
||||||
|
|
||||||
_required_keys = {"logs_directory"}
|
_required_keys = {"logs_directory"}
|
||||||
_optional_keys = {"keep_logs_after", "keep_successful_logs"}
|
_optional_keys = {"keep_logs_after", "keep_successful_logs"}
|
||||||
|
|
||||||
|
|
@ -79,8 +69,8 @@ class PersistLogsValidator(StrictDictValidator):
|
||||||
@property
|
@property
|
||||||
def logs_directory(self) -> str:
|
def logs_directory(self) -> str:
|
||||||
"""
|
"""
|
||||||
Required field. Write log files to this directory with names like
|
Write log files to this directory with names like
|
||||||
``YYYY-mm-dd-HHMMSS.subscription_name.(success|error).log``.
|
``YYYY-mm-dd-HHMMSS.subscription_name.(success|error).log``. (required)
|
||||||
"""
|
"""
|
||||||
return self._logs_directory.value
|
return self._logs_directory.value
|
||||||
|
|
||||||
|
|
@ -105,54 +95,15 @@ class PersistLogsValidator(StrictDictValidator):
|
||||||
@property
|
@property
|
||||||
def keep_successful_logs(self) -> bool:
|
def keep_successful_logs(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Defaults to ``True``. When this key is ``False``, only write log files for failed
|
If the ``persist_logs:`` key is in the configuration, then ``ytdl-sub`` *always*
|
||||||
subscriptions.
|
writes log files for the subscription both for successful downloads and when it
|
||||||
|
encounters an error while downloading. When this key is ``False``, only write
|
||||||
|
log files for errors. (default ``True``)
|
||||||
"""
|
"""
|
||||||
return self._keep_successful_logs.value
|
return self._keep_successful_logs.value
|
||||||
|
|
||||||
|
|
||||||
class ConfigOptions(StrictDictValidator):
|
class ConfigOptions(StrictDictValidator):
|
||||||
"""
|
|
||||||
ytdl-sub is configured using a ``config.yaml`` file.
|
|
||||||
|
|
||||||
The ``config.yaml`` is made up of two sections:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
configuration:
|
|
||||||
presets:
|
|
||||||
|
|
||||||
|
|
||||||
Note for Windows users, paths can be represented with ``C:/forward/slashes/like/linux``.
|
|
||||||
If you prefer to use a Windows backslash, note that it must have
|
|
||||||
``C:\\\\double\\\\bashslash\\\\paths`` in order to escape the backslash character. This is due
|
|
||||||
to it being a YAML escape character.
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
configuration:
|
|
||||||
dl_aliases:
|
|
||||||
mv: "--preset music_video"
|
|
||||||
u: "--download.url"
|
|
||||||
|
|
||||||
experimental:
|
|
||||||
enable_update_with_info_json: True
|
|
||||||
|
|
||||||
ffmpeg_path: "/usr/bin/ffmpeg"
|
|
||||||
ffprobe_path: "/usr/bin/ffprobe"
|
|
||||||
|
|
||||||
file_name_max_bytes: 255
|
|
||||||
lock_directory: "/tmp"
|
|
||||||
|
|
||||||
persist_logs:
|
|
||||||
keep_successful_logs: True
|
|
||||||
logs_directory: "/var/log/ytdl-sub-logs"
|
|
||||||
|
|
||||||
umask: "022"
|
|
||||||
working_directory: ".ytdl-sub-working-directory"
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
_optional_keys = {
|
_optional_keys = {
|
||||||
"working_directory",
|
"working_directory",
|
||||||
"umask",
|
"umask",
|
||||||
|
|
@ -208,8 +159,7 @@ class ConfigOptions(StrictDictValidator):
|
||||||
def working_directory(self) -> str:
|
def working_directory(self) -> str:
|
||||||
"""
|
"""
|
||||||
The directory to temporarily store downloaded files before moving them into their final
|
The directory to temporarily store downloaded files before moving them into their final
|
||||||
directory. Defaults to ``.ytdl-sub-working-directory``, created in the same directory
|
directory. (default ``./.ytdl-sub-working-directory``)
|
||||||
that ytdl-sub is invoked from.
|
|
||||||
"""
|
"""
|
||||||
# Expands tildas to actual paths, use native os sep
|
# Expands tildas to actual paths, use native os sep
|
||||||
return os.path.expanduser(self._working_directory.value.replace(posixpath.sep, os.sep))
|
return os.path.expanduser(self._working_directory.value.replace(posixpath.sep, os.sep))
|
||||||
|
|
@ -217,7 +167,7 @@ class ConfigOptions(StrictDictValidator):
|
||||||
@property
|
@property
|
||||||
def umask(self) -> Optional[str]:
|
def umask(self) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Umask in octal format to apply to every created file. Defaults to ``022``.
|
Umask in octal format to apply to every created file. (default ``022``)
|
||||||
"""
|
"""
|
||||||
return self._umask.value
|
return self._umask.value
|
||||||
|
|
||||||
|
|
@ -226,7 +176,7 @@ class ConfigOptions(StrictDictValidator):
|
||||||
"""
|
"""
|
||||||
.. _dl_aliases:
|
.. _dl_aliases:
|
||||||
|
|
||||||
Alias definitions to shorten :ref:`dl arguments <usage:Download Options>`. For example,
|
Alias definitions to shorten ``ytdl-sub dl`` arguments. For example,
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
|
@ -278,23 +228,23 @@ class ConfigOptions(StrictDictValidator):
|
||||||
The directory to temporarily store file locks, which prevents multiple instances
|
The directory to temporarily store file locks, which prevents multiple instances
|
||||||
of ``ytdl-sub`` from running. Note that file locks do not work on
|
of ``ytdl-sub`` from running. Note that file locks do not work on
|
||||||
network-mounted directories. Ensure that this directory resides on the host
|
network-mounted directories. Ensure that this directory resides on the host
|
||||||
machine. Defaults to ``/tmp``.
|
machine. (default ``/tmp``)
|
||||||
"""
|
"""
|
||||||
return self._lock_directory.value
|
return self._lock_directory.value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ffmpeg_path(self) -> str:
|
def ffmpeg_path(self) -> str:
|
||||||
"""
|
"""
|
||||||
Path to ffmpeg executable. Defaults to ``/usr/bin/ffmpeg`` for Linux,
|
Path to ffmpeg executable. (default ``/usr/bin/ffmpeg`` for Linux,
|
||||||
``./ffmpeg.exe`` in the same directory as ytdl-sub for Windows.
|
``./ffmpeg.exe`` in the same directory as ytdl-sub for Windows)
|
||||||
"""
|
"""
|
||||||
return self._ffmpeg_path.value
|
return self._ffmpeg_path.value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ffprobe_path(self) -> str:
|
def ffprobe_path(self) -> str:
|
||||||
"""
|
"""
|
||||||
Path to ffprobe executable. Defaults to ``/usr/bin/ffprobe`` for Linux,
|
Path to ffprobe executable. (default ``/usr/bin/ffprobe`` for Linux,
|
||||||
``./ffprobe.exe`` in the same directory as ytdl-sub for Windows.
|
``./ffprobe.exe`` in the same directory as ytdl-sub for Windows)
|
||||||
"""
|
"""
|
||||||
return self._ffprobe_path.value
|
return self._ffprobe_path.value
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,29 @@
|
||||||
from typing import Any, Dict, Iterable, Optional, Set, Type, TypeVar
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Iterable
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
from typing import Type
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
from ytdl_sub.entries.variables.override_variables import (
|
from ytdl_sub.entries.variables.override_variables import REQUIRED_OVERRIDE_VARIABLE_NAMES
|
||||||
REQUIRED_OVERRIDE_VARIABLE_NAMES,
|
from ytdl_sub.entries.variables.override_variables import OverrideHelpers
|
||||||
OverrideHelpers,
|
|
||||||
)
|
|
||||||
from ytdl_sub.script.parser import parse
|
from ytdl_sub.script.parser import parse
|
||||||
from ytdl_sub.script.script import Script
|
from ytdl_sub.script.script import Script
|
||||||
from ytdl_sub.script.types.function import BuiltInFunction
|
from ytdl_sub.script.types.function import BuiltInFunction
|
||||||
from ytdl_sub.script.types.resolvable import Resolvable, String
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
|
from ytdl_sub.script.types.resolvable import String
|
||||||
from ytdl_sub.script.types.syntax_tree import SyntaxTree
|
from ytdl_sub.script.types.syntax_tree import SyntaxTree
|
||||||
from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved
|
from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved
|
||||||
from ytdl_sub.utils.exceptions import (
|
from ytdl_sub.utils.exceptions import InvalidVariableNameException
|
||||||
InvalidVariableNameException,
|
from ytdl_sub.utils.exceptions import StringFormattingException
|
||||||
StringFormattingException,
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
ValidationException,
|
|
||||||
)
|
|
||||||
from ytdl_sub.utils.script import ScriptUtils
|
from ytdl_sub.utils.script import ScriptUtils
|
||||||
from ytdl_sub.utils.scriptable import Scriptable
|
from ytdl_sub.utils.scriptable import Scriptable
|
||||||
from ytdl_sub.validators.string_formatter_validators import (
|
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
||||||
StringFormatterValidator,
|
from ytdl_sub.validators.string_formatter_validators import UnstructuredDictFormatterValidator
|
||||||
UnstructuredDictFormatterValidator,
|
|
||||||
)
|
|
||||||
|
|
||||||
ExpectedT = TypeVar("ExpectedT")
|
ExpectedT = TypeVar("ExpectedT")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,20 @@
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC
|
||||||
|
from abc import abstractmethod
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from typing import Dict, Generic, List, Optional, Tuple, Type
|
from typing import Dict
|
||||||
|
from typing import Generic
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.config.validators.options import OptionsValidatorT, ToggleableOptionsDictValidator
|
from ytdl_sub.config.validators.options import OptionsValidatorT
|
||||||
|
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.utils.file_handler import FileMetadata
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
from ytdl_sub.ytdl_additions.enhanced_download_archive import (
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import DownloadArchiver
|
||||||
DownloadArchiver,
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
||||||
EnhancedDownloadArchive,
|
|
||||||
)
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
from typing import Dict, List, Optional, Tuple, Type
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin, SplitPlugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
|
from ytdl_sub.config.plugin.plugin import SplitPlugin
|
||||||
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
||||||
from ytdl_sub.config.validators.options import OptionsValidator
|
from ytdl_sub.config.validators.options import OptionsValidator
|
||||||
from ytdl_sub.downloaders.url.downloader import (
|
from ytdl_sub.downloaders.url.downloader import UrlDownloaderCollectionVariablePlugin
|
||||||
UrlDownloaderCollectionVariablePlugin,
|
from ytdl_sub.downloaders.url.downloader import UrlDownloaderThumbnailPlugin
|
||||||
UrlDownloaderThumbnailPlugin,
|
|
||||||
)
|
|
||||||
from ytdl_sub.plugins.audio_extract import AudioExtractPlugin
|
from ytdl_sub.plugins.audio_extract import AudioExtractPlugin
|
||||||
from ytdl_sub.plugins.chapters import ChaptersPlugin
|
from ytdl_sub.plugins.chapters import ChaptersPlugin
|
||||||
from ytdl_sub.plugins.date_range import DateRangePlugin
|
from ytdl_sub.plugins.date_range import DateRangePlugin
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
from typing import Iterable, List, Optional, Set, Tuple, Type
|
from typing import Iterable
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.validators.options import OptionsValidator, OptionsValidatorT
|
from ytdl_sub.config.validators.options import OptionsValidator
|
||||||
|
from ytdl_sub.config.validators.options import OptionsValidatorT
|
||||||
|
|
||||||
|
|
||||||
class PresetPlugins:
|
class PresetPlugins:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
import copy
|
import copy
|
||||||
from typing import Any, Dict, List, Set
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from mergedeep import mergedeep
|
from mergedeep import mergedeep
|
||||||
|
|
||||||
|
|
@ -7,14 +10,17 @@ from ytdl_sub.config.config_validator import ConfigValidator
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.config.plugin.plugin_mapping import PluginMapping
|
from ytdl_sub.config.plugin.plugin_mapping import PluginMapping
|
||||||
from ytdl_sub.config.plugin.preset_plugins import PresetPlugins
|
from ytdl_sub.config.plugin.preset_plugins import PresetPlugins
|
||||||
from ytdl_sub.config.preset_options import OutputOptions, YTDLOptions
|
from ytdl_sub.config.preset_options import OutputOptions
|
||||||
|
from ytdl_sub.config.preset_options import YTDLOptions
|
||||||
from ytdl_sub.downloaders.url.validators import MultiUrlValidator
|
from ytdl_sub.downloaders.url.validators import MultiUrlValidator
|
||||||
from ytdl_sub.prebuilt_presets import PREBUILT_PRESET_NAMES, PUBLISHED_PRESET_NAMES
|
from ytdl_sub.prebuilt_presets import PREBUILT_PRESET_NAMES
|
||||||
|
from ytdl_sub.prebuilt_presets import PUBLISHED_PRESET_NAMES
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
from ytdl_sub.utils.yaml import dump_yaml
|
from ytdl_sub.utils.yaml import dump_yaml
|
||||||
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
||||||
from ytdl_sub.validators.validators import StringListValidator, validation_exception
|
from ytdl_sub.validators.validators import StringListValidator
|
||||||
|
from ytdl_sub.validators.validators import validation_exception
|
||||||
|
|
||||||
PRESET_KEYS = {
|
PRESET_KEYS = {
|
||||||
"preset",
|
"preset",
|
||||||
|
|
@ -49,12 +55,6 @@ class _PresetShell(StrictDictValidator):
|
||||||
|
|
||||||
|
|
||||||
class Preset(_PresetShell):
|
class Preset(_PresetShell):
|
||||||
"""
|
|
||||||
Custom presets are defined in this section. Refer to the
|
|
||||||
:ref:`Getting Started Guide<guides/getting_started/first_config:Basic Configuration>`
|
|
||||||
on how to configure.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def preset_partial_validate(cls, config: ConfigValidator, name: str, value: Any) -> None:
|
def preset_partial_validate(cls, config: ConfigValidator, name: str, value: Any) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,24 @@
|
||||||
from typing import Any, Dict, Optional, Set
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.config.defaults import DEFAULT_DOWNLOAD_ARCHIVE_NAME
|
from ytdl_sub.config.defaults import DEFAULT_DOWNLOAD_ARCHIVE_NAME
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
||||||
from ytdl_sub.config.validators.options import OptionsDictValidator
|
from ytdl_sub.config.validators.options import OptionsDictValidator
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES as v
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES as v
|
||||||
from ytdl_sub.utils.exceptions import SubscriptionPermissionError, ValidationException
|
from ytdl_sub.utils.exceptions import SubscriptionPermissionError
|
||||||
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
from ytdl_sub.utils.file_handler import FileHandler
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
from ytdl_sub.validators.file_path_validators import (
|
from ytdl_sub.validators.file_path_validators import OverridesStringFormatterFilePathValidator
|
||||||
OverridesStringFormatterFilePathValidator,
|
from ytdl_sub.validators.file_path_validators import StringFormatterFileNameValidator
|
||||||
StringFormatterFileNameValidator,
|
|
||||||
)
|
|
||||||
from ytdl_sub.validators.string_datetime import StringDatetimeValidator
|
from ytdl_sub.validators.string_datetime import StringDatetimeValidator
|
||||||
|
from ytdl_sub.validators.string_formatter_validators import OverridesIntegerFormatterValidator
|
||||||
|
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
|
||||||
|
from ytdl_sub.validators.string_formatter_validators import StandardizedDateValidator
|
||||||
|
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import (
|
from ytdl_sub.validators.string_formatter_validators import (
|
||||||
OverridesIntegerFormatterValidator,
|
|
||||||
OverridesStringFormatterValidator,
|
|
||||||
StandardizedDateValidator,
|
|
||||||
StringFormatterValidator,
|
|
||||||
UnstructuredOverridesDictFormatterValidator,
|
UnstructuredOverridesDictFormatterValidator,
|
||||||
)
|
)
|
||||||
from ytdl_sub.validators.validators import BoolValidator
|
from ytdl_sub.validators.validators import BoolValidator
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from typing import Dict, Set, TypeVar
|
from typing import Dict
|
||||||
|
from typing import Set
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
|
|
@ -59,9 +61,9 @@ class ToggleableOptionsDictValidator(OptionsDictValidator):
|
||||||
_optional_keys = {"enable"}
|
_optional_keys = {"enable"}
|
||||||
|
|
||||||
def __init__(self, name, value):
|
def __init__(self, name, value):
|
||||||
assert "enable" in self._optional_keys, (
|
assert (
|
||||||
f"{self.__class__.__name__} does not have enable as an optional field"
|
"enable" in self._optional_keys
|
||||||
)
|
), f"{self.__class__.__name__} does not have enable as an optional field"
|
||||||
super().__init__(name, value)
|
super().__init__(name, value)
|
||||||
|
|
||||||
self._enable = self._validate_key(
|
self._enable = self._validate_key(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
from typing import Dict, List, Optional, Set
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.config.plugin.plugin_mapping import PluginMapping
|
from ytdl_sub.config.plugin.plugin_mapping import PluginMapping
|
||||||
|
|
@ -7,7 +9,8 @@ from ytdl_sub.config.plugin.preset_plugins import PresetPlugins
|
||||||
from ytdl_sub.config.preset_options import OutputOptions
|
from ytdl_sub.config.preset_options import OutputOptions
|
||||||
from ytdl_sub.config.validators.options import OptionsValidator
|
from ytdl_sub.config.validators.options import OptionsValidator
|
||||||
from ytdl_sub.downloaders.url.validators import MultiUrlValidator
|
from ytdl_sub.downloaders.url.validators import MultiUrlValidator
|
||||||
from ytdl_sub.entries.script.variable_definitions import UNRESOLVED_VARIABLES, VARIABLES
|
from ytdl_sub.entries.script.variable_definitions import UNRESOLVED_VARIABLES
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
from ytdl_sub.script.script import Script
|
from ytdl_sub.script.script import Script
|
||||||
from ytdl_sub.script.utils.name_validation import is_function
|
from ytdl_sub.script.utils.name_validation import is_function
|
||||||
from ytdl_sub.utils.script import ScriptUtils
|
from ytdl_sub.utils.script import ScriptUtils
|
||||||
|
|
@ -35,21 +38,6 @@ class ResolutionLevel:
|
||||||
return "internal"
|
return "internal"
|
||||||
raise ValueError("Invalid resolution level")
|
raise ValueError("Invalid resolution level")
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def level_number(cls, resolution_arg: str) -> int:
|
|
||||||
"""
|
|
||||||
Numeric resolution level
|
|
||||||
"""
|
|
||||||
if resolution_arg in ("0", "original"):
|
|
||||||
return 0
|
|
||||||
if resolution_arg in ("1", "fill"):
|
|
||||||
return 1
|
|
||||||
if resolution_arg in ("2", "resolve"):
|
|
||||||
return 2
|
|
||||||
if resolution_arg in ("3", "internal"):
|
|
||||||
return 3
|
|
||||||
raise ValueError("Invalid resolution level")
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def all(cls) -> List[int]:
|
def all(cls) -> List[int]:
|
||||||
"""
|
"""
|
||||||
|
|
@ -59,6 +47,7 @@ class ResolutionLevel:
|
||||||
|
|
||||||
|
|
||||||
class VariableValidation:
|
class VariableValidation:
|
||||||
|
|
||||||
def _get_resolve_partial_filter(self) -> Set[str]:
|
def _get_resolve_partial_filter(self) -> Set[str]:
|
||||||
# Exclude sanitized variables from partial validation. This lessens the work
|
# Exclude sanitized variables from partial validation. This lessens the work
|
||||||
# and prevents double-evaluation, which can lead to bad behavior like double-prints.
|
# and prevents double-evaluation, which can lead to bad behavior like double-prints.
|
||||||
|
|
@ -68,7 +57,7 @@ class VariableValidation:
|
||||||
if name not in self.unresolved_variables and not name.endswith("_sanitized")
|
if name not in self.unresolved_variables and not name.endswith("_sanitized")
|
||||||
}
|
}
|
||||||
|
|
||||||
def _apply_resolution_level(self, mocks: Optional[Dict[str, str]]) -> None:
|
def _apply_resolution_level(self) -> None:
|
||||||
if self._resolution_level == ResolutionLevel.FILL:
|
if self._resolution_level == ResolutionLevel.FILL:
|
||||||
self.unresolved_variables |= VARIABLES.variable_names(include_sanitized=True)
|
self.unresolved_variables |= VARIABLES.variable_names(include_sanitized=True)
|
||||||
# Only partial resolve definitions that are already resolved
|
# Only partial resolve definitions that are already resolved
|
||||||
|
|
@ -86,16 +75,6 @@ class VariableValidation:
|
||||||
else:
|
else:
|
||||||
raise ValueError("Invalid resolution level for validation")
|
raise ValueError("Invalid resolution level for validation")
|
||||||
|
|
||||||
if mocks is not None:
|
|
||||||
for mock_name in mocks.keys():
|
|
||||||
if mock_name in self.unresolved_variables:
|
|
||||||
self.unresolved_variables.remove(mock_name)
|
|
||||||
|
|
||||||
self.script.add(
|
|
||||||
variables=mocks,
|
|
||||||
unresolvable=self.unresolved_variables,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.script = self.script.resolve_partial(
|
self.script = self.script.resolve_partial(
|
||||||
unresolvable=self.unresolved_variables,
|
unresolvable=self.unresolved_variables,
|
||||||
output_filter=self._get_resolve_partial_filter(),
|
output_filter=self._get_resolve_partial_filter(),
|
||||||
|
|
@ -108,7 +87,6 @@ class VariableValidation:
|
||||||
output_options: OutputOptions,
|
output_options: OutputOptions,
|
||||||
plugins: PresetPlugins,
|
plugins: PresetPlugins,
|
||||||
resolution_level: int = ResolutionLevel.RESOLVE,
|
resolution_level: int = ResolutionLevel.RESOLVE,
|
||||||
mocks: Optional[Dict[str, str]] = None,
|
|
||||||
):
|
):
|
||||||
self.overrides = overrides
|
self.overrides = overrides
|
||||||
self.downloader_options = downloader_options
|
self.downloader_options = downloader_options
|
||||||
|
|
@ -126,7 +104,8 @@ class VariableValidation:
|
||||||
additional_options=[self.output_options, self.downloader_options]
|
additional_options=[self.output_options, self.downloader_options]
|
||||||
)
|
)
|
||||||
self._resolution_level = resolution_level
|
self._resolution_level = resolution_level
|
||||||
self._apply_resolution_level(mocks=mocks)
|
|
||||||
|
self._apply_resolution_level()
|
||||||
|
|
||||||
def _add_runtime_variables(self, plugin_op: PluginOperation, options: OptionsValidator) -> None:
|
def _add_runtime_variables(self, plugin_op: PluginOperation, options: OptionsValidator) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
@ -139,20 +118,6 @@ class VariableValidation:
|
||||||
|
|
||||||
self.unresolved_runtime_variables -= added_variables | modified_variables
|
self.unresolved_runtime_variables -= added_variables | modified_variables
|
||||||
|
|
||||||
def _output_override_variables(self) -> Dict:
|
|
||||||
output = {}
|
|
||||||
for name in self.overrides.keys:
|
|
||||||
value = self.script.definition_of(name)
|
|
||||||
if name in self.script.function_names:
|
|
||||||
# Keep custom functions as-is
|
|
||||||
output[name] = self.overrides.dict_with_format_strings[name]
|
|
||||||
elif resolved := value.maybe_resolvable:
|
|
||||||
output[name] = resolved.native
|
|
||||||
else:
|
|
||||||
output[name] = ScriptUtils.to_native_script(value)
|
|
||||||
|
|
||||||
return output
|
|
||||||
|
|
||||||
def ensure_proper_usage(self, partial_resolve_formatters: bool = False) -> Dict:
|
def ensure_proper_usage(self, partial_resolve_formatters: bool = False) -> Dict:
|
||||||
"""
|
"""
|
||||||
Validate variables resolve as plugins are executed, and return
|
Validate variables resolve as plugins are executed, and return
|
||||||
|
|
@ -213,6 +178,19 @@ class VariableValidation:
|
||||||
if url_output["url"]:
|
if url_output["url"]:
|
||||||
resolved_subscription["download"].append(url_output)
|
resolved_subscription["download"].append(url_output)
|
||||||
|
|
||||||
resolved_subscription["overrides"] = self._output_override_variables()
|
# TODO: make function
|
||||||
|
resolved_subscription["overrides"] = {}
|
||||||
|
for name in self.overrides.keys:
|
||||||
|
value = self.script.definition_of(name)
|
||||||
|
if name in self.script.function_names:
|
||||||
|
# Keep custom functions as-is
|
||||||
|
resolved_subscription["overrides"][name] = self.overrides.dict_with_format_strings[
|
||||||
|
name
|
||||||
|
]
|
||||||
|
elif resolved := value.maybe_resolvable:
|
||||||
|
resolved_subscription["overrides"][name] = resolved.native
|
||||||
|
else:
|
||||||
|
resolved_subscription["overrides"][name] = ScriptUtils.to_native_script(value)
|
||||||
|
|
||||||
|
assert not self.unresolved_runtime_variables
|
||||||
return resolved_subscription
|
return resolved_subscription
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Iterable, List, Optional
|
from typing import Dict
|
||||||
|
from typing import Iterable
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.config.validators.options import OptionsDictValidator
|
from ytdl_sub.config.validators.options import OptionsDictValidator
|
||||||
from ytdl_sub.downloaders.source_plugin import SourcePlugin
|
from ytdl_sub.downloaders.source_plugin import SourcePlugin
|
||||||
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.entries.script.variable_definitions import (
|
from ytdl_sub.entries.script.variable_definitions import VARIABLE_SCRIPTS
|
||||||
VARIABLE_SCRIPTS,
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
VARIABLES,
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
VariableDefinitions,
|
|
||||||
)
|
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
from ytdl_sub.utils.file_handler import FileHandler, get_file_extension
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
from ytdl_sub.ytdl_additions.enhanced_download_archive import (
|
from ytdl_sub.utils.file_handler import get_file_extension
|
||||||
DownloadMapping,
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import DownloadMapping
|
||||||
EnhancedDownloadArchive,
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
||||||
)
|
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,16 @@
|
||||||
import abc
|
import abc
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from typing import Dict, Generic, Iterable, List, Optional, Type, final
|
from typing import Dict
|
||||||
|
from typing import Generic
|
||||||
|
from typing import Iterable
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Type
|
||||||
|
from typing import final
|
||||||
|
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.config.plugin.plugin import BasePlugin, Plugin
|
from ytdl_sub.config.plugin.plugin import BasePlugin
|
||||||
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.validators.options import OptionsValidatorT
|
from ytdl_sub.config.validators.options import OptionsValidatorT
|
||||||
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,33 @@
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Iterable, Iterator, List, Optional, Set, Tuple
|
from typing import Dict
|
||||||
|
from typing import Iterable
|
||||||
|
from typing import Iterator
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from yt_dlp.utils import RejectedVideoReached
|
from yt_dlp.utils import RejectedVideoReached
|
||||||
|
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.downloaders.source_plugin import SourcePlugin, SourcePluginExtension
|
from ytdl_sub.downloaders.source_plugin import SourcePlugin
|
||||||
from ytdl_sub.downloaders.url.validators import (
|
from ytdl_sub.downloaders.source_plugin import SourcePluginExtension
|
||||||
MultiUrlValidator,
|
from ytdl_sub.downloaders.url.validators import MultiUrlValidator
|
||||||
UrlThumbnailListValidator,
|
from ytdl_sub.downloaders.url.validators import UrlThumbnailListValidator
|
||||||
UrlValidator,
|
from ytdl_sub.downloaders.url.validators import UrlValidator
|
||||||
)
|
|
||||||
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
||||||
from ytdl_sub.downloaders.ytdlp import YTDLP
|
from ytdl_sub.downloaders.ytdlp import YTDLP
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.entries.entry_parent import EntryParent
|
from ytdl_sub.entries.entry_parent import EntryParent
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
from ytdl_sub.utils.file_handler import FileHandler
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
from ytdl_sub.utils.thumbnail import (
|
from ytdl_sub.utils.thumbnail import ThumbnailTypes
|
||||||
ThumbnailTypes,
|
from ytdl_sub.utils.thumbnail import download_and_convert_url_thumbnail
|
||||||
download_and_convert_url_thumbnail,
|
from ytdl_sub.utils.thumbnail import try_convert_download_thumbnail
|
||||||
try_convert_download_thumbnail,
|
|
||||||
)
|
|
||||||
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
@ -93,6 +97,7 @@ class UrlDownloaderThumbnailPlugin(UrlDownloaderBasePluginExtension):
|
||||||
|
|
||||||
# If latest entry, always update the thumbnail on each entry
|
# If latest entry, always update the thumbnail on each entry
|
||||||
if thumbnail_id == ThumbnailTypes.LATEST_ENTRY:
|
if thumbnail_id == ThumbnailTypes.LATEST_ENTRY:
|
||||||
|
|
||||||
# always save in dry-run even if it doesn't exist...
|
# always save in dry-run even if it doesn't exist...
|
||||||
if self.is_dry_run or entry.is_thumbnail_downloaded():
|
if self.is_dry_run or entry.is_thumbnail_downloaded():
|
||||||
self.save_file(
|
self.save_file(
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,18 @@
|
||||||
from typing import Any, Dict, List, Optional, Set
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
||||||
from ytdl_sub.config.preset_options import YTDLOptions
|
from ytdl_sub.config.preset_options import YTDLOptions
|
||||||
from ytdl_sub.config.validators.options import OptionsValidator
|
from ytdl_sub.config.validators.options import OptionsValidator
|
||||||
from ytdl_sub.script.parser import parse
|
from ytdl_sub.script.parser import parse
|
||||||
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import (
|
from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator
|
||||||
DictFormatterValidator,
|
from ytdl_sub.validators.string_formatter_validators import OverridesBooleanFormatterValidator
|
||||||
OverridesBooleanFormatterValidator,
|
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
|
||||||
OverridesStringFormatterValidator,
|
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
||||||
StringFormatterValidator,
|
|
||||||
)
|
|
||||||
from ytdl_sub.validators.validators import ListValidator
|
from ytdl_sub.validators.validators import ListValidator
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import copy
|
import copy
|
||||||
from typing import Dict, Optional
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import mergedeep
|
import mergedeep
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,15 @@ import os
|
||||||
import time
|
import time
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Callable, Dict, List, Optional
|
from typing import Callable
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import yt_dlp as ytdl
|
import yt_dlp as ytdl
|
||||||
from yt_dlp.utils import ExistingVideoReached, MaxDownloadsReached, RejectedVideoReached
|
from yt_dlp.utils import ExistingVideoReached
|
||||||
|
from yt_dlp.utils import MaxDownloadsReached
|
||||||
|
from yt_dlp.utils import RejectedVideoReached
|
||||||
|
|
||||||
from ytdl_sub.thread.log_entries_downloaded_listener import LogEntriesDownloadedListener
|
from ytdl_sub.thread.log_entries_downloaded_listener import LogEntriesDownloadedListener
|
||||||
from ytdl_sub.utils.exceptions import FileNotDownloadedException
|
from ytdl_sub.utils.exceptions import FileNotDownloadedException
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,18 @@
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, Optional, Type, TypeVar, final
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Type
|
||||||
|
from typing import TypeVar
|
||||||
|
from typing import final
|
||||||
|
|
||||||
from yt_dlp.utils import LazyList, sanitize_filename
|
from yt_dlp.utils import LazyList
|
||||||
|
from yt_dlp.utils import sanitize_filename
|
||||||
|
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,24 @@ import copy
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, Optional, Type, TypeVar, final
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Type
|
||||||
|
from typing import TypeVar
|
||||||
|
from typing import final
|
||||||
|
|
||||||
from ytdl_sub.entries.base_entry import BaseEntry
|
from ytdl_sub.entries.base_entry import BaseEntry
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
from ytdl_sub.entries.script.variable_types import ArrayVariable, StringVariable, Variable
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
|
from ytdl_sub.entries.script.variable_types import ArrayVariable
|
||||||
|
from ytdl_sub.entries.script.variable_types import StringVariable
|
||||||
|
from ytdl_sub.entries.script.variable_types import Variable
|
||||||
from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved
|
from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved
|
||||||
from ytdl_sub.utils.script import ScriptUtils
|
from ytdl_sub.utils.script import ScriptUtils
|
||||||
from ytdl_sub.utils.scriptable import Scriptable
|
from ytdl_sub.utils.scriptable import Scriptable
|
||||||
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_EXTS, VIDEO_CODEC_EXTS
|
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_EXTS
|
||||||
|
from ytdl_sub.validators.audo_codec_validator import VIDEO_CODEC_EXTS
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
import math
|
import math
|
||||||
from typing import Any, Dict, List, Optional, Set
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from ytdl_sub.entries.base_entry import BaseEntry, BaseEntryT
|
from ytdl_sub.entries.base_entry import BaseEntry
|
||||||
|
from ytdl_sub.entries.base_entry import BaseEntryT
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
from ytdl_sub.entries.script.variable_types import MetadataVariable
|
from ytdl_sub.entries.script.variable_types import MetadataVariable
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ from yt_dlp.utils import sanitize_filename
|
||||||
|
|
||||||
from ytdl_sub.script.functions import Functions
|
from ytdl_sub.script.functions import Functions
|
||||||
from ytdl_sub.script.types.map import Map
|
from ytdl_sub.script.types.map import Map
|
||||||
from ytdl_sub.script.types.resolvable import AnyArgument, Integer, ReturnableArgument, String
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
|
from ytdl_sub.script.types.resolvable import ReturnableArgument
|
||||||
|
from ytdl_sub.script.types.resolvable import String
|
||||||
from ytdl_sub.script.utils.exceptions import RuntimeException
|
from ytdl_sub.script.utils.exceptions import RuntimeException
|
||||||
from ytdl_sub.utils.file_path import FilePathTruncater
|
from ytdl_sub.utils.file_path import FilePathTruncater
|
||||||
|
|
||||||
|
|
@ -46,12 +49,12 @@ class CustomFunctions:
|
||||||
return String(FilePathTruncater.maybe_truncate_file_path(filepath.value))
|
return String(FilePathTruncater.maybe_truncate_file_path(filepath.value))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def sanitize(*value: AnyArgument) -> String:
|
def sanitize(value: AnyArgument) -> String:
|
||||||
"""
|
"""
|
||||||
Sanitize a string using yt-dlp's ``sanitize_filename`` method to ensure it's safe to use
|
Sanitize a string using yt-dlp's ``sanitize_filename`` method to ensure it's safe to use
|
||||||
for file/directory names on any OS.
|
for file/directory names on any OS.
|
||||||
"""
|
"""
|
||||||
return String("".join(sanitize_filename(str(val)) for val in value))
|
return String(sanitize_filename(str(value)))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def sanitize_plex_episode(string: String) -> String:
|
def sanitize_plex_episode(string: String) -> String:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from functools import cache, cached_property
|
from functools import cache
|
||||||
from typing import Dict, Optional, Set
|
from functools import cached_property
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.entries.script.custom_functions import CustomFunctions
|
from ytdl_sub.entries.script.custom_functions import CustomFunctions
|
||||||
from ytdl_sub.entries.script.variable_types import (
|
from ytdl_sub.entries.script.variable_types import ArrayMetadataVariable
|
||||||
ArrayMetadataVariable,
|
from ytdl_sub.entries.script.variable_types import IntegerMetadataVariable
|
||||||
IntegerMetadataVariable,
|
from ytdl_sub.entries.script.variable_types import IntegerVariable
|
||||||
IntegerVariable,
|
from ytdl_sub.entries.script.variable_types import MapMetadataVariable
|
||||||
MapMetadataVariable,
|
from ytdl_sub.entries.script.variable_types import MapVariable
|
||||||
MapVariable,
|
from ytdl_sub.entries.script.variable_types import MetadataVariable
|
||||||
MetadataVariable,
|
from ytdl_sub.entries.script.variable_types import StringDateMetadataVariable
|
||||||
StringDateMetadataVariable,
|
from ytdl_sub.entries.script.variable_types import StringDateVariable
|
||||||
StringDateVariable,
|
from ytdl_sub.entries.script.variable_types import StringMetadataVariable
|
||||||
StringMetadataVariable,
|
from ytdl_sub.entries.script.variable_types import StringVariable
|
||||||
StringVariable,
|
from ytdl_sub.entries.script.variable_types import Variable
|
||||||
Variable,
|
|
||||||
)
|
|
||||||
|
|
||||||
# This file contains mixins to a BaseEntry subclass. Ignore pylint's "no kwargs member" suggestion
|
# This file contains mixins to a BaseEntry subclass. Ignore pylint's "no kwargs member" suggestion
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
|
|
@ -1215,14 +1215,6 @@ class VariableDefinitions(
|
||||||
VARIABLES.entry_metadata,
|
VARIABLES.entry_metadata,
|
||||||
} | self.injected_variables()
|
} | self.injected_variables()
|
||||||
|
|
||||||
def get(self, name: str) -> Optional[Variable]:
|
|
||||||
"""
|
|
||||||
Returns the variable attribute if it exists. None otherwise.
|
|
||||||
"""
|
|
||||||
if not hasattr(self, name):
|
|
||||||
return None
|
|
||||||
return getattr(self, name)
|
|
||||||
|
|
||||||
|
|
||||||
# Singletons to use externally
|
# Singletons to use externally
|
||||||
VARIABLES: VariableDefinitions = VariableDefinitions()
|
VARIABLES: VariableDefinitions = VariableDefinitions()
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,17 @@
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC
|
||||||
|
from abc import abstractmethod
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Dict, List, Optional, Type, TypeVar
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Type
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
from ytdl_sub.script.types.array import Array
|
from ytdl_sub.script.types.array import Array
|
||||||
from ytdl_sub.script.types.map import Map
|
from ytdl_sub.script.types.map import Map
|
||||||
from ytdl_sub.script.types.resolvable import Boolean, Integer, String
|
from ytdl_sub.script.types.resolvable import Boolean
|
||||||
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
|
from ytdl_sub.script.types.resolvable import String
|
||||||
|
|
||||||
ENTRY_METADATA_VARIABLE_NAME = "entry_metadata"
|
ENTRY_METADATA_VARIABLE_NAME = "entry_metadata"
|
||||||
PLAYLIST_METADATA_VARIABLE_NAME = "playlist_metadata"
|
PLAYLIST_METADATA_VARIABLE_NAME = "playlist_metadata"
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
from typing import Dict, Set
|
from typing import Dict
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.entries.script.function_scripts import CUSTOM_FUNCTION_SCRIPTS
|
from ytdl_sub.entries.script.function_scripts import CUSTOM_FUNCTION_SCRIPTS
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLE_SCRIPTS
|
from ytdl_sub.entries.script.variable_definitions import VARIABLE_SCRIPTS
|
||||||
from ytdl_sub.entries.script.variable_types import (
|
from ytdl_sub.entries.script.variable_types import ArrayVariable
|
||||||
ArrayVariable,
|
from ytdl_sub.entries.script.variable_types import BooleanVariable
|
||||||
BooleanVariable,
|
from ytdl_sub.entries.script.variable_types import MapVariable
|
||||||
MapVariable,
|
from ytdl_sub.entries.script.variable_types import StringVariable
|
||||||
StringVariable,
|
from ytdl_sub.entries.script.variable_types import Variable
|
||||||
Variable,
|
|
||||||
)
|
|
||||||
from ytdl_sub.script.functions import Functions
|
from ytdl_sub.script.functions import Functions
|
||||||
from ytdl_sub.script.utils.name_validation import is_valid_name
|
from ytdl_sub.script.utils.name_validation import is_valid_name
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from ytdl_sub.cli.parsers.main import parser
|
from ytdl_sub.cli.parsers.main import parser
|
||||||
from ytdl_sub.utils.logger import Logger, LoggerLevels
|
from ytdl_sub.utils.logger import Logger
|
||||||
|
|
||||||
|
|
||||||
def _main() -> int:
|
def _main() -> int:
|
||||||
|
|
@ -10,11 +10,6 @@ def _main() -> int:
|
||||||
args, _ = parser.parse_known_args()
|
args, _ = parser.parse_known_args()
|
||||||
Logger.set_log_level(log_level_name=args.ytdl_sub_log_level)
|
Logger.set_log_level(log_level_name=args.ytdl_sub_log_level)
|
||||||
|
|
||||||
# Suppress all logs during inspection since the output of the subcommand itself
|
|
||||||
# is all that is necessary
|
|
||||||
if args.subparser == "inspect":
|
|
||||||
Logger.set_log_level(log_level_name=LoggerLevels.QUIET.name)
|
|
||||||
|
|
||||||
# pylint: disable=import-outside-toplevel
|
# pylint: disable=import-outside-toplevel
|
||||||
import ytdl_sub.cli.entrypoint
|
import ytdl_sub.cli.entrypoint
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,21 @@
|
||||||
import os.path
|
import os.path
|
||||||
from typing import Any, Dict, Optional, Set
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
||||||
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
||||||
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
from ytdl_sub.utils.exceptions import FileNotDownloadedException
|
from ytdl_sub.utils.exceptions import FileNotDownloadedException
|
||||||
from ytdl_sub.utils.file_handler import FileMetadata
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
from ytdl_sub.validators.audo_codec_validator import (
|
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_EXTS
|
||||||
AUDIO_CODEC_EXTS,
|
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_TYPES_EXTENSION_MAPPING
|
||||||
AUDIO_CODEC_TYPES_EXTENSION_MAPPING,
|
from ytdl_sub.validators.audo_codec_validator import AudioTypeValidator
|
||||||
AudioTypeValidator,
|
|
||||||
)
|
|
||||||
from ytdl_sub.validators.validators import FloatValidator
|
from ytdl_sub.validators.validators import FloatValidator
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,26 @@
|
||||||
import collections
|
import collections
|
||||||
import re
|
import re
|
||||||
from typing import Dict, List, Optional, Set
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
||||||
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
||||||
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
||||||
from ytdl_sub.entries.entry import (
|
from ytdl_sub.entries.entry import Entry
|
||||||
Entry,
|
from ytdl_sub.entries.entry import ytdl_sub_chapters_from_comments
|
||||||
ytdl_sub_chapters_from_comments,
|
from ytdl_sub.entries.entry import ytdl_sub_split_by_chapters_parent_uid
|
||||||
ytdl_sub_split_by_chapters_parent_uid,
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
)
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
|
||||||
from ytdl_sub.utils.chapters import Chapters
|
from ytdl_sub.utils.chapters import Chapters
|
||||||
from ytdl_sub.utils.ffmpeg import set_ffmpeg_metadata_chapters
|
from ytdl_sub.utils.ffmpeg import set_ffmpeg_metadata_chapters
|
||||||
from ytdl_sub.utils.file_handler import FileMetadata
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
from ytdl_sub.validators.regex_validator import RegexListValidator
|
from ytdl_sub.validators.regex_validator import RegexListValidator
|
||||||
from ytdl_sub.validators.string_select_validator import StringSelectValidator
|
from ytdl_sub.validators.string_select_validator import StringSelectValidator
|
||||||
from ytdl_sub.validators.validators import BoolValidator, ListValidator
|
from ytdl_sub.validators.validators import BoolValidator
|
||||||
|
from ytdl_sub.validators.validators import ListValidator
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
from typing import List, Optional, Set, Tuple
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import List, Optional
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import mediafile
|
import mediafile
|
||||||
|
|
||||||
|
|
@ -6,7 +7,8 @@ from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.validators.options import OptionsValidator
|
from ytdl_sub.config.validators.options import OptionsValidator
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.utils.ffmpeg import FFMPEG
|
from ytdl_sub.utils.ffmpeg import FFMPEG
|
||||||
from ytdl_sub.utils.file_handler import FileHandler, FileMetadata
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_EXTS
|
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_EXTS
|
||||||
from ytdl_sub.validators.string_formatter_validators import OverridesBooleanFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import OverridesBooleanFormatterValidator
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,22 @@
|
||||||
import os
|
import os
|
||||||
from subprocess import CalledProcessError
|
from subprocess import CalledProcessError
|
||||||
from typing import Any, Dict, Optional, Set
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
||||||
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
from ytdl_sub.utils.exceptions import FileNotDownloadedException, ValidationException
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
|
from ytdl_sub.utils.exceptions import FileNotDownloadedException
|
||||||
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
from ytdl_sub.utils.ffmpeg import FFMPEG
|
from ytdl_sub.utils.ffmpeg import FFMPEG
|
||||||
from ytdl_sub.utils.file_handler import FileHandler, FileMetadata
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
from ytdl_sub.validators.audo_codec_validator import FileTypeValidator
|
from ytdl_sub.validators.audo_codec_validator import FileTypeValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
|
||||||
from ytdl_sub.validators.string_select_validator import StringSelectValidator
|
from ytdl_sub.validators.string_select_validator import StringSelectValidator
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import Dict, Optional
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import Dict, Optional
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import Dict, Optional
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.validators.options import OptionsValidator
|
from ytdl_sub.config.validators.options import OptionsValidator
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import copy
|
import copy
|
||||||
from typing import Any, List, Tuple
|
from typing import Any
|
||||||
|
from typing import List
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,22 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, Dict, List
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
|
||||||
import mediafile
|
import mediafile
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.validators.options import OptionsDictValidator
|
from ytdl_sub.config.validators.options import OptionsDictValidator
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
from ytdl_sub.utils.file_handler import FileMetadata
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_EXTS
|
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_EXTS
|
||||||
from ytdl_sub.validators.string_formatter_validators import (
|
from ytdl_sub.validators.string_formatter_validators import ListFormatterValidator
|
||||||
ListFormatterValidator,
|
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
||||||
StringFormatterValidator,
|
|
||||||
)
|
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
||||||
|
|
@ -146,7 +147,8 @@ class MusicTagsPlugin(Plugin[MusicTagsOptions]):
|
||||||
else:
|
else:
|
||||||
if len(tag_value) > 1:
|
if len(tag_value) > 1:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Music tag '%s' does not support lists. Only setting the first element",
|
"Music tag '%s' does not support lists. "
|
||||||
|
"Only setting the first element",
|
||||||
tag_name,
|
tag_name,
|
||||||
)
|
)
|
||||||
setattr(audio_file, tag_name, tag_value[0])
|
setattr(audio_file, tag_name, tag_value[0])
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,24 @@ import os
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.utils.file_handler import FileHandler, FileMetadata
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
from ytdl_sub.utils.xml import (
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
XmlElement,
|
from ytdl_sub.utils.xml import XmlElement
|
||||||
to_max_3_byte_utf8_dict,
|
from ytdl_sub.utils.xml import to_max_3_byte_utf8_dict
|
||||||
to_max_3_byte_utf8_string,
|
from ytdl_sub.utils.xml import to_max_3_byte_utf8_string
|
||||||
to_xml,
|
from ytdl_sub.utils.xml import to_xml
|
||||||
)
|
|
||||||
from ytdl_sub.validators.file_path_validators import StringFormatterFileNameValidator
|
from ytdl_sub.validators.file_path_validators import StringFormatterFileNameValidator
|
||||||
from ytdl_sub.validators.nfo_validators import NfoTagsValidator
|
from ytdl_sub.validators.nfo_validators import NfoTagsValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import (
|
from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator
|
||||||
DictFormatterValidator,
|
from ytdl_sub.validators.string_formatter_validators import OverridesBooleanFormatterValidator
|
||||||
OverridesBooleanFormatterValidator,
|
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
||||||
StringFormatterValidator,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SharedNfoTagsOptions(ToggleableOptionsDictValidator):
|
class SharedNfoTagsOptions(ToggleableOptionsDictValidator):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.plugins.nfo_tags import NfoTagsValidator, SharedNfoTagsOptions, SharedNfoTagsPlugin
|
from ytdl_sub.plugins.nfo_tags import NfoTagsValidator
|
||||||
|
from ytdl_sub.plugins.nfo_tags import SharedNfoTagsOptions
|
||||||
|
from ytdl_sub.plugins.nfo_tags import SharedNfoTagsPlugin
|
||||||
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
||||||
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,23 @@
|
||||||
from typing import Any, Dict, List, Optional, Set, Tuple
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import SplitPlugin
|
from ytdl_sub.config.plugin.plugin import SplitPlugin
|
||||||
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
||||||
from ytdl_sub.config.validators.options import OptionsDictValidator
|
from ytdl_sub.config.validators.options import OptionsDictValidator
|
||||||
from ytdl_sub.entries.entry import Entry, ytdl_sub_split_by_chapters_parent_uid
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
from ytdl_sub.entries.entry import ytdl_sub_split_by_chapters_parent_uid
|
||||||
from ytdl_sub.utils.chapters import Chapters, Timestamp
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
|
from ytdl_sub.utils.chapters import Chapters
|
||||||
|
from ytdl_sub.utils.chapters import Timestamp
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
from ytdl_sub.utils.ffmpeg import FFMPEG
|
from ytdl_sub.utils.ffmpeg import FFMPEG
|
||||||
from ytdl_sub.utils.file_handler import FileHandler, FileMetadata
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
from ytdl_sub.validators.string_select_validator import StringSelectValidator
|
from ytdl_sub.validators.string_select_validator import StringSelectValidator
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
from typing import List, Optional
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.validators.options import OptionsValidator
|
from ytdl_sub.config.validators.options import OptionsValidator
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.utils.ffmpeg import FFMPEG
|
from ytdl_sub.utils.ffmpeg import FFMPEG
|
||||||
from ytdl_sub.utils.file_handler import FileHandler, FileMetadata
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
from ytdl_sub.validators.string_formatter_validators import OverridesBooleanFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import OverridesBooleanFormatterValidator
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.plugins.nfo_tags import NfoTagsValidator, SharedNfoTagsOptions, SharedNfoTagsPlugin
|
from ytdl_sub.plugins.nfo_tags import NfoTagsValidator
|
||||||
|
from ytdl_sub.plugins.nfo_tags import SharedNfoTagsOptions
|
||||||
|
from ytdl_sub.plugins.nfo_tags import SharedNfoTagsPlugin
|
||||||
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,28 @@
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional, Set, Tuple
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
||||||
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
||||||
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError
|
from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError
|
||||||
from ytdl_sub.utils.file_handler import FileHandler, FileMetadata
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
from ytdl_sub.utils.subtitles import SUBTITLE_EXTENSIONS
|
from ytdl_sub.utils.subtitles import SUBTITLE_EXTENSIONS
|
||||||
from ytdl_sub.validators.file_path_validators import StringFormatterFileNameValidator
|
from ytdl_sub.validators.file_path_validators import StringFormatterFileNameValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
||||||
from ytdl_sub.validators.string_select_validator import StringSelectValidator
|
from ytdl_sub.validators.string_select_validator import StringSelectValidator
|
||||||
from ytdl_sub.validators.validators import BoolValidator, StringListValidator
|
from ytdl_sub.validators.validators import BoolValidator
|
||||||
|
from ytdl_sub.validators.validators import StringListValidator
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from typing import Dict, Optional, Type, TypeVar
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Type
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
|
|
@ -10,10 +13,8 @@ from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.utils.file_handler import FileMetadata
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import (
|
from ytdl_sub.validators.string_formatter_validators import FloatFormatterValidator
|
||||||
FloatFormatterValidator,
|
from ytdl_sub.validators.string_formatter_validators import OverridesFloatFormatterValidator
|
||||||
OverridesFloatFormatterValidator,
|
|
||||||
)
|
|
||||||
from ytdl_sub.validators.validators import ProbabilityValidator
|
from ytdl_sub.validators.validators import ProbabilityValidator
|
||||||
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
from typing import Any, Dict, Set
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
import mergedeep
|
import mergedeep
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from ytdl_sub.prebuilt_presets import PrebuiltPresets, get_prebuilt_preset_package_name
|
from ytdl_sub.prebuilt_presets import PrebuiltPresets
|
||||||
|
from ytdl_sub.prebuilt_presets import get_prebuilt_preset_package_name
|
||||||
|
|
||||||
PREBUILT_PRESET_PACKAGE_NAME = get_prebuilt_preset_package_name(__file__)
|
PREBUILT_PRESET_PACKAGE_NAME = get_prebuilt_preset_package_name(__file__)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from ytdl_sub.prebuilt_presets import PrebuiltPresets, get_prebuilt_preset_package_name
|
from ytdl_sub.prebuilt_presets import PrebuiltPresets
|
||||||
|
from ytdl_sub.prebuilt_presets import get_prebuilt_preset_package_name
|
||||||
|
|
||||||
PREBUILT_PRESET_PACKAGE_NAME = get_prebuilt_preset_package_name(__file__)
|
PREBUILT_PRESET_PACKAGE_NAME = get_prebuilt_preset_package_name(__file__)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from ytdl_sub.prebuilt_presets import PrebuiltPresets, get_prebuilt_preset_package_name
|
from ytdl_sub.prebuilt_presets import PrebuiltPresets
|
||||||
|
from ytdl_sub.prebuilt_presets import get_prebuilt_preset_package_name
|
||||||
|
|
||||||
PREBUILT_PRESET_PACKAGE_NAME = get_prebuilt_preset_package_name(__file__)
|
PREBUILT_PRESET_PACKAGE_NAME = get_prebuilt_preset_package_name(__file__)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import Callable, Dict
|
from typing import Callable
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
from ytdl_sub.script.functions.array_functions import ArrayFunctions
|
from ytdl_sub.script.functions.array_functions import ArrayFunctions
|
||||||
from ytdl_sub.script.functions.boolean_functions import BooleanFunctions
|
from ytdl_sub.script.functions.boolean_functions import BooleanFunctions
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,18 @@
|
||||||
import itertools
|
import itertools
|
||||||
from typing import List, Optional
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.script.types.array import Array
|
from ytdl_sub.script.types.array import Array
|
||||||
from ytdl_sub.script.types.resolvable import (
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
AnyArgument,
|
from ytdl_sub.script.types.resolvable import Boolean
|
||||||
Boolean,
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
Integer,
|
from ytdl_sub.script.types.resolvable import Lambda
|
||||||
Lambda,
|
from ytdl_sub.script.types.resolvable import LambdaReduce
|
||||||
LambdaReduce,
|
from ytdl_sub.script.types.resolvable import LambdaTwo
|
||||||
LambdaTwo,
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
Resolvable,
|
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
||||||
)
|
from ytdl_sub.script.utils.exceptions import ArrayValueDoesNotExist
|
||||||
from ytdl_sub.script.utils.exceptions import (
|
from ytdl_sub.script.utils.exceptions import FunctionRuntimeException
|
||||||
UNREACHABLE,
|
|
||||||
ArrayValueDoesNotExist,
|
|
||||||
FunctionRuntimeException,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ArrayFunctions:
|
class ArrayFunctions:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
from ytdl_sub.script.types.array import Array
|
from ytdl_sub.script.types.array import Array
|
||||||
from ytdl_sub.script.types.map import Map
|
from ytdl_sub.script.types.map import Map
|
||||||
from ytdl_sub.script.types.resolvable import AnyArgument, Boolean, Float, Integer, String
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
|
from ytdl_sub.script.types.resolvable import Boolean
|
||||||
|
from ytdl_sub.script.types.resolvable import Float
|
||||||
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
|
from ytdl_sub.script.types.resolvable import String
|
||||||
|
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from ytdl_sub.script.types.resolvable import (
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
AnyArgument,
|
from ytdl_sub.script.types.resolvable import Boolean
|
||||||
Boolean,
|
from ytdl_sub.script.types.resolvable import ReturnableArgumentA
|
||||||
ReturnableArgumentA,
|
from ytdl_sub.script.types.resolvable import ReturnableArgumentB
|
||||||
ReturnableArgumentB,
|
|
||||||
)
|
|
||||||
from ytdl_sub.script.utils.exceptions import FunctionRuntimeException
|
from ytdl_sub.script.utils.exceptions import FunctionRuntimeException
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from ytdl_sub.script.types.resolvable import Integer, String
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
|
from ytdl_sub.script.types.resolvable import String
|
||||||
|
|
||||||
|
|
||||||
class DateFunctions:
|
class DateFunctions:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
from ytdl_sub.script.types.resolvable import AnyArgument, ReturnableArgument, String
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
|
from ytdl_sub.script.types.resolvable import ReturnableArgument
|
||||||
|
from ytdl_sub.script.types.resolvable import String
|
||||||
from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError
|
from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,12 @@ from typing import Any
|
||||||
|
|
||||||
from ytdl_sub.script.types.array import Array
|
from ytdl_sub.script.types.array import Array
|
||||||
from ytdl_sub.script.types.map import Map
|
from ytdl_sub.script.types.map import Map
|
||||||
from ytdl_sub.script.types.resolvable import (
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
AnyArgument,
|
from ytdl_sub.script.types.resolvable import Boolean
|
||||||
Boolean,
|
from ytdl_sub.script.types.resolvable import Float
|
||||||
Float,
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
Integer,
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
Resolvable,
|
from ytdl_sub.script.types.resolvable import String
|
||||||
String,
|
|
||||||
)
|
|
||||||
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,18 @@
|
||||||
from typing import Dict, Optional
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.script.types.array import Array
|
from ytdl_sub.script.types.array import Array
|
||||||
from ytdl_sub.script.types.map import Map
|
from ytdl_sub.script.types.map import Map
|
||||||
from ytdl_sub.script.types.resolvable import (
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
AnyArgument,
|
from ytdl_sub.script.types.resolvable import Boolean
|
||||||
Boolean,
|
from ytdl_sub.script.types.resolvable import Hashable
|
||||||
Hashable,
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
Integer,
|
from ytdl_sub.script.types.resolvable import LambdaThree
|
||||||
LambdaThree,
|
from ytdl_sub.script.types.resolvable import LambdaTwo
|
||||||
LambdaTwo,
|
from ytdl_sub.script.types.resolvable import String
|
||||||
String,
|
from ytdl_sub.script.utils.exceptions import FunctionRuntimeException
|
||||||
)
|
from ytdl_sub.script.utils.exceptions import KeyDoesNotExistRuntimeException
|
||||||
from ytdl_sub.script.utils.exceptions import (
|
from ytdl_sub.script.utils.exceptions import KeyNotHashableRuntimeException
|
||||||
FunctionRuntimeException,
|
|
||||||
KeyDoesNotExistRuntimeException,
|
|
||||||
KeyNotHashableRuntimeException,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class MapFunctions:
|
class MapFunctions:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@ import math
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.script.types.array import Array
|
from ytdl_sub.script.types.array import Array
|
||||||
from ytdl_sub.script.types.resolvable import AnyArgument, Float, Integer, Numeric
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
|
from ytdl_sub.script.types.resolvable import Float
|
||||||
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
|
from ytdl_sub.script.types.resolvable import Numeric
|
||||||
|
|
||||||
|
|
||||||
def _to_numeric(value: int | float) -> Numeric:
|
def _to_numeric(value: int | float) -> Numeric:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.script.types.resolvable import AnyArgument, Integer, ReturnableArgument
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
|
from ytdl_sub.script.types.resolvable import ReturnableArgument
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
|
|
||||||
logger = Logger.get(name="preset")
|
logger = Logger.get(name="preset")
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
import re
|
import re
|
||||||
from typing import AnyStr, List, Match, Optional
|
from typing import AnyStr
|
||||||
|
from typing import List
|
||||||
|
from typing import Match
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.script.functions.array_functions import ArrayFunctions
|
from ytdl_sub.script.functions.array_functions import ArrayFunctions
|
||||||
from ytdl_sub.script.types.array import Array
|
from ytdl_sub.script.types.array import Array
|
||||||
from ytdl_sub.script.types.resolvable import Boolean, Float, Integer, String
|
from ytdl_sub.script.types.resolvable import Boolean
|
||||||
|
from ytdl_sub.script.types.resolvable import Float
|
||||||
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
|
from ytdl_sub.script.types.resolvable import String
|
||||||
from ytdl_sub.script.utils.exceptions import FunctionRuntimeException
|
from ytdl_sub.script.utils.exceptions import FunctionRuntimeException
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.script.types.array import Array
|
from ytdl_sub.script.types.array import Array
|
||||||
from ytdl_sub.script.types.resolvable import AnyArgument, Boolean, Float, Integer, Numeric, String
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
|
from ytdl_sub.script.types.resolvable import Boolean
|
||||||
|
from ytdl_sub.script.types.resolvable import Float
|
||||||
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
|
from ytdl_sub.script.types.resolvable import Numeric
|
||||||
|
from ytdl_sub.script.types.resolvable import String
|
||||||
|
|
||||||
|
|
||||||
class StringFunctions:
|
class StringFunctions:
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,39 @@
|
||||||
import json
|
import json
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Dict, List, Optional, Set
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.script.functions import Functions
|
from ytdl_sub.script.functions import Functions
|
||||||
from ytdl_sub.script.types.array import UnresolvedArray
|
from ytdl_sub.script.types.array import UnresolvedArray
|
||||||
from ytdl_sub.script.types.function import Argument, BuiltInFunction, CustomFunction, Function
|
from ytdl_sub.script.types.function import Argument
|
||||||
|
from ytdl_sub.script.types.function import BuiltInFunction
|
||||||
|
from ytdl_sub.script.types.function import CustomFunction
|
||||||
|
from ytdl_sub.script.types.function import Function
|
||||||
from ytdl_sub.script.types.map import UnresolvedMap
|
from ytdl_sub.script.types.map import UnresolvedMap
|
||||||
from ytdl_sub.script.types.resolvable import Boolean, Float, Integer, Lambda, NonHashable, String
|
from ytdl_sub.script.types.resolvable import Boolean
|
||||||
|
from ytdl_sub.script.types.resolvable import Float
|
||||||
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
|
from ytdl_sub.script.types.resolvable import Lambda
|
||||||
|
from ytdl_sub.script.types.resolvable import NonHashable
|
||||||
|
from ytdl_sub.script.types.resolvable import String
|
||||||
from ytdl_sub.script.types.syntax_tree import SyntaxTree
|
from ytdl_sub.script.types.syntax_tree import SyntaxTree
|
||||||
from ytdl_sub.script.types.variable import FunctionArgument, Variable
|
from ytdl_sub.script.types.variable import FunctionArgument
|
||||||
|
from ytdl_sub.script.types.variable import Variable
|
||||||
from ytdl_sub.script.utils.exception_formatters import ParserExceptionFormatter
|
from ytdl_sub.script.utils.exception_formatters import ParserExceptionFormatter
|
||||||
from ytdl_sub.script.utils.exceptions import (
|
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
||||||
UNREACHABLE,
|
from ytdl_sub.script.utils.exceptions import CycleDetected
|
||||||
CycleDetected,
|
from ytdl_sub.script.utils.exceptions import FunctionDoesNotExist
|
||||||
FunctionDoesNotExist,
|
from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments
|
||||||
IncompatibleFunctionArguments,
|
from ytdl_sub.script.utils.exceptions import InvalidCustomFunctionArgumentName
|
||||||
InvalidCustomFunctionArgumentName,
|
from ytdl_sub.script.utils.exceptions import InvalidSyntaxException
|
||||||
InvalidSyntaxException,
|
from ytdl_sub.script.utils.exceptions import InvalidVariableName
|
||||||
InvalidVariableName,
|
from ytdl_sub.script.utils.exceptions import UserException
|
||||||
UserException,
|
from ytdl_sub.script.utils.exceptions import VariableDoesNotExist
|
||||||
VariableDoesNotExist,
|
from ytdl_sub.script.utils.name_validation import is_function
|
||||||
)
|
from ytdl_sub.script.utils.name_validation import to_function_name
|
||||||
from ytdl_sub.script.utils.name_validation import (
|
from ytdl_sub.script.utils.name_validation import validate_variable_name
|
||||||
is_function,
|
|
||||||
to_function_name,
|
|
||||||
validate_variable_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
|
|
@ -572,6 +580,7 @@ class _Parser:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _parse(self) -> SyntaxTree:
|
def _parse(self) -> SyntaxTree:
|
||||||
|
|
||||||
while ch := self._read():
|
while ch := self._read():
|
||||||
continue_parse = self._parse_main_loop(ch)
|
continue_parse = self._parse_main_loop(ch)
|
||||||
if not continue_parse:
|
if not continue_parse:
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,32 @@
|
||||||
# pylint: disable=missing-raises-doc
|
# pylint: disable=missing-raises-doc
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Dict, List, Optional, Set
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.script.functions import Functions
|
from ytdl_sub.script.functions import Functions
|
||||||
from ytdl_sub.script.parser import parse
|
from ytdl_sub.script.parser import parse
|
||||||
from ytdl_sub.script.script_output import ScriptOutput
|
from ytdl_sub.script.script_output import ScriptOutput
|
||||||
from ytdl_sub.script.types.resolvable import Argument, BuiltInFunctionType, Lambda, Resolvable
|
from ytdl_sub.script.types.resolvable import Argument
|
||||||
from ytdl_sub.script.types.syntax_tree import ResolvedSyntaxTree, SyntaxTree
|
from ytdl_sub.script.types.resolvable import BuiltInFunctionType
|
||||||
from ytdl_sub.script.types.variable import FunctionArgument, Variable
|
from ytdl_sub.script.types.resolvable import Lambda
|
||||||
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
|
from ytdl_sub.script.types.syntax_tree import ResolvedSyntaxTree
|
||||||
|
from ytdl_sub.script.types.syntax_tree import SyntaxTree
|
||||||
|
from ytdl_sub.script.types.variable import FunctionArgument
|
||||||
|
from ytdl_sub.script.types.variable import Variable
|
||||||
from ytdl_sub.script.types.variable_dependency import VariableDependency
|
from ytdl_sub.script.types.variable_dependency import VariableDependency
|
||||||
from ytdl_sub.script.utils.exceptions import (
|
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
||||||
UNREACHABLE,
|
from ytdl_sub.script.utils.exceptions import CycleDetected
|
||||||
CycleDetected,
|
from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments
|
||||||
IncompatibleFunctionArguments,
|
from ytdl_sub.script.utils.exceptions import InvalidCustomFunctionArguments
|
||||||
InvalidCustomFunctionArguments,
|
from ytdl_sub.script.utils.exceptions import RuntimeException
|
||||||
RuntimeException,
|
from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved
|
||||||
ScriptVariableNotResolved,
|
from ytdl_sub.script.utils.name_validation import is_function
|
||||||
)
|
from ytdl_sub.script.utils.name_validation import to_function_definition_name
|
||||||
from ytdl_sub.script.utils.name_validation import (
|
from ytdl_sub.script.utils.name_validation import to_function_name
|
||||||
is_function,
|
from ytdl_sub.script.utils.name_validation import validate_variable_name
|
||||||
to_function_definition_name,
|
|
||||||
to_function_name,
|
|
||||||
validate_variable_name,
|
|
||||||
)
|
|
||||||
from ytdl_sub.script.utils.type_checking import FunctionSpec
|
from ytdl_sub.script.utils.type_checking import FunctionSpec
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -733,6 +737,7 @@ class Script:
|
||||||
|
|
||||||
partially_resolved = True
|
partially_resolved = True
|
||||||
while partially_resolved:
|
while partially_resolved:
|
||||||
|
|
||||||
partially_resolved = False
|
partially_resolved = False
|
||||||
|
|
||||||
for variable in list(to_partially_resolve):
|
for variable in list(to_partially_resolve):
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, Dict
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
from ytdl_sub.script.types.resolvable import Resolvable
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved
|
from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, Dict, List, Type
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
from ytdl_sub.script.types.resolvable import (
|
from ytdl_sub.script.types.resolvable import Argument
|
||||||
Argument,
|
from ytdl_sub.script.types.resolvable import FutureResolvable
|
||||||
FutureResolvable,
|
from ytdl_sub.script.types.resolvable import NonHashable
|
||||||
NonHashable,
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
Resolvable,
|
from ytdl_sub.script.types.resolvable import ResolvableToJson
|
||||||
ResolvableToJson,
|
|
||||||
)
|
|
||||||
from ytdl_sub.script.types.variable import Variable
|
from ytdl_sub.script.types.variable import Variable
|
||||||
from ytdl_sub.script.types.variable_dependency import VariableDependency
|
from ytdl_sub.script.types.variable_dependency import VariableDependency
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,38 @@
|
||||||
import functools
|
import functools
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Callable, Dict, List, Optional, Type, Union
|
from typing import Callable
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Type
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from ytdl_sub.script.functions import Functions
|
from ytdl_sub.script.functions import Functions
|
||||||
from ytdl_sub.script.types.array import Array, UnresolvedArray
|
from ytdl_sub.script.types.array import Array
|
||||||
from ytdl_sub.script.types.resolvable import (
|
from ytdl_sub.script.types.array import UnresolvedArray
|
||||||
Argument,
|
from ytdl_sub.script.types.resolvable import Argument
|
||||||
Boolean,
|
from ytdl_sub.script.types.resolvable import Boolean
|
||||||
BuiltInFunctionType,
|
from ytdl_sub.script.types.resolvable import BuiltInFunctionType
|
||||||
FunctionType,
|
from ytdl_sub.script.types.resolvable import FunctionType
|
||||||
FutureResolvable,
|
from ytdl_sub.script.types.resolvable import FutureResolvable
|
||||||
Integer,
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
Lambda,
|
from ytdl_sub.script.types.resolvable import Lambda
|
||||||
NamedCustomFunction,
|
from ytdl_sub.script.types.resolvable import NamedCustomFunction
|
||||||
Resolvable,
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
ReturnableArgument,
|
from ytdl_sub.script.types.resolvable import ReturnableArgument
|
||||||
ReturnableArgumentA,
|
from ytdl_sub.script.types.resolvable import ReturnableArgumentA
|
||||||
ReturnableArgumentB,
|
from ytdl_sub.script.types.resolvable import ReturnableArgumentB
|
||||||
)
|
from ytdl_sub.script.types.variable import FunctionArgument
|
||||||
from ytdl_sub.script.types.variable import FunctionArgument, Variable
|
from ytdl_sub.script.types.variable import Variable
|
||||||
from ytdl_sub.script.types.variable_dependency import VariableDependency
|
from ytdl_sub.script.types.variable_dependency import VariableDependency
|
||||||
from ytdl_sub.script.utils.exception_formatters import FunctionArgumentsExceptionFormatter
|
from ytdl_sub.script.utils.exception_formatters import FunctionArgumentsExceptionFormatter
|
||||||
from ytdl_sub.script.utils.exceptions import (
|
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
||||||
UNREACHABLE,
|
from ytdl_sub.script.utils.exceptions import FunctionRuntimeException
|
||||||
FunctionRuntimeException,
|
from ytdl_sub.script.utils.exceptions import RuntimeException
|
||||||
RuntimeException,
|
from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError
|
||||||
UserThrownRuntimeError,
|
from ytdl_sub.script.utils.type_checking import FunctionSpec
|
||||||
)
|
from ytdl_sub.script.utils.type_checking import is_union
|
||||||
from ytdl_sub.script.utils.type_checking import FunctionSpec, is_union
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
import itertools
|
import itertools
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, Dict, List, Type
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
from ytdl_sub.script.types.resolvable import (
|
from ytdl_sub.script.types.resolvable import Argument
|
||||||
Argument,
|
from ytdl_sub.script.types.resolvable import FutureResolvable
|
||||||
FutureResolvable,
|
from ytdl_sub.script.types.resolvable import Hashable
|
||||||
Hashable,
|
from ytdl_sub.script.types.resolvable import NonHashable
|
||||||
NonHashable,
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
Resolvable,
|
from ytdl_sub.script.types.resolvable import ResolvableToJson
|
||||||
ResolvableToJson,
|
|
||||||
)
|
|
||||||
from ytdl_sub.script.types.variable import Variable
|
from ytdl_sub.script.types.variable import Variable
|
||||||
from ytdl_sub.script.types.variable_dependency import VariableDependency
|
from ytdl_sub.script.types.variable_dependency import VariableDependency
|
||||||
from ytdl_sub.script.utils.exceptions import KeyNotHashableRuntimeException
|
from ytdl_sub.script.utils.exceptions import KeyNotHashableRuntimeException
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
import json
|
import json
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC
|
||||||
|
from abc import abstractmethod
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, Generic, List, Type, TypeVar
|
from typing import Any
|
||||||
|
from typing import Generic
|
||||||
|
from typing import List
|
||||||
|
from typing import Type
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
NumericT = TypeVar("NumericT", bound=int | float)
|
NumericT = TypeVar("NumericT", bound=int | float)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.script.types.function import BuiltInFunction
|
from ytdl_sub.script.types.function import BuiltInFunction
|
||||||
from ytdl_sub.script.types.resolvable import Argument, Resolvable, String
|
from ytdl_sub.script.types.resolvable import Argument
|
||||||
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
|
from ytdl_sub.script.types.resolvable import String
|
||||||
from ytdl_sub.script.types.variable import Variable
|
from ytdl_sub.script.types.variable import Variable
|
||||||
from ytdl_sub.script.types.variable_dependency import VariableDependency
|
from ytdl_sub.script.types.variable_dependency import VariableDependency
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,24 @@
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC
|
||||||
|
from abc import abstractmethod
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Dict, Iterable, List, Set, Tuple, Type, TypeVar, final
|
from typing import Dict
|
||||||
|
from typing import Iterable
|
||||||
|
from typing import List
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import Type
|
||||||
|
from typing import TypeVar
|
||||||
|
from typing import final
|
||||||
|
|
||||||
from ytdl_sub.script.types.resolvable import (
|
from ytdl_sub.script.types.resolvable import Argument
|
||||||
Argument,
|
from ytdl_sub.script.types.resolvable import BuiltInFunctionType
|
||||||
BuiltInFunctionType,
|
from ytdl_sub.script.types.resolvable import FunctionType
|
||||||
FunctionType,
|
from ytdl_sub.script.types.resolvable import Lambda
|
||||||
Lambda,
|
from ytdl_sub.script.types.resolvable import NamedCustomFunction
|
||||||
NamedCustomFunction,
|
from ytdl_sub.script.types.resolvable import ParsedCustomFunction
|
||||||
ParsedCustomFunction,
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
Resolvable,
|
from ytdl_sub.script.types.variable import FunctionArgument
|
||||||
)
|
from ytdl_sub.script.types.variable import Variable
|
||||||
from ytdl_sub.script.types.variable import FunctionArgument, Variable
|
|
||||||
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
||||||
|
|
||||||
TypeT = TypeVar("TypeT")
|
TypeT = TypeVar("TypeT")
|
||||||
|
|
@ -37,7 +44,7 @@ class VariableDependency(ABC):
|
||||||
output.append(arg)
|
output.append(arg)
|
||||||
elif instance and isinstance(arg, ttype):
|
elif instance and isinstance(arg, ttype):
|
||||||
output.append(arg)
|
output.append(arg)
|
||||||
elif type(arg) is ttype: # pylint: disable=unidiomatic-typecheck
|
elif type(arg) == ttype: # pylint: disable=unidiomatic-typecheck
|
||||||
output.append(arg)
|
output.append(arg)
|
||||||
|
|
||||||
if isinstance(arg, VariableDependency):
|
if isinstance(arg, VariableDependency):
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
import sys
|
import sys
|
||||||
from typing import List, TypeVar
|
from typing import List
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
from ytdl_sub.script.types.resolvable import BuiltInFunctionType
|
from ytdl_sub.script.types.resolvable import BuiltInFunctionType
|
||||||
from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments, UserException
|
from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments
|
||||||
from ytdl_sub.script.utils.type_checking import FunctionSpec, is_union
|
from ytdl_sub.script.utils.exceptions import UserException
|
||||||
|
from ytdl_sub.script.utils.type_checking import FunctionSpec
|
||||||
|
from ytdl_sub.script.utils.type_checking import is_union
|
||||||
|
|
||||||
UserExceptionT = TypeVar("UserExceptionT", bound=UserException)
|
UserExceptionT = TypeVar("UserExceptionT", bound=UserException)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ytdl_sub.script.functions import Functions
|
from ytdl_sub.script.functions import Functions
|
||||||
from ytdl_sub.script.utils.exceptions import InvalidFunctionName, InvalidVariableName
|
from ytdl_sub.script.utils.exceptions import InvalidFunctionName
|
||||||
|
from ytdl_sub.script.utils.exceptions import InvalidVariableName
|
||||||
|
|
||||||
_NAME_REGEX_VALIDATOR = re.compile(r"^[a-z][a-z0-9_]*$")
|
_NAME_REGEX_VALIDATOR = re.compile(r"^[a-z][a-z0-9_]*$")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,24 @@ import inspect
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from inspect import FullArgSpec
|
from inspect import FullArgSpec
|
||||||
from types import NoneType
|
from types import NoneType
|
||||||
from typing import Callable, List, Optional, Type, TypeVar, Union, get_origin
|
from typing import Callable
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Type
|
||||||
|
from typing import TypeVar
|
||||||
|
from typing import Union
|
||||||
|
from typing import get_origin
|
||||||
|
|
||||||
from ytdl_sub.script.types.resolvable import (
|
from ytdl_sub.script.types.resolvable import Argument
|
||||||
Argument,
|
from ytdl_sub.script.types.resolvable import BuiltInFunctionType
|
||||||
Boolean,
|
from ytdl_sub.script.types.resolvable import FutureResolvable
|
||||||
BuiltInFunctionType,
|
from ytdl_sub.script.types.resolvable import Lambda
|
||||||
Float,
|
from ytdl_sub.script.types.resolvable import LambdaReduce
|
||||||
FutureResolvable,
|
from ytdl_sub.script.types.resolvable import LambdaThree
|
||||||
Integer,
|
from ytdl_sub.script.types.resolvable import LambdaTwo
|
||||||
Lambda,
|
from ytdl_sub.script.types.resolvable import NamedCustomFunction
|
||||||
LambdaReduce,
|
from ytdl_sub.script.types.resolvable import NamedType
|
||||||
LambdaThree,
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
LambdaTwo,
|
|
||||||
NamedCustomFunction,
|
|
||||||
NamedType,
|
|
||||||
Resolvable,
|
|
||||||
)
|
|
||||||
from ytdl_sub.script.types.variable import Variable
|
from ytdl_sub.script.types.variable import Variable
|
||||||
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
||||||
|
|
||||||
|
|
@ -251,17 +252,6 @@ class FunctionSpec:
|
||||||
return l_type
|
return l_type
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def has_sanitized_output(self) -> bool:
|
|
||||||
"""
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
If this function were to be sanitized, whether it's redundant or not based on its
|
|
||||||
output
|
|
||||||
"""
|
|
||||||
return inspect.isclass(self.return_type) and issubclass(
|
|
||||||
self.return_type, (Integer, Float, Boolean)
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _to_human_readable_name(cls, python_type: Type[NamedType] | Type[Union[NamedType]]) -> str:
|
def _to_human_readable_name(cls, python_type: Type[NamedType] | Type[Union[NamedType]]) -> str:
|
||||||
if is_optional(python_type):
|
if is_optional(python_type):
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,20 @@
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.config.config_validator import ConfigOptions
|
from ytdl_sub.config.config_validator import ConfigOptions
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.config.plugin.preset_plugins import PresetPlugins
|
from ytdl_sub.config.plugin.preset_plugins import PresetPlugins
|
||||||
from ytdl_sub.config.preset import Preset
|
from ytdl_sub.config.preset import Preset
|
||||||
from ytdl_sub.config.preset_options import OutputOptions, YTDLOptions
|
from ytdl_sub.config.preset_options import OutputOptions
|
||||||
from ytdl_sub.config.validators.variable_validation import ResolutionLevel, VariableValidation
|
from ytdl_sub.config.preset_options import YTDLOptions
|
||||||
|
from ytdl_sub.config.validators.variable_validation import ResolutionLevel
|
||||||
|
from ytdl_sub.config.validators.variable_validation import VariableValidation
|
||||||
from ytdl_sub.downloaders.url.validators import MultiUrlValidator
|
from ytdl_sub.downloaders.url.validators import MultiUrlValidator
|
||||||
from ytdl_sub.entries.variables.override_variables import SubscriptionVariables
|
from ytdl_sub.entries.variables.override_variables import SubscriptionVariables
|
||||||
from ytdl_sub.utils.exceptions import SubscriptionPermissionError
|
from ytdl_sub.utils.exceptions import SubscriptionPermissionError
|
||||||
from ytdl_sub.utils.file_handler import FileHandler, FileHandlerTransactionLog
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
|
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
from ytdl_sub.utils.yaml import dump_yaml
|
from ytdl_sub.utils.yaml import dump_yaml
|
||||||
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
||||||
|
|
@ -254,11 +257,7 @@ class BaseSubscription(ABC):
|
||||||
"""
|
"""
|
||||||
return self._preset_options.yaml(subscription_only=False)
|
return self._preset_options.yaml(subscription_only=False)
|
||||||
|
|
||||||
def resolved_yaml(
|
def resolved_yaml(self, resolution_level: int = ResolutionLevel.RESOLVE) -> str:
|
||||||
self,
|
|
||||||
resolution_level: int = ResolutionLevel.RESOLVE,
|
|
||||||
mocks: Optional[Dict[str, str]] = None,
|
|
||||||
) -> str:
|
|
||||||
"""
|
"""
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
|
@ -273,6 +272,5 @@ class BaseSubscription(ABC):
|
||||||
output_options=self.output_options,
|
output_options=self.output_options,
|
||||||
plugins=self.plugins,
|
plugins=self.plugins,
|
||||||
resolution_level=resolution_level,
|
resolution_level=resolution_level,
|
||||||
mocks=mocks,
|
|
||||||
).ensure_proper_usage(partial_resolve_formatters=True)
|
).ensure_proper_usage(partial_resolve_formatters=True)
|
||||||
return dump_yaml(out)
|
return dump_yaml(out)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
import copy
|
import copy
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from mergedeep import mergedeep
|
from mergedeep import mergedeep
|
||||||
|
|
||||||
|
|
@ -140,6 +143,7 @@ class Subscription(SubscriptionDownload):
|
||||||
}
|
}
|
||||||
|
|
||||||
for subscription_name, subscription_object in subscriptions_dicts.items():
|
for subscription_name, subscription_object in subscriptions_dicts.items():
|
||||||
|
|
||||||
# Hard-override subscriptions here
|
# Hard-override subscriptions here
|
||||||
mergedeep.merge(
|
mergedeep.merge(
|
||||||
subscription_object,
|
subscription_object,
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,15 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin, SplitPlugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
|
from ytdl_sub.config.plugin.plugin import SplitPlugin
|
||||||
from ytdl_sub.config.plugin.plugin_mapping import PluginMapping
|
from ytdl_sub.config.plugin.plugin_mapping import PluginMapping
|
||||||
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
||||||
from ytdl_sub.downloaders.info_json.info_json_downloader import (
|
from ytdl_sub.downloaders.info_json.info_json_downloader import InfoJsonDownloader
|
||||||
InfoJsonDownloader,
|
from ytdl_sub.downloaders.info_json.info_json_downloader import InfoJsonDownloaderOptions
|
||||||
InfoJsonDownloaderOptions,
|
|
||||||
)
|
|
||||||
from ytdl_sub.downloaders.source_plugin import SourcePlugin
|
from ytdl_sub.downloaders.source_plugin import SourcePlugin
|
||||||
from ytdl_sub.downloaders.url.downloader import MultiUrlDownloader
|
from ytdl_sub.downloaders.url.downloader import MultiUrlDownloader
|
||||||
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
||||||
|
|
@ -22,7 +22,9 @@ from ytdl_sub.subscriptions.base_subscription import BaseSubscription
|
||||||
from ytdl_sub.subscriptions.subscription_ytdl_options import SubscriptionYTDLOptions
|
from ytdl_sub.subscriptions.subscription_ytdl_options import SubscriptionYTDLOptions
|
||||||
from ytdl_sub.utils.datetime import to_date_range
|
from ytdl_sub.utils.datetime import to_date_range
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
from ytdl_sub.utils.file_handler import FileHandler, FileHandlerTransactionLog, FileMetadata
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
|
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
|
||||||
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
|
|
||||||
logger: logging.Logger = Logger.get()
|
logger: logging.Logger = Logger.get()
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,22 @@
|
||||||
import copy
|
import copy
|
||||||
import dataclasses
|
import dataclasses
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC
|
||||||
from typing import Dict, List, Optional, final
|
from abc import abstractmethod
|
||||||
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import final
|
||||||
|
|
||||||
from ytdl_sub.config.config_file import ConfigFile
|
from ytdl_sub.config.config_file import ConfigFile
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.entries.variables.override_variables import SubscriptionVariables
|
from ytdl_sub.entries.variables.override_variables import SubscriptionVariables
|
||||||
from ytdl_sub.utils.script import ScriptUtils
|
from ytdl_sub.utils.script import ScriptUtils
|
||||||
from ytdl_sub.validators.string_formatter_validators import UnstructuredDictFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import UnstructuredDictFormatterValidator
|
||||||
from ytdl_sub.validators.validators import (
|
from ytdl_sub.validators.validators import DictValidator
|
||||||
DictValidator,
|
from ytdl_sub.validators.validators import LiteralDictValidator
|
||||||
LiteralDictValidator,
|
from ytdl_sub.validators.validators import StringListValidator
|
||||||
StringListValidator,
|
from ytdl_sub.validators.validators import StringValidator
|
||||||
StringValidator,
|
from ytdl_sub.validators.validators import Validator
|
||||||
Validator,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SubscriptionOutput(Validator, ABC):
|
class SubscriptionOutput(Validator, ABC):
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional, Type, TypeVar
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Type
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
from yt_dlp import match_filter_func
|
from yt_dlp import match_filter_func
|
||||||
|
|
||||||
|
|
@ -11,7 +15,9 @@ from ytdl_sub.plugins.audio_extract import AudioExtractPlugin
|
||||||
from ytdl_sub.plugins.chapters import ChaptersPlugin
|
from ytdl_sub.plugins.chapters import ChaptersPlugin
|
||||||
from ytdl_sub.plugins.file_convert import FileConvertPlugin
|
from ytdl_sub.plugins.file_convert import FileConvertPlugin
|
||||||
from ytdl_sub.plugins.format import FormatPlugin
|
from ytdl_sub.plugins.format import FormatPlugin
|
||||||
from ytdl_sub.plugins.match_filters import MatchFiltersPlugin, combine_filters, default_filters
|
from ytdl_sub.plugins.match_filters import MatchFiltersPlugin
|
||||||
|
from ytdl_sub.plugins.match_filters import combine_filters
|
||||||
|
from ytdl_sub.plugins.match_filters import default_filters
|
||||||
from ytdl_sub.plugins.subtitles import SubtitlesPlugin
|
from ytdl_sub.plugins.subtitles import SubtitlesPlugin
|
||||||
from ytdl_sub.plugins.throttle_protection import ThrottleProtectionPlugin
|
from ytdl_sub.plugins.throttle_protection import ThrottleProtectionPlugin
|
||||||
from ytdl_sub.utils.ffmpeg import FFMPEG
|
from ytdl_sub.utils.ffmpeg import FFMPEG
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ import threading
|
||||||
import time
|
import time
|
||||||
from json import JSONDecodeError
|
from json import JSONDecodeError
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Set
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
import re
|
import re
|
||||||
from typing import Dict, List, Tuple
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from ytdl_sub.entries.entry import Entry, ytdl_sub_chapters_from_comments
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.entries.script.variable_definitions import VARIABLES, VariableDefinitions
|
from ytdl_sub.entries.entry import ytdl_sub_chapters_from_comments
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
|
||||||
from ytdl_sub.utils.file_handler import FileMetadata
|
from ytdl_sub.utils.file_handler import FileMetadata
|
||||||
|
|
||||||
v: VariableDefinitions = VARIABLES
|
v: VariableDefinitions = VARIABLES
|
||||||
|
|
||||||
|
|
||||||
class Timestamp:
|
class Timestamp:
|
||||||
|
|
||||||
# Captures the following formats:
|
# Captures the following formats:
|
||||||
# 0:00 title
|
# 0:00 title
|
||||||
# 00:00 title
|
# 00:00 title
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict
|
||||||
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.utils.chapters import Chapters
|
from ytdl_sub.utils.chapters import Chapters
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue