Merge branch 'master' into emby

This commit is contained in:
Jesse Bannon 2025-06-01 08:46:15 -07:00
commit 9f54aeda69
199 changed files with 5270 additions and 710 deletions

View file

@ -19,7 +19,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Run unit tests with coverage
run: |
@ -42,7 +42,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Run integration tests with coverage
run: |
@ -66,7 +66,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Run prebuilt preset integration tests with coverage
run: |
@ -89,7 +89,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Run e2e tests with coverage
run: |

View file

@ -9,7 +9,7 @@ on:
- master
jobs:
test-lint:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
permissions:
contents: read
@ -19,7 +19,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Run linters
run: |
@ -27,7 +27,7 @@ jobs:
make check_lint
test-unit:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
permissions:
contents: read
@ -37,7 +37,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Run unit tests with coverage
run: |
@ -53,7 +53,7 @@ jobs:
key: ${{github.sha}}-coverage-unit
test-integration:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
permissions:
contents: read
@ -63,7 +63,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Run integration tests with coverage
run: |
@ -79,7 +79,7 @@ jobs:
key: ${{github.sha}}-coverage-integration
test-integration-prebuilt-presets:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
permissions:
contents: read
@ -89,7 +89,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Run prebuilt preset integration tests with coverage
run: |
@ -105,7 +105,7 @@ jobs:
key: ${{github.sha}}-coverage-integration-prebuilt-presets
test-e2e:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
permissions:
contents: read
@ -115,7 +115,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Run e2e tests with coverage
run: |
@ -125,7 +125,7 @@ jobs:
coverage run -m pytest tests/e2e && coverage xml -o /opt/coverage/e2e/coverage.xml
codecov-upload:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs: [
test-unit,
test-integration,

View file

@ -63,10 +63,10 @@ jobs:
echo 'init_contents=__pypi_version__ = "${{ env.PYPI_VERSION }}";__local_version__ = "${{ env.LOCAL_VERSION }}"' >> "$GITHUB_OUTPUT"
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ "3.10" ]
python-version: [ "3.12" ]
permissions:
contents: read
@ -92,7 +92,7 @@ jobs:
# Build ARM64 container, only on master branch to save time testing
package-arm64:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs: [
build
]
@ -141,7 +141,7 @@ jobs:
# Build AMD64 container
package-amd64:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs: [
build
]
@ -186,7 +186,7 @@ jobs:
# On master branch, build the docker manifest file from the cached
# docker builds and push to the registry
deploy:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs: [
version,
build,

View file

@ -63,10 +63,10 @@ jobs:
echo 'init_contents=__pypi_version__ = "${{ env.PYPI_VERSION }}";__local_version__ = "${{ env.LOCAL_VERSION }}"' >> "$GITHUB_OUTPUT"
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ "3.10" ]
python-version: [ "3.12" ]
permissions:
contents: read
@ -92,7 +92,7 @@ jobs:
# Build ARM64 container, only on master branch to save time testing
package-arm64:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs: [
build
]
@ -141,7 +141,7 @@ jobs:
# Build AMD64 container
package-amd64:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs: [
build
]
@ -186,7 +186,7 @@ jobs:
# On master branch, build the docker manifest file from the cached
# docker builds and push to the registry
deploy:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs: [
version,
build,

View file

@ -63,10 +63,10 @@ jobs:
echo 'init_contents=__pypi_version__ = "${{ env.PYPI_VERSION }}";__local_version__ = "${{ env.LOCAL_VERSION }}"' >> "$GITHUB_OUTPUT"
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ "3.10" ]
python-version: [ "3.12" ]
permissions:
contents: read
@ -92,7 +92,7 @@ jobs:
# Build ARM64 container, only on master branch to save time testing
package-arm64:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs: [
build
]
@ -136,7 +136,7 @@ jobs:
# Build AMD64 container
package-amd64:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs: [
build
]
@ -180,7 +180,7 @@ jobs:
# On master branch, build the docker manifest file from the cached
# docker builds and push to the registry
deploy:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs: [
version,
build,

View file

@ -61,9 +61,16 @@ jobs:
strategy:
matrix:
arch: [ "aarch64", "x86_64" ]
runs-on: ubuntu-latest
include:
- arch: "aarch64"
runner: "ubuntu-24.04-arm"
container: "quay.io/pypa/manylinux_2_28_aarch64"
- arch: "x86_64"
runner: "ubuntu-latest"
container: "quay.io/pypa/manylinux_2_28_x86_64"
runs-on: ${{ matrix.runner }}
container:
image: quay.io/pypa/manylinux_2_28_x86_64
image: ${{ matrix.container }}
steps:
- uses: actions/checkout@v3
- name: Write version to init file
@ -76,17 +83,17 @@ jobs:
dnf install -y epel-release tar wget make gcc openssl-devel bzip2-devel libffi-devel zlib-devel
- name: Install Python
run: |
wget https://www.python.org/ftp/python/3.10.10/Python-3.10.10.tar.xz
tar -xf Python-3.10.10.tar.xz
cd Python-3.10.10 && ./configure --with-ensurepip=install --prefix=/usr/local --enable-shared LDFLAGS="-Wl,-rpath /usr/local/lib"
wget https://www.python.org/ftp/python/3.12.9/Python-3.12.9.tar.xz
tar -xf Python-3.12.9.tar.xz
cd Python-3.12.9 && ./configure --with-ensurepip=install --prefix=/usr/local --enable-shared LDFLAGS="-Wl,-rpath /usr/local/lib"
make -j 8
make altinstall
python3.10 --version
python3.10 -m ensurepip --upgrade
python3.12 --version
python3.12 -m ensurepip --upgrade
- name: Build Package
run: |
python3.10 -m pip install -e .
python3.10 -m pip install pyinstaller
python3.12 -m pip install -e .
python3.12 -m pip install pyinstaller
# Build executable
pyinstaller ytdl-sub.spec
mkdir -p /opt/builds
@ -95,7 +102,7 @@ jobs:
mv dist/ytdl-sub /opt/builds/ytdl-sub_${{ matrix.arch }}
- name: Upload build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ytdl-sub_${{ matrix.arch }}
path: /opt/builds/ytdl-sub_${{ matrix.arch }}
@ -112,7 +119,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Write version to init file
run: |
echo '${{ needs.version.outputs.init_contents }}'> src/ytdl_sub/__init__.py
@ -124,7 +131,7 @@ jobs:
.\dist\ytdl-sub.exe -h
- name: Upload build
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ytdl-sub_exe
path: .\dist\ytdl-sub.exe
@ -145,19 +152,19 @@ jobs:
echo '${{ needs.version.outputs.init_contents }}' > src/ytdl_sub/__init__.py
- name: Restore exe build
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: ytdl-sub_exe
path: /opt/builds
- name: Restore aarch64 build
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: ytdl-sub_aarch64
path: /opt/builds
- name: Restore x86_64 build
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: ytdl-sub_x86_64
path: /opt/builds
@ -193,13 +200,13 @@ jobs:
name: pypi-publish
needs:
- version
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
python-version: '3.12'
- name: Write version to init file
run: |
echo '${{ needs.version.outputs.init_contents }}' > src/ytdl_sub/__init__.py

View file

@ -14,9 +14,9 @@ else
endif
lint:
@-isort .
@-black .
@-pylint src/
python3 -m isort .
python3 -m black .
python3 -m pylint src
check_lint:
isort . --check-only --diff \
&& black . --check \

View file

@ -3,8 +3,10 @@ FROM ghcr.io/linuxserver/baseimage-alpine:edge
###############################################################################
# YTDL-SUB INSTALL
# Needed for phantomjs
# For phantomjs
ENV OPENSSL_CONF="/etc/ssl"
# For downloading thumbnails
ENV SSL_CERT_DIR="/etc/ssl/certs/"
COPY root/ /
RUN mkdir -p /config && \
@ -55,6 +57,12 @@ RUN mkdir -p /config && \
# CONTAINER CONFIGS
ENV EDITOR="nano" \
HOME="/config"
HOME="/config" \
DOCKER_MODS=linuxserver/mods:universal-stdout-logs|linuxserver/mods:universal-cron \
DEFAULT_WORKSPACE=/config \
CRON_SCRIPT="/config/cron" \
CRON_WRAPPER_SCRIPT="/config/.cron_wrapper" \
LOGS_TO_STDOUT=/config/.cron.log \
LSIO_FIRST_PARTY=false
VOLUME /config

View file

@ -1,7 +1,9 @@
FROM lscr.io/linuxserver/code-server:4.18.0-ls181
FROM lscr.io/linuxserver/code-server:4.98.2
# Needed for phantomjs
ENV OPENSSL_CONF=/etc/ssl
# For phantomjs
ENV OPENSSL_CONF="/etc/ssl"
# For downloading thumbnails
ENV SSL_CERT_DIR="/etc/ssl/certs/"
###############################################################################
# YTDL-SUB INSTALL
@ -20,7 +22,6 @@ RUN mkdir -p /config && \
g++ \
nano \
make \
python3.10-dev \
python3-pip \
fontconfig \
xz-utils \
@ -59,7 +60,7 @@ RUN mkdir -p /config && \
phantomjs --version ; \
fi && \
# Install ytdl-sub, ensure it is installed properly
pip install --no-cache-dir ytdl_sub-*.whl && \
pip install --no-cache-dir --break-system-packages ytdl_sub-*.whl && \
ytdl-sub -h && \
# Delete unneeded packages after install
rm ytdl_sub-*.whl && \
@ -68,7 +69,6 @@ RUN mkdir -p /config && \
make \
xz-utils \
bzip2 \
python3.10-dev \
python3-venv && \
apt-get autoremove -y && \
apt-get purge -y --auto-remove && \
@ -77,11 +77,13 @@ RUN mkdir -p /config && \
###############################################################################
# CONTAINER CONFIGS
ENV YTDL_SUB_TYPE="gui" \
EDITOR="nano" \
ENV EDITOR="nano" \
HOME="/config" \
DOCKER_MODS=linuxserver/mods:universal-cron \
DEFAULT_WORKSPACE=/config/ytdl-sub-configs
DOCKER_MODS=linuxserver/mods:universal-stdout-logs|linuxserver/mods:universal-cron \
DEFAULT_WORKSPACE=/config/ytdl-sub-configs \
CRON_SCRIPT="/config/ytdl-sub-configs/cron" \
CRON_WRAPPER_SCRIPT="/config/.cron_wrapper" \
LOGS_TO_STDOUT=/config/.cron.log \
LSIO_FIRST_PARTY=false
VOLUME /config

View file

@ -1,10 +1,12 @@
FROM ghcr.io/linuxserver/baseimage-ubuntu:jammy
FROM ghcr.io/linuxserver/baseimage-ubuntu:noble
# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
ARG DEBIAN_FRONTEND=noninteractive
# Needed for phantomjs
ENV OPENSSL_CONF=/etc/ssl
# For phantomjs
ENV OPENSSL_CONF="/etc/ssl"
# For downloading thumbnails
ENV SSL_CERT_DIR="/etc/ssl/certs/"
###############################################################################
# YTDL-SUB INSTALL
@ -23,7 +25,6 @@ RUN mkdir -p /config && \
g++ \
nano \
make \
python3.10-dev \
python3-pip \
fontconfig \
xz-utils \
@ -62,7 +63,7 @@ RUN mkdir -p /config && \
phantomjs --version ; \
fi && \
# Install ytdl-sub, ensure it is installed properly
pip install --no-cache-dir ytdl_sub-*.whl && \
pip install --no-cache-dir --break-system-packages ytdl_sub-*.whl && \
ytdl-sub -h && \
# Delete unneeded packages after install
rm ytdl_sub-*.whl && \
@ -71,7 +72,6 @@ RUN mkdir -p /config && \
make \
xz-utils \
bzip2 \
python3.10-dev \
python3-venv && \
apt-get autoremove -y && \
apt-get purge -y --auto-remove && \
@ -81,6 +81,12 @@ RUN mkdir -p /config && \
# CONTAINER CONFIGS
ENV EDITOR="nano" \
HOME="/config"
HOME="/config" \
DOCKER_MODS=linuxserver/mods:universal-stdout-logs|linuxserver/mods:universal-cron \
DEFAULT_WORKSPACE=/config \
CRON_SCRIPT="/config/cron" \
CRON_WRAPPER_SCRIPT="/config/.cron_wrapper" \
LOGS_TO_STDOUT=/config/.cron.log \
LSIO_FIRST_PARTY=false
VOLUME /config

View file

@ -0,0 +1,68 @@
#!/usr/bin/with-contenv bash
echo "Starting ytdl-sub..."
# copy config
[[ ! -e "$DEFAULT_WORKSPACE/config.yaml" ]] && \
mkdir -p "$DEFAULT_WORKSPACE" && \
cp /defaults/config.yaml "$DEFAULT_WORKSPACE/config.yaml"
[[ ! -e "$DEFAULT_WORKSPACE/subscriptions.yaml" ]] && \
mkdir -p "$DEFAULT_WORKSPACE" && \
cp /defaults/subscriptions.yaml "$DEFAULT_WORKSPACE/subscriptions.yaml"
[[ ! -d "$DEFAULT_WORKSPACE/examples" ]] && \
mkdir -p "$DEFAULT_WORKSPACE/examples" && \
cp -r /defaults/examples/* "$DEFAULT_WORKSPACE/examples"
[[ ! -e "/config/.bashrc" ]] && \
echo "alias ls='ls --color=auto'" > /config/.bashrc && \
echo "cd ." >> /config/.bashrc
# permissions
chown -R ${PUID:-abc}:${PGID:-abc} \
/config
# always create empty cron log file on start
echo "" > "$LOGS_TO_STDOUT"
# set up cron
if [ "$CRON_SCHEDULE" != "" ] ; then
[[ ! -e "$CRON_SCRIPT" ]] && \
cp /defaults/cron "$CRON_SCRIPT"
# create cron script wrapper
echo '#!/bin/bash' > "$CRON_WRAPPER_SCRIPT"
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> "$CRON_WRAPPER_SCRIPT"
echo "cd \"$DEFAULT_WORKSPACE\"" >> "$CRON_WRAPPER_SCRIPT"
echo ". \"$CRON_SCRIPT\" | tee -a \"$LOGS_TO_STDOUT\"" >> "$CRON_WRAPPER_SCRIPT"
chmod +x "$CRON_WRAPPER_SCRIPT"
chown abc:abc "$CRON_WRAPPER_SCRIPT"
# Set the crontab file to the schedule, cleanly
CRON_SCHEDULE_CLEAN="${CRON_SCHEDULE//\"/}"
CRON_SCHEDULE_CLEAN="${CRON_SCHEDULE_CLEAN//\'/}"
echo "# min hour day month weekday command" > /config/crontabs/abc
echo "$CRON_SCHEDULE_CLEAN $CRON_WRAPPER_SCRIPT" >> /config/crontabs/abc
chmod +x "$CRON_SCRIPT"
chown abc:abc "$CRON_SCRIPT"
crontab -u abc /config/crontabs/abc
CRON_SUCCESS=$?
if [ $CRON_SUCCESS -eq 0 ] ; then
echo "Cron enabled with schedule $CRON_SCHEDULE_CLEAN"
if [ "$CRON_RUN_ON_START" = true ] ; then
echo "Running cron script on start in the background"
# ensure it runs as abc to respect puid/guid with delay for tail to start
su -s "/bin/bash" -c "sleep 5 && . '$CRON_WRAPPER_SCRIPT'" abc > /dev/null 2>&1 &
fi
else
echo "Error in CRON_SCHEDULE definition, disabling cron."
exit 1
fi
else
echo "CRON_SCHEDULE not specified, leaving crontabs as-is. Current configuration in /config/crontabs/abc"
cat /config/crontabs/abc
fi

View file

@ -1,23 +0,0 @@
#!/usr/bin/with-contenv bash
# Exit if not gui
if [ "$YTDL_SUB_TYPE" != "gui" ] ; then
exit 0
fi
echo "Checking ytdl-sub-gui defaults..."
# copy config
[[ ! -e /config/ytdl-sub-configs/config.yaml ]] && \
mkdir -p /config/ytdl-sub-configs && \
cp /defaults/config.yaml /config/ytdl-sub-configs/config.yaml
[[ ! -e /config/ytdl-sub-configs/subscriptions.yaml ]] && \
mkdir -p /config/ytdl-sub-configs && \
cp /defaults/subscriptions.yaml /config/ytdl-sub-configs/subscriptions.yaml
[[ ! -d /config/ytdl-sub-configs/examples ]] && \
mkdir -p /config/ytdl-sub-configs/examples && \
cp /defaults/examples/* /config/ytdl-sub-configs/examples
# permissions
chown -R ${PUID:-abc}:${PGID:-abc} \
/config

View file

@ -1,20 +0,0 @@
#!/usr/bin/with-contenv bash
# Exit if gui
if [ "$YTDL_SUB_TYPE" == "gui" ] ; then
exit 0
fi
echo "Checking ytdl-sub defaults..."
# copy config
[[ ! -e /config/config.yaml ]] && \
cp /defaults/config.yaml /config/config.yaml
[[ ! -e /config/subscriptions.yaml ]] && \
cp /defaults/subscriptions.yaml /config/subscriptions.yaml
[[ ! -d /config/examples ]] && \
cp -R /defaults/examples /config/
# permissions
chown -R ${PUID:-abc}:${PGID:-abc} \
/config

View file

@ -0,0 +1,4 @@
echo "Beginning cron job..."
# Place your ytdl-sub command(s) here.
# This script is executed in the same relative path as this file.

View file

@ -0,0 +1,15 @@
――――――――――――――――――――――――――――――――――――
██╗ ██╗████████╗██████╗ ██╗
╚██╗ ██╔╝╚══██╔══╝██╔══██╗██║
╚████╔╝ ██║ ██║ ██║██║
╚██╔╝ ██║ ██║ ██║██║
██║ ██║ ██████╔╝███████╗
╚═╝ ╚═╝ ╚═════╝ ╚══════╝
███████╗██╗ ██╗██████╗
██╔════╝██║ ██║██╔══██╗
███████╗██║ ██║██████╔╝
╚════██║██║ ██║██╔══██╗
███████║╚██████╔╝██████╔╝
╚══════╝ ╚═════╝ ╚═════╝
――――――――――――――――――――――――――――――――――――

View file

@ -6,8 +6,34 @@ services:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
- CRON_SCHEDULE="*/1 * * * *"
- CRON_RUN_ON_START=true
volumes:
- ./volumes/ytdl-sub-gui:/config
ports:
- 8443:8443
restart: unless-stopped
ytdl-sub:
image: ytdl-sub:local
container_name: ytdl-sub
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
- CRON_SCHEDULE="*/1 * * * *"
- CRON_RUN_ON_START=true
volumes:
- ./volumes/ytdl-sub:/config
restart: unless-stopped
ytdl-sub-ubuntu:
image: ytdl-sub-ubuntu:local
container_name: ytdl-sub-ubuntu
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
- CRON_SCHEDULE="*/1 * * * *"
- CRON_RUN_ON_START=true
volumes:
- ./volumes/ytdl-sub:/config
restart: unless-stopped

View file

@ -456,7 +456,7 @@ with a ``.nfo`` extension. You can add any values into the NFO.
``kodi_safe``
:expected type: Optional[Boolean]
:expected type: OverridesBooleanFormatterValidator
:description:
Defaults to False. Kodi does not support > 3-byte unicode characters, which include
emojis and some foreign language characters. Setting this to True will replace those
@ -554,7 +554,7 @@ Usage:
``kodi_safe``
:expected type: Optional[Boolean]
:expected type: OverridesBooleanFormatterValidator
:description:
Defaults to False. Kodi does not support > 3-byte unicode characters, which include
emojis and some foreign language characters. Setting this to True will replace those
@ -640,6 +640,8 @@ Defines where to output files and thumbnails after all post-processing has compl
maintain_download_archive: True
keep_files_before: now
keep_files_after: 19000101
keep_max_files: 1000
keep_files_date_eval: "{upload_date_standardized}"
``download_archive_name``
@ -690,6 +692,16 @@ Defines where to output files and thumbnails after all post-processing has compl
``keep_max_files``.
``keep_files_date_eval``
:expected type: str
:description:
Uses this standardized date in the form of YYYY-MM-DD to record in the
download archive for a given entry. Subsequently, uses this value to
perform evaluation for keep_files_before/after and keep_max_files. Defaults
to the entry's upload_date_standardized variable.
``keep_max_files``
:expected type: Optional[OverridesFormatter]
@ -966,6 +978,9 @@ scripted.
presets:
my_example_preset:
throttle_protection:
sleep_per_request_s:
min: 5.5
max: 10.4
sleep_per_download_s:
min: 2.2
max: 10.8
@ -1001,6 +1016,16 @@ scripted.
ytdl-sub to perform post-processing.
``sleep_per_request_s``
:expected type: Optional[Range]
:description:
Number in seconds to sleep between each request during metadata download. Note that
metadata download refers to the initial info.json download, not the actual audio/video
download for the entry. Also, yt-dlp only supports a single value at this time for this,
so will always use the max value.
``sleep_per_subscription_s``
:expected type: Optional[Range]

View file

@ -659,3 +659,9 @@ ytdl_sub_input_url_index
:type: ``Integer``
:description:
The index of the input URL as defined in the subscription, top-most being the 0th index.
ytdl_sub_keep_files_date_eval
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:type: ``String``
:description:
The standardized date variable supplied in ``output_options.keep_files_date_eval``.

View file

@ -523,6 +523,38 @@ sub
----------------------------------------------------------------------------------------------------
Print Functions
---------------
print
~~~~~
:spec: ``print(message: AnyArgument, passthrough: ReturnableArgument, level: Optional[Integer]) -> ReturnableArgument``
:description:
Print the ``message`` and return ``passthrough``.
Optionally can pass level, where < 0 is debug, 0 is info, 1 is warning, > 1 is error.
Defaults to info.
print_if_false
~~~~~~~~~~~~~~
:spec: ``print_if_false(message: AnyArgument, passthrough: ReturnableArgument, level: Optional[Integer]) -> ReturnableArgument``
:description:
Print the ``message`` if ``passthrough`` evaluates to ``false``. Return ``passthrough``.
Optionally can pass level, where < 0 is debug, 0 is info, 1 is warning, > 1 is error.
Defaults to info.
print_if_true
~~~~~~~~~~~~~
:spec: ``print_if_true(message: AnyArgument, passthrough: ReturnableArgument, level: Optional[Integer]) -> ReturnableArgument``
:description:
Print the ``message`` if ``passthrough`` evaluates to ``true``. Return ``passthrough``.
Optionally can pass level, where < 0 is debug, 0 is info, 1 is warning, > 1 is error.
Defaults to info.
----------------------------------------------------------------------------------------------------
Regex Functions
---------------
@ -634,7 +666,7 @@ capitalize
concat
~~~~~~
:spec: ``concat(values: String, ...) -> String``
:spec: ``concat(values: AnyArgument, ...) -> String``
:description:
Concatenate multiple Strings into a single String.
@ -660,6 +692,24 @@ contains_any
:description:
Returns true if any element in ``contains_array`` is in ``string``. False otherwise.
join
~~~~
:spec: ``join(separator: String, array: Array) -> String``
:description:
Join all elements in the array together as a string, and insert the
separator between them.
:usage:
.. code-block:: python
{
%join( ", ", ["item1", "item2"] )
}
# "item1, item2"
lower
~~~~~
:spec: ``lower(string: String) -> String``
@ -710,6 +760,23 @@ string
:description:
Cast to String.
strip
~~~~~
:spec: ``strip(string: String) -> String``
:description:
Strip a string of all its whitespace at the beginning and end.
:usage:
.. code-block:: python
{
%trim(" delete the outer! ")
}
# "delete the outer!"
titlecase
~~~~~~~~~
:spec: ``titlecase(string: String) -> String``

View file

@ -62,6 +62,29 @@ See the prebuilt preset :doc:`chunk_initial_download </prebuilt_presets/helpers>
See the prebuilt preset :doc:`Filter Keywords </prebuilt_presets/helpers>`.
...prevent creation of NFO file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Creation of NFO files is done by the NFO tags plugin. It, as any other plugin, can be disabled:
.. code-block:: yaml
nfo_tags:
enabled: False
...prevent download of images
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The :ref:`config_reference/prebuilt_presets/tv_show:TV Show` presets by default downloads images corresponding to show and each episode.
This can be prevented by overriding following variables:
.. code-block:: yaml
overrides:
tv_show_fanart_file_name: "" # to stop creation of fanart.jpg in subscription
tv_show_poster_file_name: "" # to stop creation of poster.jpg in subscription
thumbnail_name: "" # to stop creation of episode thumbnails
There is a bug where...
-----------------------

View file

@ -1,127 +1,43 @@
Automating Downloads
====================
One of the key capabilities of ``ytdl-sub`` automating new downloads.
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
.. _cron scheduling syntax: https://crontab.guru/#0_*/6_*_*_*
.. _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``.
Cron is preconfigured in every ytdl-sub docker container. Enable by adding the following
ENV variables to your docker setup.
Access your container at http://localhost:8443/, then in the GUI terminal run these commands:
.. code-block:: yaml
.. code-block:: shell
services:
ytdl-sub:
environment:
- CRON_SCHEDULE="0 */6 * * *"
- CRON_RUN_ON_START=false
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:
- ``CRON_SCHEDULE`` follows the standard `cron scheduling syntax`_. The above value will run the script once every 6 hours.
- ``CRON_RUN_ON_START`` toggles whether to run your cron script on container start in addition to the cron schedule.
.. code-block:: shell
The cron script will reside in the main directory with the file name ``cron``.
Cron logs should show when viewing the Docker logs.
/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/run_cron
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> /config/run_cron
echo "echo 'Cron started, running ytdl-sub...'" >> /config/run_cron
echo "cd /config" >> /config/run_cron
echo "ytdl-sub --config=config.yaml sub subscriptions.yaml" >> /config/run_cron
chmod +x /config/run_cron
chown abc:abc /config/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
-----
Must configure crontab manually, like so:
.. code-block:: shell

View file

@ -79,7 +79,6 @@ Docker Compose is an easy "set it and forget it" install method. Follow the inst
- 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

View file

@ -28,23 +28,18 @@ Plex
----------------------------------------------
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.
Example
~~~~~~~
-------
Must define ``tv_show_directory``. Available presets:
* ``"Kodi TV Show by Date"``
* ``"Jellyfin TV Show by Date"``
* ``"Plex TV Show by Date"``
* ``Kodi TV Show by Date``
* ``Jellyfin TV Show by Date``
* ``Plex TV Show by Date``
.. code-block:: yaml
@ -72,30 +67,68 @@ Must define ``tv_show_directory``. Available presets:
- "https://www.youtube.com/@rickbeato240"
Advanced Usage
~~~~~~~~~~~~~~
--------------
If you prefer a different organization method, you can instead apply multiple presets to your subscriptions.
If you prefer a different season/episode organization method, you can set the following override variables.
You will need a base of one of the below:
.. code-block:: yaml
* ``kodi_tv_show_by_date``
* ``jellyfin_tv_show_by_date``
* ``plex_tv_show_by_date``
__preset__:
overrides:
tv_show_directory: "/tv_shows"
tv_show_by_date_season_ordering: "upload-year-month"
tv_show_by_date_episode_ordering: "upload-day"
And then add one of these:
Or for a specific preset
* ``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.
.. code-block:: yaml
"~Kids Toys Play":
url: "https://www.youtube.com/@KidsToysPlayChannel"
tv_show_by_date_season_ordering: "upload-year-month"
tv_show_by_date_episode_ordering: "upload-day"
The following are supported. Be sure the combined season + episode ordering
include the year, month, day, i.e. upload-year + upload-month-day.
Season Ordering
~~~~~~~~~~~~~~~
``tv_show_by_date_season_ordering`` supports one of the following:
* ``upload-year`` (default)
* ``upload-year-month``
* ``release-year``
* ``release-year-month``
Episode Ordering
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``tv_show_by_date_episode_ordering`` supports one of the following:
* ``upload-month-day`` (default)
* ``upload-month-day-reversed``
* Reversed means more recent episodes appear at the top of a season by having a lower value.
* ``upload-day``
* ``release-day``
* ``release-month-day``
* ``release-month-day-reversed``
* ``download-index``
* Episodes are numbered by the download order. **NOTE**: this is fetched using the length of the download archive. Do not use if you intend to remove old videos.
TV Show by Date presets use the following for defaults:
.. code-block:: yaml
tv_show_by_date_season_ordering: "upload-year"
tv_show_by_date_episode_ordering: "upload-month-day"
TV Show Collection
------------------
==================
TV Show Collections set each URL as its own season. If a video belongs to multiple URLs
(i.e. a channel and a channel's playlist), the video will only download once and reside in
@ -109,12 +142,12 @@ Two main use cases of a collection are:
represents a separate channel/playlist.
Example
~~~~~~~
-------
Must define ``tv_show_directory``. Available presets:
* ``"Kodi TV Show Collection"``
* ``"Jellyfin TV Show Collection"``
* ``"Plex TV Show Collection"``
* ``Kodi TV Show Collection``
* ``Jellyfin TV Show Collection``
* ``Plex TV Show Collection``
.. code-block:: yaml
@ -132,21 +165,44 @@ Must define ``tv_show_directory``. Available presets:
s02_url: "https://www.youtube.com/playlist?list=PLE62gWlWZk5NWVAVuf0Lm9jdv_-_KXs0W"
Advanced Usage
~~~~~~~~~~~~~~
--------------
If you prefer a different organization method, you can instead apply multiple presets to your subscriptions.
If you prefer a different episode organization method, you can set the following override variables.
You will need a base of one of the below:
.. code-block:: yaml
* ``kodi_tv_show_collection``
* ``jellyfin_tv_show_collection``
* ``plex_tv_show_collection``
__preset__:
overrides:
tv_show_directory: "/tv_shows"
tv_show_collection_episode_ordering: "release-year-month-day"
And then add one of these:
Or for a specific preset
* ``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``
.. code-block:: yaml
"~Beyond the Guitar":
tv_show_collection_episode_ordering: "release-year-month-day"
s01_name: "Videos"
s01_url: "https://www.youtube.com/c/BeyondTheGuitar"
s02_name: "Covers"
s02_url: "https://www.youtube.com/playlist?list=PLE62gWlWZk5NWVAVuf0Lm9jdv_-_KXs0W"
The following are supported.
Episode Ordering
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``tv_show_collection_episode_ordering`` supports one of the following:
* ``upload-year-month-day`` (default)
* ``upload-year-month-day-reversed``
* ``release-year-month-day``
* ``release-year-month-day-reversed``
* ``playlist-index``
* Only use ``playlist-index`` episode formatting for playlists that will be fully downloaded once and never again. Otherwise, indices can change.
* ``playlist-index-reversed``
TV Show Collection presets use upload-year-month-day as the default.

View file

@ -15,7 +15,7 @@ classifiers = [
"Programming Language :: Python :: 3.11",
]
dependencies = [
"yt-dlp[default]==2024.12.23",
"yt-dlp[default]==2025.5.22",
"colorama~=0.4",
"mergedeep~=1.3",
"mediafile~=0.12",
@ -48,8 +48,8 @@ test = [
]
lint = [
"black==24.10.0",
"isort==5.13.2",
"pylint==3.3.3",
"isort==6.0.1",
"pylint==3.3.7",
]
docs = [
"sphinx>=7,<9",

View file

@ -271,6 +271,6 @@ def main() -> List[Subscription]:
transaction_log_file_path=args.transaction_log,
)
output_summary(subscriptions)
output_summary(subscriptions, suppress_colors=args.suppress_colors)
return subscriptions

View file

@ -8,16 +8,16 @@ from ytdl_sub.utils.logger import Logger
logger = Logger.get()
def _green(value: str) -> str:
return Fore.GREEN + value + Fore.RESET
def _green(value: str, suppress_colors: bool = False) -> str:
return value if suppress_colors else Fore.GREEN + value + Fore.RESET
def _red(value: str) -> str:
return Fore.RED + value + Fore.RESET
def _red(value: str, suppress_colors: bool = False) -> str:
return value if suppress_colors else Fore.RED + value + Fore.RESET
def _no_color(value: str) -> str:
return Fore.RESET + value + Fore.RESET
def _no_color(value: str, suppress_colors: bool = False) -> str:
return value if suppress_colors else Fore.RESET + value + Fore.RESET
def _str_int(value: int) -> str:
@ -26,21 +26,23 @@ def _str_int(value: int) -> str:
return str(value)
def _color_int(value: int) -> str:
def _color_int(value: int, suppress_colors: bool = False) -> str:
str_int = _str_int(value)
if value > 0:
return _green(str_int)
return _green(str_int, suppress_colors)
if value < 0:
return _red(str_int)
return _no_color(str_int)
return _red(str_int, suppress_colors)
return _no_color(str_int, suppress_colors)
def output_summary(subscriptions: List[Subscription]) -> None:
def output_summary(subscriptions: List[Subscription], suppress_colors: bool) -> None:
"""
Parameters
----------
subscriptions
Processed subscriptions
suppress_colors
Whether to have color or not
Returns
-------
@ -65,21 +67,21 @@ def output_summary(subscriptions: List[Subscription]) -> None:
# Initialize widths to 0
width_sub_name: int = max(len(sub.name) for sub in subscriptions) + 4 # aesthetics
width_num_entries_added: int = len(_color_int(total_added))
width_num_entries_modified: int = len(_color_int(total_modified))
width_num_entries_removed: int = len(_color_int(total_removed))
width_num_entries_added: int = len(_color_int(total_added, suppress_colors))
width_num_entries_modified: int = len(_color_int(total_modified, suppress_colors))
width_num_entries_removed: int = len(_color_int(total_removed, suppress_colors))
width_num_entries: int = len(str(total_entries)) + 4 # aesthetics
# Build the summary
for subscription in subscriptions:
num_entries_added = _color_int(subscription.num_entries_added)
num_entries_modified = _color_int(subscription.num_entries_modified)
num_entries_removed = _color_int(subscription.num_entries_removed * -1)
num_entries_added = _color_int(subscription.num_entries_added, suppress_colors)
num_entries_modified = _color_int(subscription.num_entries_modified, suppress_colors)
num_entries_removed = _color_int(subscription.num_entries_removed * -1, suppress_colors)
num_entries = str(subscription.num_entries)
status = (
_red(subscription.exception.__class__.__name__)
_red(subscription.exception.__class__.__name__, suppress_colors)
if subscription.exception
else _green("")
else _green("", suppress_colors)
)
summary.append(
@ -92,14 +94,16 @@ def output_summary(subscriptions: List[Subscription]) -> None:
)
total_errors_str = (
_green("Success") if total_errors == 0 else _red(f"Error{'s' if total_errors > 1 else ''}")
_green("Success", suppress_colors)
if total_errors == 0
else _red(f"Error{'s' if total_errors > 1 else ''}", suppress_colors)
)
summary.append(
f"{total_subs_str:<{width_sub_name}} "
f"{_color_int(total_added):>{width_num_entries_added}} "
f"{_color_int(total_modified):>{width_num_entries_modified}} "
f"{_color_int(total_removed):>{width_num_entries_removed}} "
f"{_color_int(total_added, suppress_colors):>{width_num_entries_added}} "
f"{_color_int(total_modified, suppress_colors):>{width_num_entries_modified}} "
f"{_color_int(total_removed * -1, suppress_colors):>{width_num_entries_removed}} "
f"{total_entries:>{width_num_entries}} "
f"{total_errors_str}"
)

View file

@ -44,6 +44,7 @@ class MainArguments:
short="-m",
long="--match",
)
SUPPRESS_COLORS = CLIArgument(short="-nc", long="--suppress-colors")
@classmethod
def all(cls) -> List[CLIArgument]:
@ -59,6 +60,7 @@ class MainArguments:
cls.TRANSACTION_LOG,
cls.SUPPRESS_TRANSACTION_LOG,
cls.MATCH,
cls.SUPPRESS_COLORS,
]
@classmethod
@ -129,6 +131,13 @@ def _add_shared_arguments(arg_parser: argparse.ArgumentParser, suppress_defaults
help="do not output transaction logs to console or file",
default=argparse.SUPPRESS if suppress_defaults else False,
)
arg_parser.add_argument(
MainArguments.SUPPRESS_COLORS.short,
MainArguments.SUPPRESS_COLORS.long,
action="store_true",
help="do not use colors in ytdl-sub output",
default=argparse.SUPPRESS if suppress_defaults else False,
)
arg_parser.add_argument(
MainArguments.MATCH.short,
MainArguments.MATCH.long,

View file

@ -221,3 +221,12 @@ class Overrides(UnstructuredDictFormatterValidator, Scriptable):
return self._apply_to_resolvable(
formatter=formatter, entry=None, function_overrides=None
).native
def evaluate_boolean(
self, formatter: StringFormatterValidator, entry: Optional[Entry] = None
) -> bool:
"""
Apply a formatter, and evaluate it to a boolean
"""
output = self.apply_formatter(formatter=formatter, entry=entry)
return ScriptUtils.bool_formatter_output(output)

View file

@ -13,7 +13,6 @@ from ytdl_sub.config.validators.options import OptionsValidatorT
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
from ytdl_sub.entries.entry import Entry
from ytdl_sub.utils.file_handler import FileMetadata
from ytdl_sub.utils.script import ScriptUtils
from ytdl_sub.ytdl_additions.enhanced_download_archive import DownloadArchiver
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
@ -49,9 +48,7 @@ class Plugin(BasePlugin[OptionsValidatorT], Generic[OptionsValidatorT], ABC):
Returns True if enabled, False if disabled.
"""
if isinstance(self.plugin_options, ToggleableOptionsDictValidator):
return ScriptUtils.bool_formatter_output(
self.overrides.apply_formatter(self.plugin_options.enable)
)
return self.overrides.evaluate_boolean(self.plugin_options.enable)
return True
def ytdl_options_match_filters(self) -> Tuple[List[str], List[str]]:

View file

@ -1,15 +1,19 @@
from typing import Any
from typing import Dict
from typing import Optional
from typing import Set
from ytdl_sub.config.defaults import DEFAULT_DOWNLOAD_ARCHIVE_NAME
from ytdl_sub.config.overrides import Overrides
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
from ytdl_sub.config.validators.options import OptionsDictValidator
from ytdl_sub.entries.script.variable_definitions import VARIABLES as v
from ytdl_sub.validators.file_path_validators import OverridesStringFormatterFilePathValidator
from ytdl_sub.validators.file_path_validators import StringFormatterFileNameValidator
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
from ytdl_sub.validators.string_datetime import StringDatetimeValidator
from ytdl_sub.validators.string_formatter_validators import OverridesIntegerFormatterValidator
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
from ytdl_sub.validators.string_formatter_validators import StandardizedDateValidator
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
from ytdl_sub.validators.string_formatter_validators import (
UnstructuredOverridesDictFormatterValidator,
@ -65,7 +69,7 @@ class YTDLOptions(UnstructuredOverridesDictFormatterValidator):
# pylint: disable=line-too-long
class OutputOptions(StrictDictValidator):
class OutputOptions(OptionsDictValidator):
"""
Defines where to output files and thumbnails after all post-processing has completed.
@ -87,6 +91,8 @@ class OutputOptions(StrictDictValidator):
maintain_download_archive: True
keep_files_before: now
keep_files_after: 19000101
keep_max_files: 1000
keep_files_date_eval: "{upload_date_standardized}"
"""
_required_keys = {"output_directory", "file_name"}
@ -99,6 +105,8 @@ class OutputOptions(StrictDictValidator):
"keep_files_before",
"keep_files_after",
"keep_max_files",
"download_archive_standardized_date",
"keep_files_date_eval",
}
@classmethod
@ -156,6 +164,11 @@ class OutputOptions(StrictDictValidator):
self._keep_max_files = self._validate_key_if_present(
"keep_max_files", OverridesIntegerFormatterValidator
)
self._keep_files_date_eval = self._validate_key(
"keep_files_date_eval",
StandardizedDateValidator,
default=f"{{{v.upload_date_standardized.variable_name}}}",
)
if (
self._keep_files_before or self._keep_files_after or self._keep_max_files
@ -272,6 +285,18 @@ class OutputOptions(StrictDictValidator):
"""
return self._keep_files_after
@property
def keep_files_date_eval(self) -> StandardizedDateValidator:
"""
:expected type: str
:description:
Uses this standardized date in the form of YYYY-MM-DD to record in the
download archive for a given entry. Subsequently, uses this value to
perform evaluation for keep_files_before/after and keep_max_files. Defaults
to the entry's upload_date_standardized variable.
"""
return self._keep_files_date_eval
@property
def keep_max_files(self) -> Optional[OverridesIntegerFormatterValidator]:
"""
@ -283,3 +308,10 @@ class OutputOptions(StrictDictValidator):
applied. Can be used in conjunction with ``keep_files_before`` and ``keep_files_after``.
"""
return self._keep_max_files
def added_variables(self, unresolved_variables: Set[str]) -> Dict[PluginOperation, Set[str]]:
return {
# PluginOperation.MODIFY_ENTRY_METADATA: {
# VARIABLES.ytdl_sub_entry_date_eval.variable_name
# }
}

View file

@ -57,13 +57,14 @@ def _add_dummy_overrides(overrides: Overrides) -> Dict[str, str]:
def _get_added_and_modified_variables(
plugins: PresetPlugins, downloader_options: MultiUrlValidator
plugins: PresetPlugins, downloader_options: MultiUrlValidator, output_options: OutputOptions
) -> Iterable[Tuple[OptionsValidator, Set[str], Set[str]]]:
"""
Iterates and returns the plugin options, added variables, modified variables
"""
options: List[OptionsValidator] = plugins.plugin_options
options.append(downloader_options)
options.append(output_options)
for plugin_options in options:
added_variables: Set[str] = set()
@ -117,6 +118,7 @@ class VariableValidation:
) in _get_added_and_modified_variables(
plugins=self.plugins,
downloader_options=self.downloader_options,
output_options=self.output_options,
):
for added_variable in added_variables:
@ -183,6 +185,9 @@ class VariableValidation:
self._add_variables(PluginOperation.DOWNLOADER, options=self.downloader_options)
self._add_subscription_override_variables()
# Always add output options first
self._add_variables(PluginOperation.MODIFY_ENTRY_METADATA, options=self.output_options)
# Metadata variables to be added
for plugin_options in PluginMapping.order_options_by(
self.plugins.zipped(), PluginOperation.MODIFY_ENTRY_METADATA

View file

@ -25,7 +25,6 @@ from ytdl_sub.entries.script.variable_definitions import VARIABLES
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
from ytdl_sub.utils.file_handler import FileHandler
from ytdl_sub.utils.logger import Logger
from ytdl_sub.utils.script import ScriptUtils
from ytdl_sub.utils.thumbnail import ThumbnailTypes
from ytdl_sub.utils.thumbnail import download_and_convert_url_thumbnail
from ytdl_sub.utils.thumbnail import try_convert_download_thumbnail
@ -459,11 +458,9 @@ class MultiUrlDownloader(SourcePlugin[MultiUrlValidator]):
metadata_ytdl_options = self.metadata_ytdl_options(
ytdl_option_overrides=validator.ytdl_options.to_native_dict(self.overrides)
)
download_reversed = ScriptUtils.bool_formatter_output(
self.overrides.apply_formatter(validator.download_reverse)
)
include_sibling_metadata = ScriptUtils.bool_formatter_output(
self.overrides.apply_formatter(validator.include_sibling_metadata)
download_reversed = self.overrides.evaluate_boolean(validator.download_reverse)
include_sibling_metadata = self.overrides.evaluate_boolean(
validator.include_sibling_metadata
)
parents, orphan_entries = self._download_url_metadata(
@ -534,8 +531,8 @@ class MultiUrlDownloader(SourcePlugin[MultiUrlValidator]):
download_logger.info("Entry rejected by download match-filter, skipping ..")
return None
upload_date_idx = self._enhanced_download_archive.mapping.get_num_entries_with_upload_date(
upload_date_standardized=entry.get(v.upload_date_standardized, str)
upload_date_idx = self._enhanced_download_archive.mapping.get_num_entries_with_date(
standardized_date=entry.get(v.ytdl_sub_keep_files_date_eval, str)
)
download_idx = self._enhanced_download_archive.num_entries

View file

@ -823,6 +823,17 @@ class YtdlSubVariableDefinitions(ABC):
variable_name="upload_date_index_reversed_padded", pad=2
)
@cached_property
def ytdl_sub_keep_files_date_eval(self: "VariableDefinitions") -> StringVariable:
"""
:description:
The standardized date variable supplied in ``output_options.keep_files_date_eval``.
"""
return StringVariable(
variable_name="ytdl_sub_entry_date_eval",
definition=f"{{%string({self.upload_date_standardized.variable_name})}}",
)
class EntryVariableDefinitions(ABC):
@cached_property
@ -1121,6 +1132,7 @@ class VariableDefinitions(
self.ytdl_sub_input_url,
self.ytdl_sub_input_url_index,
self.ytdl_sub_input_url_count,
self.ytdl_sub_keep_files_date_eval,
}
@cache

View file

@ -5,7 +5,6 @@ from typing import Tuple
from ytdl_sub.config.plugin.plugin import Plugin
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
from ytdl_sub.utils.datetime import to_date_str
from ytdl_sub.utils.script import ScriptUtils
from ytdl_sub.validators.string_datetime import StringDatetimeValidator
from ytdl_sub.validators.string_formatter_validators import OverridesBooleanFormatterValidator
@ -95,9 +94,7 @@ class DateRangePlugin(Plugin[DateRangeOptions]):
date_validator=self.plugin_options.after, overrides=self.overrides
)
after_filter = f"upload_date >= {after_str}"
if ScriptUtils.bool_formatter_output(
self.overrides.apply_formatter(self.plugin_options.breaks)
):
if self.overrides.evaluate_boolean(self.plugin_options.breaks):
breaking_match_filters.append(after_filter)
else:
match_filters.append(after_filter)

View file

@ -7,7 +7,6 @@ from ytdl_sub.config.validators.options import OptionsValidator
from ytdl_sub.entries.entry import Entry
from ytdl_sub.utils.exceptions import StringFormattingException
from ytdl_sub.utils.logger import Logger
from ytdl_sub.utils.script import ScriptUtils
from ytdl_sub.validators.string_formatter_validators import ListFormatterValidator
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
@ -53,10 +52,9 @@ class FilterExcludePlugin(Plugin[FilterExcludeOptions]):
return entry
for formatter in self.plugin_options.list:
out = ScriptUtils.bool_formatter_output(
self.overrides.apply_formatter(formatter=formatter, entry=entry)
)
if bool(out):
should_exclude = self.overrides.evaluate_boolean(formatter=formatter, entry=entry)
if should_exclude:
logger.info(
"Filtering '%s' from the filter %s evaluating to True",
entry.title,

View file

@ -61,10 +61,10 @@ class FilterIncludePlugin(Plugin[FilterIncludeOptions]):
return entry
for formatter in self.plugin_options.list:
out = ScriptUtils.bool_formatter_output(
should_exclude = ScriptUtils.bool_formatter_output(
self.overrides.apply_formatter(formatter=formatter, entry=entry)
)
if not bool(out):
if not should_exclude:
logger.info(
"Filtering '%s' from the filter %s evaluating to False",
entry.title,

View file

@ -5,7 +5,6 @@ from pathlib import Path
from typing import Any
from typing import Dict
from typing import List
from typing import Optional
from ytdl_sub.config.plugin.plugin import Plugin
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
@ -19,8 +18,8 @@ from ytdl_sub.utils.xml import to_xml
from ytdl_sub.validators.file_path_validators import StringFormatterFileNameValidator
from ytdl_sub.validators.nfo_validators import NfoTagsValidator
from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator
from ytdl_sub.validators.string_formatter_validators import OverridesBooleanFormatterValidator
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
from ytdl_sub.validators.validators import BoolValidator
class SharedNfoTagsOptions(ToggleableOptionsDictValidator):
@ -54,8 +53,8 @@ class SharedNfoTagsOptions(ToggleableOptionsDictValidator):
)
self._tags = self._validate_key_if_present(key="tags", validator=NfoTagsValidator)
self._kodi_safe = self._validate_key_if_present(
key="kodi_safe", validator=BoolValidator, default=False
).value
key="kodi_safe", validator=OverridesBooleanFormatterValidator, default="False"
)
@property
def nfo_name(self) -> StringFormatterFileNameValidator:
@ -81,9 +80,9 @@ class SharedNfoTagsOptions(ToggleableOptionsDictValidator):
return self._tags
@property
def kodi_safe(self) -> Optional[bool]:
def kodi_safe(self) -> OverridesBooleanFormatterValidator:
"""
:expected type: Optional[Boolean]
:expected type: OverridesBooleanFormatterValidator
:description:
Defaults to False. Kodi does not support > 3-byte unicode characters, which include
emojis and some foreign language characters. Setting this to True will replace those
@ -141,7 +140,7 @@ class SharedNfoTagsPlugin(Plugin[SharedNfoTagsOptions], ABC):
if not nfo_tags:
return
if self.plugin_options.kodi_safe:
if self.overrides.evaluate_boolean(self.plugin_options.kodi_safe):
nfo_root = to_max_3_byte_utf8_string(nfo_root)
nfo_tags = {
to_max_3_byte_utf8_string(key): [

View file

@ -146,7 +146,12 @@ class SubtitlesPlugin(Plugin[SubtitleOptions]):
plugin_options_type = SubtitleOptions
def ytdl_options(self) -> Optional[Dict]:
builder = YTDLOptionsBuilder().add({"writesubtitles": True})
builder = YTDLOptionsBuilder().add(
{
"writesubtitles": True,
"sleep_interval_subtitles": 5.367, # for safe measure
}
)
if self.plugin_options.embed_subtitles:
builder.add(

View file

@ -1,5 +1,6 @@
import random
import time
from typing import Dict
from typing import Optional
from ytdl_sub.config.overrides import Overrides
@ -40,6 +41,22 @@ class RandomizedRangeValidator(StrictDictValidator):
f"max ({self._max}) must be greater than or equal to min ({self._min})"
)
def min_value(self) -> float:
"""
Returns
-------
Minimum value
"""
return self._min
def max_value(self) -> float:
"""
Returns
-------
Maximum value
"""
return self._max
def randomized_float(self) -> float:
"""
Returns
@ -70,6 +87,9 @@ class ThrottleProtectionOptions(ToggleableOptionsDictValidator):
presets:
my_example_preset:
throttle_protection:
sleep_per_request_s:
min: 5.5
max: 10.4
sleep_per_download_s:
min: 2.2
max: 10.8
@ -84,6 +104,7 @@ class ThrottleProtectionOptions(ToggleableOptionsDictValidator):
_optional_keys = {
"enable",
"sleep_per_request_s",
"sleep_per_download_s",
"sleep_per_subscription_s",
"max_downloads_per_subscription",
@ -93,6 +114,9 @@ class ThrottleProtectionOptions(ToggleableOptionsDictValidator):
def __init__(self, name, value):
super().__init__(name, value)
self._sleep_per_request_s = self._validate_key_if_present(
key="sleep_per_request_s", validator=RandomizedRangeValidator
)
self._sleep_per_download_s = self._validate_key_if_present(
key="sleep_per_download_s", validator=RandomizedRangeValidator
)
@ -106,6 +130,18 @@ class ThrottleProtectionOptions(ToggleableOptionsDictValidator):
key="subscription_download_probability", validator=ProbabilityValidator
)
@property
def sleep_per_request_s(self) -> Optional[RandomizedRangeValidator]:
"""
:expected type: Optional[Range]
:description:
Number in seconds to sleep between each request during metadata download. Note that
metadata download refers to the initial info.json download, not the actual audio/video
download for the entry. Also, yt-dlp only supports a single value at this time for this,
so will always use the max value.
"""
return self._sleep_per_request_s
@property
def sleep_per_download_s(self) -> Optional[RandomizedRangeValidator]:
"""
@ -165,6 +201,11 @@ class ThrottleProtectionPlugin(Plugin[ThrottleProtectionOptions]):
self.plugin_options.max_downloads_per_subscription.randomized_int()
)
def ytdl_options(self) -> Optional[Dict]:
if self.plugin_options.sleep_per_request_s is not None:
return {"sleep_interval_requests": self.plugin_options.sleep_per_request_s.max_value()}
return {}
def initialize_subscription(self) -> bool:
if self.plugin_options.subscription_download_probability:
proba = self.plugin_options.subscription_download_probability.value

View file

@ -12,28 +12,6 @@ class TvShowByDatePresets(PrebuiltPresets):
}
class TvShowByDateOldPresets(PrebuiltPresets):
"""
TV Show by Date presets create a TV show from a single URL using upload dates as season/episode
numbers.
"""
preset_names = {
"kodi_tv_show_by_date",
"jellyfin_tv_show_by_date",
"plex_tv_show_by_date",
}
class TvShowByDateEpisodeFormattingPresets(PrebuiltPresets):
preset_names = {
"season_by_year__episode_by_month_day",
"season_by_year__episode_by_month_day_reversed",
"season_by_year_month__episode_by_day",
"season_by_year__episode_by_download_index",
}
class TvShowCollectionPresets(PrebuiltPresets):
preset_names = {
"Kodi TV Show Collection",
@ -48,24 +26,3 @@ class TvShowCollectionOldPresets(PrebuiltPresets):
"jellyfin_tv_show_collection",
"plex_tv_show_collection",
}
class TvShowCollectionEpisodeFormattingPresets(PrebuiltPresets):
preset_names = {
"season_by_collection__episode_by_year_month_day",
"season_by_collection__episode_by_year_month_day_reversed",
"season_by_collection__episode_by_playlist_index",
"season_by_collection__episode_by_playlist_index_reversed",
}
class TvShowCollectionSeasonPresets(PrebuiltPresets):
"""Now Deprecated"""
preset_names = {
"collection_season_1",
"collection_season_2",
"collection_season_3",
"collection_season_4",
"collection_season_5",
}

View file

@ -9,6 +9,7 @@ presets:
thumbnail_name: "{thumbnail_file_name}"
info_json_name: "{episode_file_path}.{info_json_ext}"
maintain_download_archive: True
keep_files_date_eval: "{episode_date_standardized}"
ytdl_options:
break_on_existing: True
@ -36,14 +37,11 @@ presets:
tv_show_genre: "{subscription_indent_1}"
tv_show_content_rating: "{subscription_indent_2}"
season_directory_name: "Season {season_number_padded}"
episode_title: "{upload_date_standardized} - {title}"
episode_title: "{episode_date_standardized} - {title}"
episode_plot: "{webpage_url}\n\n{description}"
episode_year: "{upload_year}"
episode_content_rating: "{tv_show_content_rating}"
episode_date_standardized: "{upload_date_standardized}"
episode_file_name: "s{season_number_padded}.e{episode_number_padded} - {file_title}"
episode_file_path: "{season_directory_name_sanitized}/{episode_file_name_sanitized}"
thumbnail_file_name: "{episode_file_path}-thumb.jpg"
episode_year: "{%slice(episode_date_standardized, 0, 4)}"

View file

@ -35,22 +35,125 @@ presets:
# TV show from one or more sources. Uses {url}'s avatar and banner as poster and fanart
_tv_show_by_date:
preset: "_multi_url_bilateral"
preset:
- "_multi_url_bilateral"
- "_tv_show_by_date_asserts"
overrides:
avatar_uncropped_thumbnail_file_name: "{tv_show_poster_file_name}"
banner_uncropped_thumbnail_file_name: "{tv_show_fanart_file_name}"
_tv_show_by_date_asserts:
overrides:
s01_url: ""
s01_name: ""
assert_not_collection: >-
{
%assert(
%and(
%not( %bool(s01_url) ),
%not( %bool(s01_name) )
),
"Provided `s01_url` or `s01_name` variable to TV Show by Date preset when it expects `url`. Perhaps you meant to use the `TV Show Collection` preset?"
)
}
####################################################################################################
_tv_show_by_date_season_episode_ordering:
overrides:
tv_show_by_date_season_ordering: >-
{ %throw("Must specify tv_show_by_date_season_ordering") }
"%season_ordering_": >-
{ %eq( %lower(tv_show_by_date_season_ordering), $0 ) }
season_number: >-
{
%elif(
%season_ordering_( "upload-year" ), upload_year,
%season_ordering_( "upload-year-month" ), %concat(upload_year, upload_month_padded),
%season_ordering_( "release-year" ), release_year,
%season_ordering_( "release-year-month" ), %concat(release_year, release_month_padded),
%throw(
'tv_show_by_date_season_ordering must be one of the following: "upload-year", "upload-year-month", "release-year", "release-year-month"'
)
)
}
# both year and year-month are fixed width, until the year 10000 :)
season_number_padded: "{season_number}"
##################################### episode overrides
tv_show_by_date_episode_ordering: >-
{ %throw("Must specify tv_show_by_date_episode_ordering") }
"%episode_ordering_": >-
{ %eq( %lower(tv_show_by_date_episode_ordering), $0 ) }
episode_number_and_padded_: >-
{
%elif(
%episode_ordering_( "upload-day" ), [ %concat(upload_day, upload_date_index_padded), 4 ],
%episode_ordering_( "upload-month-day" ), [ %concat(upload_month, upload_day_padded, upload_date_index_padded), 6],
%episode_ordering_( "upload-month-day-reversed" ), [ %concat(upload_day_of_year_reversed, upload_date_index_reversed_padded), 5],
%episode_ordering_( "release-day" ), [ %concat(release_day, upload_date_index_padded), 4 ],
%episode_ordering_( "release-month-day" ), [ %concat(release_month, release_day_padded, upload_date_index_padded), 6],
%episode_ordering_( "release-month-day-reversed" ), [ %concat(release_day_of_year_reversed, upload_date_index_reversed_padded), 5],
%episode_ordering_( "download-index" ), [ download_index, 6 ],
%throw(
'tv_show_by_date_episode_ordering must be one of the following: "upload-day", "upload-month-day", "upload-month-day-reversed", "release-day", "release-month-day", "release-month-day-reversed", "download-index"'
)
)
}
episode_number: "{ %array_at(episode_number_and_padded_, 0) }"
episode_number_padded: "{ %pad_zero( %int(episode_number), %int(%array_at(episode_number_and_padded_, 1))) }"
episode_date_standardized: >-
{
%if(
%contains(tv_show_by_date_season_ordering, "release"),
release_date_standardized,
upload_date_standardized
)
}
##################################### season/episode pairing validation
"%ordering_pair_eq": >-
{
%eq([tv_show_by_date_season_ordering, tv_show_by_date_episode_ordering], [$0, $1])
}
tv_show_by_date_ordering_pair_validation_: >-
{
%assert_then(
%or(
%ordering_pair_eq("upload-year", "upload-month-day"),
%ordering_pair_eq("upload-year", "upload-month-day-reversed"),
%ordering_pair_eq("upload-year", "download-index"),
%ordering_pair_eq("upload-year-month", "upload-day"),
%ordering_pair_eq("release-year", "release-month-day"),
%ordering_pair_eq("release-year", "release-month-day-reversed"),
%ordering_pair_eq("release-year", "download-index"),
%ordering_pair_eq("release-year-month", "release-day")
),
episode_number_and_padded_,
"Detected incompatibility between tv_show_by_date_season_ordering and tv_show_by_date_episode_ordering. Ensure you are not using both upload and release date, and that the year/month/day are included in the combined season and episode."
)
}
####################################################################################################
# LEGACY PRESETS
_season_by_year:
preset: "_tv_show_by_date_season_episode_ordering"
overrides:
season_number: "{upload_year}"
season_number_padded: "{season_number}"
tv_show_by_date_season_ordering: "upload-year"
_season_by_year_month:
preset: "_tv_show_by_date_season_episode_ordering"
overrides:
season_number: "{upload_year}{upload_month_padded}"
season_number_padded: "{season_number}"
tv_show_by_date_season_ordering: "upload-year-month"
####################################################################################################
@ -58,26 +161,22 @@ presets:
preset:
- "_season_by_year_month"
overrides:
episode_number: "{upload_day}{upload_date_index_padded}"
episode_number_padded: "{upload_day_padded}{upload_date_index_padded}"
tv_show_by_date_episode_ordering: "upload-day"
season_by_year__episode_by_month_day:
preset:
- "_season_by_year"
overrides:
episode_number: "{upload_month}{upload_day_padded}{upload_date_index_padded}"
episode_number_padded: "{upload_month_padded}{upload_day_padded}{upload_date_index_padded}"
tv_show_by_date_episode_ordering: "upload-month-day"
season_by_year__episode_by_month_day_reversed:
preset:
- "_season_by_year"
overrides:
episode_number: "{upload_day_of_year_reversed}{upload_date_index_reversed_padded}"
episode_number_padded: "{upload_day_of_year_reversed_padded}{upload_date_index_reversed_padded}"
tv_show_by_date_episode_ordering: "upload-month-day-reversed"
season_by_year__episode_by_download_index:
preset:
- "_season_by_year"
overrides:
episode_number: "{download_index}"
episode_number_padded: "{download_index_padded6}"
tv_show_by_date_episode_ordering: "download-index"

View file

@ -39,31 +39,68 @@ presets:
###############################
season_by_collection__episode_by_year_month_day:
_tv_show_collection_episode_ordering:
overrides:
episode_number: "{upload_year_truncated}{upload_month_padded}{upload_day_padded}{upload_date_index_padded}"
episode_number_padded: "{episode_number}"
tv_show_collection_episode_ordering: >-
{ %throw("Must specify tv_show_collection_episode_ordering") }
"%episode_ordering_": >-
{ %eq( %lower(tv_show_collection_episode_ordering), $0 ) }
episode_number_and_padded_: >-
{
%elif(
%episode_ordering_( "upload-year-month-day" ), [ %concat(upload_year_truncated, upload_month_padded, upload_day_padded, upload_date_index_padded), 8 ],
%episode_ordering_( "upload-year-month-day-reversed" ), [ %concat(upload_year_truncated_reversed, upload_month_reversed_padded, upload_day_reversed_padded, upload_date_index_reversed_padded), 8],
%episode_ordering_( "release-year-month-day" ), [ %concat(release_year_truncated, release_month_padded, release_day_padded, upload_date_index_padded), 8 ],
%episode_ordering_( "release-year-month-day-reversed" ), [ %concat(release_year_truncated_reversed, release_month_reversed_padded, release_day_reversed_padded, upload_date_index_reversed_padded), 8],
%episode_ordering_( "playlist-index" ), [ %concat(playlist_index), 6],
%episode_ordering_( "playlist-index-reversed" ), [ %concat(playlist_index_reversed), 6],
%throw(
'tv_show_collection_episode_ordering must be one of the following: "upload-year-month-day", "upload-year-month-day-reversed", "release-year-month-day", "release-year-month-day-reversed", "playlist-index", "playlist-index-reversed"'
)
)
}
episode_number: "{ %array_at(episode_number_and_padded_, 0) }"
episode_number_padded: "{ %pad_zero( %int(episode_number), %int(%array_at(episode_number_and_padded_, 1))) }"
episode_date_standardized: >-
{
%if(
%contains(tv_show_collection_episode_ordering, "release"),
release_date_standardized,
upload_date_standardized
)
}
### LEGACY PRESETS
season_by_collection__episode_by_year_month_day:
preset: "_tv_show_collection_episode_ordering"
overrides:
tv_show_collection_episode_ordering: "upload-year-month-day"
season_by_collection__episode_by_year_month_day_reversed:
preset: "_tv_show_collection_episode_ordering"
overrides:
episode_number: "{upload_year_truncated_reversed}{upload_month_reversed_padded}{upload_day_reversed_padded}{upload_date_index_reversed_padded}"
episode_number_padded: "{episode_number}"
tv_show_collection_episode_ordering: "upload-year-month-day-reversed"
season_by_collection__episode_by_playlist_index:
preset: "_tv_show_collection_episode_ordering"
overrides:
episode_number: "{playlist_index}"
episode_number_padded: "{playlist_index_padded6}"
tv_show_collection_episode_ordering: "playlist-index"
season_by_collection__episode_by_playlist_index_reversed:
preset: "_tv_show_collection_episode_ordering"
overrides:
episode_number: "{playlist_index_reversed}"
episode_number_padded: "{playlist_index_reversed_padded6}"
tv_show_collection_episode_ordering: "playlist-index-reversed"
##############
_tv_show_collection:
preset:
- "_tv_show_collection_bilateral"
- "_tv_show_collection_asserts"
download:
- url: "{collection_season_1_url}"
@ -1017,6 +1054,16 @@ presets:
ytdl_options:
playlist_items: "-1:0:-1"
_tv_show_collection_asserts:
overrides:
url: ""
assert_not_by_date: >-
{
%assert(
%not( %bool(url) ),
"Provided `url` to TV Show Collection preset when it expects `s01_url`. Perhaps you meant to use the `TV Show by Date` preset?"
)
}
####################################################################################################
# DEPRECATED SEASON PRESETS

View file

@ -9,6 +9,7 @@ from ytdl_sub.script.functions.error_functions import ErrorFunctions
from ytdl_sub.script.functions.json_functions import JsonFunctions
from ytdl_sub.script.functions.map_functions import MapFunctions
from ytdl_sub.script.functions.numeric_functions import NumericFunctions
from ytdl_sub.script.functions.print_functions import PrintFunctions
from ytdl_sub.script.functions.regex_functions import RegexFunctions
from ytdl_sub.script.functions.string_functions import StringFunctions
from ytdl_sub.script.types.resolvable import Resolvable
@ -26,6 +27,7 @@ class Functions(
RegexFunctions,
DateFunctions,
JsonFunctions,
PrintFunctions,
):
_custom_functions: Dict[str, Callable[..., Resolvable]] = {}

View file

@ -0,0 +1,67 @@
from typing import Optional
from ytdl_sub.script.types.resolvable import AnyArgument
from ytdl_sub.script.types.resolvable import Integer
from ytdl_sub.script.types.resolvable import ReturnableArgument
from ytdl_sub.utils.logger import Logger
logger = Logger.get(name="preset")
def _log(message: AnyArgument, level: Optional[Integer]) -> None:
if level is None:
logger.info(str(message))
return
level_value: int = level.native
if level_value < 0:
logger.debug(str(message))
elif level_value == 0:
logger.info(str(message))
elif level_value == 1:
logger.warning(str(message))
else: # > 1
logger.error(str(message))
class PrintFunctions:
@staticmethod
def print(
message: AnyArgument, passthrough: ReturnableArgument, level: Optional[Integer] = None
) -> ReturnableArgument:
"""
:description:
Print the ``message`` and return ``passthrough``.
Optionally can pass level, where < 0 is debug, 0 is info, 1 is warning, > 1 is error.
Defaults to info.
"""
_log(message=message, level=level)
return passthrough
@staticmethod
def print_if_true(
message: AnyArgument, passthrough: ReturnableArgument, level: Optional[Integer] = None
) -> ReturnableArgument:
"""
:description:
Print the ``message`` if ``passthrough`` evaluates to ``true``. Return ``passthrough``.
Optionally can pass level, where < 0 is debug, 0 is info, 1 is warning, > 1 is error.
Defaults to info.
"""
if passthrough.value:
_log(message=message, level=level)
return passthrough
@staticmethod
def print_if_false(
message: AnyArgument, passthrough: ReturnableArgument, level: Optional[Integer] = None
) -> ReturnableArgument:
"""
:description:
Print the ``message`` if ``passthrough`` evaluates to ``false``. Return ``passthrough``.
Optionally can pass level, where < 0 is debug, 0 is info, 1 is warning, > 1 is error.
Defaults to info.
"""
if not passthrough.value:
_log(message=message, level=level)
return passthrough

View file

@ -127,12 +127,12 @@ class StringFunctions:
return Array([String(split_val) for split_val in string.value.split(sep=sep.value)])
@staticmethod
def concat(*values: String) -> String:
def concat(*values: AnyArgument) -> String:
"""
:description:
Concatenate multiple Strings into a single String.
"""
return String("".join(val.value for val in values))
return String("".join(str(val.value) for val in values))
@staticmethod
def pad(string: String, length: Integer, char: String) -> String:
@ -176,3 +176,41 @@ class StringFunctions:
# World
"""
return String(string.value.encode("utf-8").decode("unicode_escape"))
@staticmethod
def join(separator: String, array: Array) -> String:
"""
:description:
Join all elements in the array together as a string, and insert the
separator between them.
:usage:
.. code-block:: python
{
%join( ", ", ["item1", "item2"] )
}
# "item1, item2"
"""
return String(separator.value.join(str(val) for val in array.value))
@staticmethod
def strip(string: String) -> String:
"""
:description:
Strip a string of all its whitespace at the beginning and end.
:usage:
.. code-block:: python
{
%trim(" delete the outer! ")
}
# "delete the outer!"
"""
return String(string.value.strip())

View file

@ -17,6 +17,7 @@ from ytdl_sub.downloaders.source_plugin import SourcePlugin
from ytdl_sub.downloaders.url.downloader import MultiUrlDownloader
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
from ytdl_sub.entries.entry import Entry
from ytdl_sub.entries.script.variable_definitions import VARIABLES
from ytdl_sub.subscriptions.base_subscription import BaseSubscription
from ytdl_sub.subscriptions.subscription_ytdl_options import SubscriptionYTDLOptions
from ytdl_sub.utils.datetime import to_date_range
@ -215,9 +216,23 @@ class SubscriptionDownload(BaseSubscription, ABC):
FileHandler.delete(entry.get_download_thumbnail_path())
FileHandler.delete(entry.get_download_info_json_path())
@classmethod
def _preprocess_entry(cls, plugins: List[Plugin], entry: Entry) -> Optional[Entry]:
def _preprocess_entry(self, plugins: List[Plugin], entry: Entry) -> Optional[Entry]:
maybe_entry: Optional[Entry] = entry
# Inject OutputOption variables here
entry.add(
{
VARIABLES.ytdl_sub_keep_files_date_eval: (
self.output_options.keep_files_date_eval.format_string
)
}
)
# Run it to make sure it's actually a standardized date
_ = self.overrides.apply_formatter(
formatter=self.output_options.keep_files_date_eval, entry=entry
)
for plugin in PluginMapping.order_plugins_by(
plugins, PluginOperation.MODIFY_ENTRY_METADATA
):

View file

@ -19,6 +19,7 @@ from ytdl_sub.plugins.match_filters import MatchFiltersPlugin
from ytdl_sub.plugins.match_filters import combine_filters
from ytdl_sub.plugins.match_filters import default_filters
from ytdl_sub.plugins.subtitles import SubtitlesPlugin
from ytdl_sub.plugins.throttle_protection import ThrottleProtectionPlugin
from ytdl_sub.utils.ffmpeg import FFMPEG
from ytdl_sub.utils.logger import Logger
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
@ -175,6 +176,7 @@ class SubscriptionYTDLOptions:
self._global_options,
self._output_options,
self._plugin_match_filters,
self._plugin_ytdl_options(ThrottleProtectionPlugin),
self._plugin_ytdl_options(FormatPlugin),
self._plugin_ytdl_options(AudioExtractPlugin), # will override format
self._user_ytdl_options, # user ytdl options...

View file

@ -220,10 +220,17 @@ class Chapters:
# Timestamp captured, store it
if match := Timestamp.TIMESTAMP_REGEX.search(line):
timestamp_str = match.group(1)
timestamps.append(Timestamp.from_str(timestamp_str))
# Remove timestamp and surrounding whitespace from it
title_str = re.sub(f"\\s*{re.escape(timestamp_str)}\\s*", " ", line).strip()
timestamp = Timestamp.from_str(timestamp_str)
if timestamps and (timestamps[-1].timestamp_sec == timestamp.timestamp_sec):
# duplicate timestamp... combine into one chapter
titles[-1] += " // " + title_str
continue
timestamps.append(timestamp)
titles.append(title_str)
# If more than 3 timestamps were parsed, return it

View file

@ -1,3 +1,4 @@
from datetime import datetime
from typing import Dict
from typing import Set
from typing import Union
@ -73,6 +74,20 @@ class StringFormatterValidator(StringValidator):
return resolved
class StandardizedDateValidator(StringFormatterValidator):
_expected_value_type_name = "standardized_date"
def post_process(self, resolved: str) -> str:
try:
datetime.strptime(resolved, "%Y-%m-%d")
except ValueError as exc:
raise self._validation_exception(
f"Expected a standardized date in the form of YYYY-MM-DD, but received '{resolved}'"
) from exc
return resolved
# pylint: disable=line-too-long
class OverridesStringFormatterValidator(StringFormatterValidator):
"""

View file

@ -75,7 +75,7 @@ class DownloadMapping:
DownloadMapping for the entry
"""
return DownloadMapping(
upload_date=entry.get(v.upload_date_standardized, str),
upload_date=entry.get(v.ytdl_sub_keep_files_date_eval, str),
extractor=entry.download_archive_extractor,
file_names=set(),
)
@ -248,20 +248,18 @@ class DownloadMappings:
del self._entry_mappings[entry_id]
return self
def get_num_entries_with_upload_date(self, upload_date_standardized: str) -> int:
def get_num_entries_with_date(self, standardized_date: str) -> int:
"""
Parameters
----------
upload_date_standardized
standardized_date
A standardized upload date
Returns
-------
Number of entries in the mapping with this upload date
"""
return len(
[_ for _ in self._entry_mappings.values() if _.upload_date == upload_date_standardized]
)
return len([_ for _ in self._entry_mappings.values() if _.upload_date == standardized_date])
def get_num_entries(self) -> int:
"""

View file

@ -1,3 +1,5 @@
from typing import List
import pytest
from conftest import assert_logs
from expected_download import assert_expected_downloads
@ -17,6 +19,7 @@ def subscription_dict(output_directory):
"subscription_indent_1": "Acoustic",
"music_directory": output_directory,
},
"throttle_protection": {"sleep_per_request_s": {"min": 0.1, "max": 0.5}},
}
@ -34,6 +37,21 @@ class TestSoundcloudDiscography:
output_directory,
dry_run,
):
ignored_mp3s: List[str] = [
"j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.mp3",
"j_b/[2021] Purple Clouds/01 - Purple Clouds.mp3",
"j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3",
"j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3",
"j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3",
"j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3",
"j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3",
"j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3",
"j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3",
"j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3",
"j_b/[2022] Acoustic Treats/09 - Finding Home.mp3",
"j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3",
"j_b/[2022] Acoustic Treats/11 - Untold History.mp3",
]
discography_subscription = Subscription.from_dict(
preset_dict=subscription_dict,
preset_name="j_b",
@ -49,6 +67,7 @@ class TestSoundcloudDiscography:
output_directory=output_directory,
dry_run=dry_run,
expected_download_summary_file_name="soundcloud/test_soundcloud_discography.json",
ignore_md5_hashes_for=ignored_mp3s,
)
# Ensure another invocation will hit ExistingVideoReached
@ -65,4 +84,5 @@ class TestSoundcloudDiscography:
output_directory=output_directory,
dry_run=dry_run,
expected_download_summary_file_name="soundcloud/test_soundcloud_discography.json",
ignore_md5_hashes_for=ignored_mp3s,
)

View file

@ -5,6 +5,7 @@ from pathlib import Path
from typing import Callable
from typing import Dict
from typing import List
from typing import Optional
from unittest.mock import patch
import pytest
@ -53,6 +54,7 @@ def mock_entry_dict_factory(mock_downloaded_file_path) -> Callable:
is_youtube_channel: bool = False,
mock_download_to_working_dir: bool = True,
is_extracted_audio: bool = False,
release_date: Optional[str] = None,
) -> Dict:
entry_dict = {
v.uid.metadata_key: uid,
@ -71,6 +73,10 @@ def mock_entry_dict_factory(mock_downloaded_file_path) -> Callable:
v.description.metadata_key: "The Description",
}
# TODO: Make this required eventually
if release_date is not None:
entry_dict[v.release_date.metadata_key] = release_date
if is_youtube_channel:
entry_dict[v.playlist_metadata.metadata_key]["thumbnails"] = [
{
@ -153,6 +159,7 @@ def mock_download_collection_entries(
mock_entry_dict_factory(
uid="21-1",
upload_date="20210808",
release_date="20010808",
playlist_title="Download First",
playlist_index=1,
playlist_count=4,
@ -163,6 +170,7 @@ def mock_download_collection_entries(
mock_entry_dict_factory(
uid="20-1",
upload_date="20200808",
release_date="20000808",
playlist_title="Download First",
playlist_index=2,
playlist_count=4,
@ -173,6 +181,7 @@ def mock_download_collection_entries(
mock_entry_dict_factory(
uid="20-2",
upload_date="20200808",
release_date="20000808",
playlist_title="Download First",
playlist_index=3,
playlist_count=4,
@ -183,6 +192,7 @@ def mock_download_collection_entries(
mock_entry_dict_factory(
uid="20-3",
upload_date="20200807",
release_date="20000807",
playlist_title="Download First",
playlist_index=4,
playlist_count=4,
@ -196,6 +206,7 @@ def mock_download_collection_entries(
mock_entry_dict_factory(
uid="20-3",
upload_date="20200807",
release_date="20000807",
playlist_title="Download Second",
playlist_index=1,
playlist_count=5,
@ -206,6 +217,7 @@ def mock_download_collection_entries(
mock_entry_dict_factory(
uid="20-4",
upload_date="20200806",
release_date="20000806",
playlist_title="Download Second",
playlist_index=2,
playlist_count=5,
@ -216,6 +228,7 @@ def mock_download_collection_entries(
mock_entry_dict_factory(
uid="20-5",
upload_date="20200706",
release_date="20000706",
playlist_title="Download Second",
playlist_index=3,
playlist_count=5,
@ -226,6 +239,7 @@ def mock_download_collection_entries(
mock_entry_dict_factory(
uid="20-6",
upload_date="20200706",
release_date="20000706",
playlist_title="Download Second",
playlist_index=4,
playlist_count=5,
@ -236,6 +250,7 @@ def mock_download_collection_entries(
mock_entry_dict_factory(
uid="20-7",
upload_date="20200606",
release_date="20000606",
playlist_title="Download Second",
playlist_index=5,
playlist_count=5,

View file

@ -1,3 +1,4 @@
import re
from pathlib import Path
from typing import Dict
from unittest.mock import patch
@ -11,6 +12,7 @@ from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.downloaders.ytdlp import YTDLP
from ytdl_sub.entries.entry import Entry
from ytdl_sub.subscriptions.subscription import Subscription
from ytdl_sub.utils.exceptions import ValidationException
from ytdl_sub.utils.file_handler import FileHandler
from ytdl_sub.utils.thumbnail import try_convert_download_thumbnail
@ -223,3 +225,35 @@ class TestOutputOptions:
dry_run=False,
expected_download_summary_file_name="plugins/output_options/test_missing_thumb.json",
)
def test_invalid_keep_files_date_eval(
self,
config: ConfigFile,
subscription_name: str,
output_options_subscription_dict: Dict,
output_directory: str,
mock_download_collection_entries,
):
output_options_subscription_dict["output_options"]["keep_files_date_eval"] = "nope"
subscription = Subscription.from_dict(
config=config,
preset_name=subscription_name,
preset_dict=output_options_subscription_dict,
)
expected_error_msg = (
"Validation error in subscription_test.output_options.keep_files_date_eval: "
"Expected a standardized date in the form of YYYY-MM-DD, but received 'nope'"
)
with (
mock_download_collection_entries(
is_youtube_channel=False,
num_urls=1,
is_extracted_audio=False,
is_dry_run=True,
),
pytest.raises(ValidationException, match=re.escape(expected_error_msg)),
):
subscription.download(dry_run=True)

View file

@ -1,19 +1,30 @@
import re
from typing import Set
import pytest
from expected_download import assert_expected_downloads
from expected_transaction_log import assert_transaction_log_matches
from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.prebuilt_presets.tv_show import TvShowByDateEpisodeFormattingPresets
from ytdl_sub.prebuilt_presets.tv_show import TvShowByDatePresets
from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError
from ytdl_sub.subscriptions.subscription import Subscription
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS = {
"Kodi TV Show by Date": "kodi_tv_show_by_date",
"Jellyfin TV Show by Date": "jellyfin_tv_show_by_date",
"Plex TV Show by Date": "plex_tv_show_by_date",
}
DEFAULT_SEASON_ORDERING = "upload-year"
DEFAULT_EPISODE_ORDERING = "upload-month-day"
DEFAULT_EPISODE_ORDERING_PRESET = "season_by_year__episode_by_month_day"
VALID_ORDERING_COMBOS = [
# upload
("upload-year", "upload-month-day"),
("upload-year", "upload-month-day-reversed"),
("upload-year", "download-index"),
("upload-year-month", "upload-day"),
# release
("release-year", "release-month-day"),
("release-year", "release-month-day-reversed"),
("release-year", "download-index"),
("release-year-month", "release-day"),
]
class TestPrebuiltTVShowPresets:
@ -24,24 +35,28 @@ class TestPrebuiltTVShowPresets:
subscription_name: str,
output_directory: str,
tv_show_preset: str,
episode_ordering_preset: str,
season_ordering: str,
episode_ordering: str,
is_youtube_channel: bool = True,
is_many_urls: bool = False,
):
expected_summary_name = "unit/{}/{}/is_yt_{}{}".format(
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS[tv_show_preset],
episode_ordering_preset,
expected_summary_name = "integration/by-date/{}/{}/{}/is_yt_{}{}".format(
tv_show_preset.split(" ")[0],
season_ordering,
episode_ordering,
int(is_youtube_channel),
"_many_urls" if is_many_urls else "",
)
preset_dict = {
"preset": [tv_show_preset, episode_ordering_preset],
"preset": tv_show_preset,
"overrides": {
"url": "https://your.name.here",
"tv_show_name": "Best Prebuilt TV Show by Date",
"tv_show_directory": output_directory,
"tv_show_by_date_season_ordering": season_ordering,
"tv_show_by_date_episode_ordering": episode_ordering,
},
}
if is_many_urls:
@ -67,16 +82,19 @@ class TestPrebuiltTVShowPresets:
)
###################################### Perform reformat
reformatted_tv_show_structure_preset = "season_by_year__episode_by_download_index"
reformatted_expected_summary_name = "unit/{}/{}/is_yt_{}{}".format(
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS[tv_show_preset],
reformatted_tv_show_structure_preset,
reformatted_season_ordering = "upload-year"
reformatted_episode_ordering = "download-index"
reformatted_expected_summary_name = "integration/by-date/{}/{}/{}/is_yt_{}{}".format(
tv_show_preset.split(" ")[0],
reformatted_season_ordering,
reformatted_episode_ordering,
int(is_youtube_channel),
"_many_urls" if is_many_urls else "",
)
reformatted_preset_dict = {
"preset": [tv_show_preset, reformatted_tv_show_structure_preset],
"preset": tv_show_preset,
"output_options": {
"migrated_download_archive_name": ".ytdl-sub-{tv_show_name_sanitized}-download-archive.json"
},
@ -84,6 +102,8 @@ class TestPrebuiltTVShowPresets:
"url": "https://your.name.here",
"tv_show_name": "Best Prebuilt TV Show by Date",
"tv_show_directory": output_directory,
"tv_show_by_date_season_ordering": reformatted_season_ordering,
"tv_show_by_date_episode_ordering": reformatted_episode_ordering,
},
}
if is_many_urls:
@ -98,7 +118,7 @@ class TestPrebuiltTVShowPresets:
output_directory=output_directory,
transaction_log=reformatted_transaction_log,
transaction_log_summary_file_name=(
f"{expected_summary_name}_reformatted_to_{reformatted_tv_show_structure_preset}.txt"
f"{expected_summary_name}_reformatted_to_{reformatted_season_ordering}.txt"
),
)
assert_expected_downloads(
@ -123,11 +143,13 @@ class TestPrebuiltTVShowPresets:
subscription_name=subscription_name,
output_directory=output_directory,
tv_show_preset=tv_show_preset,
episode_ordering_preset=DEFAULT_EPISODE_ORDERING_PRESET,
season_ordering=DEFAULT_SEASON_ORDERING,
episode_ordering=DEFAULT_EPISODE_ORDERING,
)
@pytest.mark.parametrize(
"episode_ordering_preset", TvShowByDateEpisodeFormattingPresets.preset_names
"season_ordering, episode_ordering",
VALID_ORDERING_COMBOS,
)
def test_episode_ordering_presets(
self,
@ -135,7 +157,8 @@ class TestPrebuiltTVShowPresets:
subscription_name,
output_directory,
mock_download_collection_entries,
episode_ordering_preset: str,
season_ordering: str,
episode_ordering: str,
):
with mock_download_collection_entries(
@ -146,5 +169,91 @@ class TestPrebuiltTVShowPresets:
subscription_name=subscription_name,
output_directory=output_directory,
tv_show_preset="Kodi TV Show by Date",
episode_ordering_preset=episode_ordering_preset,
season_ordering=season_ordering,
episode_ordering=episode_ordering,
)
def test_invalid_season_ordering(
self, config, subscription_name, output_directory, mock_download_collection_entries
):
expected_message = (
"tv_show_by_date_season_ordering must be one of the following: "
'"upload-year", '
'"upload-year-month", '
'"release-year", '
'"release-year-month"'
)
with (
mock_download_collection_entries(is_youtube_channel=True, num_urls=1),
pytest.raises(UserThrownRuntimeError, match=re.escape(expected_message)),
):
self.run(
config=config,
subscription_name=subscription_name,
output_directory=output_directory,
tv_show_preset="Kodi TV Show by Date",
season_ordering="nope",
episode_ordering=DEFAULT_EPISODE_ORDERING,
)
def test_invalid_episode_ordering(
self, config, subscription_name, output_directory, mock_download_collection_entries
):
expected_message = (
"tv_show_by_date_episode_ordering must be one of the following: "
'"upload-day", '
'"upload-month-day", '
'"upload-month-day-reversed", '
'"release-day", '
'"release-month-day", '
'"release-month-day-reversed", '
'"download-index"'
)
with (
mock_download_collection_entries(is_youtube_channel=True, num_urls=1),
pytest.raises(UserThrownRuntimeError, match=re.escape(expected_message)),
):
self.run(
config=config,
subscription_name=subscription_name,
output_directory=output_directory,
tv_show_preset="Kodi TV Show by Date",
season_ordering=DEFAULT_SEASON_ORDERING,
episode_ordering="not-a-valid",
)
def test_invalid_season_episode_ordering_combo(
self, config, subscription_name, output_directory, mock_download_collection_entries
):
expected_message = (
"Detected incompatibility between tv_show_by_date_season_ordering "
"and tv_show_by_date_episode_ordering. Ensure you are not using both "
"upload and release date, and that the year/month/day are included in "
"the combined season and episode."
)
possible_seasons: Set[str] = set()
possible_episodes: Set[str] = set()
for season_ordering, episode_ordering in VALID_ORDERING_COMBOS:
possible_seasons.add(season_ordering)
possible_episodes.add(episode_ordering)
for season_ordering in possible_seasons:
for episode_ordering in possible_episodes:
if (season_ordering, episode_ordering) in VALID_ORDERING_COMBOS:
continue
with (
mock_download_collection_entries(is_youtube_channel=True, num_urls=1),
pytest.raises(UserThrownRuntimeError, match=re.escape(expected_message)),
):
self.run(
config=config,
subscription_name=subscription_name,
output_directory=output_directory,
tv_show_preset="Kodi TV Show by Date",
season_ordering=season_ordering,
episode_ordering=episode_ordering,
)

View file

@ -1,3 +1,4 @@
import re
from typing import Dict
from typing import List
@ -6,17 +7,11 @@ from expected_download import assert_expected_downloads
from expected_transaction_log import assert_transaction_log_matches
from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.prebuilt_presets.tv_show import TvShowCollectionEpisodeFormattingPresets
from ytdl_sub.prebuilt_presets.tv_show import TvShowCollectionPresets
from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError
from ytdl_sub.subscriptions.subscription import Subscription
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS = {
"Kodi TV Show Collection": "kodi_tv_show_collection",
"Jellyfin TV Show Collection": "jellyfin_tv_show_collection",
"Plex TV Show Collection": "plex_tv_show_collection",
}
DEFAULT_EPISODE_ORDERING_PRESET = "season_by_collection__episode_by_year_month_day"
DEFAULT_EPISODE_ORDERING = "upload-year-month-day"
class TestPrebuiltTvShowCollectionPresets:
@ -27,22 +22,19 @@ class TestPrebuiltTvShowCollectionPresets:
subscription_name: str,
output_directory: str,
media_player_preset: str,
tv_show_structure_preset: str,
episode_ordering: str,
season_indices: List[int],
is_youtube_channel: bool = True,
):
expected_summary_name = "unit/{}/{}/s_{}/is_yt_{}".format(
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS[media_player_preset],
tv_show_structure_preset,
expected_summary_name = "integration/collection/{}/{}/s_{}/is_yt_{}".format(
media_player_preset.split(" ")[0],
episode_ordering,
len(season_indices),
int(is_youtube_channel),
)
parent_presets: List[str] = [media_player_preset, tv_show_structure_preset]
overrides: Dict[str, str] = {}
for season_index in season_indices:
parent_presets.append(f"collection_season_{season_index}")
overrides = dict(
overrides,
**{
@ -55,12 +47,13 @@ class TestPrebuiltTvShowCollectionPresets:
config=config,
preset_name=subscription_name,
preset_dict={
"preset": parent_presets,
"preset": media_player_preset,
"overrides": dict(
overrides,
**{
"tv_show_name": "Best Prebuilt TV Show Collection",
"tv_show_directory": output_directory,
"tv_show_collection_episode_ordering": episode_ordering,
},
),
},
@ -79,12 +72,10 @@ class TestPrebuiltTvShowCollectionPresets:
)
###################################### Perform reformat
reformatted_tv_show_structure_preset = (
"season_by_collection__episode_by_playlist_index_reversed"
)
reformatted_expected_summary_name = "unit/{}/{}/s_{}/is_yt_{}".format(
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS[media_player_preset],
reformatted_tv_show_structure_preset,
reformatted_tv_show_collection_episode_ordering = "playlist-index-reversed"
reformatted_expected_summary_name = "integration/collection/{}/{}/s_{}/is_yt_{}".format(
media_player_preset.split(" ")[0],
reformatted_tv_show_collection_episode_ordering,
len(season_indices),
int(is_youtube_channel),
)
@ -93,7 +84,7 @@ class TestPrebuiltTvShowCollectionPresets:
config=config,
preset_name=subscription_name,
preset_dict={
"preset": parent_presets + [reformatted_tv_show_structure_preset],
"preset": media_player_preset,
"output_options": {
"migrated_download_archive_name": ".ytdl-sub-{tv_show_name_sanitized}-download-archive.json"
},
@ -102,6 +93,7 @@ class TestPrebuiltTvShowCollectionPresets:
**{
"tv_show_name": "Best Prebuilt TV Show Collection",
"tv_show_directory": output_directory,
"tv_show_collection_episode_ordering": reformatted_tv_show_collection_episode_ordering,
},
),
},
@ -112,7 +104,7 @@ class TestPrebuiltTvShowCollectionPresets:
output_directory=output_directory,
transaction_log=reformatted_transaction_log,
transaction_log_summary_file_name=(
f"{expected_summary_name}_reformatted_to_{reformatted_tv_show_structure_preset}.txt"
f"{expected_summary_name}_reformatted_to_{reformatted_tv_show_collection_episode_ordering}.txt"
),
)
assert_expected_downloads(
@ -141,12 +133,20 @@ class TestPrebuiltTvShowCollectionPresets:
subscription_name=subscription_name,
output_directory=output_directory,
media_player_preset=media_player_preset,
tv_show_structure_preset=DEFAULT_EPISODE_ORDERING_PRESET,
episode_ordering=DEFAULT_EPISODE_ORDERING,
season_indices=season_indices,
)
@pytest.mark.parametrize(
"episode_ordering_preset", TvShowCollectionEpisodeFormattingPresets.preset_names
"episode_ordering",
[
"upload-year-month-day",
"upload-year-month-day-reversed",
"release-year-month-day",
"release-year-month-day-reversed",
"playlist-index",
"playlist-index-reversed",
],
)
@pytest.mark.parametrize("season_indices", [[1], [1, 2]])
def test_episode_ordering_presets(
@ -155,7 +155,7 @@ class TestPrebuiltTvShowCollectionPresets:
subscription_name,
output_directory,
mock_download_collection_entries,
episode_ordering_preset: str,
episode_ordering: str,
season_indices: List[int],
):
@ -167,6 +167,32 @@ class TestPrebuiltTvShowCollectionPresets:
subscription_name=subscription_name,
output_directory=output_directory,
media_player_preset="Kodi TV Show Collection",
tv_show_structure_preset=episode_ordering_preset,
episode_ordering=episode_ordering,
season_indices=season_indices,
)
def test_invalid_episode_ordering(
self, config, subscription_name, output_directory, mock_download_collection_entries
):
expected_message = (
"tv_show_collection_episode_ordering must be one of the following: "
'"upload-year-month-day", '
'"upload-year-month-day-reversed", '
'"release-year-month-day", '
'"release-year-month-day-reversed", '
'"playlist-index", '
'"playlist-index-reversed"'
)
with (
mock_download_collection_entries(is_youtube_channel=True, num_urls=1),
pytest.raises(UserThrownRuntimeError, match=re.escape(expected_message)),
):
self.run(
config=config,
subscription_name=subscription_name,
output_directory=output_directory,
media_player_preset="Kodi TV Show Collection",
episode_ordering="does-not-exist",
season_indices=[1],
)

View file

@ -2,18 +2,18 @@
".ytdl-sub-subscription_test-download-archive.json": "76e202bd03ceef93daaffffee2cfa193",
"JMC/Mock Entry 20-1.info.json": "INFO_JSON",
"JMC/Mock Entry 20-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-1.mp4": "dbaeb2a3bfd1de1c7e9615e8bdacb910",
"JMC/Mock Entry 20-1.mp4": "d8dc9918d1646c92b4a4bd246291d849",
"JMC/Mock Entry 20-1.nfo": "5d001a105d2380844db181911d5df5c6",
"JMC/Mock Entry 20-2.info.json": "INFO_JSON",
"JMC/Mock Entry 20-2.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-2.mp4": "76c2c70572489c684923a51cb1b50687",
"JMC/Mock Entry 20-2.mp4": "6f925179a5b6bf7ffcaf2f70ad585296",
"JMC/Mock Entry 20-2.nfo": "dccdded1ca7ebb38d2c9a0e5130bea33",
"JMC/Mock Entry 20-3.info.json": "INFO_JSON",
"JMC/Mock Entry 20-3.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-3.mp4": "7bb4f21d59a6fb91836537b27a24e776",
"JMC/Mock Entry 20-3.mp4": "b48f1803f14be665677e9ac9da787593",
"JMC/Mock Entry 20-3.nfo": "7b1eab48693161e83c21203b1308b64e",
"JMC/Mock Entry 21-1.info.json": "INFO_JSON",
"JMC/Mock Entry 21-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 21-1.mp4": "7b008531ca5660b51fb8adc83c799084",
"JMC/Mock Entry 21-1.mp4": "5fb865f27ee1cac381597d1e182dfa48",
"JMC/Mock Entry 21-1.nfo": "3b4b0e6820f80370d6738ce828f14a89"
}

View file

@ -0,0 +1,22 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-Best Prebuilt TV Show by Date-download-archive.json": "456d8882fc5e35d74f19b386d1d9a059",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "1d0714fb3ca4d31a0f88492a06a6142d",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3.nfo": "dbe61f2c8ae41041773f713ba5376726",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "a8f3f8580989f3927606bf6060a64e30",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2.nfo": "0f071078c9fa2569bbcb998664d40681",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "265b1104b382fd157a123842e49fcdfd",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1.nfo": "837a61dca11bbe1874ea07cb8ef8a7c9",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "09fa4599fd48836c6c0da0760c306006",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show by Date/tvshow.nfo": "2439ebc18e46a67064956cb940c992e9"
}

View file

@ -0,0 +1,22 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-subscription_test-download-archive.json": "e30d83126c2c6981c936ed894a6f159b",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080701 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080701 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080701 - Mock Entry 20-3.mp4": "c712d7fd5dfdb9bb6c2be99f7c796c6f",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080701 - Mock Entry 20-3.nfo": "7c0f2a9d38bf617377e474fcb9bf2bc2",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080801 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080801 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080801 - Mock Entry 20-2.mp4": "7ec7ac1923053c4b5653bbfb8924fdc6",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080801 - Mock Entry 20-2.nfo": "1f4dec756555ee345cd9d6489b63e070",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080802 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080802 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080802 - Mock Entry 20-1.mp4": "414c243016f406451c790757949173aa",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080802 - Mock Entry 20-1.nfo": "f6f704ae3ae0c4055590a147eb425609",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e080801 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e080801 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e080801 - Mock Entry 21-1.mp4": "e2f858efd08ac82749fd01db65d8341e",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e080801 - Mock Entry 21-1.nfo": "c6e0d368bfe9d70134e5a2ff2d3dccc6",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show by Date/tvshow.nfo": "2439ebc18e46a67064956cb940c992e9"
}

View file

@ -0,0 +1,22 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-subscription_test-download-archive.json": "95d3790190cece6e49d2f4d5f68868b1",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0701 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0701 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0701 - Mock Entry 20-3.mp4": "6dd6860e8075e5e99c85e14729c41bdb",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0701 - Mock Entry 20-3.nfo": "92d978e6f64d97e7e71e7045c9d2fb1f",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0801 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0801 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0801 - Mock Entry 20-2.mp4": "6b3537db708f88a877d3c5273df02eb0",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0801 - Mock Entry 20-2.nfo": "b1a3768f43d0f7f4dde1207a8670f9b1",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0802 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0802 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0802 - Mock Entry 20-1.mp4": "7e40cf2da8eedd93b3df9a017c78cd2e",
"Best Prebuilt TV Show by Date/Season 200008/s200008.e0802 - Mock Entry 20-1.nfo": "ea37e0d89713f971a87ddf67f8933be1",
"Best Prebuilt TV Show by Date/Season 200108/s200108.e0801 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 200108/s200108.e0801 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 200108/s200108.e0801 - Mock Entry 21-1.mp4": "c14c0b1901c456e87e1070539d32917e",
"Best Prebuilt TV Show by Date/Season 200108/s200108.e0801 - Mock Entry 21-1.nfo": "4e18e9e0454bc948cf8daa0151a0b137",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show by Date/tvshow.nfo": "2439ebc18e46a67064956cb940c992e9"
}

View file

@ -0,0 +1,22 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-subscription_test-download-archive.json": "d2888d629be62badedce415f8296a995",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000001 - Mock Entry 20-3.mp4": "f94c693da1964bd8e916459253ede6d4",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000001 - Mock Entry 20-3.nfo": "57b7ef31d0b9948bd67ba6a7c83dd22b",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000002 - Mock Entry 20-2.mp4": "68a76930c4456ab58f30ad1a3eb109aa",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000002 - Mock Entry 20-2.nfo": "1cc84f0bbe25315268dc453db8941c7f",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000003 - Mock Entry 20-1.mp4": "b24b301ec95f359ba28ca503e678522f",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e000003 - Mock Entry 20-1.nfo": "e77cc16953d13241f83fbd01792c15ba",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e000004 - Mock Entry 21-1.mp4": "cf36da70822036f06e5c834dac291dd3",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e000004 - Mock Entry 21-1.nfo": "cbd1abadd656f6d047775969604e9af4",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show by Date/tvshow.nfo": "2439ebc18e46a67064956cb940c992e9"
}

View file

@ -0,0 +1,22 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-subscription_test-download-archive.json": "1e8b4072d6d6aace4cac0c94ac0e711e",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14698 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14698 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14698 - Mock Entry 20-1.mp4": "f4846a3b9ee6a16df3348916077d6476",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14698 - Mock Entry 20-1.nfo": "ad715f955b255f356b6263f06941bf05",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14699 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14699 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14699 - Mock Entry 20-2.mp4": "82a1f043b879412d6219e16993b8b188",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14699 - Mock Entry 20-2.nfo": "2fa884c057a44122a245efe3c33921cd",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14799 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14799 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14799 - Mock Entry 20-3.mp4": "6626433c9c3399c6403ba5753e3b31c2",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e14799 - Mock Entry 20-3.nfo": "63f4405964a11f99ff1595cc18266489",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e14699 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e14699 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e14699 - Mock Entry 21-1.mp4": "bac622134b8f65eaeccce6f3b822be64",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e14699 - Mock Entry 21-1.nfo": "6b9659879d7a1b9f5e2dccee70d7fe66",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show by Date/tvshow.nfo": "2439ebc18e46a67064956cb940c992e9"
}

View file

@ -0,0 +1,22 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-subscription_test-download-archive.json": "f13a43a83e725981df8417ab1d36705a",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080701 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080701 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080701 - Mock Entry 20-3.mp4": "219480c0ee2075ed86ccba740cca3d70",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080701 - Mock Entry 20-3.nfo": "6085b15cd1a32e8b45b97cee69ca4741",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080801 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080801 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080801 - Mock Entry 20-2.mp4": "7ed6abcf342149769ea2de23a0fee0a1",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080801 - Mock Entry 20-2.nfo": "599b687960602264db2f7f44dbd2f849",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080802 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080802 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080802 - Mock Entry 20-1.mp4": "1431320eb3acc337b1c70a895362397a",
"Best Prebuilt TV Show by Date/Season 2000/s2000.e080802 - Mock Entry 20-1.nfo": "6da492b1897671a3309df38e6fa33279",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e080801 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e080801 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e080801 - Mock Entry 21-1.mp4": "5c7f600b9a40039ea77729deda8d103f",
"Best Prebuilt TV Show by Date/Season 2001/s2001.e080801 - Mock Entry 21-1.nfo": "294fb0959c2cf640312f112c0a7aae27",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show by Date/tvshow.nfo": "2439ebc18e46a67064956cb940c992e9"
}

View file

@ -0,0 +1,22 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-subscription_test-download-archive.json": "5269b5e9e4fad7b63b6fdb3fef477b1e",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0701 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0701 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0701 - Mock Entry 20-3.mp4": "b095358d6b335a25f3be3ae44a6d10ac",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0701 - Mock Entry 20-3.nfo": "4ba0e01c1e7295952c3f5e6b9b251d7d",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0801 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0801 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0801 - Mock Entry 20-2.mp4": "43f73b6f99439e4873bf8d4ba1802452",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0801 - Mock Entry 20-2.nfo": "db9196b729c7b2cd26e3f0fc649b39f0",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0802 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0802 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0802 - Mock Entry 20-1.mp4": "632af351287dde4d1a096460f6bd93b1",
"Best Prebuilt TV Show by Date/Season 202008/s202008.e0802 - Mock Entry 20-1.nfo": "ba4a387d9462f416ba176c31c1c55316",
"Best Prebuilt TV Show by Date/Season 202108/s202108.e0801 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 202108/s202108.e0801 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 202108/s202108.e0801 - Mock Entry 21-1.mp4": "bf0104b783e168b150ea165faa898915",
"Best Prebuilt TV Show by Date/Season 202108/s202108.e0801 - Mock Entry 21-1.nfo": "93dd5c4c493422f9a60e61a6b965b39a",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show by Date/tvshow.nfo": "2439ebc18e46a67064956cb940c992e9"
}

View file

@ -0,0 +1,22 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-subscription_test-download-archive.json": "456d8882fc5e35d74f19b386d1d9a059",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "1d0714fb3ca4d31a0f88492a06a6142d",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3.nfo": "dbe61f2c8ae41041773f713ba5376726",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "a8f3f8580989f3927606bf6060a64e30",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2.nfo": "0f071078c9fa2569bbcb998664d40681",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "265b1104b382fd157a123842e49fcdfd",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1.nfo": "837a61dca11bbe1874ea07cb8ef8a7c9",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "09fa4599fd48836c6c0da0760c306006",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show by Date/tvshow.nfo": "2439ebc18e46a67064956cb940c992e9"
}

View file

@ -0,0 +1,22 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-Best Prebuilt TV Show by Date-download-archive.json": "456d8882fc5e35d74f19b386d1d9a059",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "1d0714fb3ca4d31a0f88492a06a6142d",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry 20-3.nfo": "dbe61f2c8ae41041773f713ba5376726",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "a8f3f8580989f3927606bf6060a64e30",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry 20-2.nfo": "0f071078c9fa2569bbcb998664d40681",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "265b1104b382fd157a123842e49fcdfd",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry 20-1.nfo": "837a61dca11bbe1874ea07cb8ef8a7c9",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "09fa4599fd48836c6c0da0760c306006",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show by Date/tvshow.nfo": "2439ebc18e46a67064956cb940c992e9"
}

View file

@ -0,0 +1,22 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-subscription_test-download-archive.json": "05539b932348da7e949a63eb71f77efc",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14698 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14698 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14698 - Mock Entry 20-1.mp4": "c27d1898d39763a265e4fe4451777688",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14698 - Mock Entry 20-1.nfo": "88fee5353ad7eecd96865b34654bbde6",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14699 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14699 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14699 - Mock Entry 20-2.mp4": "80c087803d5ac9c0efe02361fdaaa5bd",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14699 - Mock Entry 20-2.nfo": "d781b80ef24916acbf3bf181ab32ddea",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14799 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14799 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14799 - Mock Entry 20-3.mp4": "1b5084c06b33f7e0d6daf7cff03adc73",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e14799 - Mock Entry 20-3.nfo": "252b3639b4d1686f8c79476943f89439",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e14699 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e14699 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e14699 - Mock Entry 21-1.mp4": "a83870aaca55947b7a91ac90109163af",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e14699 - Mock Entry 21-1.nfo": "e7374b766d9ec0599ecf209a0f78c0ba",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show by Date/tvshow.nfo": "2439ebc18e46a67064956cb940c992e9"
}

View file

@ -0,0 +1,22 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-subscription_test-download-archive.json": "e30d83126c2c6981c936ed894a6f159b",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080701 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080701 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080701 - Mock Entry 20-3.mp4": "c712d7fd5dfdb9bb6c2be99f7c796c6f",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080701 - Mock Entry 20-3.nfo": "7c0f2a9d38bf617377e474fcb9bf2bc2",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080801 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080801 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080801 - Mock Entry 20-2.mp4": "7ec7ac1923053c4b5653bbfb8924fdc6",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080801 - Mock Entry 20-2.nfo": "1f4dec756555ee345cd9d6489b63e070",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080802 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080802 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080802 - Mock Entry 20-1.mp4": "414c243016f406451c790757949173aa",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080802 - Mock Entry 20-1.nfo": "f6f704ae3ae0c4055590a147eb425609",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e080801 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e080801 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e080801 - Mock Entry 21-1.mp4": "e2f858efd08ac82749fd01db65d8341e",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e080801 - Mock Entry 21-1.nfo": "c6e0d368bfe9d70134e5a2ff2d3dccc6",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show by Date/tvshow.nfo": "2439ebc18e46a67064956cb940c992e9"
}

View file

@ -0,0 +1,17 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-Best Prebuilt TV Show by Date-download-archive.json": "0011c85c3339ac1301d80be2f3330e67",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000001 - Mock Entry -.mp4": "1d0714fb3ca4d31a0f88492a06a6142d",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000002 - Mock Entry -.mp4": "a8f3f8580989f3927606bf6060a64e30",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e000003 - Mock Entry -.mp4": "265b1104b382fd157a123842e49fcdfd",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e000004 - Mock Entry -.mp4": "09fa4599fd48836c6c0da0760c306006",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
}

View file

@ -0,0 +1,17 @@
{
"Best Prebuilt TV Show by Date/.ytdl-sub-subscription_test-download-archive.json": "6cd67e6b935bc5b2521f6ed0fa2ea2ed",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080701 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080701 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080701 - Mock Entry -.mp4": "c712d7fd5dfdb9bb6c2be99f7c796c6f",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080801 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080801 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080801 - Mock Entry -.mp4": "7ec7ac1923053c4b5653bbfb8924fdc6",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080802 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080802 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2020/s2020.e080802 - Mock Entry -.mp4": "414c243016f406451c790757949173aa",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e080801 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e080801 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show by Date/Season 2021/s2021.e080801 - Mock Entry -.mp4": "e2f858efd08ac82749fd01db65d8341e",
"Best Prebuilt TV Show by Date/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
}

View file

@ -0,0 +1,23 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-Best Prebuilt TV Show Collection-download-archive.json": "809885e6c29bba06215b840516628090",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3.mp4": "e107a93fa177c5f8594ccc3e023db8e8",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3.nfo": "ddf2763f976aaa79199bddbfd3b66501",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2.mp4": "2788e6b165908e6d52d7d771859b085e",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2.nfo": "cda58b9d5b7ee05d5e4d5144ebfe0f94",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1.mp4": "6f0fd7cb3b3c49a8cf7baa6657cb5148",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1.nfo": "4d5775492f2731cb5dc04a84ebcb029d",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1.mp4": "6a983aa1b5dff65c54bd5f0b78003e07",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1.nfo": "2980b224863465a8b8a465c9d381d1f4",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "a3f1061135b7aa0c25e5176a271d32f0"
}

View file

@ -0,0 +1,40 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-Best Prebuilt TV Show Collection-download-archive.json": "7331c3a7cc0b43cd547b82af4ec35a3f",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7.mp4": "6390603e1f9642ea573f25179b42f6af",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7.nfo": "42ad110e3f608de3edb94735631d39a7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6.mp4": "179e310bd4de1638d84b6da787ff9fa8",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6.nfo": "ea4dee97b5bb9e49cb72f0942f851feb",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.mp4": "3c412f47cb87e820138fb8909c672216",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.nfo": "7f71bd60012d850ece38fa644eeddc5e",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4.mp4": "8409a144e67c50573bae29bf76431d76",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4.nfo": "c487f013b8d5adc399a793bc803b898f",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3.mp4": "e107a93fa177c5f8594ccc3e023db8e8",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3.nfo": "4eedc1c0e99858530e6228001d024766",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2.mp4": "2788e6b165908e6d52d7d771859b085e",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2.nfo": "cc1541a65508fcbfd9f024042cb6b6ce",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1.mp4": "6f0fd7cb3b3c49a8cf7baa6657cb5148",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1.nfo": "d5fa573faf1d29c367117917417df62c",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1.mp4": "6a983aa1b5dff65c54bd5f0b78003e07",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1.nfo": "6c40cd5d13c8d088e57906e809a591f8",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/season02-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "61943a17325c5188475651ca7c68446d"
}

View file

@ -0,0 +1,23 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "ede1deeba072bae50f7f7039deca0543",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080701 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080701 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080701 - Mock Entry 20-3.mp4": "a874866ad7096eb3bf31c72ea3315354",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080701 - Mock Entry 20-3.nfo": "043c6de15ab09f32e64414d1f4a8a89c",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080801 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080801 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080801 - Mock Entry 20-2.mp4": "fe6fcf8bfc13c0913ad1509703b447f1",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080801 - Mock Entry 20-2.nfo": "4fb018858502fe2c7a0d3dcb89145a8d",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080802 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080802 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080802 - Mock Entry 20-1.mp4": "1d0f1081b402ebea9aeedf75f891c811",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080802 - Mock Entry 20-1.nfo": "6ac2ee3bd87b453d56bd90b42bbf52a0",
"Best Prebuilt TV Show Collection/Season 01/s01.e21080801 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e21080801 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e21080801 - Mock Entry 21-1.mp4": "e5a844cc2c8fe19037afdf0692731414",
"Best Prebuilt TV Show Collection/Season 01/s01.e21080801 - Mock Entry 21-1.nfo": "d54ba1888f0083f8de6f401e399ad379",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "a3f1061135b7aa0c25e5176a271d32f0"
}

View file

@ -0,0 +1,40 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "9b9e26ff3d036f450501bf5adb979aeb",
"Best Prebuilt TV Show Collection/Season 01/s01.e20060601 - Mock Entry 20-7-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20060601 - Mock Entry 20-7.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20060601 - Mock Entry 20-7.mp4": "fab0f2d0a74558a86b3935c6b962ebe3",
"Best Prebuilt TV Show Collection/Season 01/s01.e20060601 - Mock Entry 20-7.nfo": "9ceac835c0166bf4f7354106379e6d17",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070601 - Mock Entry 20-6-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070601 - Mock Entry 20-6.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070601 - Mock Entry 20-6.mp4": "9c2569c62ff81f067fe3d91324942c11",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070601 - Mock Entry 20-6.nfo": "35f15e5437cae813095fe2ca3bd2ca18",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070602 - Mock Entry 20-5-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070602 - Mock Entry 20-5.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070602 - Mock Entry 20-5.mp4": "921e686edbf2a2e11f8d3eba9ef32592",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070602 - Mock Entry 20-5.nfo": "9aa69e4c86bb282ac57b2024ec2fbd34",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080601 - Mock Entry 20-4-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080601 - Mock Entry 20-4.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080601 - Mock Entry 20-4.mp4": "a9fae3eca046637910a6e79aae4a8354",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080601 - Mock Entry 20-4.nfo": "709533b6b8f501196db0d98dfe2b2b16",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080701 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080701 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080701 - Mock Entry 20-3.mp4": "a874866ad7096eb3bf31c72ea3315354",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080701 - Mock Entry 20-3.nfo": "05f34cd0e6be4b09ea96134faec892f6",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080801 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080801 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080801 - Mock Entry 20-2.mp4": "fe6fcf8bfc13c0913ad1509703b447f1",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080801 - Mock Entry 20-2.nfo": "54b4f84daf25626703f7b3a36b0dea49",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080802 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080802 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080802 - Mock Entry 20-1.mp4": "1d0f1081b402ebea9aeedf75f891c811",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080802 - Mock Entry 20-1.nfo": "3d2644161e57b94cfac5e95732864cc3",
"Best Prebuilt TV Show Collection/Season 02/s02.e21080801 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e21080801 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e21080801 - Mock Entry 21-1.mp4": "e5a844cc2c8fe19037afdf0692731414",
"Best Prebuilt TV Show Collection/Season 02/s02.e21080801 - Mock Entry 21-1.nfo": "fd91adb2089d0fcdbb2e568a10ac880e",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/season02-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "61943a17325c5188475651ca7c68446d"
}

View file

@ -0,0 +1,23 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "809885e6c29bba06215b840516628090",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3.mp4": "e107a93fa177c5f8594ccc3e023db8e8",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3.nfo": "ddf2763f976aaa79199bddbfd3b66501",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2.mp4": "2788e6b165908e6d52d7d771859b085e",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2.nfo": "cda58b9d5b7ee05d5e4d5144ebfe0f94",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1.mp4": "6f0fd7cb3b3c49a8cf7baa6657cb5148",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1.nfo": "4d5775492f2731cb5dc04a84ebcb029d",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1.mp4": "6a983aa1b5dff65c54bd5f0b78003e07",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1.nfo": "2980b224863465a8b8a465c9d381d1f4",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "a3f1061135b7aa0c25e5176a271d32f0"
}

View file

@ -0,0 +1,23 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-Best Prebuilt TV Show Collection-download-archive.json": "809885e6c29bba06215b840516628090",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3.mp4": "e107a93fa177c5f8594ccc3e023db8e8",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-3.nfo": "ddf2763f976aaa79199bddbfd3b66501",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2.mp4": "2788e6b165908e6d52d7d771859b085e",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-2.nfo": "cda58b9d5b7ee05d5e4d5144ebfe0f94",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1.mp4": "6f0fd7cb3b3c49a8cf7baa6657cb5148",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-1.nfo": "4d5775492f2731cb5dc04a84ebcb029d",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1.mp4": "6a983aa1b5dff65c54bd5f0b78003e07",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 21-1.nfo": "2980b224863465a8b8a465c9d381d1f4",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "a3f1061135b7aa0c25e5176a271d32f0"
}

View file

@ -0,0 +1,40 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "7331c3a7cc0b43cd547b82af4ec35a3f",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7.mp4": "6390603e1f9642ea573f25179b42f6af",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7.nfo": "42ad110e3f608de3edb94735631d39a7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6.mp4": "179e310bd4de1638d84b6da787ff9fa8",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6.nfo": "ea4dee97b5bb9e49cb72f0942f851feb",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.mp4": "3c412f47cb87e820138fb8909c672216",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.nfo": "7f71bd60012d850ece38fa644eeddc5e",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4.mp4": "8409a144e67c50573bae29bf76431d76",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4.nfo": "c487f013b8d5adc399a793bc803b898f",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3.mp4": "e107a93fa177c5f8594ccc3e023db8e8",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3.nfo": "4eedc1c0e99858530e6228001d024766",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2.mp4": "2788e6b165908e6d52d7d771859b085e",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2.nfo": "cc1541a65508fcbfd9f024042cb6b6ce",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1.mp4": "6f0fd7cb3b3c49a8cf7baa6657cb5148",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1.nfo": "d5fa573faf1d29c367117917417df62c",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1.mp4": "6a983aa1b5dff65c54bd5f0b78003e07",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1.nfo": "6c40cd5d13c8d088e57906e809a591f8",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/season02-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "61943a17325c5188475651ca7c68446d"
}

View file

@ -0,0 +1,40 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-Best Prebuilt TV Show Collection-download-archive.json": "7331c3a7cc0b43cd547b82af4ec35a3f",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7.mp4": "6390603e1f9642ea573f25179b42f6af",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 20-7.nfo": "42ad110e3f608de3edb94735631d39a7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6.mp4": "179e310bd4de1638d84b6da787ff9fa8",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-6.nfo": "ea4dee97b5bb9e49cb72f0942f851feb",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.mp4": "3c412f47cb87e820138fb8909c672216",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.nfo": "7f71bd60012d850ece38fa644eeddc5e",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4.mp4": "8409a144e67c50573bae29bf76431d76",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-4.nfo": "c487f013b8d5adc399a793bc803b898f",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3.mp4": "e107a93fa177c5f8594ccc3e023db8e8",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 20-3.nfo": "4eedc1c0e99858530e6228001d024766",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2.mp4": "2788e6b165908e6d52d7d771859b085e",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-2.nfo": "cc1541a65508fcbfd9f024042cb6b6ce",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1.mp4": "6f0fd7cb3b3c49a8cf7baa6657cb5148",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-1.nfo": "d5fa573faf1d29c367117917417df62c",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1.mp4": "6a983aa1b5dff65c54bd5f0b78003e07",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 21-1.nfo": "6c40cd5d13c8d088e57906e809a591f8",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/season02-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "61943a17325c5188475651ca7c68446d"
}

View file

@ -0,0 +1,23 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "4e5ef7394c029e7fe230f82dfe134e4c",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 21-1.mp4": "79cac07b1964b53ff128ef041e3ed10b",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry 21-1.nfo": "2a3d9b51221a541fefc29eebffe47cd4",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-1.mp4": "ebd20e58d50951bfcd2316bcf660ba11",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-1.nfo": "ec57b2c78058e18cdc015813e8a14b9d",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-2.mp4": "331068e0bf01c2baaa131c7760a46c02",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-2.nfo": "cd919caf88b0eed99fd2a595c1afa6b1",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-3.mp4": "c646ebe3838f553abb5e9cb1dd96b85f",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-3.nfo": "7c4b28456fe5d398b7dad966eb194421",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "a3f1061135b7aa0c25e5176a271d32f0"
}

View file

@ -0,0 +1,40 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "c7c2427315924db344d4659a60c59bc9",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-4-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-4.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-4.mp4": "a37dba001208063f0c04b2a681973c1c",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry 20-4.nfo": "7d8f03bdcd8ee66fd1578a86f20365cc",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.mp4": "3c412f47cb87e820138fb8909c672216",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry 20-5.nfo": "7f71bd60012d850ece38fa644eeddc5e",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-6-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-6.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-6.mp4": "0bee8e6eb39dbfa8aab81fb78c74ffa0",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry 20-6.nfo": "39996f43e9761247dce614247f99c808",
"Best Prebuilt TV Show Collection/Season 01/s01.e000005 - Mock Entry 20-7-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000005 - Mock Entry 20-7.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000005 - Mock Entry 20-7.mp4": "db88af54bfd315035ce187c2da47f95a",
"Best Prebuilt TV Show Collection/Season 01/s01.e000005 - Mock Entry 20-7.nfo": "cae377877c966dad492eaa3f224b86ba",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 21-1.mp4": "79cac07b1964b53ff128ef041e3ed10b",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry 21-1.nfo": "974bb83bd43b9579ab1716f66589ccc1",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-1.mp4": "ebd20e58d50951bfcd2316bcf660ba11",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry 20-1.nfo": "b12dcb09ffad7f23f21d350e1f60f128",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-2.mp4": "331068e0bf01c2baaa131c7760a46c02",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry 20-2.nfo": "e6fd0fc3e95b77c595d1a77c2060fd98",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 20-3.mp4": "c646ebe3838f553abb5e9cb1dd96b85f",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry 20-3.nfo": "23386ea27c1e64afcecdb235acb81b79",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/season02-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "61943a17325c5188475651ca7c68446d"
}

View file

@ -0,0 +1,23 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "df87dea55d4f4076ab4c075a3bceaa3d",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052498 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052498 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052498 - Mock Entry 20-1.mp4": "170f6eaaa831b92e80ba798b5ae50b60",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052498 - Mock Entry 20-1.nfo": "93e75d3231077883d37c5baac435e182",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052499 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052499 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052499 - Mock Entry 20-2.mp4": "0e1805471b84d94f605f645d9ea94c9e",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052499 - Mock Entry 20-2.nfo": "6d022da37f3545d9ab8608f11b8059cd",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052599 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052599 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052599 - Mock Entry 20-3.mp4": "2b59eab2673eb7f2a0ec91033737634a",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052599 - Mock Entry 20-3.nfo": "f47403746915586d1bd87436210311c5",
"Best Prebuilt TV Show Collection/Season 01/s01.e99052499 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e99052499 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e99052499 - Mock Entry 21-1.mp4": "450737dd9b8307f498eddb2ac7f4e567",
"Best Prebuilt TV Show Collection/Season 01/s01.e99052499 - Mock Entry 21-1.nfo": "5c095683a8c1ae4ff950d4302dc5f06e",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "a3f1061135b7aa0c25e5176a271d32f0"
}

View file

@ -0,0 +1,40 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "e89ac9f59f9f9ef22e01c9055708b81c",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052699 - Mock Entry 20-4-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052699 - Mock Entry 20-4.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052699 - Mock Entry 20-4.mp4": "1ea0b0274a45288449dddcb1c91a0ac7",
"Best Prebuilt TV Show Collection/Season 01/s01.e100052699 - Mock Entry 20-4.nfo": "f670533b516a47b833cd0ae04bec5877",
"Best Prebuilt TV Show Collection/Season 01/s01.e100062698 - Mock Entry 20-5-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e100062698 - Mock Entry 20-5.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e100062698 - Mock Entry 20-5.mp4": "9b03d1c2e2be9cd75920821accae7774",
"Best Prebuilt TV Show Collection/Season 01/s01.e100062698 - Mock Entry 20-5.nfo": "a223cdfe24fb5d285704351f38db7b46",
"Best Prebuilt TV Show Collection/Season 01/s01.e100062699 - Mock Entry 20-6-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e100062699 - Mock Entry 20-6.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e100062699 - Mock Entry 20-6.mp4": "2240a972bc91ef589b3b0a25f1e41725",
"Best Prebuilt TV Show Collection/Season 01/s01.e100062699 - Mock Entry 20-6.nfo": "bb1cc5d794aa28d43e405179622f2095",
"Best Prebuilt TV Show Collection/Season 01/s01.e100072599 - Mock Entry 20-7-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e100072599 - Mock Entry 20-7.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e100072599 - Mock Entry 20-7.mp4": "5944f9af51010e2783576fdbd2ad5436",
"Best Prebuilt TV Show Collection/Season 01/s01.e100072599 - Mock Entry 20-7.nfo": "dbd5b09d734a10795a11344a5b536b8f",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052498 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052498 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052498 - Mock Entry 20-1.mp4": "170f6eaaa831b92e80ba798b5ae50b60",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052498 - Mock Entry 20-1.nfo": "bb5c4debab0a9f5bbd0a4e303c9bed2d",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052499 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052499 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052499 - Mock Entry 20-2.mp4": "0e1805471b84d94f605f645d9ea94c9e",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052499 - Mock Entry 20-2.nfo": "de6eab4d23acac23213ee25adb8095ac",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052599 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052599 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052599 - Mock Entry 20-3.mp4": "2b59eab2673eb7f2a0ec91033737634a",
"Best Prebuilt TV Show Collection/Season 02/s02.e100052599 - Mock Entry 20-3.nfo": "23e88cb7a059946b12c0702a1f987bc7",
"Best Prebuilt TV Show Collection/Season 02/s02.e99052499 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e99052499 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e99052499 - Mock Entry 21-1.mp4": "450737dd9b8307f498eddb2ac7f4e567",
"Best Prebuilt TV Show Collection/Season 02/s02.e99052499 - Mock Entry 21-1.nfo": "ee3a0c5681e7bf7923f72c323e7a9795",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/season02-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "61943a17325c5188475651ca7c68446d"
}

View file

@ -0,0 +1,23 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "8f0390db6223f1c48072c28aabdc4162",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080701 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080701 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080701 - Mock Entry 20-3.mp4": "680b08a1e5032d89188def2784e62146",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080701 - Mock Entry 20-3.nfo": "2ecfb16f4216df21e9485b90b14e355f",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080801 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080801 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080801 - Mock Entry 20-2.mp4": "3c0dcdd38605f032c98aac9068732329",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080801 - Mock Entry 20-2.nfo": "090cfb9795b2ddd210afb93873cb60ce",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080802 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080802 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080802 - Mock Entry 20-1.mp4": "29d7648807690a4af93541ae340dd7bc",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080802 - Mock Entry 20-1.nfo": "e4aa8129a961c47e3151062b95f39b73",
"Best Prebuilt TV Show Collection/Season 01/s01.e01080801 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e01080801 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e01080801 - Mock Entry 21-1.mp4": "9abd6ecaf194553e9486e1bf02f552cf",
"Best Prebuilt TV Show Collection/Season 01/s01.e01080801 - Mock Entry 21-1.nfo": "34704ea06cbdfaa1c9939e061fd1633a",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "a3f1061135b7aa0c25e5176a271d32f0"
}

View file

@ -0,0 +1,40 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "b6ee943d41ca8b0f9b54bb9cb04da7de",
"Best Prebuilt TV Show Collection/Season 01/s01.e00060601 - Mock Entry 20-7-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e00060601 - Mock Entry 20-7.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e00060601 - Mock Entry 20-7.mp4": "a75f9d2b28d82b78ae30da3962f57f61",
"Best Prebuilt TV Show Collection/Season 01/s01.e00060601 - Mock Entry 20-7.nfo": "29b6f491d1d7cb5e62f6a3dd290ba74a",
"Best Prebuilt TV Show Collection/Season 01/s01.e00070601 - Mock Entry 20-6-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e00070601 - Mock Entry 20-6.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e00070601 - Mock Entry 20-6.mp4": "18226f783f8c3fac3089d61307bee3ba",
"Best Prebuilt TV Show Collection/Season 01/s01.e00070601 - Mock Entry 20-6.nfo": "8ce2b32b9371cc45908acb73a5c5d5e6",
"Best Prebuilt TV Show Collection/Season 01/s01.e00070602 - Mock Entry 20-5-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e00070602 - Mock Entry 20-5.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e00070602 - Mock Entry 20-5.mp4": "180e86031e6af3ea1a54714460a6bf1f",
"Best Prebuilt TV Show Collection/Season 01/s01.e00070602 - Mock Entry 20-5.nfo": "4567dfd30fc7287eea63f28e465d9c54",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080601 - Mock Entry 20-4-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080601 - Mock Entry 20-4.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080601 - Mock Entry 20-4.mp4": "09fba17ad8bf9deb8157ff83880185c3",
"Best Prebuilt TV Show Collection/Season 01/s01.e00080601 - Mock Entry 20-4.nfo": "0fc29c2520ae80c4390a5b68d02e6794",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080701 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080701 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080701 - Mock Entry 20-3.mp4": "680b08a1e5032d89188def2784e62146",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080701 - Mock Entry 20-3.nfo": "7276a8c14720f76cf4e5e624eb1dea2d",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080801 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080801 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080801 - Mock Entry 20-2.mp4": "3c0dcdd38605f032c98aac9068732329",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080801 - Mock Entry 20-2.nfo": "028a4161b6bccda2cf8d2a0a3ff13f4f",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080802 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080802 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080802 - Mock Entry 20-1.mp4": "29d7648807690a4af93541ae340dd7bc",
"Best Prebuilt TV Show Collection/Season 02/s02.e00080802 - Mock Entry 20-1.nfo": "7303574842c9409a6521486ddeb7cde9",
"Best Prebuilt TV Show Collection/Season 02/s02.e01080801 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e01080801 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e01080801 - Mock Entry 21-1.mp4": "9abd6ecaf194553e9486e1bf02f552cf",
"Best Prebuilt TV Show Collection/Season 02/s02.e01080801 - Mock Entry 21-1.nfo": "5b9d248c2fd2460030aa590d8660d957",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/season02-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "61943a17325c5188475651ca7c68446d"
}

View file

@ -0,0 +1,23 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "e26598ffd47b150e6bf09e5490546e94",
"Best Prebuilt TV Show Collection/Season 01/s01.e79052499 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e79052499 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e79052499 - Mock Entry 21-1.mp4": "cda96931a134eeb6e05e0b5aec03ddfe",
"Best Prebuilt TV Show Collection/Season 01/s01.e79052499 - Mock Entry 21-1.nfo": "a7e21040a3fcb264f287e4eba1853f94",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052498 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052498 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052498 - Mock Entry 20-1.mp4": "a7f2ca37b817da0512af297b5652e5e8",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052498 - Mock Entry 20-1.nfo": "78c08ad76d004a74cdba012f0b746c22",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052499 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052499 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052499 - Mock Entry 20-2.mp4": "35ebd30923d8f321e023281ec6ef4e6f",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052499 - Mock Entry 20-2.nfo": "d9031d8608d12742c40a3279138c8371",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052599 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052599 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052599 - Mock Entry 20-3.mp4": "204ce9c28ab7b69c659f0f76b6c75bfa",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052599 - Mock Entry 20-3.nfo": "74bd8dc59c5b76ae112d90638977c464",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "a3f1061135b7aa0c25e5176a271d32f0"
}

View file

@ -0,0 +1,40 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "2990d95213df5a6c87825a28daa970f4",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052699 - Mock Entry 20-4-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052699 - Mock Entry 20-4.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052699 - Mock Entry 20-4.mp4": "611d34cf77a2123181a7c4096623f6b9",
"Best Prebuilt TV Show Collection/Season 01/s01.e80052699 - Mock Entry 20-4.nfo": "0242d92e5e0d26745948b42c25eecfba",
"Best Prebuilt TV Show Collection/Season 01/s01.e80062698 - Mock Entry 20-5-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e80062698 - Mock Entry 20-5.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e80062698 - Mock Entry 20-5.mp4": "f09ce6574a040cea52b7177f74b9ccea",
"Best Prebuilt TV Show Collection/Season 01/s01.e80062698 - Mock Entry 20-5.nfo": "52b17bcad30adb6eaef4c3b21c1af76b",
"Best Prebuilt TV Show Collection/Season 01/s01.e80062699 - Mock Entry 20-6-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e80062699 - Mock Entry 20-6.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e80062699 - Mock Entry 20-6.mp4": "435692c75994d929807b5f09726728ad",
"Best Prebuilt TV Show Collection/Season 01/s01.e80062699 - Mock Entry 20-6.nfo": "31fb72d089fd680fea1340f3d3c41d64",
"Best Prebuilt TV Show Collection/Season 01/s01.e80072599 - Mock Entry 20-7-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e80072599 - Mock Entry 20-7.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e80072599 - Mock Entry 20-7.mp4": "613c386e00bf1c87e4f1d1acbbd98281",
"Best Prebuilt TV Show Collection/Season 01/s01.e80072599 - Mock Entry 20-7.nfo": "df65227ee260219883ff618c9fbdf1d4",
"Best Prebuilt TV Show Collection/Season 02/s02.e79052499 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e79052499 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e79052499 - Mock Entry 21-1.mp4": "cda96931a134eeb6e05e0b5aec03ddfe",
"Best Prebuilt TV Show Collection/Season 02/s02.e79052499 - Mock Entry 21-1.nfo": "0e4ea058d6a1e8760c80d3a02d25aafc",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052498 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052498 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052498 - Mock Entry 20-1.mp4": "a7f2ca37b817da0512af297b5652e5e8",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052498 - Mock Entry 20-1.nfo": "1095322364e512dff963a44b2beffe30",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052499 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052499 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052499 - Mock Entry 20-2.mp4": "35ebd30923d8f321e023281ec6ef4e6f",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052499 - Mock Entry 20-2.nfo": "5130c71d99f1c0726fee8cb8c9d82ba7",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052599 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052599 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052599 - Mock Entry 20-3.mp4": "204ce9c28ab7b69c659f0f76b6c75bfa",
"Best Prebuilt TV Show Collection/Season 02/s02.e80052599 - Mock Entry 20-3.nfo": "bde2a5401c49b58de0eacea4145d91ae",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/season02-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "61943a17325c5188475651ca7c68446d"
}

View file

@ -0,0 +1,23 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "ede1deeba072bae50f7f7039deca0543",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080701 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080701 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080701 - Mock Entry 20-3.mp4": "a874866ad7096eb3bf31c72ea3315354",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080701 - Mock Entry 20-3.nfo": "043c6de15ab09f32e64414d1f4a8a89c",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080801 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080801 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080801 - Mock Entry 20-2.mp4": "fe6fcf8bfc13c0913ad1509703b447f1",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080801 - Mock Entry 20-2.nfo": "4fb018858502fe2c7a0d3dcb89145a8d",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080802 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080802 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080802 - Mock Entry 20-1.mp4": "1d0f1081b402ebea9aeedf75f891c811",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080802 - Mock Entry 20-1.nfo": "6ac2ee3bd87b453d56bd90b42bbf52a0",
"Best Prebuilt TV Show Collection/Season 01/s01.e21080801 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e21080801 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e21080801 - Mock Entry 21-1.mp4": "e5a844cc2c8fe19037afdf0692731414",
"Best Prebuilt TV Show Collection/Season 01/s01.e21080801 - Mock Entry 21-1.nfo": "d54ba1888f0083f8de6f401e399ad379",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "a3f1061135b7aa0c25e5176a271d32f0"
}

View file

@ -0,0 +1,40 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "9b9e26ff3d036f450501bf5adb979aeb",
"Best Prebuilt TV Show Collection/Season 01/s01.e20060601 - Mock Entry 20-7-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20060601 - Mock Entry 20-7.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20060601 - Mock Entry 20-7.mp4": "fab0f2d0a74558a86b3935c6b962ebe3",
"Best Prebuilt TV Show Collection/Season 01/s01.e20060601 - Mock Entry 20-7.nfo": "9ceac835c0166bf4f7354106379e6d17",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070601 - Mock Entry 20-6-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070601 - Mock Entry 20-6.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070601 - Mock Entry 20-6.mp4": "9c2569c62ff81f067fe3d91324942c11",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070601 - Mock Entry 20-6.nfo": "35f15e5437cae813095fe2ca3bd2ca18",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070602 - Mock Entry 20-5-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070602 - Mock Entry 20-5.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070602 - Mock Entry 20-5.mp4": "921e686edbf2a2e11f8d3eba9ef32592",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070602 - Mock Entry 20-5.nfo": "9aa69e4c86bb282ac57b2024ec2fbd34",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080601 - Mock Entry 20-4-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080601 - Mock Entry 20-4.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080601 - Mock Entry 20-4.mp4": "a9fae3eca046637910a6e79aae4a8354",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080601 - Mock Entry 20-4.nfo": "709533b6b8f501196db0d98dfe2b2b16",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080701 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080701 - Mock Entry 20-3.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080701 - Mock Entry 20-3.mp4": "a874866ad7096eb3bf31c72ea3315354",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080701 - Mock Entry 20-3.nfo": "05f34cd0e6be4b09ea96134faec892f6",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080801 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080801 - Mock Entry 20-2.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080801 - Mock Entry 20-2.mp4": "fe6fcf8bfc13c0913ad1509703b447f1",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080801 - Mock Entry 20-2.nfo": "54b4f84daf25626703f7b3a36b0dea49",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080802 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080802 - Mock Entry 20-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080802 - Mock Entry 20-1.mp4": "1d0f1081b402ebea9aeedf75f891c811",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080802 - Mock Entry 20-1.nfo": "3d2644161e57b94cfac5e95732864cc3",
"Best Prebuilt TV Show Collection/Season 02/s02.e21080801 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e21080801 - Mock Entry 21-1.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e21080801 - Mock Entry 21-1.mp4": "e5a844cc2c8fe19037afdf0692731414",
"Best Prebuilt TV Show Collection/Season 02/s02.e21080801 - Mock Entry 21-1.nfo": "fd91adb2089d0fcdbb2e568a10ac880e",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a",
"Best Prebuilt TV Show Collection/season01-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/season02-poster.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/tvshow.nfo": "61943a17325c5188475651ca7c68446d"
}

View file

@ -0,0 +1,18 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-Best Prebuilt TV Show Collection-download-archive.json": "ba324b2c6532fe9d8fbe03e0dd6d0410",
"Best Prebuilt TV Show Collection/Season 01/Season01.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry -.mp4": "e107a93fa177c5f8594ccc3e023db8e8",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry -.mp4": "2788e6b165908e6d52d7d771859b085e",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry -.mp4": "6f0fd7cb3b3c49a8cf7baa6657cb5148",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry -.mp4": "6a983aa1b5dff65c54bd5f0b78003e07",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
}

View file

@ -0,0 +1,31 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-Best Prebuilt TV Show Collection-download-archive.json": "6ec6913047c175cedcbd41cb3ef402fc",
"Best Prebuilt TV Show Collection/Season 01/Season01.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000001 - Mock Entry -.mp4": "6390603e1f9642ea573f25179b42f6af",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000002 - Mock Entry -.mp4": "179e310bd4de1638d84b6da787ff9fa8",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000003 - Mock Entry -.mp4": "3c412f47cb87e820138fb8909c672216",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e000004 - Mock Entry -.mp4": "8409a144e67c50573bae29bf76431d76",
"Best Prebuilt TV Show Collection/Season 02/Season02.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000001 - Mock Entry -.mp4": "e107a93fa177c5f8594ccc3e023db8e8",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000002 - Mock Entry -.mp4": "2788e6b165908e6d52d7d771859b085e",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000003 - Mock Entry -.mp4": "6f0fd7cb3b3c49a8cf7baa6657cb5148",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e000004 - Mock Entry -.mp4": "6a983aa1b5dff65c54bd5f0b78003e07",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
}

View file

@ -0,0 +1,18 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "87f96a1e055447383bfea0a12680438d",
"Best Prebuilt TV Show Collection/Season 01/Season01.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080701 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080701 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080701 - Mock Entry -.mp4": "a874866ad7096eb3bf31c72ea3315354",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080801 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080801 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080801 - Mock Entry -.mp4": "fe6fcf8bfc13c0913ad1509703b447f1",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080802 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080802 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080802 - Mock Entry -.mp4": "1d0f1081b402ebea9aeedf75f891c811",
"Best Prebuilt TV Show Collection/Season 01/s01.e21080801 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e21080801 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e21080801 - Mock Entry -.mp4": "e5a844cc2c8fe19037afdf0692731414",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
}

View file

@ -0,0 +1,31 @@
{
"Best Prebuilt TV Show Collection/.ytdl-sub-subscription_test-download-archive.json": "04d06f293fcb5164266bedf66b4d4264",
"Best Prebuilt TV Show Collection/Season 01/Season01.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20060601 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20060601 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20060601 - Mock Entry -.mp4": "fab0f2d0a74558a86b3935c6b962ebe3",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070601 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070601 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070601 - Mock Entry -.mp4": "9c2569c62ff81f067fe3d91324942c11",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070602 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070602 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20070602 - Mock Entry -.mp4": "921e686edbf2a2e11f8d3eba9ef32592",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080601 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080601 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 01/s01.e20080601 - Mock Entry -.mp4": "a9fae3eca046637910a6e79aae4a8354",
"Best Prebuilt TV Show Collection/Season 02/Season02.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080701 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080701 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080701 - Mock Entry -.mp4": "a874866ad7096eb3bf31c72ea3315354",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080801 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080801 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080801 - Mock Entry -.mp4": "fe6fcf8bfc13c0913ad1509703b447f1",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080802 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080802 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e20080802 - Mock Entry -.mp4": "1d0f1081b402ebea9aeedf75f891c811",
"Best Prebuilt TV Show Collection/Season 02/s02.e21080801 - Mock Entry --thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Best Prebuilt TV Show Collection/Season 02/s02.e21080801 - Mock Entry -.info.json": "INFO_JSON",
"Best Prebuilt TV Show Collection/Season 02/s02.e21080801 - Mock Entry -.mp4": "e5a844cc2c8fe19037afdf0692731414",
"Best Prebuilt TV Show Collection/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
}

View file

@ -2,18 +2,18 @@
".ytdl-sub-subscription_test-download-archive.json": "76e202bd03ceef93daaffffee2cfa193",
"JMC/Mock Entry 20-1.info.json": "INFO_JSON",
"JMC/Mock Entry 20-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-1.mp4": "40efe3f597c40c11d0d3f2f87cc7650b",
"JMC/Mock Entry 20-1.mp4": "f9f1542629edf78fb9d80f2517e6530e",
"JMC/Mock Entry 20-1.nfo": "fefcf0b3e4f4ff80ad636584d50dadec",
"JMC/Mock Entry 20-2.info.json": "INFO_JSON",
"JMC/Mock Entry 20-2.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-2.mp4": "0747f56d03e720128b1fa5ef25bcf3c8",
"JMC/Mock Entry 20-2.mp4": "48a46efb360b908a5c9653ef266f6574",
"JMC/Mock Entry 20-2.nfo": "025c0b631da5ff5470382b38fce78d2d",
"JMC/Mock Entry 20-3.info.json": "INFO_JSON",
"JMC/Mock Entry 20-3.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-3.mp4": "eb776b8e6da77a848666d88623600fd6",
"JMC/Mock Entry 20-3.mp4": "69b89a35ca5554d047d7ea375635e557",
"JMC/Mock Entry 20-3.nfo": "618b0ff948d9de2e10cf1da8c0dd6615",
"JMC/Mock Entry 21-1.info.json": "INFO_JSON",
"JMC/Mock Entry 21-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 21-1.mp4": "5d56530dc8a4cfe55efb791d82bae0f0",
"JMC/Mock Entry 21-1.mp4": "a3a18a3acf6e28ab921b8458d1526886",
"JMC/Mock Entry 21-1.nfo": "e5c715749efc1603a6e2f59244d87aba"
}

View file

@ -2,18 +2,18 @@
".ytdl-sub-subscription_test-download-archive.json": "19cf39d57914ba9cbd1e57ba6f1e0683",
"JMC/Mock Entry 20-1.info.json": "INFO_JSON",
"JMC/Mock Entry 20-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-1.mkv": "1514f89a141f7b5ee3fdde9a70e63f57",
"JMC/Mock Entry 20-1.mkv": "eb9a8ff61701ab673c2f06147fe29a4e",
"JMC/Mock Entry 20-1.nfo": "fefcf0b3e4f4ff80ad636584d50dadec",
"JMC/Mock Entry 20-2.info.json": "INFO_JSON",
"JMC/Mock Entry 20-2.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-2.mkv": "da089645cc944fdb411ecc46facfe9f6",
"JMC/Mock Entry 20-2.mkv": "65d047562c61a068e8a92bd8df8801fa",
"JMC/Mock Entry 20-2.nfo": "025c0b631da5ff5470382b38fce78d2d",
"JMC/Mock Entry 20-3.info.json": "INFO_JSON",
"JMC/Mock Entry 20-3.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-3.mkv": "5dbae183aa57c4062af9d5a2e0e0f8fe",
"JMC/Mock Entry 20-3.mkv": "98582526fcb3bea10ab7b3df7a5bc65d",
"JMC/Mock Entry 20-3.nfo": "618b0ff948d9de2e10cf1da8c0dd6615",
"JMC/Mock Entry 21-1.info.json": "INFO_JSON",
"JMC/Mock Entry 21-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 21-1.mkv": "61910bf74a0175fbdf595095109d1a1c",
"JMC/Mock Entry 21-1.mkv": "3fe368f6d4bd9662a24abca9215b4d26",
"JMC/Mock Entry 21-1.nfo": "e5c715749efc1603a6e2f59244d87aba"
}

View file

@ -1,12 +1,12 @@
{
".ytdl-sub-subscription_test-download-archive.json": "7c6fbd0631d7d02025f3da457ba203e3",
"Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "7d2ee7fe8003ea63ece37dd2a441c123",
"Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "06e7e5beab0b68e4ee3535c801448b4c",
"Season 2020/s2020.e000001 - Mock Entry 20-3.nfo": "dbe61f2c8ae41041773f713ba5376726",
"Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "699017cd1b67ae216eda769bef413415",
"Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "dfe89d82ae778bae164e161f10ac9adc",
"Season 2020/s2020.e000002 - Mock Entry 20-2.nfo": "0f071078c9fa2569bbcb998664d40681",
"Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "a16741d4fbf657d1de4c50493db14062",
"Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "273785dcc28969f4de4a6e3e5ff1e61e",
"Season 2020/s2020.e000003 - Mock Entry 20-1.nfo": "837a61dca11bbe1874ea07cb8ef8a7c9",
"Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "7433153952b069a5674e2a3ed529b49b",
"Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "2170bfbc2b85057ba0ec403e7e5ea66d",
"Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
}

View file

@ -2,19 +2,19 @@
".ytdl-sub-JMC-migrated-download-archive.json": "456d8882fc5e35d74f19b386d1d9a059",
"Season 2020/s2020.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "7d2ee7fe8003ea63ece37dd2a441c123",
"Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "06e7e5beab0b68e4ee3535c801448b4c",
"Season 2020/s2020.e000001 - Mock Entry 20-3.nfo": "dbe61f2c8ae41041773f713ba5376726",
"Season 2020/s2020.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "699017cd1b67ae216eda769bef413415",
"Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "dfe89d82ae778bae164e161f10ac9adc",
"Season 2020/s2020.e000002 - Mock Entry 20-2.nfo": "0f071078c9fa2569bbcb998664d40681",
"Season 2020/s2020.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "a16741d4fbf657d1de4c50493db14062",
"Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "273785dcc28969f4de4a6e3e5ff1e61e",
"Season 2020/s2020.e000003 - Mock Entry 20-1.nfo": "837a61dca11bbe1874ea07cb8ef8a7c9",
"Season 2021/s2021.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2021/s2021.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "7433153952b069a5674e2a3ed529b49b",
"Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "2170bfbc2b85057ba0ec403e7e5ea66d",
"Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
}

View file

@ -2,19 +2,19 @@
".ytdl-sub-subscription_test-download-archive.json": "456d8882fc5e35d74f19b386d1d9a059",
"Season 2020/s2020.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "7d2ee7fe8003ea63ece37dd2a441c123",
"Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "06e7e5beab0b68e4ee3535c801448b4c",
"Season 2020/s2020.e000001 - Mock Entry 20-3.nfo": "dbe61f2c8ae41041773f713ba5376726",
"Season 2020/s2020.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "699017cd1b67ae216eda769bef413415",
"Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "dfe89d82ae778bae164e161f10ac9adc",
"Season 2020/s2020.e000002 - Mock Entry 20-2.nfo": "0f071078c9fa2569bbcb998664d40681",
"Season 2020/s2020.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "a16741d4fbf657d1de4c50493db14062",
"Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "273785dcc28969f4de4a6e3e5ff1e61e",
"Season 2020/s2020.e000003 - Mock Entry 20-1.nfo": "837a61dca11bbe1874ea07cb8ef8a7c9",
"Season 2021/s2021.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2021/s2021.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "7433153952b069a5674e2a3ed529b49b",
"Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "2170bfbc2b85057ba0ec403e7e5ea66d",
"Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
}

View file

@ -1,16 +1,16 @@
{
".ytdl-sub-subscription_test-download-archive.json": "e049068ba7f5bdc27c474b18f4c6b402",
"Season 2020/s2020.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "7d2ee7fe8003ea63ece37dd2a441c123",
"Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "06e7e5beab0b68e4ee3535c801448b4c",
"Season 2020/s2020.e000001 - Mock Entry 20-3.nfo": "dbe61f2c8ae41041773f713ba5376726",
"Season 2020/s2020.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "699017cd1b67ae216eda769bef413415",
"Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "dfe89d82ae778bae164e161f10ac9adc",
"Season 2020/s2020.e000002 - Mock Entry 20-2.nfo": "0f071078c9fa2569bbcb998664d40681",
"Season 2020/s2020.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "a16741d4fbf657d1de4c50493db14062",
"Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "273785dcc28969f4de4a6e3e5ff1e61e",
"Season 2020/s2020.e000003 - Mock Entry 20-1.nfo": "837a61dca11bbe1874ea07cb8ef8a7c9",
"Season 2021/s2021.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "7433153952b069a5674e2a3ed529b49b",
"Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "2170bfbc2b85057ba0ec403e7e5ea66d",
"Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
}

View file

@ -1,19 +1,19 @@
{
".ytdl-sub-j_b-download-archive.json": "1a99156e9ece62539fb2608416a07200",
"j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.mp3": "b35d01351e5dd1195e90a41b2edeb5b7",
"j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.mp3": "0aecc0e9832768002f41e09a7e70b305",
"j_b/[2021] Baby Santana's Dorian Groove/folder.jpg": "967892be44b8c47e1be73f055a7c6f08",
"j_b/[2021] Purple Clouds/01 - Purple Clouds.mp3": "5c107c122048389aa40936c4fba0436e",
"j_b/[2021] Purple Clouds/01 - Purple Clouds.mp3": "2d4154dfa596c905d71cfd970f5dc9d3",
"j_b/[2021] Purple Clouds/folder.jpg": "967892be44b8c47e1be73f055a7c6f08",
"j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3": "e737c2ba118920643cec9eac09a283ea",
"j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3": "d5def3e4329b9b95c5354c838dd3bc91",
"j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3": "1694c4a2889aa7dacafc5f2fdb4fe1d7",
"j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3": "9c8ddee6aaf88b38706ce6bbdf907878",
"j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3": "4bf9e700137cb1b58e730dd312e00bb4",
"j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3": "c1920254046eda0d84b36dd34f9bafdb",
"j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3": "26f2eb8395b23cecc4000e2fd58304bf",
"j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3": "e3ceb5ae25c115d037a298b4620bce9f",
"j_b/[2022] Acoustic Treats/09 - Finding Home.mp3": "f3dcfe7c8569853a02eb12ad21b0e248",
"j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3": "4fb9a18b3fdd788ce9d9f4c8a07b6028",
"j_b/[2022] Acoustic Treats/11 - Untold History.mp3": "ad186ee1d0029f8de02357e8b8712a4b",
"j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3": "10c925fc97629ca788c44ae8082ee889",
"j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3": "da0e8a7db660adbfef255ba1763c384c",
"j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3": "42284493f75a55bd1b1d3f1ac8d1ffe1",
"j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3": "d660abefa257a10cbeae434c770bf3e5",
"j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3": "565d4dcf92e40e1485ed77fa79b52c17",
"j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3": "7c5903693230ca9ac8b44b76ed004eb4",
"j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3": "dfec9909cb8156ec8d5c28cfce858f36",
"j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3": "2c8769a9de3d1033d0e152c642512e40",
"j_b/[2022] Acoustic Treats/09 - Finding Home.mp3": "b3920d39deb847be938e03e3d74d4ac9",
"j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3": "759394ebe3db9ccef564fa9d7c0dfd09",
"j_b/[2022] Acoustic Treats/11 - Untold History.mp3": "477af6c479263539f244db8d9de04201",
"j_b/[2022] Acoustic Treats/folder.jpg": "967892be44b8c47e1be73f055a7c6f08"
}

Some files were not shown because too many files have changed in this diff Show more