[DOCS] Begin complete overhaul of readthedocs (#847)

Readthedocs for ytdl-sub is getting a massive overhaul to both look and read like a modernized app. It is still very-much work-in-progress, stay tuned for more!

Huge thanks to @Svagtlys (aka Momo) for driving this
This commit is contained in:
Qualis Svagtlys 2023-12-27 12:27:40 -06:00 committed by GitHub
parent 02d51d6aec
commit 008bcf1b2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 3211 additions and 1059 deletions

View file

@ -1,16 +1,17 @@
version: 2
build:
os: ubuntu-20.04
os: "ubuntu-22.04"
tools:
python: "3.10"
sphinx:
configuration: docs/conf.py
configuration: docs/source/conf.py
python:
install:
- requirements: docs/source/requirements.txt
- method: pip
path: .
extra_requirements:
- docs
- docs

View file

@ -39,14 +39,14 @@ executable: clean
pyinstaller ytdl-sub.spec
mv dist/ytdl-sub dist/ytdl-sub${EXEC_SUFFIX}
docs:
sphinx-build -a -b html docs docs/_html
sphinx-build -M html docs/source/ docs/build/
clean:
rm -rf \
.pytest_cache/ \
build/ \
dist/ \
src/ytdl_sub.egg-info/ \
docs/_html/ \
docs/build/ \
.coverage \
docker/root/*.whl \
docker/root/defaults/examples \

View file

@ -5,8 +5,8 @@
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
SOURCEDIR = source
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:

View file

@ -1,67 +0,0 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath("../src"))
# -- Project information -----------------------------------------------------
project = "ytdl-sub"
copyright = "2022, Jesse Bannon"
author = "Jesse Bannon"
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.napoleon",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = "sphinx_rtd_theme"
html_theme_options = {"navigation_depth": 10}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ["_static"]
# Do not show full module path in api docs
add_module_names = False
python_use_unqualified_type_names = False
napoleon_numpy_docstrings = True
napoleon_use_rtype = False
# -- Options for autodocs -------------------------------------------------
autodoc_default_options = {"autodoc_typehints_format": "short"}

View file

@ -1,454 +0,0 @@
Config
======
ytdl-sub is configured using a ``config.yaml`` file.
.. _config:
config.yaml
-----------
The ``config.yaml`` is made up of two sections:
.. code-block:: yaml
configuration:
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``.
If you wish to represent paths like Windows, you will need to ``C:\\double\\bashslash\\paths``
in order to escape the backslash 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
""""""""""""
Within ``configuration``, define whether logs from subscription downloads
should be persisted.
.. code-block:: yaml
configuration:
persist_logs:
logs_directory: "/path/to/log/directory"
Log files are stored as
``YYYY-mm-dd-HHMMSS.subscription_name.(success|error).log``.
.. autoclass:: ytdl_sub.config.config_validator.PersistLogsValidator()
:members:
:member-order: bysource
presets
^^^^^^^
``presets`` define a `formula` for how to format downloaded media and metadata.
download_strategy
"""""""""""""""""
Download strategies dictate what is getting downloaded from a source. Each
download strategy has its own set of parameters.
.. _url:
url
'''
.. autoclass:: ytdl_sub.downloaders.url.url.UrlDownloadOptions()
:members: url, playlist_thumbnails, source_thumbnails, download_reverse
:member-order: bysource
multi_url
'''''''''
.. autoclass:: ytdl_sub.downloaders.url.multi_url.MultiUrlDownloadOptions()
:members: urls, variables
-------------------------------------------------------------------------------
output_options
""""""""""""""
.. autoclass:: ytdl_sub.config.preset_options.OutputOptions()
:members:
:member-order: bysource
:exclude-members: get_upload_date_range_to_keep, partial_validate
-------------------------------------------------------------------------------
.. _ytdl_options:
ytdl_options
""""""""""""
.. autoclass:: ytdl_sub.config.preset_options.YTDLOptions()
-------------------------------------------------------------------------------
.. _overrides:
overrides
"""""""""
.. autoclass:: ytdl_sub.config.overrides.Overrides()
.. _parent preset:
preset
""""""
Presets support inheritance by defining a parent preset:
.. code-block:: yaml
presets:
custom_preset:
...
parent_preset:
...
child_preset:
preset: "parent_preset"
In the example above, ``child_preset`` inherits all fields defined in ``parent_preset``.
It is advantageous to use parent presets where possible to reduce duplicate yaml
definitions.
Presets also support inheritance from multiple presets:
.. code-block:: yaml
child_preset:
preset:
- "custom_preset"
- "parent_preset"
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.
If you are only inheriting from one preset, the syntax ``preset: "parent_preset"`` is
valid YAML. Inheriting from multiple presets require use of a list.
-------------------------------------------------------------------------------
Plugins
"""""""
Plugins are used to perform any type of post-processing to the already downloaded files.
audio_extract
'''''''''''''
.. autoclass:: ytdl_sub.plugins.audio_extract.AudioExtractOptions()
:members:
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
chapters
''''''''
.. autoclass:: ytdl_sub.plugins.chapters.ChaptersOptions()
:members:
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
date_range
''''''''''
.. autoclass:: ytdl_sub.plugins.date_range.DateRangeOptions()
:members:
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
embed_thumbnail
''''''''''''''''
.. autoclass:: ytdl_sub.plugins.embed_thumbnail.EmbedThumbnailOptions()
-------------------------------------------------------------------------------
file_convert
''''''''''''
.. autoclass:: ytdl_sub.plugins.file_convert.FileConvertOptions()
:members:
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
format
''''''
.. autoclass:: ytdl_sub.plugins.format.FormatOptions()
-------------------------------------------------------------------------------
match_filters
'''''''''''''
.. autoclass:: ytdl_sub.plugins.match_filters.MatchFiltersOptions()
:members:
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
music_tags
''''''''''
.. autoclass:: ytdl_sub.plugins.music_tags.MusicTagsOptions()
-------------------------------------------------------------------------------
nfo_tags
''''''''
.. autoclass:: ytdl_sub.plugins.nfo_tags.NfoTagsOptions()
:members: nfo_name, nfo_root, tags, kodi_safe
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
output_directory_nfo_tags
'''''''''''''''''''''''''
.. autoclass:: ytdl_sub.plugins.output_directory_nfo_tags.OutputDirectoryNfoTagsOptions()
:members: nfo_name, nfo_root, tags, kodi_safe
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
regex
'''''
.. autoclass:: ytdl_sub.plugins.regex.RegexOptions()
:members: skip_if_match_fails
.. autoclass:: ytdl_sub.plugins.regex.VariableRegex()
:members: match, capture_group_names, capture_group_defaults, exclude
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
split_by_chapters
'''''''''''''''''
.. autoclass:: ytdl_sub.plugins.split_by_chapters.SplitByChaptersOptions()
:members: when_no_chapters
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
subtitles
'''''''''
.. autoclass:: ytdl_sub.plugins.subtitles.SubtitleOptions()
:members: subtitles_name, subtitles_type, embed_subtitles, languages, allow_auto_generated_subtitles
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
throttle_protection
'''''''''''''''''''
.. autoclass:: ytdl_sub.plugins.throttle_protection.ThrottleProtectionOptions()
:members:
:member-order: bysource
-------------------------------------------------------------------------------
video_tags
''''''''''
.. autoclass:: ytdl_sub.plugins.video_tags.VideoTagsOptions()
-------------------------------------------------------------------------------
.. _subscription_yaml:
subscription.yaml
-----------------
The ``subscription.yaml`` file is where we use our `presets`_ in the `config.yaml`_
to define a `subscription`: something we want to recurrently download such as a specific
channel or playlist.
The only difference between a ``subscription`` and ``preset`` is that the subscription
must have all required fields and ``{variables}`` defined so it can perform a download.
Below is an example that downloads a YouTube playlist:
.. code-block:: yaml
:caption: config.yaml
presets:
playlist_preset_ex:
download:
download_strategy: "url"
url: "{url}"
output_options:
output_directory: "{output_directory}/{playlist_name}"
file_name: "{playlist_name}.{title}.{ext}"
overrides:
output_directory: "/path/to/ytdl-sub-videos"
.. code-block:: yaml
:caption: subscription.yaml
my_subscription_name:
preset: "playlist_preset_ex"
overrides:
playlist_name: "diy-playlist"
url: "https://youtube.com/playlist?list=UCsvn_Po0SmunchJYtttWpOxMg"
Our preset ``playlist_preset_ex`` defines three
custom variables: ``{output_directory}``, ``{playlist_name}``, and ``{url}``. The subscription sets
the `parent preset`_ to ``playlist_preset_ex``, and must define the variables ``{playlist_name}``
and ``{url}`` since the preset did not.
.. _beautifying subscriptions:
Beautifying Subscriptions
^^^^^^^^^^^^^^^^^^^^^^^^^
Subscriptions support using presets as keys, and using keys to set override variables as values.
For example:
.. code-block:: yaml
:caption: subscription.yaml
TV Show Full Archive:
= News:
"Breaking News": "https://www.youtube.com/@SomeBreakingNews"
TV Show Only Recent:
= Tech | TV-Y:
"Two Minute Papers": "https://www.youtube.com/@TwoMinutePapers"
Will create two subscriptions named "Breaking News" and "Two Minute Papers", equivalent to:
.. code-block:: yaml
"Breaking News":
preset:
- "TV Show Full Archive"
overrides:
subscription_indent_1: "News"
subscription_name: "Breaking News"
subscription_value: "https://www.youtube.com/@SomeBreakingNews"
"Two Minute Papers":
preset:
- "TV Show Only Recent"
overrides:
subscription_indent_1: "Tech"
subscription_indent_2: "TV-Y"
subscription_name: "Two Minute Papers"
subscription_value: "https://www.youtube.com/@TwoMinutePapers"
You can provide as many parent presets in the form of keys, and subscription indents as ``=keys``.
This can drastically simplify subscription definitions by setting things like so in your
parent preset:
.. code-block:: yaml
presets:
"TV Show Preset":
overrides:
subscription_indent_1: "default-genre"
subscription_indent_2: "default-content-rating"
tv_show_name: "{subscription_name}"
url: "{subscription_value}"
genre: "{subscription_indent_1}"
content_rating: "{subscription_indent_2}"
.. _subscription value:
File Preset
^^^^^^^^^^^
NOTE: This is deprecated in favor of using the method in :ref:`beautifying subscriptions`.
You can apply a preset to all subscriptions in the ``subscription.yaml`` file
by using the file-wide ``__preset__``:
.. code-block:: yaml
:caption: subscription.yaml
__preset__:
preset: "playlist_preset_ex"
my_subscription_name:
overrides:
url: "https://youtube.com/playlist?list=UCsvn_Po0SmunchJYtttWpOxMg"
playlist_name: "diy-playlist"
This ``subscription.yaml`` is equivalent to the one above it because all
subscriptions automatically set ``__preset__`` as a `parent preset`_.
Subscription Value
^^^^^^^^^^^^^^^^^^^
NOTE: This is deprecated in favor of using the method in :ref:`beautifying subscriptions`.
With a clever config and use of ``__preset__``, your subscriptions can typically boil
down to a name and url. You can set ``__value__`` to the name of an override variable,
and use the override variable ``subscription_name`` to achieve one-liner subscriptions.
Using the example above, we can do:
.. code-block:: yaml
:caption: subscription.yaml
__preset__:
preset:
- "tv_show"
overrides:
tv_show_name: "{subscription_name}"
__value__: "url"
# single-line subscription, sets "Brandon Acker" and the subscription value
# to the override variables tv_show_name and url
"Brandon Acker": "https://www.youtube.com/@brandonacker"
Traditional subscriptions that can override presets will still work when using ``__value__``.
``__value__`` can also be set within a :ref:`config`.
-------------------------------------------------------------------------------
.. _source-variables:
Source Variables
----------------
.. autoclass:: ytdl_sub.entries.script.variable_definitions.VariableDefinitions()
:members:
:inherited-members:
:undoc-members:
Override Variables
------------------
.. autoclass:: ytdl_sub.entries.variables.override_variables.OverrideVariables()
:members:
:member-order: bysource
-------------------------------------------------------------------------------
Config Types
------------
The `config.yaml`_ uses various types for its configurable fields. Below is a definition for each type.
.. autoclass:: ytdl_sub.validators.string_formatter_validators.StringFormatterValidator()
.. autoclass:: ytdl_sub.validators.string_formatter_validators.OverridesStringFormatterValidator()
.. autoclass:: ytdl_sub.validators.file_path_validators.StringFormatterFileNameValidator()
.. autoclass:: ytdl_sub.validators.string_datetime.StringDatetimeValidator()
.. autoclass:: ytdl_sub.validators.string_formatter_validators.DictFormatterValidator()
.. autoclass:: ytdl_sub.validators.string_formatter_validators.OverridesDictFormatterValidator()

View file

@ -1,29 +0,0 @@
Getting Started
===============
Walk-through Guide
-------------------
If you haven't read it yet, it's highly recommended to go through our
`walk-through guide <https://github.com/jmbannon/ytdl-sub/wiki/1.-Introduction>`_
to get familiar with how ``ytdl-sub`` works.
Example Configs
---------------
If you are ready to start downloading, see our
`examples directory <https://github.com/jmbannon/ytdl-sub/tree/master/examples>`_
for ready-to-use configs and subscriptions. Read through them carefully before use.
Using Example Configs
^^^^^^^^^^^^^^^^^^^^^^
Copy and paste the examples into local yaml files, modify the
``working_directory`` and ``output_directory`` with your desired paths,
and perform a dry-run using
.. code-block:: bash
ytdl-sub \
--dry-run \
--config path/to/config.yaml \
sub path/to/subscriptions.yaml
This will simulate what a download will look like.

View file

@ -1,29 +0,0 @@
ytdl-sub readthedocs
====================
Our readthedocs page is dedicated towards ytdl-sub config documentation.
If you are new to ytdl-sub, head over to the
`GitHub Wiki <https://github.com/jmbannon/ytdl-sub/wiki>`_
to see our
`walkthrough <https://github.com/jmbannon/ytdl-sub/wiki/1.-Introduction>`_ and
`FAQ <https://github.com/jmbannon/ytdl-sub/wiki/FAQ>`_. For full examples of
ytdl-sub configs, check out the
`examples directory <https://github.com/jmbannon/ytdl-sub/tree/master/examples>`_.
For navigating config docs, use the left-side bar on the
:ref:`config` page to find every available ytdl-sub field.
Contents
========
.. toctree::
:maxdepth: 2
install
usage
getting_started
presets
config
deprecation_notices

View file

@ -1,256 +0,0 @@
Install
=======
``ytdl-sub`` can be installed on the following platforms.
.. contents::
:depth: 3
All installations require a 64-bit CPU. 32-bit is not supported.
Docker Compose
--------------
The ytdl-sub Docker images use
`LSIO-based images <https://www.linuxserver.io/>`_
and installs ytdl-sub on top. There are a few flavors to choose from.
For automating ``subscriptions.yaml`` downloads to pull new media, see
`this guide <https://github.com/jmbannon/ytdl-sub/wiki/7.-Automate-Downloading-New-Content-Using-Your-Configs/>`_
on how set up a cron job in any of the docker containers.
GUI
^^^^
The GUI image uses LSIO's
`code-server <https://hub.docker.com/r/linuxserver/code-server>`_
for its base image. More info on other code-server environment variables
can be found within its documentation. This is the recommended way to use ``ytdl-sub``.
After starting, code-server will be running at http://localhost:8443/
.. code-block:: yaml
services:
ytdl-sub:
image: ghcr.io/jmbannon/ytdl-sub-gui:latest
container_name: ytdl-sub
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
volumes:
- <path/to/ytdl-sub/config>:/config
- <path/to/tv_shows>:/tv_shows # optional
- <path/to/movies>:/movies # optional
- <path/to/music_videos>:/music_videos # optional
- <path/to/music>:/music # optional
ports:
- 8443:8443
restart: unless-stopped
Headless
^^^^^^^^^^
The headless image uses LSIO's
`baseimage-alpine <https://github.com/linuxserver/docker-baseimage-alpine>`_
for its base image. With this image, ``ytdl-sub`` is meant to be ran from console
via exec'ing into the image using the command:
.. code-block:: bash
docker exec -u abc -it ytdl-sub /bin/bash
.. code-block:: yaml
services:
ytdl-sub:
image: ghcr.io/jmbannon/ytdl-sub:latest
container_name: ytdl-sub
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
- DOCKER_MODS=linuxserver/mods:universal-cron
volumes:
- <path/to/ytdl-sub/config>:/config
- <path/to/tv_shows>:/tv_shows # optional
- <path/to/movies>:/movies # optional
- <path/to/music_videos>:/music_videos # optional
- <path/to/music>:/music # optional
restart: unless-stopped
Passthrough
^^^^^^^^^^^
For CPU or GPU passthrough, you must use either the GUI image or the headless Ubuntu image
``ghcr.io/jmbannon/ytdl-sub:ubuntu-latest``.
The docker-compose examples use the GUI image.
CPU
____
.. code-block:: yaml
services:
ytdl-sub:
image: ghcr.io/jmbannon/ytdl-sub-gui:latest
container_name: ytdl-sub
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
volumes:
- <path/to/ytdl-sub/config>:/config
- <path/to/tv_shows>:/tv_shows # optional
- <path/to/movies>:/movies # optional
- <path/to/music_videos>:/music_videos # optional
- <path/to/music>:/music # optional
ports:
- 8443:8443
devices:
- /dev/dri:/dev/dri # CPU passthrough
restart: unless-stopped
GPU
____
.. code-block:: yaml
services:
ytdl-sub:
image: ghcr.io/jmbannon/ytdl-sub-gui:latest
container_name: ytdl-sub
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
- NVIDIA_DRIVER_CAPABILITIES=all # Nvidia ENV args
- NVIDIA_VISIBLE_DEVICES=all
volumes:
- <path/to/ytdl-sub/config>:/config
- <path/to/tv_shows>:/tv_shows # optional
- <path/to/movies>:/movies # optional
- <path/to/music_videos>:/music_videos # optional
- <path/to/music>:/music # optional
ports:
- 8443:8443
deploy:
resources:
reservations:
devices:
- capabilities: [gpu] # GPU passthrough
restart: unless-stopped
Docker
--------------
.. code-block:: bash
docker run -d \
--name=ytdl-sub \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=America/Los_Angeles \
-p 8443:8443 \
-v <path/to/ytdl-sub/config>:/config \
-v <OPTIONAL/path/to/tv_shows>:/tv_shows \
-v <OPTIONAL/path/to/movies>:/movies \
-v <OPTIONAL/path/to/music_videos>:/music_videos \
-v <OPTIONAL/path/to/music>:/music \
--restart unless-stopped \
ghcr.io/jmbannon/ytdl-sub-gui:latest
Windows
--------------
From powershell, run:
.. code-block:: powershell
# Download ffmpeg/ffprobe dependencies from yt-dlp
curl.exe -L -o ffmpeg.zip https://github.com/yt-dlp/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip
tar -xf ffmpeg.zip
move "ffmpeg-master-latest-win64-gpl\bin\ffmpeg.exe" "ffmpeg.exe"
move "ffmpeg-master-latest-win64-gpl\bin\ffprobe.exe" "ffprobe.exe"
# Download ytdl-sub
curl.exe -L -o ytdl-sub.exe https://github.com/jmbannon/ytdl-sub/releases/latest/download/ytdl-sub.exe
ytdl-sub.exe -h
Unraid
--------------
See the
`community app <https://unraid.net/community/apps?q=ytdl-sub#r>`_
``ytdl-sub``. Uses Docker under the hood.
Linux
--------------
Requires ffmpeg as a dependency. Can typically be installed with any Linux package manager.
.. code-block:: bash
curl -L -o ytdl-sub https://github.com/jmbannon/ytdl-sub/releases/latest/download/ytdl-sub
chmod +x ytdl-sub
ytdl-sub -h
You can also install using yt-dlp's ffmpeg builds. This ensures your ffmpeg is up to date:
.. code-block:: bash
curl -L -o ffmpeg.tar.gz https://github.com/yt-dlp/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz
tar -xf ffmpeg.tar.gz
chmod +x ffmpeg-master-latest-linux64-gpl/bin/ffmpeg
chmod +x ffmpeg-master-latest-linux64-gpl/bin/ffprobe
# May need sudo / root permissions to perform
mv ffmpeg-master-latest-linux64-gpl/bin/ffmpeg /usr/bin/ffmpeg
mv ffmpeg-master-latest-linux64-gpl/bin/ffprobe /usr/bin/ffprobe
Linux ARM
--------------
Requires ffmpeg as a dependency. Can typically be installed with any Linux package manager.
.. code-block:: bash
curl -L -o ytdl-sub https://github.com/jmbannon/ytdl-sub/releases/latest/download/ytdl-sub_aarch64
chmod +x ytdl-sub
ytdl-sub -h
You can also install using yt-dlp's ffmpeg builds. This ensures your ffmpeg is up to date:
.. code-block:: bash
curl -L -o ffmpeg.tar.gz https://github.com/yt-dlp/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linuxarm64-gpl.tar.xz
tar -xf ffmpeg.tar.gz
chmod +x ffmpeg-master-latest-linuxarm64-gpl/bin/ffmpeg
chmod +x ffmpeg-master-latest-linuxarm64-gpl/bin/ffprobe
# May need sudo / root permissions to perform
mv ffmpeg-master-latest-linuxarm64-gpl/bin/ffmpeg /usr/bin/ffmpeg
mv ffmpeg-master-latest-linuxarm64-gpl/bin/ffprobe /usr/bin/ffprobe
PIP
--------------
You can install our
`PyPI package <https://pypi.org/project/ytdl-sub/>`_.
Both ffmpeg and Python 3.10 or greater are required.
.. code-block:: bash
python3 -m pip install -U ytdl-sub
Local Install
--------------
With a Python 3.10 virtual environment, you can clone and install the repo using
.. code-block:: bash
git clone https://github.com/jmbannon/ytdl-sub.git
cd ytdl-sub
pip install -e .
Local Docker Build
-------------------
Run ``make docker`` in the root directory of this repo to build the image. This
will build the python wheel and install it in the Dockerfile.

View file

@ -7,8 +7,8 @@ REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
set SOURCEDIR=source
set BUILDDIR=build
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (

View file

@ -1,183 +0,0 @@
Presets
=======
``ytdl-sub`` offers a number of built-in presets using best practices for formatting
media in various players. For advanced users, you can find the prebuilt preset
definitions
`here <https://github.com/jmbannon/ytdl-sub/tree/master/src/ytdl_sub/prebuilt_presets>`_.
TV Shows
--------
There are two main methods for downloading and formatting videos as a TV show.
TV Show by Date
^^^^^^^^^^^^^^^
TV Show by Date will organize something like a YouTube channel or playlist
into a tv show, where seasons and episodes are organized using upload date.
Player Presets
""""""""""""""
* ``kodi_tv_show_by_date``
* ``jellyfin_tv_show_by_date``
* ``plex_tv_show_by_date``
Episode Formatting Presets
""""""""""""""""""""""""""
* ``season_by_year__episode_by_month_day``
* ``season_by_year_month__episode_by_day``
* ``season_by_year__episode_by_month_day_reversed``
* Episode numbers are reversed, meaning more recent episodes appear at the
top of a season by having a lower value.
* ``season_by_year__episode_by_download_index``
* Episodes are numbered by the download order. NOTE that this fetched using
the length of the download archive. Do not use if you intend to remove
old videos.
Usage
"""""
A preset/subscription requires specifying a player and episode formatting preset
and overriding the following variables:
.. code-block:: yaml
rick_a_tv_show_by_date:
preset:
- "jellyfin_tv_show_by_date"
- "season_by_year__episode_by_month_day"
overrides:
# required
tv_show_name: "Rick A"
tv_show_directory: "/path/to/youtube_shows"
url: "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
# can be modified from their default value
# tv_show_genre: "ytdl-sub"
# tv_show_content_rating: "TV-14"
# episode_title: "{upload_date_standardized} - {title}"
# episode_description: "{webpage_url}"
In addition, you can add additional URLs to create a single TV by using the override variables
``url2``, ``url3``, ..., ``url20``:
.. code-block:: yaml
overrides:
tv_show_name: "Rick A"
tv_show_directory: "/path/to/youtube_shows"
url: "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
url2: "https://www.youtube.com/@just.rick_6"
TV Show Collection
^^^^^^^^^^^^^^^^^^
TV Show Collections are made up from multiple URLs, where each URL is a season.
If a video belongs to multiple URLs (i.e. a channel and a channel's playlist),
it will resolve to the bottom-most season.
Two main use cases of a collection are:
1. Organize a YouTube channel TV show where Season 1 contains any video
not in a 'season playlist', Season 2 for 'Playlist A', Season 3 for
'Playlist B', etc.
2. Organize one or more YouTube channels/playlists, where each season
represents a separate channel/playlist.
Player Presets
""""""""""""""
* ``kodi_tv_show_collection``
* ``jellyfin_tv_show_collection``
* ``plex_tv_show_collection``
Episode Formatting Presets
""""""""""""""""""""""""""
* ``season_by_collection__episode_by_year_month_day``
* ``season_by_collection__episode_by_year_month_day_reversed``
* ``season_by_collection__episode_by_playlist_index``
* Only use playlist_index episode formatting for playlists that
will be fully downloaded once and never again. Otherwise,
indices can change.
* ``season_by_collection__episode_by_playlist_index_reversed``
Season Presets
""""""""""""""
* ``collection_season_1``
* ``collection_season_2``
* ``collection_season_3``
* ``collection_season_4``
* ``...``
* ``collection_season_40``
Example
"""""""
A preset/subscription requires specifying a player, episode formatting, and
one or more season presets, with the following override variables:
.. code-block:: yaml
rick_a_tv_show_collection:
preset:
- "jellyfin_tv_show_collection"
- "season_by_collection__episode_by_year_month_day_reversed"
- "collection_season_1"
- "collection_season_2"
overrides:
# required
tv_show_name: "Rick A"
tv_show_directory: "/path/to/youtube_shows"
collection_season_1_url: "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
collection_season_1_name: "All Videos"
collection_season_2_url: "https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
collection_season_2_name: "Official Music Videos"
# can be modified from their default value
# tv_show_genre: "ytdl-sub"
# episode_title: "{upload_date_standardized} - {title}"
# episode_description: "{webpage_url}"
Common
------
Common presets are applicable to any config.
Best Video Quality
^^^^^^^^^^^^^^^^^^
Add the following preset to download the best available video and audio quality, and remux
it into an MP4 container:
* ``best_video_quality``
Max 1080p
^^^^^^^^^^^^^^^^^^
Add the following preset to download the best available audio and video quality, with the video not greater than 1080p, and remux it into an MP4 container:
* ``max_1080p``
Chunk Initial Download
^^^^^^^^^^^^^^^^^^^^^^
If you are archiving a large channel, ``ytdl-sub`` will try pulling each video's metadata from
newest to oldest before starting any downloads. It is a long process and not ideal. A better method
is to chunk the process by using the following preset:
* ``chunk_initial_download``
It will download videos starting from the oldest one, and only download 20 at a time. You can
change this number by setting:
.. code-block:: yaml
ytdl_options:
max_downloads: 30 # Desired number to download per invocation
Once the entire channel is downloaded, remove this preset. Then it will pull metadata from newest to
oldest again, and stop pulling additional metadata once it reaches a video that has already been
downloaded.

87
docs/source/conf.py Normal file
View file

@ -0,0 +1,87 @@
# Configuration file for the Sphinx documentation builder.
# For the full list of built-in configuration values, see the documentation:
# 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"
copyright = "2023, Jesse Bannon"
author = "Jesse Bannon"
release = "2023.12.15"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.autosectionlabel",
"sphinx.ext.extlinks",
"sphinx.ext.napoleon",
"sphinx_copybutton",
"sphinx_design",
]
templates_path = ["_templates"]
exclude_patterns = []
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = "sphinx_book_theme"
html_theme_options = {
"icon_links": [
{
"name": "GitHub",
"url": "https://github.com/jmbannon/ytdl-sub",
"icon": "fa-brands fa-square-github",
"type": "fontawesome",
},
{
"name": "Discord",
"url": "https://discord.gg/v8j9RAHb4k",
"icon": "https://img.shields.io/discord/994270357957648404?logo=Discord",
"type": "url",
},
],
"announcement": ("Please excuse our mess as we update these documents"),
"navigation_depth": 10,
"show_toc_level": 10,
}
html_static_path = ["_static"]
# Make sure the all autosectionlabel targets are unique
autosectionlabel_prefix_document = True
suppress_warnings = [
"autosectionlabel.*",
]
extlinks = {
"yt-dlp": ("https://github.com/yt-dlp/yt-dlp/%s", "yt-dlp%s"),
"unraid": ("https://unraid.net/%s", "unraid%s"),
"lsio": ("https://www.linuxserver.io/%s", "lsio%s"),
"lsio-gh": ("https://github.com/linuxserver/%s", "%s image"),
"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

View file

@ -0,0 +1,134 @@
==================
Configuration File
==================
-----------
config.yaml
-----------
ytdl-sub is configured using a ``config.yaml`` file.
The ``config.yaml`` is made up of two sections:
.. code-block:: yaml
configuration:
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``.
If you wish to represent paths like Windows, you will need to ``C:\\double\\bashslash\\paths``
in order to escape the backslash 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
""""""""""""
Within ``configuration``, define whether logs from subscription downloads
should be persisted.
.. code-block:: yaml
configuration:
persist_logs:
logs_directory: "/path/to/log/directory"
Log files are stored as
``YYYY-mm-dd-HHMMSS.subscription_name.(success|error).log``.
.. autoclass:: ytdl_sub.config.config_validator.PersistLogsValidator()
:members:
:member-order: bysource
presets
~~~~~~~
``presets`` define a `formula` for how to format downloaded media and metadata.
download_strategy
"""""""""""""""""
Download strategies dictate what is getting downloaded from a source. Each
download strategy has its own set of parameters.
.. _url:
url
'''
.. autoclass:: ytdl_sub.downloaders.url.url.UrlDownloadOptions()
:members: url, playlist_thumbnails, source_thumbnails, download_reverse
:member-order: bysource
multi_url
'''''''''
.. autoclass:: ytdl_sub.downloaders.url.multi_url.MultiUrlDownloadOptions()
:members: urls, variables
-------------------------------------------------------------------------------
output_options
""""""""""""""
.. autoclass:: ytdl_sub.config.preset_options.OutputOptions()
:members:
:member-order: bysource
:exclude-members: get_upload_date_range_to_keep, partial_validate
-------------------------------------------------------------------------------
.. _ytdl_options:
ytdl_options
""""""""""""
.. autoclass:: ytdl_sub.config.preset_options.YTDLOptions()
-------------------------------------------------------------------------------
.. _overrides:
overrides
"""""""""
.. autoclass:: ytdl_sub.config.overrides.Overrides()
.. _parent preset:
preset
""""""
Presets support inheritance by defining a parent preset:
.. code-block:: yaml
presets:
custom_preset:
...
parent_preset:
...
child_preset:
preset: "parent_preset"
In the example above, ``child_preset`` inherits all fields defined in ``parent_preset``.
It is advantageous to use parent presets where possible to reduce duplicate yaml
definitions.
Presets also support inheritance from multiple presets:
.. code-block:: yaml
child_preset:
preset:
- "custom_preset"
- "parent_preset"
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.
If you are only inheriting from one preset, the syntax ``preset: "parent_preset"`` is
valid YAML. Inheriting from multiple presets require use of a list.

View file

@ -0,0 +1,12 @@
=========
Reference
=========
This section contains direct references to the code of ``ytdl-sub`` and information on how it functions.
.. toctree::
config_yaml
subscriptions_yaml
plugins
scripting/index
prebuilt_presets/index

View file

@ -0,0 +1,767 @@
Plugins
=======
audio_extract
-------------
Extracts audio from a video file.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
audio_extract:
codec: "mp3"
quality: 128
codec
~~~~~
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.
quality
~~~~~~~
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.
chapters
--------
Embeds chapters to video files if they are present. Additional options to add SponsorBlock
chapters and remove specific ones. Can also remove chapters using regex.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
chapters:
# Embedded Chapter Fields
embed_chapters: True
allow_chapters_from_comments: False
remove_chapters_regex:
- "Intro"
- "Outro"
# Sponsorblock Fields
sponsorblock_categories:
- "outro"
- "selfpromo"
- "preview"
- "interaction"
- "sponsor"
- "music_offtopic"
- "intro"
remove_sponsorblock_categories: "all"
force_key_frames: False
allow_chapters_from_comments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Optional. If chapters do not exist in the video/description itself, attempt to scrape
comments to find the chapters. Defaults to False.
embed_chapters
~~~~~~~~~~~~~~
Optional. Embed chapters into the file. Defaults to True.
force_key_frames
~~~~~~~~~~~~~~~~
Optional. 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. Defaults to
False.
remove_chapters_regex
~~~~~~~~~~~~~~~~~~~~~
Optional. List of regex patterns to match chapter titles against and remove them from the
entry.
remove_sponsorblock_categories
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Optional. List of SponsorBlock categories to remove from the output file. Can only remove
categories that are specified in ``sponsorblock_categories`` or "all", which removes
everything specified in ``sponsorblock_categories``.
sponsorblock_categories
~~~~~~~~~~~~~~~~~~~~~~~
Optional. List of SponsorBlock categories to embed as chapters. Supports "sponsor",
"intro", "outro", "selfpromo", "preview", "filler", "interaction", "music_offtopic",
"poi_highlight", or "all" to include all categories.
date_range
----------
Only download files uploaded within the specified date range.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
date_range:
before: "now"
after: "today-2weeks"
after
~~~~~
Optional. Only download videos after this datetime.
before
~~~~~~
Optional. Only download videos before this datetime.
embed_thumbnail
---------------
Whether to embed thumbnails to the audio/video file or not.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
embed_thumbnail: True
file_convert
------------
Converts video files from one extension to another.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
file_convert:
convert_to: "mp4"
Supports custom ffmpeg conversions:
.. code-block:: yaml
presets:
my_example_preset:
file_convert:
convert_to: "mkv"
convert_with: "ffmpeg"
ffmpeg_post_process_args: >
-bitexact
-vcodec copy
-acodec copy
-scodec mov_text
convert_to
~~~~~~~~~~
Convert to a desired file type. Supports:
* Video: avi, flv, mkv, mov, mp4, webm
* Audio: aac, flac, mp3, m4a, opus, vorbis, wav
convert_with
~~~~~~~~~~~~
Optional. Supports ``yt-dlp`` and ``ffmpeg``. ``yt-dlp`` will convert files within
yt-dlp whereas ``ffmpeg`` specifies it will be converted using a custom command specified
with ``ffmpeg_post_process_args``. Defaults to ``yt-dlp``.
ffmpeg_post_process_args
~~~~~~~~~~~~~~~~~~~~~~~~
Optional. ffmpeg args to post-process an entry file with. The args will be inserted in the
form of:
.. code-block:: bash
ffmpeg -i input_file.ext {ffmpeg_post_process_args) output_file.output_ext
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``.
format
------
Set ``--format`` to pass into yt-dlp to download a specific format quality.
Uses the same syntax as yt-dlp.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
format: "(bv*[height<=1080]+bestaudio/best[height<=1080])"
format
~~~~~~
yt-dlp format, uses same syntax as yt-dlp.
match_filters
-------------
Set ``--match-filters``` to pass into yt-dlp to filter entries from being downloaded.
Uses the same syntax as yt-dlp.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
match_filters:
filters: "original_url!*=/shorts/"
Supports one or multiple filters:
.. code-block:: yaml
presets:
my_example_preset:
match_filters:
filters:
- "age_limit<?18"
- "like_count>?100"
# Other common match-filters
# - "original_url!*=/shorts/ & !is_live"
# - "age_limit<?18"
# - "availability=?public"
filters
~~~~~~~
The filters themselves. If used multiple times, the filter matches if at least one of the
conditions are met. For logical AND's between match filters, use the ``&`` operator in
a single match filter. These are applied when gathering metadata.
music_tags
----------
Adds tags to every download audio file using
`MediaFile <https://mediafile.readthedocs.io/en/latest/>`_,
the same audio file tagging package used by
`beets <https://beets.readthedocs.io/en/stable/>`_.
It supports basic tags like ``title``, ``album``, ``artist`` and ``albumartist``. You can find
a full list of tags for various file types in MediaFile's
`source code <https://github.com/beetbox/mediafile/blob/v0.9.0/mediafile.py#L1770>`_.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
music_tags:
tags:
artist: "{artist}"
album: "{album}"
# Supports id3v2.4 multi-tags
genres:
- "{genre}"
- "ytdl-sub"
albumartists:
- "{artist}"
- "ytdl-sub"
embed_thumbnail
~~~~~~~~~~~~~~~
Optional. Whether to embed the thumbnail into the audio file.
tags
~~~~
Key, values of tag names, tag values. Supports source and override variables.
Supports lists which will get written to MP3s as id3v2.4 multi-tags.
nfo_tags
--------
Adds an NFO file for every download file. An NFO file is simply an XML file
with a ``.nfo`` extension. You can add any values into the NFO.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
nfo_tags:
# required
nfo_name: "{title_sanitized}.nfo"
nfo_root: "episodedetails"
tags:
title: "{title}"
season: "{upload_year}"
episode: "{upload_month}{upload_day_padded}"
# optional
kodi_safe: False
kodi_safe
~~~~~~~~~
Optional. Kodi does not support > 3-byte unicode characters, which include emojis and some
foreign language characters. Setting this to True will replace those characters with '□'.
Defaults to False.
nfo_name
~~~~~~~~
The NFO file name.
nfo_root
~~~~~~~~
The root tag of the NFO's XML. In the usage above, it would look like
.. code-block:: xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<episodedetails>
</episodedetails>
tags
~~~~
Tags within the nfo_root tag. In the usage above, it would look like
.. code-block:: xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<episodedetails>
<title>Awesome Youtube Video</title>
<season>2022</season>
<episode>502</episode>
</episodedetails>
Also supports xml attributes and duplicate keys:
.. code-block:: yaml
tags:
season:
attributes:
name: "Best Year"
tag: "{upload_year}"
genre:
- "Comedy"
- "Drama"
Which translates to
.. code-block:: xml
<season name="Best Year">2022</season>
<genre>Comedy</genre>
<genre>Drama</genre>
output_directory_nfo_tags
-------------------------
Adds a single NFO file in the output directory. An NFO file is simply an XML file with a
``.nfo`` extension. It uses the last entry's source variables which can change per download
invocation. Be cautious of which variables you use.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
output_directory_nfo_tags:
# required
nfo_name: "tvshow.nfo"
nfo_root: "tvshow"
tags:
title: "Sweet youtube TV show"
# optional
kodi_safe: False
kodi_safe
~~~~~~~~~
Optional. Kodi does not support > 3-byte unicode characters, which include emojis and some
foreign language characters. Setting this to True will replace those characters with '□'.
Defaults to False.
nfo_name
~~~~~~~~
The NFO file name.
nfo_root
~~~~~~~~
The root tag of the NFO's XML. In the usage above, it would look like
.. code-block:: xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<tvshow>
</tvshow>
tags
~~~~
Tags within the nfo_root tag. In the usage above, it would look like
.. code-block:: xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<tvshow>
<title>Sweet youtube TV show</title>
</tvshow>
Also supports xml attributes and duplicate keys:
.. code-block:: yaml
tags:
named_season:
- tag: "{source_title}"
attributes:
number: "{collection_index}"
genre:
- "Comedy"
- "Drama"
Which translates to
.. code-block:: xml
<title year="2022">Sweet youtube TV show</season>
<genre>Comedy</genre>
<genre>Drama</genre>
output_options
--------------
Defines where to output files and thumbnails after all post-processing has completed.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
output_options:
# required
output_directory: "/path/to/videos_or_music"
file_name: "{title_sanitized}.{ext}"
# optional
thumbnail_name: "{title_sanitized}.{thumbnail_ext}"
info_json_name: "{title_sanitized}.{info_json_ext}"
download_archive_name: ".ytdl-sub-{subscription_name}-download-archive.json"
migrated_download_archive_name: ".ytdl-sub-{subscription_name_sanitized}-download-archive.json"
maintain_download_archive: True
keep_files_before: now
keep_files_after: 19000101
download_archive_name
~~~~~~~~~~~~~~~~~~~~~
Optional. The file name to store a subscriptions download archive placed relative to
the output directory. Defaults to ``.ytdl-sub-{subscription_name}-download-archive.json``
file_name
~~~~~~~~~
Required. 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.
info_json_name
~~~~~~~~~~~~~~
Optional. The file name for the media's info json file. This can include directories such
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.
keep_files_after
~~~~~~~~~~~~~~~~
Optional. Requires ``maintain_download_archive`` set to True.
Only keeps files that are uploaded after this datetime. By default, ytdl-sub will keep
files after ``19000101``, which implies all files. Can be used in conjunction with
``keep_max_files``.
keep_files_before
~~~~~~~~~~~~~~~~~
Optional. Requires ``maintain_download_archive`` set to True.
Only keeps files that are uploaded before this datetime. By default, ytdl-sub will keep
files before ``now``, which implies all files. Can be used in conjunction with
``keep_max_files``.
keep_max_files
~~~~~~~~~~~~~~
Optional. Requires ``maintain_download_archive`` set to True.
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``.
maintain_download_archive
~~~~~~~~~~~~~~~~~~~~~~~~~
Optional. Maintains a download archive file in the output directory for a subscription.
It is named ``.ytdl-sub-{subscription_name}-download-archive.json``, stored in the
output directory.
The download archive contains a mapping of ytdl IDs to downloaded files. This is used to
create a ytdl download-archive file when invoking a download on a subscription. This will
prevent ytdl from redownloading media already downloaded.
Defaults to False.
migrated_download_archive_name
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Optional. Intended to be used if you are migrating a subscription with either a new
subscription name or output directory. It will try to load the archive file using this name
first, and fallback to ``download_archive_name``. It will always save to this file
and remove the original ``download_archive_name``.
output_directory
~~~~~~~~~~~~~~~~
Required. The output directory to store all media files downloaded.
thumbnail_name
~~~~~~~~~~~~~~
Optional. The file name for the media's thumbnail image. This can include directories such
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.
overrides
---------
Optional. This section allows you to define variables that can be used in any string formatter.
For example, if you want your file and thumbnail files to match without copy-pasting a large
format string, you can define something like:
.. code-block:: yaml
presets:
my_example_preset:
overrides:
output_directory: "/path/to/media"
custom_file_name: "{upload_date_standardized}.{title_sanitized}"
# Then use the override variables in the output options
output_options:
output_directory: "{output_directory}"
file_name: "{custom_file_name}.{ext}"
thumbnail_name: "{custom_file_name}.{thumbnail_ext}"
Override variables can contain explicit values and other variables, including both override
and source variables.
In addition, any override variable defined will automatically create a ``sanitized`` variable
for use. In the example above, ``output_directory_sanitized`` will exist and perform
sanitization on the value when used.
regex
-----
Performs regex matching on an entry's source or override variables. Regex can be used to filter
entries from proceeding with download or capture groups to create new source variables.
NOTE that YAML differentiates between single-quote (``'``) and double-quote (``"``), which can
affect regex. Double-quote implies string literals, i.e. ``"\n"`` is the literal chars ``\n``,
whereas single-quote, ``'\n'`` gets evaluated to a new line. To escape ``\`` when using
single-quote, use ``\\``. This is necessary if you want your regex to be something like
``\d\n`` to match a number and adjacent new-line. It must be written as ``\\d\n``.
If you want to regex-search multiple source variables to create a logical OR effect, you can
create an override variable that contains the concatenation of them, and search that with regex.
For example, creating the override variable ``"title_and_description": "{title} {description}"``
and using ``title_and_description`` can regex match/exclude from either ``title`` or
``description``.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
regex:
# By default, if any match fails and has no defaults, the entry will
# be skipped. If False, ytdl-sub will error and stop all downloads
# from proceeding.
skip_if_match_fails: True
from:
# For each entry's `title` value...
title:
# Perform this regex match on it to act as a filter.
# This will only download videos with "[Official Video]" in it. Note that we
# double backslash to make YAML happy
match:
- '\\[Official Video\\]'
# For each entry's `description` value...
description:
# Match with capture groups and defaults.
# This tries to scrape a date from the description and produce new
# source variables
match:
- '([0-9]{4})-([0-9]{2})-([0-9]{2})'
# Exclude any entry where the description contains #short
exclude:
- '#short'
# Each capture group creates these new source variables, respectively,
# as well a sanitized version, i.e. `captured_upload_year_sanitized`
capture_group_names:
- "captured_upload_year"
- "captured_upload_month"
- "captured_upload_day"
# And if the string does not match, use these as respective default
# values for the new source variables.
capture_group_defaults:
- "{upload_year}"
- "{upload_month}"
- "{upload_day}"
skip_if_match_fails
~~~~~~~~~~~~~~~~~~~
Defaults to True. If True, when any match fails and has no defaults, the entry will be
skipped. If False, ytdl-sub will error and all downloads will not proceed.
split_by_chapters
-----------------
Splits a file by chapters into multiple files. Each file becomes its own entry with the
new source variables ``chapter_title``, ``chapter_title_sanitized``, ``chapter_index``,
``chapter_index_padded``, ``chapter_count``.
If a file has no chapters, and ``when_no_chapters`` is set to "pass", then ``chapter_title`` is
set to the entry's title and ``chapter_index``, ``chapter_count`` are both set to 1.
Note that when using this plugin and performing dry-run, it assumes embedded chapters are being
used with no modifications.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
split_by_chapters:
when_no_chapters: "pass"
when_no_chapters
~~~~~~~~~~~~~~~~
Behavior to perform when no chapters are present. Supports "pass" (continue processing),
"drop" (exclude it from output), and "error" (stop processing for everything).
subtitles
---------
Defines how to download and store subtitles. Using this plugin creates two new variables:
``lang`` and ``subtitles_ext``. ``lang`` is dynamic since you can download multiple subtitles.
It will set the respective language to the correct subtitle file.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
subtitles:
subtitles_name: "{title_sanitized}.{lang}.{subtitles_ext}"
subtitles_type: "srt"
embed_subtitles: False
languages: "en" # supports list of multiple languages
allow_auto_generated_subtitles: False
allow_auto_generated_subtitles
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Optional. Whether to allow auto generated subtitles. Defaults to False.
embed_subtitles
~~~~~~~~~~~~~~~
Optional. Whether to embed the subtitles into the video file. Defaults to False.
NOTE: webm files can only embed "vtt" subtitle types.
languages
~~~~~~~~~
Optional. Language code(s) to download for subtitles. Supports a single or list of multiple
language codes. Defaults to "en".
subtitles_name
~~~~~~~~~~~~~~
Optional. The file name for the media's subtitles if they are present. This can include
directories such as ``"Season {upload_year}/{title_sanitized}.{lang}.{subtitles_ext}"``, 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.
subtitles_type
~~~~~~~~~~~~~~
Optional. One of the subtitle file types "srt", "vtt", "ass", "lrc". Defaults to "srt"
throttle_protection
-------------------
Provides options to make ytdl-sub look more 'human-like' to protect from throttling. For
range-based values, a random number will be chosen within the range to avoid sleeps looking
scripted.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
throttle_protection:
sleep_per_download_s:
min: 2.2
max: 10.8
sleep_per_subscription_s:
min: 9.0
max: 14.1
max_downloads_per_subscription:
min: 10
max: 36
subscription_download_probability: 1.0
max_downloads_per_subscription
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Number of downloads to perform per subscription.
sleep_per_download_s
~~~~~~~~~~~~~~~~~~~~
Number in seconds to sleep between each download. Does not include time it takes for
ytdl-sub to perform post-processing.
sleep_per_subscription_s
~~~~~~~~~~~~~~~~~~~~~~~~
Number in seconds to sleep between each subscription.
subscription_download_probability
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Probability to perform any downloads, recomputed for each subscription. This is only
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.
video_tags
----------
Adds tags to every downloaded video file using ffmpeg ``-metadata key=value`` args.
Usage:
.. code-block:: yaml
presets:
my_example_preset:
video_tags:
title: "{title}"
date: "{upload_date}"
description: "{description}"
tags
~~~~
Key/values of tag names/values. Supports source and override variables.
ytdl_options
------------
Optional. This section allows you to add any ytdl argument to ytdl-sub's downloader.
The argument names can differ slightly from the command-line argument names. See
`this docstring <https://github.com/yt-dlp/yt-dlp/blob/2022.04.08/yt_dlp/YoutubeDL.py#L197>`_
for more details.
ytdl_options should be formatted like:
.. code-block:: yaml
presets:
my_example_preset:
ytdl_options:
# Ignore any download related errors and continue
ignoreerrors: True
# Stop downloading additional metadata/videos if it
# exists in your download archive
break_on_existing: True
# Stop downloading additional metadata/videos if it
# is out of your date range
break_on_reject: True
# Path to your YouTube cookies file to download 18+ restricted content
cookiefile: "/path/to/cookies/file.txt"
# Only download this number of videos/audio
max_downloads: 10
# Download and use English title/description/etc YouTube metadata
extractor_args:
youtube:
lang:
- "en"
where each key is a ytdl argument. Include in the example are some popular ytdl_options.

View file

@ -0,0 +1,7 @@
=======================
Common Preset Reference
=======================
.. highlight:: yaml
.. literalinclude:: /../../src/ytdl_sub/prebuilt_presets/helpers/common.yaml

View file

@ -0,0 +1,7 @@
========================
Players Preset Reference
========================
.. highlight:: yaml
.. literalinclude:: /../../src/ytdl_sub/prebuilt_presets/helpers/players.yaml

View file

@ -0,0 +1,7 @@
====================
URL Preset Reference
====================
.. highlight:: yaml
.. literalinclude:: /../../src/ytdl_sub/prebuilt_presets/helpers/url.yaml

View file

@ -0,0 +1,12 @@
=========================
Prebuilt Preset Reference
=========================
This section contains the code for the prebuilt presets. If you just want to understand how to use the presets, check :doc:`this section instead</prebuilt_presets/index>`.
.. toctree::
helpers_common
helpers_players
helpers_url

View file

@ -0,0 +1,17 @@
==================
Config Field Types
==================
The ``config.yaml`` uses various types for its configurable fields. Below is a definition for each type.
.. autoclass:: ytdl_sub.validators.string_formatter_validators.StringFormatterValidator()
.. autoclass:: ytdl_sub.validators.string_formatter_validators.OverridesStringFormatterValidator()
.. autoclass:: ytdl_sub.validators.file_path_validators.StringFormatterFileNameValidator()
.. autoclass:: ytdl_sub.validators.string_datetime.StringDatetimeValidator()
.. autoclass:: ytdl_sub.validators.string_formatter_validators.DictFormatterValidator()
.. autoclass:: ytdl_sub.validators.string_formatter_validators.OverridesDictFormatterValidator()

View file

@ -0,0 +1,439 @@
Entry Variables
===============
Entry Variables
---------------
channel
~~~~~~~
The channel name if it exists, otherwise returns the uploader.
channel_id
~~~~~~~~~~
The channel id if it exists, otherwise returns the entry uploader ID.
chapters
~~~~~~~~
Chapters if they exist
comments
~~~~~~~~
Comments if they are requested
creator
~~~~~~~
The creator name if it exists, otherwise returns the channel.
description
~~~~~~~~~~~
The description if it exists. Otherwise, returns an emtpy string.
duration
~~~~~~~~
The duration of the entry in seconds
epoch
~~~~~
The unix epoch of when the metadata was scraped by yt-dlp.
epoch_date
~~~~~~~~~~
The epoch's date, in YYYYMMDD format.
epoch_hour
~~~~~~~~~~
The epoch's hour
ext
~~~
The downloaded entry's file extension
extractor
~~~~~~~~~
The yt-dlp extractor name
extractor_key
~~~~~~~~~~~~~
The yt-dlp extractor key
ie_key
~~~~~~
The ie_key, used in legacy yt-dlp things as the 'info-extractor key'
info_json_ext
~~~~~~~~~~~~~
The "info.json" extension
requested_subtitles
~~~~~~~~~~~~~~~~~~~
Subtitles if they are requested and exist
sponsorblock_chapters
~~~~~~~~~~~~~~~~~~~~~
Sponsorblock Chapters if they are requested and exist
thumbnail_ext
~~~~~~~~~~~~~
The download entry's thumbnail extension. Will always return 'jpg'. Until there is a
need to support other image types, we always convert to jpg.
title
~~~~~
The title of the entry. If a title does not exist, returns its unique ID.
title_sanitized_plex
~~~~~~~~~~~~~~~~~~~~
The sanitized title with additional sanitizing for Plex. It replaces numbers with
fixed-width numbers so Plex does not recognize them as season or episode numbers.
uid
~~~
The entry's unique ID
uid_sanitized_plex
~~~~~~~~~~~~~~~~~~
The sanitized uid with additional sanitizing for Plex. Replaces numbers with
fixed-width numbers so Plex does not recognize them as season or episode numbers.
uploader
~~~~~~~~
The uploader if it exists, otherwise return the uploader ID.
uploader_id
~~~~~~~~~~~
The uploader id if it exists, otherwise return the unique ID.
uploader_url
~~~~~~~~~~~~
The uploader url if it exists, otherwise returns the webpage_url.
webpage_url
~~~~~~~~~~~
The url to the webpage.
Metadata Variables
------------------
entry_metadata
~~~~~~~~~~~~~~
The entry's info.json
playlist_metadata
~~~~~~~~~~~~~~~~~
Metadata from the playlist (i.e. the parent metadata, like playlist -> entry)
sibling_metadata
~~~~~~~~~~~~~~~~
Metadata from any sibling entries that reside in the same playlist as this entry.
source_metadata
~~~~~~~~~~~~~~~
Metadata from the source (i.e. the grandparent metadata, like channel -> playlist -> entry)
Playlist Variables
------------------
playlist_count
~~~~~~~~~~~~~~
Playlist count if it exists, otherwise returns ``1``.
Note that for channels/playlists, any change (i.e. adding or removing a video) will make
this value change. Use with caution.
playlist_description
~~~~~~~~~~~~~~~~~~~~
The playlist description if it exists, otherwise returns the entry's description.
playlist_index
~~~~~~~~~~~~~~
Playlist index if it exists, otherwise returns ``1``.
Note that for channels/playlists, any change (i.e. adding or removing a video) will make
this value change. Use with caution.
playlist_index_padded
~~~~~~~~~~~~~~~~~~~~~
playlist_index padded two digits
playlist_index_padded6
~~~~~~~~~~~~~~~~~~~~~~
playlist_index padded six digits.
playlist_index_reversed
~~~~~~~~~~~~~~~~~~~~~~~
Playlist index reversed via ``playlist_count - playlist_index + 1``
playlist_index_reversed_padded
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
playlist_index_reversed padded two digits
playlist_index_reversed_padded6
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
playlist_index_reversed padded six digits.
playlist_max_upload_date
~~~~~~~~~~~~~~~~~~~~~~~~
Max upload_date for all entries in this entry's playlist if it exists, otherwise returns
``upload_date``
playlist_max_upload_year
~~~~~~~~~~~~~~~~~~~~~~~~
Max upload_year for all entries in this entry's playlist if it exists, otherwise returns
``upload_year``
playlist_max_upload_year_truncated
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The max playlist truncated upload year for all entries in this entry's playlist if it
exists, otherwise returns ``upload_year_truncated``.
playlist_title
~~~~~~~~~~~~~~
Name of its parent playlist/channel if it exists, otherwise returns its title.
playlist_uid
~~~~~~~~~~~~
The playlist unique ID if it exists, otherwise return the entry unique ID.
playlist_uploader
~~~~~~~~~~~~~~~~~
The playlist uploader if it exists, otherwise return the entry uploader.
playlist_uploader_id
~~~~~~~~~~~~~~~~~~~~
The playlist uploader id if it exists, otherwise returns the entry uploader ID.
playlist_uploader_url
~~~~~~~~~~~~~~~~~~~~~
The playlist uploader url if it exists, otherwise returns the playlist webpage_url.
playlist_webpage_url
~~~~~~~~~~~~~~~~~~~~
The playlist webpage url if it exists. Otherwise, returns the entry webpage url.
Release Date Variables
----------------------
release_date
~~~~~~~~~~~~
The entrys release date, in YYYYMMDD format. If not present, return the upload date.
release_date_standardized
~~~~~~~~~~~~~~~~~~~~~~~~~
The release date formatted as YYYY-MM-DD
release_day
~~~~~~~~~~~
The release day as an integer (no padding).
release_day_of_year
~~~~~~~~~~~~~~~~~~~
The day of the year, i.e. February 1st returns ``32``
release_day_of_year_padded
~~~~~~~~~~~~~~~~~~~~~~~~~~
The release day of year, but padded i.e. February 1st returns "032"
release_day_of_year_reversed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The release day, but reversed using ``{total_days_in_year} + 1 - {release_day}``,
i.e. February 2nd would have release_day_of_year_reversed of ``365 + 1 - 32`` = ``334``
release_day_of_year_reversed_padded
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The reversed release day of year, but padded i.e. December 31st returns "001"
release_day_padded
~~~~~~~~~~~~~~~~~~
The entry's release day padded to two digits, i.e. the fifth returns "05"
release_day_reversed
~~~~~~~~~~~~~~~~~~~~
The release day, but reversed using ``{total_days_in_month} + 1 - {release_day}``,
i.e. August 8th would have release_day_reversed of ``31 + 1 - 8`` = ``24``
release_day_reversed_padded
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The reversed release day, but padded. i.e. August 30th returns "02".
release_month
~~~~~~~~~~~~~
The release month as an integer (no padding).
release_month_padded
~~~~~~~~~~~~~~~~~~~~
The entry's release month padded to two digits, i.e. March returns "03"
release_month_reversed
~~~~~~~~~~~~~~~~~~~~~~
The release month, but reversed
using ``13 - {release_month}``, i.e. March returns ``10``
release_month_reversed_padded
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The reversed release month, but padded. i.e. November returns "02"
release_year
~~~~~~~~~~~~
The entry's release year
release_year_truncated
~~~~~~~~~~~~~~~~~~~~~~
The last two digits of the release year, i.e. 22 in 2022
release_year_truncated_reversed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The release year truncated, but reversed using ``100 - {release_year_truncated}``, i.e.
2022 returns ``100 - 22`` = ``78``
Source Variables
----------------
source_count
~~~~~~~~~~~~
The source count if it exists, otherwise returns the playlist count.
source_description
~~~~~~~~~~~~~~~~~~
The source description if it exists, otherwise returns the playlist description.
source_index
~~~~~~~~~~~~
Source index if it exists, otherwise returns ``1``.
It is recommended to not use this unless you know the source will never add new content
(it is easy for this value to change).
source_index_padded
~~~~~~~~~~~~~~~~~~~
The source index, padded.
source_title
~~~~~~~~~~~~
Name of the source (i.e. channel with multiple playlists) if it exists, otherwise
returns its playlist_title.
source_uid
~~~~~~~~~~
The source unique id if it exists, otherwise returns the playlist unique ID.
source_uploader
~~~~~~~~~~~~~~~
The source uploader if it exists, otherwise return the playlist_uploader
source_uploader_id
~~~~~~~~~~~~~~~~~~
The source uploader id if it exists, otherwise returns the playlist_uploader_id
source_uploader_url
~~~~~~~~~~~~~~~~~~~
The source uploader url if it exists, otherwise returns the source webpage_url.
source_webpage_url
~~~~~~~~~~~~~~~~~~
The source webpage url if it exists, otherwise returns the playlist webpage url.
Upload Date Variables
---------------------
upload_date
~~~~~~~~~~~
The entrys uploaded date, in YYYYMMDD format. If not present, return todays date.
upload_date_standardized
~~~~~~~~~~~~~~~~~~~~~~~~
The uploaded date formatted as YYYY-MM-DD
upload_day
~~~~~~~~~~
The upload day as an integer (no padding).
upload_day_of_year
~~~~~~~~~~~~~~~~~~
The day of the year, i.e. February 1st returns ``32``
upload_day_of_year_padded
~~~~~~~~~~~~~~~~~~~~~~~~~
The upload day of year, but padded i.e. February 1st returns "032"
upload_day_of_year_reversed
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The upload day, but reversed using ``{total_days_in_year} + 1 - {upload_day}``,
i.e. February 2nd would have upload_day_of_year_reversed of ``365 + 1 - 32`` = ``334``
upload_day_of_year_reversed_padded
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The reversed upload day of year, but padded i.e. December 31st returns "001"
upload_day_padded
~~~~~~~~~~~~~~~~~
The entry's upload day padded to two digits, i.e. the fifth returns "05"
upload_day_reversed
~~~~~~~~~~~~~~~~~~~
The upload day, but reversed using ``{total_days_in_month} + 1 - {upload_day}``,
i.e. August 8th would have upload_day_reversed of ``31 + 1 - 8`` = ``24``
upload_day_reversed_padded
~~~~~~~~~~~~~~~~~~~~~~~~~~
The reversed upload day, but padded. i.e. August 30th returns "02".
upload_month
~~~~~~~~~~~~
The upload month as an integer (no padding).
upload_month_padded
~~~~~~~~~~~~~~~~~~~
The entry's upload month padded to two digits, i.e. March returns "03"
upload_month_reversed
~~~~~~~~~~~~~~~~~~~~~
The upload month, but reversed using ``13 - {upload_month}``, i.e. March returns ``10``
upload_month_reversed_padded
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The reversed upload month, but padded. i.e. November returns "02"
upload_year
~~~~~~~~~~~
The entry's upload year
upload_year_truncated
~~~~~~~~~~~~~~~~~~~~~
The last two digits of the upload year, i.e. 22 in 2022
upload_year_truncated_reversed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The upload year truncated, but reversed using ``100 - {upload_year_truncated}``, i.e.
2022 returns ``100 - 22`` = ``78``
Ytdl-Sub Variables
------------------
download_index
~~~~~~~~~~~~~~
The i'th entry downloaded. NOTE that this is fetched dynamically from the download
archive.
download_index_padded6
~~~~~~~~~~~~~~~~~~~~~~
The download_index padded six digits
upload_date_index
~~~~~~~~~~~~~~~~~
The i'th entry downloaded with this upload date.
upload_date_index_padded
~~~~~~~~~~~~~~~~~~~~~~~~
The upload_date_index padded two digits
upload_date_index_reversed
~~~~~~~~~~~~~~~~~~~~~~~~~~
100 - upload_date_index
upload_date_index_reversed_padded
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The upload_date_index padded two digits
ytdl_sub_input_url
~~~~~~~~~~~~~~~~~~
The input URL used in ytdl-sub to create this entry.

View file

@ -0,0 +1,9 @@
=========
Scripting
=========
.. toctree::
entry_variables
override_variables
scripting_functions
config_types

View file

@ -0,0 +1,44 @@
Override Variables
==================
subscription_indent_i
---------------------
For subscriptions in the form of
.. code-block:: yaml
Preset | = Indent Value 1:
= Indent Value 2:
"Subscription Name": "https://..."
``subscription_indent_1`` and ``subscription_indent_2`` get set to
``Indent Value 1`` and ``Indent Value 2``.
subscription_name
-----------------
Name of the subscription
subscription_value
------------------
For subscriptions in the form of
.. code-block:: yaml
"Subscription Name": "https://..."
``subscription_value`` gets set to ``https://...``.
subscription_value_i
--------------------
For subscriptions in the form of
.. code-block:: yaml
"Subscription Name":
- "https://url1.com/..."
- "https://url2.com/..."
``subscription_value_1`` and ``subscription_value_2`` get set to ``https://url1.com/...``
and ``https://url2.com/...``. Note that ``subscription_value_1`` also gets set to
``subscription_value``.

View file

@ -0,0 +1,474 @@
Scripting Functions
===================
Array Functions
---------------
array
~~~~~
``array(maybe_array: AnyArgument) -> Array``
Tries to cast an unknown variable type to an Array.
array_apply
~~~~~~~~~~~
``array_apply(array: Array, lambda_function: Lambda) -> Array``
Apply a lambda function on every element in the Array.
array_at
~~~~~~~~
``array_at(array: Array, idx: Integer) -> AnyArgument``
Return the element in the Array at index ``idx``.
array_contains
~~~~~~~~~~~~~~
``array_contains(array: Array, value: AnyArgument) -> Boolean``
Return True if the value exists in the Array. False otherwise.
array_enumerate
~~~~~~~~~~~~~~~
``array_enumerate(array: Array, lambda_function: LambdaTwo) -> Array``
Apply a lambda function on every element in the Array, where each arg
passed to the lambda function is ``idx, element`` as two separate args.
array_extend
~~~~~~~~~~~~
``array_extend(arrays: Array, ...) -> Array``
Combine multiple Arrays into a single Array.
array_flatten
~~~~~~~~~~~~~
``array_flatten(array: Array) -> Array``
Flatten any nested Arrays into a single-dimensional Array.
array_index
~~~~~~~~~~~
``array_index(array: Array, value: AnyArgument) -> Integer``
Return the index of the value within the Array if it exists. If it does not, it will
throw an error.
array_product
~~~~~~~~~~~~~
``array_product(arrays: Array, ...) -> Array``
Returns the Cartesian product of elements from different arrays
array_reduce
~~~~~~~~~~~~
``array_reduce(array: Array, lambda_reduce_function: LambdaReduce) -> AnyArgument``
Apply a reduce function on pairs of elements in the Array, until one element remains.
Executes using the left-most and reduces in the right direction.
array_reverse
~~~~~~~~~~~~~
``array_reverse(array: Array) -> Array``
Reverse an Array.
array_size
~~~~~~~~~~
``array_size(array: Array) -> Integer``
Returns the size of an Array.
array_slice
~~~~~~~~~~~
``array_slice(array: Array, start: Integer, end: Optional[Integer]) -> Array``
Returns the slice of the Array.
Boolean Functions
-----------------
and
~~~
``and(values: AnyArgument, ...) -> Boolean``
``and`` operator. Returns True if all values evaluate to True. False otherwise.
bool
~~~~
``bool(value: AnyArgument) -> Boolean``
Cast any type to a Boolean.
eq
~~
``eq(left: AnyArgument, right: AnyArgument) -> Boolean``
``==`` operator. Returns True if left == right. False otherwise.
gt
~~
``gt(left: AnyArgument, right: AnyArgument) -> Boolean``
``>`` operator. Returns True if left > right. False otherwise.
gte
~~~
``gte(left: AnyArgument, right: AnyArgument) -> Boolean``
``>=`` operator. Returns True if left >= right. False otherwise.
lt
~~
``lt(left: AnyArgument, right: AnyArgument) -> Boolean``
``<`` operator. Returns True if left < right. False otherwise.
lte
~~~
``lte(left: AnyArgument, right: AnyArgument) -> Boolean``
``<=`` operator. Returns True if left <= right. False otherwise.
ne
~~
``ne(left: AnyArgument, right: AnyArgument) -> Boolean``
``!=`` operator. Returns True if left != right. False otherwise.
not
~~~
``not(value: Boolean) -> Boolean``
``not`` operator. Returns the opposite of value.
or
~~
``or(values: AnyArgument, ...) -> Boolean``
``or`` operator. Returns True if any value evaluates to True. False otherwise.
xor
~~~
``xor(values: AnyArgument, ...) -> Boolean``
``^`` operator. Returns True if exactly one value is set to True. False otherwise.
Conditional Functions
---------------------
if
~~
``if(condition: Boolean, true: ReturnableArgumentA, false: ReturnableArgumentB) -> Union[ReturnableArgumentA, ReturnableArgumentB]``
Conditional ``if`` statement that returns the ``true`` or ``false`` parameter
depending on the ``condition`` value.
if_passthrough
~~~~~~~~~~~~~~
``if_passthrough(maybe_true_arg: ReturnableArgumentA, else_arg: ReturnableArgumentB) -> Union[ReturnableArgumentA, ReturnableArgumentB]``
Conditional ``if`` statement that returns the ``maybe_true_arg`` if it evaluates to True,
otherwise returns ``else_arg``.
Date Functions
--------------
datetime_strftime
~~~~~~~~~~~~~~~~~
``datetime_strftime(posix_timestamp: Integer, date_format: String) -> String``
Converts a posix timestamp to a date using strftime formatting.
Error Functions
---------------
assert
~~~~~~
``assert(value: ReturnableArgument, assert_message: String) -> ReturnableArgument``
Explicitly throw an error with the provided assert message if ``value`` evaluates to False.
If it evaluates to True, it will return ``value``.
throw
~~~~~
``throw(error_message: String) -> AnyArgument``
Explicitly throw an error with the provided error message.
Json Functions
--------------
from_json
~~~~~~~~~
``from_json(argument: String) -> AnyArgument``
Converts a JSON string into an actual type.
Map Functions
-------------
map
~~~
``map(maybe_mapping: AnyArgument) -> Map``
Tries to cast an unknown variable type to a Map.
map_apply
~~~~~~~~~
``map_apply(mapping: Map, lambda_function: LambdaTwo) -> Array``
Apply a lambda function on the Map, where each arg
passed to the lambda function is ``key, value`` as two separate args.
map_contains
~~~~~~~~~~~~
``map_contains(mapping: Map, key: AnyArgument) -> Boolean``
Returns True if the key is in the Map. False otherwise.
map_enumerate
~~~~~~~~~~~~~
``map_enumerate(mapping: Map, lambda_function: LambdaThree) -> Array``
Apply a lambda function on the Map, where each arg
passed to the lambda function is ``idx, key, value`` as three separate args.
map_get
~~~~~~~
``map_get(mapping: Map, key: AnyArgument, default: Optional[AnyArgument]) -> AnyArgument``
Return ``key``'s value within the Map. If ``key`` does not exist, and ``default`` is
provided, it will return ``default``. Otherwise, will error.
map_get_non_empty
~~~~~~~~~~~~~~~~~
``map_get_non_empty(mapping: Map, key: AnyArgument, default: AnyArgument) -> AnyArgument``
Return ``key``'s value within the Map. If ``key`` does not exist or is an empty string,
return ``default``. Otherwise, will error.
map_size
~~~~~~~~
``map_size(mapping: Map) -> Integer``
Returns the size of a Map.
Numeric Functions
-----------------
add
~~~
``add(values: Numeric, ...) -> Numeric``
``+`` operator. Returns the sum of all values.
div
~~~
``div(left: Numeric, right: Numeric) -> Numeric``
``/`` operator. Returns ``left / right``.
float
~~~~~
``float(value: AnyArgument) -> Float``
Cast to Float.
int
~~~
``int(value: AnyArgument) -> Integer``
Cast to Integer.
max
~~~
``max(values: Numeric, ...) -> Numeric``
Returns max of all values.
min
~~~
``min(values: Numeric, ...) -> Numeric``
Returns min of all values.
mod
~~~
``mod(left: Numeric, right: Numeric) -> Numeric``
``%`` operator. Returns ``left % right``.
mul
~~~
``mul(values: Numeric, ...) -> Numeric``
``*`` operator. Returns the product of all values.
pow
~~~
``pow(base: Numeric, exponent: Numeric) -> Numeric``
``**`` operator. Returns the exponential of the base and exponent value.
sub
~~~
``sub(values: Numeric, ...) -> Numeric``
``-`` operator. Subtracts all values from left to right.
Regex Functions
---------------
regex_fullmatch
~~~~~~~~~~~~~~~
``regex_fullmatch(regex: String, string: String) -> Array``
Checks for entire string to be a match. If a match exists, returns
the string as the first element of the Array. If there are capture groups, returns each
group as a subsequent element in the Array.
regex_match
~~~~~~~~~~~
``regex_match(regex: String, string: String) -> Array``
Checks for a match only at the beginning of the string. If a match exists, returns
the string as the first element of the Array. If there are capture groups, returns each
group as a subsequent element in the Array.
regex_search
~~~~~~~~~~~~
``regex_search(regex: String, string: String) -> Array``
Checks for a match anywhere in the string. If a match exists, returns
the string as the first element of the Array. If there are capture groups, returns each
group as a subsequent element in the Array.
String Functions
----------------
capitalize
~~~~~~~~~~
``capitalize(string: String) -> String``
Capitalize the first character in the string.
concat
~~~~~~
``concat(values: String, ...) -> String``
Concatenate multiple Strings into a single String.
lower
~~~~~
``lower(string: String) -> String``
Lower-case the entire String.
pad
~~~
``pad(string: String, length: Integer, char: String) -> String``
Pads the string to the given length
pad_zero
~~~~~~~~
``pad_zero(numeric: Numeric, length: Integer) -> String``
Pads a numeric with zeros to the given length
replace
~~~~~~~
``replace(string: String, old: String, new: String, count: Optional[Integer]) -> String``
Replace the ``old`` part of the String with the ``new``. Optionally only replace it
``count`` number of times.
slice
~~~~~
``slice(string: String, start: Integer, end: Optional[Integer]) -> String``
Returns the slice of the Array.
string
~~~~~~
``string(value: AnyArgument) -> String``
Cast to String.
titlecase
~~~~~~~~~
``titlecase(string: String) -> String``
Capitalize each word in the string.
upper
~~~~~
``upper(string: String) -> String``
Upper-case the entire String.
Ytdl-Sub Functions
------------------
legacy_bracket_safety
~~~~~~~~~~~~~~~~~~~~~
``legacy_bracket_safety(value: ReturnableArgument) -> ReturnableArgument``
ytdl-sub used to replace brackets ('{', '}') with unicode brackets ('', '') to not
interfere with its legacy variable scripting system. This function replicates that
behavior.
sanitize
~~~~~~~~
``sanitize(value: AnyArgument) -> String``
Sanitize a string using yt-dlp's ``sanitize_filename`` method to ensure it's safe to use
for file/directory names on any OS.
sanitize_plex_episode
~~~~~~~~~~~~~~~~~~~~~
``sanitize_plex_episode(string: String) -> String``
Sanitize a string using ``sanitize`` and replace numerics with their respective fixed-width
numbers. This is used to have Plex avoid scraping numbers like ``4x4`` as the
season and/or episode.
to_date_metadata
~~~~~~~~~~~~~~~~
``to_date_metadata(yyyymmdd: String) -> Map``
Takes a date in the form of YYYYMMDD and returns a Map containing:
- date (String, YYYYMMDD)
- date_standardized (String, YYYY-MM-DD)
- year (Integer)
- month (Integer)
- day (Integer)
- year_truncated (String, YY from YY[YY])
- month_padded (String)
- day_padded (String)
- year_truncated_reversed (Integer, 100 - year_truncated)
- month_reversed (Integer, 13 - month)
- month_reversed_padded (String)
- day_reversed (Integer, total_days_in_month + 1 - day)
- day_reversed_padded (String)
- day_of_year (Integer)
- day_of_year_padded (String, padded 3)
- day_of_year_reversed (Integer, total_days_in_year + 1 - day_of_year)
- day_of_year_reversed_padded (String, padded 3)
to_native_filepath
~~~~~~~~~~~~~~~~~~
``to_native_filepath(filepath: String) -> String``
Convert any unix-based path separators ('/') with the OS's native
separator.
truncate_filepath_if_too_long
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``truncate_filepath_if_too_long(filepath: String) -> String``
If a file-path is too long for the OS, this function will truncate it while preserving
the extension.

View file

@ -0,0 +1,149 @@
==================
Subscriptions File
==================
------------------
subscriptions.yaml
------------------
The ``subscriptions.yaml`` file is where we use our :ref:`config_reference/config_yaml:presets` in the :ref:`config_reference/config_yaml:config.yaml`
to define a ``subscription``: something we want to recurrently download such as a specific
channel or playlist.
The only difference between a ``subscription`` and ``preset`` is that the subscription
must have all required fields and ``{override_variables}`` defined so it can perform a download.
Below is an example that downloads a YouTube playlist:
.. code-block:: yaml
:caption: config.yaml
presets:
playlist_preset_ex:
download:
download_strategy: "url"
url: "{url}"
output_options:
output_directory: "{output_directory}/{playlist_name}"
file_name: "{playlist_name}.{title}.{ext}"
overrides:
output_directory: "/path/to/ytdl-sub-videos"
.. code-block:: yaml
:caption: subscription.yaml
my_subscription_name:
preset: "playlist_preset_ex"
overrides:
playlist_name: "diy-playlist"
url: "https://youtube.com/playlist?list=UCsvn_Po0SmunchJYtttWpOxMg"
Our preset ``playlist_preset_ex`` defines three
custom variables: ``{output_directory}``, ``{playlist_name}``, and ``{url}``. The subscription sets
the ``parent preset`` to ``playlist_preset_ex``, and must define the variables ``{playlist_name}``
and ``{url}`` since the preset did not.
Beautifying Subscriptions
~~~~~~~~~~~~~~~~~~~~~~~~~
Subscriptions support using presets as keys, and using keys to set override variables as values.
For example:
.. code-block:: yaml
:caption: subscription.yaml
TV Show Full Archive:
= News:
"Breaking News": "https://www.youtube.com/@SomeBreakingNews"
TV Show Only Recent:
= Tech | TV-Y:
"Two Minute Papers": "https://www.youtube.com/@TwoMinutePapers"
Will create two subscriptions named "Breaking News" and "Two Minute Papers", equivalent to:
.. code-block:: yaml
"Breaking News":
preset:
- "TV Show Full Archive"
overrides:
subscription_indent_1: "News"
subscription_name: "Breaking News"
subscription_value: "https://www.youtube.com/@SomeBreakingNews"
"Two Minute Papers":
preset:
- "TV Show Only Recent"
overrides:
subscription_indent_1: "Tech"
subscription_indent_2: "TV-Y"
subscription_name: "Two Minute Papers"
subscription_value: "https://www.youtube.com/@TwoMinutePapers"
You can provide as many parent presets in the form of ``keys``, and subscription indents as ``= keys``.
This can drastically simplify subscription definitions by setting things like so in your
parent preset:
.. code-block:: yaml
presets:
"TV Show Preset":
overrides:
subscription_indent_1: "default-genre"
subscription_indent_2: "default-content-rating"
tv_show_name: "{subscription_name}"
url: "{subscription_value}"
genre: "{subscription_indent_1}"
content_rating: "{subscription_indent_2}"
.. _subscription value:
File Preset
~~~~~~~~~~~
You can apply a preset to all subscriptions in the ``subscription.yaml`` file
by using the file-wide ``__preset__``:
.. code-block:: yaml
:caption: subscription.yaml
__preset__:
preset: "playlist_preset_ex"
my_subscription_name:
overrides:
url: "https://youtube.com/playlist?list=UCsvn_Po0SmunchJYtttWpOxMg"
playlist_name: "diy-playlist"
This ``subscription.yaml`` is equivalent to the one above it because all
subscriptions automatically set ``__preset__`` as a ``parent preset``.
Subscription Value
~~~~~~~~~~~~~~~~~~~
NOTE: This is deprecated in favor of using the method in :ref:`config_reference/subscriptions_yaml:beautifying subscriptions`.
With a clever config and use of ``__preset__``, your subscriptions can typically boil
down to a name and url. You can set ``__value__`` to the name of an override variable,
and use the override variable ``subscription_name`` to achieve one-liner subscriptions.
Using the example above, we can do:
.. code-block:: yaml
:caption: subscription.yaml
__preset__:
preset:
- "tv_show"
overrides:
tv_show_name: "{subscription_name}"
__value__: "url"
# single-line subscription, sets "Brandon Acker" and the subscription value
# to the override variables tv_show_name and url
"Brandon Acker": "https://www.youtube.com/@brandonacker"
Traditional subscriptions that can override presets will still work when using ``__value__``.
``__value__`` can also be set within a :ref:`config_reference/config_yaml:config.yaml`.

View file

@ -5,55 +5,55 @@ Oct 2023
--------
subscription preset and value
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The use of ``__value__`` will go away in Dec 2023 in favor of the method found in
:ref:`beautifying subscriptions`. ``__preset__`` will still be supported for the time being.
:ref:`config_reference/subscriptions_yaml:beautifying subscriptions`. ``__preset__`` will still be supported for the time being.
July 2023
---------
music_tags
^^^^^^^^^^
~~~~~~~~~~
Music tags are getting simplified. ``tags`` will now reside directly under music_tags, and
``embed_thumbnail`` is getting moved to its own plugin (supports video files as well). Convert from:
.. code-block:: yaml
my_example_preset:
music_tags:
embed_thumbnail: True
tags:
artist: "Elvis Presley"
my_example_preset:
music_tags:
embed_thumbnail: True
tags:
artist: "Elvis Presley"
To the following:
.. code-block:: yaml
my_example_preset:
embed_thumbnail: True
music_tags:
artist: "Elvis Presley"
my_example_preset:
embed_thumbnail: True
music_tags:
artist: "Elvis Presley"
The old format will be removed in October 2023.
video_tags
^^^^^^^^^^
~~~~~~~~~~
Video tags are getting simplified as well. ``tags`` will now reside directly under video_tags.
Convert from:
.. code-block:: yaml
my_example_preset:
video_tags:
tags:
title: "Elvis Presley Documentary"
my_example_preset:
video_tags:
tags:
title: "Elvis Presley Documentary"
To the following:
.. code-block:: yaml
my_example_preset:
video_tags:
title: "Elvis Presley Documentary"
my_example_preset:
video_tags:
title: "Elvis Presley Documentary"

59
docs/source/faq/index.rst Normal file
View file

@ -0,0 +1,59 @@
FAQ
===
Since ytdl-sub is relatively new to the public, there has not been many question asked yet. We will update this as
more questions get asked.
.. contents:: Frequently Asked Questions
:depth: 3
How do I...
-----------
...download age-restricted YouTube videos?
''''''''''''''''''''''''''''''''''''''''''
See
`ytdls recommended way <https://github.com/ytdl-org/youtube-dl#how-do-i-pass-cookies-to-youtube-dl>`_
to download your YouTube cookie, then add it to your
`ytdl options <https://ytdl-sub.readthedocs.io/en/latest/config.html#ytdl-options>`_ section of your config:
.. code-block:: yaml
ytdl_options:
cookiefile: "/path/to/cookies/file.txt"
...automate my downloads?
'''''''''''''''''''''''''
`This part of the wiki <https://github.com/jmbannon/ytdl-sub/wiki/7.-Automate-Downloading-New-Content-Using-Your-Configs>`_ shows how to set up ``ytdl-sub`` to run in a cron job within Docker.
There is a bug where...
-----------------------
...date_range is not downloading older videos after I changed the range
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Your preset most likely has ``break_on_existing`` set to True, which will stop downloading additional metadata/videos if the video exists in your download archive. Set the following in your config to skip downloading videos that exist instead of stopping altogether.
.. code-block:: yaml
ytdl_options:
break_on_existing: False
After your download your new date_range duration, re-enable ``break_on_existing`` to speed up successive downloads.
...it is downloading non-English title and description metadata
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Most likely the video has a non-English language set to its 'native' language. You can tell yt-dlp to explicitly download English metadata using
.. code-block:: yaml
ytdl_options:
extractor_args:
youtube:
lang:
- "en"
...Plex is not showing my TV shows correctly
''''''''''''''''''''''''''''''''''''''''''''
Set the following
`Scanner and Agent <https://i.imgur.com/zdZhCLZ.png>`_
for your library.

View file

@ -0,0 +1,5 @@
Development and Contributing
============================
.. toctree::

View file

@ -0,0 +1,21 @@
Advanced Configuration
======================
If the :doc:`prebuilt presets </prebuilt_presets/index>` aren't suitable for your needs, you may want to set up an advanced configuration.
Layout of a Config file
-----------------------
The layout of the ``config.yaml`` file is relatively straightforward:
.. code-block:: yaml
presets:
preset_name:
plugin1:
plugin1_option1: value1
Preset Inheritance
------------------

View file

@ -0,0 +1,140 @@
Automating Downloads
====================
One of the key capabilities of ``ytdl-sub`` is how well it runs without user input, but to take advantage of this you must set up scheduling to execute the commands at some interval. How you set up this scheduling depends on which version of ``ytdl-sub`` you downloaded.
:ref:`Guide for Docker and Unraid Containers <guides/getting_started/automating_downloads:docker and unraid>`
:ref:`Guide for Linux <guides/getting_started/automating_downloads:linux>`
:ref:`Guide for Windows <guides/getting_started/automating_downloads:windows>`
.. _cron tab manpage: https://man7.org/linux/man-pages/man5/crontab.5.html#EXAMPLE_CRON_FILE
.. _docker-unraid-setup:
Docker and Unraid
-----------------
.. tab-set::
.. tab-item:: GUI Image
The script that will execute automatically is located at ``/config/ytdl-sub-configs/run-cron``.
Access your container at http://localhost:8443/, then in the GUI terminal run these commands:
.. code-block:: shell
echo '#!/bin/bash' > /config/ytdl-sub-configs/run_cron
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> /config/ytdl-sub-configs/run_cron
echo "echo 'Cron started, running ytdl-sub...'" >> /config/ytdl-sub-configs/run_cron
echo "cd /config/ytdl-sub-configs" >> /config/ytdl-sub-configs/run_cron
echo "ytdl-sub --config=config.yaml sub subscriptions.yaml" >> /config/ytdl-sub-configs/run_cron
chmod +x /config/ytdl-sub-configs/run_cron
chown abc:abc /config/ytdl-sub-configs/run_cron
You can test the newly created script by running:
.. code-block:: shell
/config/ytdl-sub-configs/run_cron
To create the cron definition, run the following command:
.. code-block:: shell
echo "# min hour day month weekday command" > /config/crontabs/abc
echo " 0 */6 * * * /config/ytdl-sub-configs/run_cron" >> /config/crontabs/abc
This will run the script every 6 hours. To run every hour, change ``*/6`` to ``*/1``, or to run once a day, change the same value to the hour (in 24hr format) that you want it to run at. See the `cron tab manpage`_ for more options.
.. tab-item:: Headless Image
.. _LinuxServer's Universal Cron mod: https://github.com/linuxserver/docker-mods/tree/universal-cron
The first step is to ensure you have `LinuxServer's Universal Cron mod`_ enabled via the environment variable. For the GUI image, this is already included (no need to add it).
.. code-block:: yaml
services:
ytdl-sub:
image: ghcr.io/jmbannon/ytdl-sub:latest
container_name: ytdl-sub
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
- DOCKER_MODS=linuxserver/mods:universal-cron # <-- Make sure you have this!
volumes:
# ensure directories have user permissions
- </path/to/ytdl-sub/config>:/config
- </path/to/ytdl-sub/tv_shows>:/tv_shows
restart: unless-stopped
This line will tell your container to install and enable cron on start.
If you had to add this line, you will need to restart your container.
.. code-block:: shell
docker compose restart
The script that will execute automatically is located at ``/config/run-cron``.
Access your container from the terminal by running:
.. code-block:: shell
docker exec -itu abc ytdl-sub /bin/bash
then in the terminal run these commands:
.. code-block:: shell
echo '#!/bin/bash' > /config/ytdl-sub-configs/run_cron
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> /config/ytdl-sub-configs/run_cron
echo "echo 'Cron started, running ytdl-sub...'" >> /config/ytdl-sub-configs/run_cron
echo "cd /config/ytdl-sub-configs" >> /config/ytdl-sub-configs/run_cron
echo "ytdl-sub --config=config.yaml sub subscriptions.yaml" >> /config/ytdl-sub-configs/run_cron
chmod +x /config/ytdl-sub-configs/run_cron
chown abc:abc /config/ytdl-sub-configs/run_cron
You can test the newly created script by running:
.. code-block::
/config/run_cron
To create the cron definition, run the following command:
.. code-block:: shell
echo "# min hour day month weekday command" > /config/crontabs/abc
echo " 0 */6 * * * /config/run_cron" >> /config/crontabs/abc
This will run the script every 6 hours. To run every hour, change ``*/6`` to ``*/1``, or to run once a day, change the same value to the hour (in 24hr format) that you want it to run at. See the `cron tab manpage`_ for more options.
.. _linux-setup:
Linux
-----
.. code-block:: shell
crontab -e
0 */6 * * * /config/run_cron
.. _windows-setup:
Windows
-------
To be tested (please contact code owner or join the discord server if you can test this out for us)
.. code-block:: powershell
ytdl-sub.exe --config \path\to\config\config.yaml sub \path\to\config\subscriptions.yaml

View file

@ -0,0 +1,15 @@
=====================
Using Example Configs
=====================
Copy and paste the examples into local yaml files, modify the
``working_directory`` and ``output_directory`` with your desired paths,
and perform a dry-run using
.. code-block:: bash
ytdl-sub \
--dry-run \
--config path/to/config.yaml \
sub path/to/subscriptions.yaml
This will simulate what a download will look like.

View file

@ -0,0 +1,25 @@
Basic Configuration
===================
Your first configuration will look pretty simple:
.. code-block:: yaml
:linenos:
configuration:
working_directory: '.ytdl-sub-downloads'
The first two lines in this ``config.yaml`` file are the ``configuration``, and define the ``working_directory``, which is described near the bottom of :ref:`this section <guides/getting_started/index:quick overview of \`\`ytdl-sub\`\`>`
Line 4 begins the definition of your custom ``presets``, with line 5 being the name of your first custom ``preset``.
Lines 7 and 8 tell ``ytdl-sub`` which :doc:`/prebuilt_presets/index` to expand on; these ``presets`` already indicate that the downloaded files should be:
- in a format usable by, and with metadata accessible to, Jellyfin
- sorted by upload date, and
- only uploaded in the last 2 months (and will also delete any files in the media library which were uploaded over 2 months ago)
Line 11 is an override variable, ``tv_show_directory``, that tells ``ytdl-sub`` where to save your downloaded files once they've been processed, also known as the ``output_directory``. In this case, the downloaded files will be saved to the ``youtube`` folder in the root ``tv_shows`` directory.

View file

@ -0,0 +1,30 @@
Initial Download
================
Once you have the ``config.yaml`` and ``subscriptions.yaml`` files created and filled out, you can perform your first download. Access ``ytdl-sub``, navigate to the directory containing your ``config.yaml`` and ``subscriptions.yaml`` files, then run the below command:
.. tab-set::
.. tab-item:: Dry run
A dry run lets you check that your configuration doesn't throw any errors and what the expected output files of actually doing the download are, without actually downloading the full media.
.. code-block:: shell
ytdl-sub --dry-run sub
.. tab-item:: Normal run
A normal run will download all files as determined by your ``presets`` and, once processing is finished, move the downloaded and processed files to your ``output_directory``.
.. code-block:: shell
ytdl-sub sub
.. tab-item:: One-time download
Sometimes you may only want to download media once, in which case adding them to your ``subscriptions.yaml`` file is unneccessary. As an example, the below code will download the same videos as our subscription file:
.. code-block:: shell
ytdl-sub dl --preset "My Favorite YouTube Channels" --overrides.subscription_name "Rick Astley" --overrides.subscription_value "https://www.youtube.com/@RickAstleyYT/videos"

View file

@ -0,0 +1,21 @@
Initial Subscription
====================
Your first subscription should look similar to the below:
.. code-block:: yaml
:linenos:
__preset__:
overrides:
tv_show_directory: "/tv_shows"
"My Favorite YouTube Channels":
"Rick Astley": "https://www.youtube.com/@RickAstleyYT/videos"
The first three lines in this subscription file define where to save the downloaded files associated with all subscriptions in this file.
The fifth line in this subscription file is the ``preset``, which provides the "definitions" for the subscription as listed in :doc:`/guides/getting_started/first_config`.
The sixth line is the actual ``subscription``, named ``Rick Astley``, with a link to a :yt-dlp:`yt-dlp supported site <blob/master/supportedsites.md>`, in this case a YouTube channel.

View file

@ -0,0 +1,88 @@
Getting Started
===============
Now that you've completed your install of ``ytdl-sub``, it's time to get started. This is a 3-step process:
- Create your configuration file (if the :doc:`/prebuilt_presets/index` don't fit your needs)
- Create your subscription file
- Automate starting YTDL-Sub
Prerequisite Knowledge
----------------------
.. _navigate directories: https://en.wikipedia.org/wiki/Cd_(command)
.. _YAML syntax: https://yaml.org/spec/1.2.2/#chapter-2-language-overview
In order to use ``ytdl-sub`` in any of the forms listed in these docs, you will need some basic knowledge.
Be sure that you:
☑ Can `navigate directories`_ in a command line interface (or CLI)
☑ Have a basic understanding of `YAML syntax`_
If you plan on using the headless image of ``ytdl-sub``, you:
☑ Can use ``nano`` or ``vim`` to edit OR
☑ Can mount the config directory somewhere you can open it using gui text editors
Additional useful (but not required) knowledge:
☑ Understanding how :yt-dlp:`\ ` works
Quick Overview of ``ytdl-sub``
------------------------------
``ytdl-sub`` uses two types of YAML files:
- ``config.yaml`` defines ``presets``, which are the "definitions" of your media. ``presets`` "define" how you want your media downloaded, which formats, naming conventions to follow when saving them, etc. These ``presets`` can also inherit other ``presets``, so that you can easily modify an existing ``preset``.
- ``subscriptions.yaml`` defines ``subscriptions``, which specify the media we want to recurrently download, like YouTube channels and playlists, SoundCloud artists, or any :yt-dlp:`yt-dlp supported site <blob/master/supportedsites.md>`. ``subscriptions`` use ``presets`` to define how ``ytdl-sub`` should handle downloading, processing, and saving them.
When ``ytdl-sub`` is run, in its most basic form:
.. tab-set-code::
.. code-block:: shell
ytdl-sub sub
.. code-block:: powershell
ytdl-sub.exe sub
``ytdl-sub`` initially downloads all files to a defined ``working_directory``. This is a temporary storage spot for metadata and media files so that errors during processing- if they occur- don't affect your existing media library. Once all file processing is complete, your media files are moved to the ``output_directory``.
Ready to Start?
---------------
Now that you have installed ``ytdl-sub``, checked your skills, and gotten a bit of background on how ``ytdl-sub`` functions, read through the articles below to get started:
:doc:`Step 1: Initial Subscriptions <first_sub>`
:doc:`Step 2: Your First Download <first_download>`
:doc:`Step 3: Automating Downloads <automating_downloads>`
Want to go a step further?
If you want to use atypical paths or specific configuration options, check out :doc:`Basic Configuration <first_config>`
For tips on creating your own presets when the prebuilt presets aren't cutting it, check out :doc:`Advanced Configuration <advanced_configuration>`
Other docs that may be of use:
:doc:`/prebuilt_presets/index`
:doc:`examples`
.. toctree::
:hidden:
:caption: Getting Started Guide
:maxdepth: 1
first_sub
first_download
automating_downloads
first_config
advanced_configuration
examples

View file

@ -0,0 +1,7 @@
Guides
======
.. toctree::
install/index
getting_started/index
development/index

View file

@ -0,0 +1,43 @@
====================
Environment Agnostic
====================
The PIP install method is not recommended; use of this method may cause unintended requirement conflicts if you have other locally installed apps that depend on ffmpeg.
PIP Install
--------------
You can install our
`PyPI package <https://pypi.org/project/ytdl-sub/>`_.
Both ffmpeg and Python 3.10 or greater are required.
.. code-block:: bash
python3 -m pip install -U ytdl-sub
Install for Development
=======================
These environment-agnostic methods of installing ``ytdl-sub`` are meant for local development of ``ytdl-sub``. If you want to contribute your changes, please read :doc:`/guides/development/index`.
Local Install
--------------
With a Python 3.10 virtual environment, you can clone and install the repo.
.. code-block:: bash
git clone https://github.com/jmbannon/ytdl-sub.git
cd ytdl-sub
pip install -e .
Local Docker Build
-------------------
Run ``make docker`` in the root directory of this repo to build the image. This
will build the python wheel and install it in the Dockerfile.
.. code-block:: bash
git clone https://github.com/jmbannon/ytdl-sub.git
cd ytdl-sub
make docker

View file

@ -0,0 +1,155 @@
======
Docker
======
For automating ``subscriptions.yaml`` downloads to pull new media, see :ref:`this page <guides/getting_started/automating_downloads:docker and unraid>` on how to set up a cron job in any of the docker containers.
The ``ytdl-sub`` Docker images use :lsio:`LSIO-based images <\ >` and install ytdl-sub on top. There are two flavors to choose from.
.. margin::
.. tip::
The recommended docker image is the GUI image.
:ref:`Docker Compose <guides/install/docker:install with docker compose>` is the recommended way of setting up a ``ytdl-sub`` docker container.
GUI Image
---------
The GUI image uses LSIO's :lsio-gh:`docker-code-server image` for its base image. More info on other code-server environment variables can be found within its documentation.
After starting, code-server will be running at http://localhost:8443. Open this page in a browser to access and interact with ``ytdl-sub``.
Headless Image
--------------
The headless image uses LSIO's :lsio-gh:`docker-baseimage-alpine image` for its base image. Execute the following command to access and interact with ``ytdl-sub``:
.. code-block:: bash
docker exec -u abc -it ytdl-sub /bin/bash
Install with Docker Compose
---------------------------
Docker Compose is an easy "set it and forget it" install method. Follow the instructions below to create a ``compose.yaml`` file for your chosen ``ytdl-sub`` image.
.. margin::
.. important::
Set the PUID and PGID to the UID and GID associated with the user you want to own the downloaded files. Setting these values to root UID and GID may create issues with your media managers.
.. tab-set::
.. tab-item:: GUI Image
.. code-block:: yaml
:caption: compose.yaml
services:
ytdl-sub:
image: ghcr.io/jmbannon/ytdl-sub-gui:latest
container_name: ytdl-sub
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
volumes:
- <path/to/ytdl-sub/config>:/config
- <path/to/tv_shows>:/tv_shows # optional
- <path/to/movies>:/movies # optional
- <path/to/music_videos>:/music_videos # optional
- <path/to/music>:/music # optional
ports:
- 8443:8443
restart: unless-stopped
.. tab-item:: Headless Image
.. code-block:: yaml
:caption: compose.yaml
services:
ytdl-sub:
image: ghcr.io/jmbannon/ytdl-sub:latest
container_name: ytdl-sub
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
- DOCKER_MODS=linuxserver/mods:universal-cron
volumes:
- <path/to/ytdl-sub/config>:/config
- <path/to/tv_shows>:/tv_shows # optional
- <path/to/movies>:/movies # optional
- <path/to/music_videos>:/music_videos # optional
- <path/to/music>:/music # optional
restart: unless-stopped
Device Passthrough
~~~~~~~~~~~~~~~~~~~
For CPU or GPU passthrough, you must use either the GUI image or the headless Ubuntu image
``ghcr.io/jmbannon/ytdl-sub:ubuntu-latest``.
The docker-compose examples use the GUI image.
CPU Passthrough
^^^^^^^^^^^^^^^
.. code-block:: yaml
:emphasize-lines: 5-6
:caption: compose.yaml
services:
ytdl-sub:
image: ghcr.io/jmbannon/ytdl-sub-gui:latest
container_name: ytdl-sub
devices:
- /dev/dri:/dev/dri # CPU passthrough
restart: unless-stopped
GPU Passthrough
^^^^^^^^^^^^^^^
.. Awe
.. code-block:: yaml
:caption: compose.yaml
:emphasize-lines: 5-13
services:
ytdl-sub:
image: ghcr.io/jmbannon/ytdl-sub-gui:latest
container_name: ytdl-sub
environment:
- ..
- NVIDIA_DRIVER_CAPABILITIES=all # Nvidia ENV args
- NVIDIA_VISIBLE_DEVICES=all
deploy:
resources:
reservations:
devices:
- capabilities: ["gpu"] # GPU passthrough
restart: unless-stopped
Docker CLI
----------
If you prefer to only run the container once, you can use the CLI command instead. The following command is for the gui image, and will not restart if it comes down for any reason. See `the Docker reference <https://docs.docker.com/engine/reference/run/>`_ for further information on the parameters and other options you can use.
.. code-block:: bash
docker run -d \
--name=ytdl-sub \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=America/Los_Angeles \
-p 8443:8443 \
-v <path/to/ytdl-sub/config>:/config \
-v <OPTIONAL/path/to/tv_shows>:/tv_shows \
-v <OPTIONAL/path/to/movies>:/movies \
-v <OPTIONAL/path/to/music_videos>:/music_videos \
-v <OPTIONAL/path/to/music>:/music \
ghcr.io/jmbannon/ytdl-sub-gui:latest

View file

@ -0,0 +1,34 @@
Install by Platform
===================
``ytdl-sub`` can be installed on the following platforms.
All installations require a 64-bit CPU. 32-bit is not supported.
.. margin::
.. tip::
The recommended install method of ``ytdl-sub`` is one of our :doc:`docker containers </guides/install/docker>`. For install on Unraid, check out our :unraid:`unraid community apps <community/apps?q=ytdl-sub#r>`.
:doc:`/guides/install/docker`
:doc:`/guides/install/unraid`
:doc:`/guides/install/linux`
:doc:`/guides/install/windows`
:doc:`/guides/install/agnostic`
Once you've completed your installation, please refer to the :doc:`../getting_started/index` guide for next steps
.. toctree::
:hidden:
docker
linux
unraid
windows
agnostic

View file

@ -0,0 +1,50 @@
=====
Linux
=====
``ytdl-sub`` should be installable using any Linux package manager, and requires ffmpeg to be installed.
.. tab-set::
.. tab-item:: Linux
.. code-block:: bash
curl -L -o ytdl-sub https://github.com/jmbannon/ytdl-sub/releases/latest/download/ytdl-sub
chmod +x ytdl-sub
ytdl-sub -h
You can also install using yt-dlp's ffmpeg builds. This ensures your ffmpeg is up to date:
.. code-block:: bash
curl -L -o ffmpeg.tar.gz https://github.com/yt-dlp/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz
tar -xf ffmpeg.tar.gz
chmod +x ffmpeg-master-latest-linux64-gpl/bin/ffmpeg
chmod +x ffmpeg-master-latest-linux64-gpl/bin/ffprobe
# May need sudo / root permissions to perform
mv ffmpeg-master-latest-linux64-gpl/bin/ffmpeg /usr/bin/ffmpeg
mv ffmpeg-master-latest-linux64-gpl/bin/ffprobe /usr/bin/ffprobe
.. tab-item:: Linux ARM
.. code-block:: bash
curl -L -o ytdl-sub https://github.com/jmbannon/ytdl-sub/releases/latest/download/ytdl-sub_aarch64
chmod +x ytdl-sub
ytdl-sub -h
You can also install using yt-dlp's ffmpeg builds. This ensures your ffmpeg is up to date:
.. code-block:: bash
curl -L -o ffmpeg.tar.gz https://github.com/yt-dlp/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linuxarm64-gpl.tar.xz
tar -xf ffmpeg.tar.gz
chmod +x ffmpeg-master-latest-linuxarm64-gpl/bin/ffmpeg
chmod +x ffmpeg-master-latest-linuxarm64-gpl/bin/ffprobe
# May need sudo / root permissions to perform
mv ffmpeg-master-latest-linuxarm64-gpl/bin/ffmpeg /usr/bin/ffmpeg
mv ffmpeg-master-latest-linuxarm64-gpl/bin/ffprobe /usr/bin/ffprobe

View file

@ -0,0 +1,3 @@
Unraid
--------------
You can install our :unraid:`unraid community apps <community/apps?q=ytdl-sub#r>` through the `Unraid Community Apps plugin <https://unraid.net/community/apps>`_. Uses Docker under the hood.

View file

@ -0,0 +1,15 @@
Windows
--------------
From powershell, run:
.. code-block:: powershell
# Download ffmpeg/ffprobe dependencies from yt-dlp
curl.exe -L -o ffmpeg.zip https://github.com/yt-dlp/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip
tar -xf ffmpeg.zip
move "ffmpeg-master-latest-win64-gpl\bin\ffmpeg.exe" "ffmpeg.exe"
move "ffmpeg-master-latest-win64-gpl\bin\ffprobe.exe" "ffprobe.exe"
# Download ytdl-sub
curl.exe -L -o ytdl-sub.exe https://github.com/jmbannon/ytdl-sub/releases/latest/download/ytdl-sub.exe
ytdl-sub.exe -h

22
docs/source/index.rst Normal file
View file

@ -0,0 +1,22 @@
ytdl-sub User Guide
===================
.. toctree::
:maxdepth: 2
:titlesonly:
introduction
guides/index
prebuilt_presets/index
usage
config_reference/index
faq/index
deprecation_notices
.. note:: End goal similar to: https://picard-docs.musicbrainz.org/en/functions/list_by_type.html
Initial plans:
- pages for each prebuilt preset, showing which variables that can be overridden to do different things (i.e. episode_title)
- new wiki walkthrough that uses the README config as a starting point, and gradually adds custom changes
- pages for how to enable custom metadata agents for Kodi/Plex/jellyfin
- page dedicated to explaining the structure of a config (it's only lightly touched on now, many folks struggle to understand the 'pattern' of presets/plugins/overrides)

View file

@ -0,0 +1,43 @@
=================
What is ytdl-sub?
=================
.. _yt-dlp: https://github.com/yt-dlp/yt-dlp
.. _kodi: https://github.com/xbmc/xbmc
.. _jellyfin: https://github.com/jellyfin/jellyfin
.. _plex: https://github.com/plexinc/pms-docker
.. _emby: https://github.com/plexinc/pms-docker
``ytdl-sub`` is a command-line tool that downloads media via `yt-dlp`_ and prepares it for your favorite media player (`Kodi`_, `Jellyfin`_, `Plex`_, `Emby`_, modern music players).
Visual examples
===============
.. figure:: https://user-images.githubusercontent.com/10107080/182677243-b4184e51-9780-4094-bd40-ea4ff58555d0.PNG
:alt: The Jellyfin web interface, showing the thumbnails of various YouTube shows.
Youtube channels as TV shows in Jellyfin
.. figure:: https://user-images.githubusercontent.com/10107080/182677256-43aeb029-0c3f-4648-9fd2-352b9666b262.PNG
:alt: The Jellyfin web interace, showing the thumbnails of various music videos starring the Red Hot Chili Peppers
Music videos and concerts in Jellyfin
.. figure:: https://user-images.githubusercontent.com/10107080/182677268-d1bf2ff0-9b9c-4a04-98ec-443a67ada734.png
:alt: The Kodi app interface, showing a list of artists available to watch under the "Music videos" heading
Music videos and concerts in Kodi
.. figure:: https://user-images.githubusercontent.com/10107080/182685415-06adf477-3dd3-475d-bbcd-53b0152b9f0a.PNG
:alt: The MusicBee app interface, showing a list of album artists and the thumbnails of all downloaded songs produced by the currently selected artist
SoundCloud albums and singles in MusicBee
Why ytdl-sub?
-------------
There is a lack of open-source tools to download media and generate metadata to play it in these players. Most solutions involve using multiple tools or bash scripts to achieve this. ``ytdl-sub`` aims to consolidate all of this logic into a single easy-to-use application that can run automatically once configured.
Why download instead of stream?
-------------------------------
We believe it is important to download what you like because there is no guarantee it will stay online forever. We also believe it is important to download it in such a way that it is easy to consume. Most solutions today force you to watch/listen to your downloaded content via file system or web browser. ``ytdl-sub`` aims to format downloaded content for any media player.

View file

@ -0,0 +1,37 @@
==============
Helper Presets
==============
Common presets are not usable by themselves- setting one of these as the sole preset of your subscription and attempting to download will not work. But you can add these presets to quickly modify an existing preset to better suit your needs.
Best A/V Quality
----------------
Add the following preset to download the best available video and audio quality, and remux it into an MP4 container:
``best_video_quality``
Max 1080p Video
---------------
Add the following preset to download the best available audio and video quality, with the video not greater than 1080p, and remux it into an MP4 container:
``max_1080p``
Chunk Initial Download
----------------------
If you are archiving a large channel, ``ytdl-sub`` will try pulling each video's metadata from newest to oldest before starting any downloads. It is a long process and not ideal. A better method is to chunk the process by using the following preset:
``chunk_initial_download``
It will download videos starting from the oldest one, and only download 20 at a time. You can
change this number by setting:
.. code-block:: yaml
ytdl_options:
max_downloads: 30 # Desired number to download per invocation
Once the entire channel is downloaded, remove this preset. Then it will pull metadata from newest to oldest again, and stop pulling additional metadata once it reaches a video that has already been downloaded.

View file

@ -0,0 +1,14 @@
================
Prebuilt Presets
================
``ytdl-sub`` offers a number of built-in presets using best practices for formatting
media in various players. For advanced users, you can review the prebuilt preset
definitions :doc:`here </config_reference/prebuilt_presets/index>`.
.. toctree::
:titlesonly:
helpers
tv_shows
music

View file

@ -0,0 +1,3 @@
=============
Music Presets
=============

View file

@ -0,0 +1,171 @@
===============
TV Show Presets
===============
Player-Specific Presets
=======================
``ytdl-sub`` provides player-specific versions of certain presets, which apply settings to optimize the downloads for that player.
The following actions are taken based on the indicated player:
Jellyfin
~~~~~~~~
* Places any season-specific poster art in the main show folder
* Generates NFO tags
Kodi
~~~~
* Everything that the Jellyfin version does
* Turns on :ref:`config_reference/plugins:kodi_safe`, replacing characters that would break kodi with safer characters
Plex
~~~~
* :ref:`Special sanitization <config_reference/scripting/entry_variables:title_sanitized_plex>` of numbers so Plex doesn't recognize numbers that are part of the title as the episode number
* Converts all downloaded videos to the mp4 format
* Places any season-specific poster art into the season folder
----------------------------------------------
Generic Presets
===============
There are two main methods for downloading and formatting videos as a TV show.
TV Show by Date
---------------
TV Show by Date will organize something like a YouTube channel or playlist into a tv show, where seasons and episodes are organized using upload date.
Plug and Play Presets
~~~~~~~~~~~~~~~~~~~~~
You can use any of these presets in your ``subscriptions.yaml`` as a "One size fits all" solution- they should set all appropriate values. These will organize seasons by year and episodes by month, then day.
Must define ``tv_show_directory``
* ``"Kodi TV Show by Date"``
* ``"Jellyfin TV Show by Date"``
* ``"Plex TV Show by Date"``
Advanced Usage
~~~~~~~~~~~~~~
If you prefer a different organization method, you can instead apply multiple presets to your subscriptions.
You will need a base of one of the below:
* ``kodi_tv_show_by_date``
* ``jellyfin_tv_show_by_date``
* ``plex_tv_show_by_date``
And then add one of these:
* ``season_by_year__episode_by_month_day``
* ``season_by_year_month__episode_by_day``
* ``season_by_year__episode_by_month_day_reversed``
* Episode numbers are reversed, meaning more recent episodes appear at the top of a season by having a lower value.
* ``season_by_year__episode_by_download_index``
* Episodes are numbered by the download order. NOTE that this is fetched using the length of the download archive. Do not use if you intend to remove old videos.
An example of a subscription that will be played on Kodi, organized by year with the most recent episode at the top (having a lower episode number), with a genre of "Pop":
.. code-block:: yaml
:caption: subscriptions.yaml
__preset__:
overrides:
tv_show_directory: "/tv_shows"
kodi_tv_show_by_date:
season_by_year_episode_by_month_day_reversed:
= Pop:
"Rick A": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
You can also choose to combine multiple URLs into one show. This will result in your videos being downloaded to the same folder, and the episode numbers being shared between them (so you won't have two episode 10's, for example). Note that you may :ytdl-sub-gh:`experience issues <issues/833>` if you use more than 20 URLs at this time.
.. code-block:: yaml
:caption: subscriptions.yaml
__preset__:
overrides:
tv_show_directory: "/tv_shows"
kodi_tv_show_by_date:
season_by_year_episode_by_month_day_reversed:
= Pop:
"~Rick A":
url: "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
url2: "https://www.youtube.com/@just.rick_6"
TV Show Collection
------------------
TV Show Collections are made up of multiple URLs, where each URL is a season.
If a video belongs to multiple URLs (i.e. a channel and a channel's playlist),
it will resolve to the bottom-most season, as defined in the subscription.
Two main use cases of a collection are:
1. Organize a YouTube channel TV show where Season 1 contains any video
not in a 'season playlist', Season 2 for 'Playlist A', Season 3 for
'Playlist B', etc.
2. Organize one or more YouTube channels/playlists, where each season
represents a separate channel/playlist.
Player Presets
~~~~~~~~~~~~~~
* ``kodi_tv_show_collection``
* ``jellyfin_tv_show_collection``
* ``plex_tv_show_collection``
Episode Formatting Presets
~~~~~~~~~~~~~~~~~~~~~~~~~~
* ``season_by_collection__episode_by_year_month_day``
* ``season_by_collection__episode_by_year_month_day_reversed``
* ``season_by_collection__episode_by_playlist_index``
* Only use playlist_index episode formatting for playlists that will be fully downloaded once and never again. Otherwise, indices can change.
* ``season_by_collection__episode_by_playlist_index_reversed``
Season Presets
~~~~~~~~~~~~~~
* ``collection_season_1``
* ``collection_season_2``
* ``collection_season_3``
* ``collection_season_4``
* ``...``
* ``collection_season_40``
Example
~~~~~~~
A preset/subscription requires specifying a player, episode formatting, and
one or more season presets, with the following override variables:
.. code-block:: yaml
rick_a_tv_show_collection:
preset:
- "jellyfin_tv_show_collection"
- "season_by_collection__episode_by_year_month_day_reversed"
- "collection_season_1"
- "collection_season_2"
overrides:
# required
tv_show_name: "Rick A"
tv_show_directory: "/path/to/youtube_shows"
collection_season_1_url: "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
collection_season_1_name: "All Videos"
collection_season_2_url: "https://www.youtube.com/playlist?list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc"
collection_season_2_name: "Official Music Videos"
# can be modified from their default value
# tv_show_genre: "ytdl-sub"
# episode_title: "{upload_date_standardized} - {title}"
# episode_description: "{webpage_url}"

View file

@ -0,0 +1,3 @@
sphinx-book-theme==1.0.1
sphinx-copybutton==0.5.2
sphinx-design==0.5.0

View file

@ -3,7 +3,7 @@ Usage
.. code-block::
ytdl-sub [GENERAL OPTIONS] {sub,dl,view} [COMMAND OPTIONS]
ytdl-sub [GENERAL OPTIONS] {sub,dl,view} [COMMAND OPTIONS]
For Windows users, it would be ``ytdl-sub.exe``
@ -43,28 +43,28 @@ Download a single subscription in the form of CLI arguments.
.. code-block::
ytdl-sub [GENERAL OPTIONS] dl [SUBSCRIPTION ARGUMENTS]
ytdl-sub [GENERAL OPTIONS] dl [SUBSCRIPTION ARGUMENTS]
``SUBSCRIPTION ARGUMENTS`` are exactly the same as YAML arguments, but use periods (``.``) instead
of indents for specifying YAML from the CLI. For example, you can represent this subscription:
.. code-block:: yaml
rick_a:
preset:
- "tv_show"
overrides:
tv_show_name: "Rick A"
url: "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
rick_a:
preset:
- "tv_show"
overrides:
tv_show_name: "Rick A"
url: "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
Using the command:
.. code-block:: bash
ytdl-sub dl \
--preset "tv_show" \
--overrides.tv_show_name "Rick A" \
--overrides.url: "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
ytdl-sub dl \
--preset "tv_show" \
--overrides.tv_show_name "Rick A" \
--overrides.url: "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"
See how to shorten commands using
`download aliases <https://ytdl-sub.readthedocs.io/en/latest/config.html#ytdl_sub.config.config_validator.ConfigOptions.dl_aliases>`_.