Merge branch 'master' into emby
This commit is contained in:
commit
9f54aeda69
199 changed files with 5270 additions and 710 deletions
8
.github/workflows/ci-windows.yaml
vendored
8
.github/workflows/ci-windows.yaml
vendored
|
|
@ -19,7 +19,7 @@ jobs:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.12"
|
||||||
|
|
||||||
- name: Run unit tests with coverage
|
- name: Run unit tests with coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -42,7 +42,7 @@ jobs:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.12"
|
||||||
|
|
||||||
- name: Run integration tests with coverage
|
- name: Run integration tests with coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -66,7 +66,7 @@ jobs:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.12"
|
||||||
|
|
||||||
- name: Run prebuilt preset integration tests with coverage
|
- name: Run prebuilt preset integration tests with coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -89,7 +89,7 @@ jobs:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.12"
|
||||||
|
|
||||||
- name: Run e2e tests with coverage
|
- name: Run e2e tests with coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
22
.github/workflows/ci.yaml
vendored
22
.github/workflows/ci.yaml
vendored
|
|
@ -9,7 +9,7 @@ on:
|
||||||
- master
|
- master
|
||||||
jobs:
|
jobs:
|
||||||
test-lint:
|
test-lint:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ jobs:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.12"
|
||||||
|
|
||||||
- name: Run linters
|
- name: Run linters
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -27,7 +27,7 @@ jobs:
|
||||||
make check_lint
|
make check_lint
|
||||||
|
|
||||||
test-unit:
|
test-unit:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ jobs:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.12"
|
||||||
|
|
||||||
- name: Run unit tests with coverage
|
- name: Run unit tests with coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -53,7 +53,7 @@ jobs:
|
||||||
key: ${{github.sha}}-coverage-unit
|
key: ${{github.sha}}-coverage-unit
|
||||||
|
|
||||||
test-integration:
|
test-integration:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ jobs:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.12"
|
||||||
|
|
||||||
- name: Run integration tests with coverage
|
- name: Run integration tests with coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -79,7 +79,7 @@ jobs:
|
||||||
key: ${{github.sha}}-coverage-integration
|
key: ${{github.sha}}-coverage-integration
|
||||||
|
|
||||||
test-integration-prebuilt-presets:
|
test-integration-prebuilt-presets:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
|
|
@ -89,7 +89,7 @@ jobs:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.12"
|
||||||
|
|
||||||
- name: Run prebuilt preset integration tests with coverage
|
- name: Run prebuilt preset integration tests with coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -105,7 +105,7 @@ jobs:
|
||||||
key: ${{github.sha}}-coverage-integration-prebuilt-presets
|
key: ${{github.sha}}-coverage-integration-prebuilt-presets
|
||||||
|
|
||||||
test-e2e:
|
test-e2e:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
|
|
@ -115,7 +115,7 @@ jobs:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.12"
|
||||||
|
|
||||||
- name: Run e2e tests with coverage
|
- name: Run e2e tests with coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -125,7 +125,7 @@ jobs:
|
||||||
coverage run -m pytest tests/e2e && coverage xml -o /opt/coverage/e2e/coverage.xml
|
coverage run -m pytest tests/e2e && coverage xml -o /opt/coverage/e2e/coverage.xml
|
||||||
|
|
||||||
codecov-upload:
|
codecov-upload:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
needs: [
|
needs: [
|
||||||
test-unit,
|
test-unit,
|
||||||
test-integration,
|
test-integration,
|
||||||
|
|
|
||||||
10
.github/workflows/package-gui.yaml
vendored
10
.github/workflows/package-gui.yaml
vendored
|
|
@ -63,10 +63,10 @@ jobs:
|
||||||
echo 'init_contents=__pypi_version__ = "${{ env.PYPI_VERSION }}";__local_version__ = "${{ env.LOCAL_VERSION }}"' >> "$GITHUB_OUTPUT"
|
echo 'init_contents=__pypi_version__ = "${{ env.PYPI_VERSION }}";__local_version__ = "${{ env.LOCAL_VERSION }}"' >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [ "3.10" ]
|
python-version: [ "3.12" ]
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
@ -92,7 +92,7 @@ jobs:
|
||||||
|
|
||||||
# Build ARM64 container, only on master branch to save time testing
|
# Build ARM64 container, only on master branch to save time testing
|
||||||
package-arm64:
|
package-arm64:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
needs: [
|
needs: [
|
||||||
build
|
build
|
||||||
]
|
]
|
||||||
|
|
@ -141,7 +141,7 @@ jobs:
|
||||||
|
|
||||||
# Build AMD64 container
|
# Build AMD64 container
|
||||||
package-amd64:
|
package-amd64:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
needs: [
|
needs: [
|
||||||
build
|
build
|
||||||
]
|
]
|
||||||
|
|
@ -186,7 +186,7 @@ jobs:
|
||||||
# On master branch, build the docker manifest file from the cached
|
# On master branch, build the docker manifest file from the cached
|
||||||
# docker builds and push to the registry
|
# docker builds and push to the registry
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
needs: [
|
needs: [
|
||||||
version,
|
version,
|
||||||
build,
|
build,
|
||||||
|
|
|
||||||
10
.github/workflows/package-ubuntu.yaml
vendored
10
.github/workflows/package-ubuntu.yaml
vendored
|
|
@ -63,10 +63,10 @@ jobs:
|
||||||
echo 'init_contents=__pypi_version__ = "${{ env.PYPI_VERSION }}";__local_version__ = "${{ env.LOCAL_VERSION }}"' >> "$GITHUB_OUTPUT"
|
echo 'init_contents=__pypi_version__ = "${{ env.PYPI_VERSION }}";__local_version__ = "${{ env.LOCAL_VERSION }}"' >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [ "3.10" ]
|
python-version: [ "3.12" ]
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
@ -92,7 +92,7 @@ jobs:
|
||||||
|
|
||||||
# Build ARM64 container, only on master branch to save time testing
|
# Build ARM64 container, only on master branch to save time testing
|
||||||
package-arm64:
|
package-arm64:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
needs: [
|
needs: [
|
||||||
build
|
build
|
||||||
]
|
]
|
||||||
|
|
@ -141,7 +141,7 @@ jobs:
|
||||||
|
|
||||||
# Build AMD64 container
|
# Build AMD64 container
|
||||||
package-amd64:
|
package-amd64:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
needs: [
|
needs: [
|
||||||
build
|
build
|
||||||
]
|
]
|
||||||
|
|
@ -186,7 +186,7 @@ jobs:
|
||||||
# On master branch, build the docker manifest file from the cached
|
# On master branch, build the docker manifest file from the cached
|
||||||
# docker builds and push to the registry
|
# docker builds and push to the registry
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
needs: [
|
needs: [
|
||||||
version,
|
version,
|
||||||
build,
|
build,
|
||||||
|
|
|
||||||
10
.github/workflows/package.yaml
vendored
10
.github/workflows/package.yaml
vendored
|
|
@ -63,10 +63,10 @@ jobs:
|
||||||
echo 'init_contents=__pypi_version__ = "${{ env.PYPI_VERSION }}";__local_version__ = "${{ env.LOCAL_VERSION }}"' >> "$GITHUB_OUTPUT"
|
echo 'init_contents=__pypi_version__ = "${{ env.PYPI_VERSION }}";__local_version__ = "${{ env.LOCAL_VERSION }}"' >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [ "3.10" ]
|
python-version: [ "3.12" ]
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
@ -92,7 +92,7 @@ jobs:
|
||||||
|
|
||||||
# Build ARM64 container, only on master branch to save time testing
|
# Build ARM64 container, only on master branch to save time testing
|
||||||
package-arm64:
|
package-arm64:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
needs: [
|
needs: [
|
||||||
build
|
build
|
||||||
]
|
]
|
||||||
|
|
@ -136,7 +136,7 @@ jobs:
|
||||||
|
|
||||||
# Build AMD64 container
|
# Build AMD64 container
|
||||||
package-amd64:
|
package-amd64:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
needs: [
|
needs: [
|
||||||
build
|
build
|
||||||
]
|
]
|
||||||
|
|
@ -180,7 +180,7 @@ jobs:
|
||||||
# On master branch, build the docker manifest file from the cached
|
# On master branch, build the docker manifest file from the cached
|
||||||
# docker builds and push to the registry
|
# docker builds and push to the registry
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
needs: [
|
needs: [
|
||||||
version,
|
version,
|
||||||
build,
|
build,
|
||||||
|
|
|
||||||
41
.github/workflows/release.yaml
vendored
41
.github/workflows/release.yaml
vendored
|
|
@ -61,9 +61,16 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
arch: [ "aarch64", "x86_64" ]
|
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:
|
container:
|
||||||
image: quay.io/pypa/manylinux_2_28_x86_64
|
image: ${{ matrix.container }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Write version to init file
|
- 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
|
dnf install -y epel-release tar wget make gcc openssl-devel bzip2-devel libffi-devel zlib-devel
|
||||||
- name: Install Python
|
- name: Install Python
|
||||||
run: |
|
run: |
|
||||||
wget https://www.python.org/ftp/python/3.10.10/Python-3.10.10.tar.xz
|
wget https://www.python.org/ftp/python/3.12.9/Python-3.12.9.tar.xz
|
||||||
tar -xf Python-3.10.10.tar.xz
|
tar -xf Python-3.12.9.tar.xz
|
||||||
cd Python-3.10.10 && ./configure --with-ensurepip=install --prefix=/usr/local --enable-shared LDFLAGS="-Wl,-rpath /usr/local/lib"
|
cd Python-3.12.9 && ./configure --with-ensurepip=install --prefix=/usr/local --enable-shared LDFLAGS="-Wl,-rpath /usr/local/lib"
|
||||||
make -j 8
|
make -j 8
|
||||||
make altinstall
|
make altinstall
|
||||||
python3.10 --version
|
python3.12 --version
|
||||||
python3.10 -m ensurepip --upgrade
|
python3.12 -m ensurepip --upgrade
|
||||||
- name: Build Package
|
- name: Build Package
|
||||||
run: |
|
run: |
|
||||||
python3.10 -m pip install -e .
|
python3.12 -m pip install -e .
|
||||||
python3.10 -m pip install pyinstaller
|
python3.12 -m pip install pyinstaller
|
||||||
# Build executable
|
# Build executable
|
||||||
pyinstaller ytdl-sub.spec
|
pyinstaller ytdl-sub.spec
|
||||||
mkdir -p /opt/builds
|
mkdir -p /opt/builds
|
||||||
|
|
@ -95,7 +102,7 @@ jobs:
|
||||||
mv dist/ytdl-sub /opt/builds/ytdl-sub_${{ matrix.arch }}
|
mv dist/ytdl-sub /opt/builds/ytdl-sub_${{ matrix.arch }}
|
||||||
|
|
||||||
- name: Upload build
|
- name: Upload build
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ytdl-sub_${{ matrix.arch }}
|
name: ytdl-sub_${{ matrix.arch }}
|
||||||
path: /opt/builds/ytdl-sub_${{ matrix.arch }}
|
path: /opt/builds/ytdl-sub_${{ matrix.arch }}
|
||||||
|
|
@ -112,7 +119,7 @@ jobs:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.12"
|
||||||
- name: Write version to init file
|
- name: Write version to init file
|
||||||
run: |
|
run: |
|
||||||
echo '${{ needs.version.outputs.init_contents }}'> src/ytdl_sub/__init__.py
|
echo '${{ needs.version.outputs.init_contents }}'> src/ytdl_sub/__init__.py
|
||||||
|
|
@ -124,7 +131,7 @@ jobs:
|
||||||
.\dist\ytdl-sub.exe -h
|
.\dist\ytdl-sub.exe -h
|
||||||
|
|
||||||
- name: Upload build
|
- name: Upload build
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ytdl-sub_exe
|
name: ytdl-sub_exe
|
||||||
path: .\dist\ytdl-sub.exe
|
path: .\dist\ytdl-sub.exe
|
||||||
|
|
@ -145,19 +152,19 @@ jobs:
|
||||||
echo '${{ needs.version.outputs.init_contents }}' > src/ytdl_sub/__init__.py
|
echo '${{ needs.version.outputs.init_contents }}' > src/ytdl_sub/__init__.py
|
||||||
|
|
||||||
- name: Restore exe build
|
- name: Restore exe build
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ytdl-sub_exe
|
name: ytdl-sub_exe
|
||||||
path: /opt/builds
|
path: /opt/builds
|
||||||
|
|
||||||
- name: Restore aarch64 build
|
- name: Restore aarch64 build
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ytdl-sub_aarch64
|
name: ytdl-sub_aarch64
|
||||||
path: /opt/builds
|
path: /opt/builds
|
||||||
|
|
||||||
- name: Restore x86_64 build
|
- name: Restore x86_64 build
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ytdl-sub_x86_64
|
name: ytdl-sub_x86_64
|
||||||
path: /opt/builds
|
path: /opt/builds
|
||||||
|
|
@ -193,13 +200,13 @@ jobs:
|
||||||
name: pypi-publish
|
name: pypi-publish
|
||||||
needs:
|
needs:
|
||||||
- version
|
- version
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.12'
|
||||||
- name: Write version to init file
|
- name: Write version to init file
|
||||||
run: |
|
run: |
|
||||||
echo '${{ needs.version.outputs.init_contents }}' > src/ytdl_sub/__init__.py
|
echo '${{ needs.version.outputs.init_contents }}' > src/ytdl_sub/__init__.py
|
||||||
|
|
|
||||||
6
Makefile
6
Makefile
|
|
@ -14,9 +14,9 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
@-isort .
|
python3 -m isort .
|
||||||
@-black .
|
python3 -m black .
|
||||||
@-pylint src/
|
python3 -m pylint src
|
||||||
check_lint:
|
check_lint:
|
||||||
isort . --check-only --diff \
|
isort . --check-only --diff \
|
||||||
&& black . --check \
|
&& black . --check \
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@ FROM ghcr.io/linuxserver/baseimage-alpine:edge
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# YTDL-SUB INSTALL
|
# YTDL-SUB INSTALL
|
||||||
|
|
||||||
# Needed for phantomjs
|
# For phantomjs
|
||||||
ENV OPENSSL_CONF="/etc/ssl"
|
ENV OPENSSL_CONF="/etc/ssl"
|
||||||
|
# For downloading thumbnails
|
||||||
|
ENV SSL_CERT_DIR="/etc/ssl/certs/"
|
||||||
|
|
||||||
COPY root/ /
|
COPY root/ /
|
||||||
RUN mkdir -p /config && \
|
RUN mkdir -p /config && \
|
||||||
|
|
@ -55,6 +57,12 @@ RUN mkdir -p /config && \
|
||||||
# CONTAINER CONFIGS
|
# CONTAINER CONFIGS
|
||||||
|
|
||||||
ENV EDITOR="nano" \
|
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
|
VOLUME /config
|
||||||
|
|
@ -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
|
# For phantomjs
|
||||||
ENV OPENSSL_CONF=/etc/ssl
|
ENV OPENSSL_CONF="/etc/ssl"
|
||||||
|
# For downloading thumbnails
|
||||||
|
ENV SSL_CERT_DIR="/etc/ssl/certs/"
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# YTDL-SUB INSTALL
|
# YTDL-SUB INSTALL
|
||||||
|
|
@ -20,7 +22,6 @@ RUN mkdir -p /config && \
|
||||||
g++ \
|
g++ \
|
||||||
nano \
|
nano \
|
||||||
make \
|
make \
|
||||||
python3.10-dev \
|
|
||||||
python3-pip \
|
python3-pip \
|
||||||
fontconfig \
|
fontconfig \
|
||||||
xz-utils \
|
xz-utils \
|
||||||
|
|
@ -59,7 +60,7 @@ RUN mkdir -p /config && \
|
||||||
phantomjs --version ; \
|
phantomjs --version ; \
|
||||||
fi && \
|
fi && \
|
||||||
# Install ytdl-sub, ensure it is installed properly
|
# 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 && \
|
ytdl-sub -h && \
|
||||||
# Delete unneeded packages after install
|
# Delete unneeded packages after install
|
||||||
rm ytdl_sub-*.whl && \
|
rm ytdl_sub-*.whl && \
|
||||||
|
|
@ -68,7 +69,6 @@ RUN mkdir -p /config && \
|
||||||
make \
|
make \
|
||||||
xz-utils \
|
xz-utils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
python3.10-dev \
|
|
||||||
python3-venv && \
|
python3-venv && \
|
||||||
apt-get autoremove -y && \
|
apt-get autoremove -y && \
|
||||||
apt-get purge -y --auto-remove && \
|
apt-get purge -y --auto-remove && \
|
||||||
|
|
@ -77,11 +77,13 @@ RUN mkdir -p /config && \
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# CONTAINER CONFIGS
|
# CONTAINER CONFIGS
|
||||||
|
|
||||||
|
ENV EDITOR="nano" \
|
||||||
ENV YTDL_SUB_TYPE="gui" \
|
|
||||||
EDITOR="nano" \
|
|
||||||
HOME="/config" \
|
HOME="/config" \
|
||||||
DOCKER_MODS=linuxserver/mods:universal-cron \
|
DOCKER_MODS=linuxserver/mods:universal-stdout-logs|linuxserver/mods:universal-cron \
|
||||||
DEFAULT_WORKSPACE=/config/ytdl-sub-configs
|
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
|
VOLUME /config
|
||||||
|
|
@ -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
|
# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
# Needed for phantomjs
|
# For phantomjs
|
||||||
ENV OPENSSL_CONF=/etc/ssl
|
ENV OPENSSL_CONF="/etc/ssl"
|
||||||
|
# For downloading thumbnails
|
||||||
|
ENV SSL_CERT_DIR="/etc/ssl/certs/"
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# YTDL-SUB INSTALL
|
# YTDL-SUB INSTALL
|
||||||
|
|
@ -23,7 +25,6 @@ RUN mkdir -p /config && \
|
||||||
g++ \
|
g++ \
|
||||||
nano \
|
nano \
|
||||||
make \
|
make \
|
||||||
python3.10-dev \
|
|
||||||
python3-pip \
|
python3-pip \
|
||||||
fontconfig \
|
fontconfig \
|
||||||
xz-utils \
|
xz-utils \
|
||||||
|
|
@ -62,7 +63,7 @@ RUN mkdir -p /config && \
|
||||||
phantomjs --version ; \
|
phantomjs --version ; \
|
||||||
fi && \
|
fi && \
|
||||||
# Install ytdl-sub, ensure it is installed properly
|
# 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 && \
|
ytdl-sub -h && \
|
||||||
# Delete unneeded packages after install
|
# Delete unneeded packages after install
|
||||||
rm ytdl_sub-*.whl && \
|
rm ytdl_sub-*.whl && \
|
||||||
|
|
@ -71,7 +72,6 @@ RUN mkdir -p /config && \
|
||||||
make \
|
make \
|
||||||
xz-utils \
|
xz-utils \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
python3.10-dev \
|
|
||||||
python3-venv && \
|
python3-venv && \
|
||||||
apt-get autoremove -y && \
|
apt-get autoremove -y && \
|
||||||
apt-get purge -y --auto-remove && \
|
apt-get purge -y --auto-remove && \
|
||||||
|
|
@ -81,6 +81,12 @@ RUN mkdir -p /config && \
|
||||||
# CONTAINER CONFIGS
|
# CONTAINER CONFIGS
|
||||||
|
|
||||||
ENV EDITOR="nano" \
|
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
|
VOLUME /config
|
||||||
68
docker/root/custom-cont-init.d/defaults
Normal file
68
docker/root/custom-cont-init.d/defaults
Normal 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
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
4
docker/root/defaults/cron
Normal file
4
docker/root/defaults/cron
Normal 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.
|
||||||
15
docker/root/etc/s6-overlay/s6-rc.d/init-adduser/branding
Normal file
15
docker/root/etc/s6-overlay/s6-rc.d/init-adduser/branding
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
――――――――――――――――――――――――――――――――――――
|
||||||
|
██╗ ██╗████████╗██████╗ ██╗
|
||||||
|
╚██╗ ██╔╝╚══██╔══╝██╔══██╗██║
|
||||||
|
╚████╔╝ ██║ ██║ ██║██║
|
||||||
|
╚██╔╝ ██║ ██║ ██║██║
|
||||||
|
██║ ██║ ██████╔╝███████╗
|
||||||
|
╚═╝ ╚═╝ ╚═════╝ ╚══════╝
|
||||||
|
|
||||||
|
███████╗██╗ ██╗██████╗
|
||||||
|
██╔════╝██║ ██║██╔══██╗
|
||||||
|
███████╗██║ ██║██████╔╝
|
||||||
|
╚════██║██║ ██║██╔══██╗
|
||||||
|
███████║╚██████╔╝██████╔╝
|
||||||
|
╚══════╝ ╚═════╝ ╚═════╝
|
||||||
|
――――――――――――――――――――――――――――――――――――
|
||||||
|
|
@ -6,8 +6,34 @@ services:
|
||||||
- PUID=1000
|
- PUID=1000
|
||||||
- PGID=1000
|
- PGID=1000
|
||||||
- TZ=America/Los_Angeles
|
- TZ=America/Los_Angeles
|
||||||
|
- CRON_SCHEDULE="*/1 * * * *"
|
||||||
|
- CRON_RUN_ON_START=true
|
||||||
volumes:
|
volumes:
|
||||||
- ./volumes/ytdl-sub-gui:/config
|
- ./volumes/ytdl-sub-gui:/config
|
||||||
ports:
|
ports:
|
||||||
- 8443:8443
|
- 8443:8443
|
||||||
restart: unless-stopped
|
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
|
||||||
|
|
|
||||||
|
|
@ -456,7 +456,7 @@ with a ``.nfo`` extension. You can add any values into the NFO.
|
||||||
|
|
||||||
``kodi_safe``
|
``kodi_safe``
|
||||||
|
|
||||||
:expected type: Optional[Boolean]
|
:expected type: OverridesBooleanFormatterValidator
|
||||||
:description:
|
:description:
|
||||||
Defaults to False. Kodi does not support > 3-byte unicode characters, which include
|
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
|
emojis and some foreign language characters. Setting this to True will replace those
|
||||||
|
|
@ -554,7 +554,7 @@ Usage:
|
||||||
|
|
||||||
``kodi_safe``
|
``kodi_safe``
|
||||||
|
|
||||||
:expected type: Optional[Boolean]
|
:expected type: OverridesBooleanFormatterValidator
|
||||||
:description:
|
:description:
|
||||||
Defaults to False. Kodi does not support > 3-byte unicode characters, which include
|
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
|
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
|
maintain_download_archive: True
|
||||||
keep_files_before: now
|
keep_files_before: now
|
||||||
keep_files_after: 19000101
|
keep_files_after: 19000101
|
||||||
|
keep_max_files: 1000
|
||||||
|
keep_files_date_eval: "{upload_date_standardized}"
|
||||||
|
|
||||||
``download_archive_name``
|
``download_archive_name``
|
||||||
|
|
||||||
|
|
@ -690,6 +692,16 @@ Defines where to output files and thumbnails after all post-processing has compl
|
||||||
``keep_max_files``.
|
``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``
|
``keep_max_files``
|
||||||
|
|
||||||
:expected type: Optional[OverridesFormatter]
|
:expected type: Optional[OverridesFormatter]
|
||||||
|
|
@ -966,6 +978,9 @@ scripted.
|
||||||
presets:
|
presets:
|
||||||
my_example_preset:
|
my_example_preset:
|
||||||
throttle_protection:
|
throttle_protection:
|
||||||
|
sleep_per_request_s:
|
||||||
|
min: 5.5
|
||||||
|
max: 10.4
|
||||||
sleep_per_download_s:
|
sleep_per_download_s:
|
||||||
min: 2.2
|
min: 2.2
|
||||||
max: 10.8
|
max: 10.8
|
||||||
|
|
@ -1001,6 +1016,16 @@ scripted.
|
||||||
ytdl-sub to perform post-processing.
|
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``
|
``sleep_per_subscription_s``
|
||||||
|
|
||||||
:expected type: Optional[Range]
|
:expected type: Optional[Range]
|
||||||
|
|
|
||||||
|
|
@ -659,3 +659,9 @@ ytdl_sub_input_url_index
|
||||||
:type: ``Integer``
|
:type: ``Integer``
|
||||||
:description:
|
:description:
|
||||||
The index of the input URL as defined in the subscription, top-most being the 0th index.
|
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``.
|
||||||
|
|
|
||||||
|
|
@ -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
|
Regex Functions
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
@ -634,7 +666,7 @@ capitalize
|
||||||
|
|
||||||
concat
|
concat
|
||||||
~~~~~~
|
~~~~~~
|
||||||
:spec: ``concat(values: String, ...) -> String``
|
:spec: ``concat(values: AnyArgument, ...) -> String``
|
||||||
|
|
||||||
:description:
|
:description:
|
||||||
Concatenate multiple Strings into a single String.
|
Concatenate multiple Strings into a single String.
|
||||||
|
|
@ -660,6 +692,24 @@ contains_any
|
||||||
:description:
|
:description:
|
||||||
Returns true if any element in ``contains_array`` is in ``string``. False otherwise.
|
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
|
lower
|
||||||
~~~~~
|
~~~~~
|
||||||
:spec: ``lower(string: String) -> String``
|
:spec: ``lower(string: String) -> String``
|
||||||
|
|
@ -710,6 +760,23 @@ string
|
||||||
:description:
|
:description:
|
||||||
Cast to String.
|
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
|
titlecase
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
:spec: ``titlecase(string: String) -> String``
|
:spec: ``titlecase(string: String) -> String``
|
||||||
|
|
|
||||||
|
|
@ -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>`.
|
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...
|
There is a bug where...
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,127 +1,43 @@
|
||||||
Automating Downloads
|
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 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 Linux <guides/getting_started/automating_downloads:linux>`
|
||||||
|
|
||||||
:ref:`Guide for Windows <guides/getting_started/automating_downloads:windows>`
|
: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-unraid-setup:
|
||||||
|
|
||||||
Docker and Unraid
|
Docker and Unraid
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
.. tab-set::
|
Cron is preconfigured in every ytdl-sub docker container. Enable by adding the following
|
||||||
|
ENV variables to your docker setup.
|
||||||
|
|
||||||
.. tab-item:: GUI Image
|
.. code-block:: yaml
|
||||||
|
|
||||||
The script that will execute automatically is located at ``/config/ytdl-sub-configs/run_cron``.
|
services:
|
||||||
|
ytdl-sub:
|
||||||
|
environment:
|
||||||
|
- CRON_SCHEDULE="0 */6 * * *"
|
||||||
|
- CRON_RUN_ON_START=false
|
||||||
|
|
||||||
Access your container at http://localhost:8443/, then in the GUI terminal run these commands:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
- ``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.
|
||||||
|
|
||||||
echo '#!/bin/bash' > /config/ytdl-sub-configs/run_cron
|
The cron script will reside in the main directory with the file name ``cron``.
|
||||||
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> /config/ytdl-sub-configs/run_cron
|
Cron logs should show when viewing the Docker logs.
|
||||||
echo "echo 'Cron started, running ytdl-sub...'" >> /config/ytdl-sub-configs/run_cron
|
|
||||||
echo "cd /config/ytdl-sub-configs" >> /config/ytdl-sub-configs/run_cron
|
|
||||||
echo "ytdl-sub --config=config.yaml sub subscriptions.yaml" >> /config/ytdl-sub-configs/run_cron
|
|
||||||
chmod +x /config/ytdl-sub-configs/run_cron
|
|
||||||
chown abc:abc /config/ytdl-sub-configs/run_cron
|
|
||||||
|
|
||||||
You can test the newly created script by running:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
/config/ytdl-sub-configs/run_cron
|
|
||||||
|
|
||||||
To create the cron definition, run the following command:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
echo "# min hour day month weekday command" > /config/crontabs/abc
|
|
||||||
echo " 0 */6 * * * /config/ytdl-sub-configs/run_cron" >> /config/crontabs/abc
|
|
||||||
|
|
||||||
This will run the script every 6 hours. To run every hour, change ``*/6`` to ``*/1``, or to run once a day, change the same value to the hour (in 24hr format) that you want it to run at. See the `cron tab manpage`_ for more options.
|
|
||||||
|
|
||||||
.. tab-item:: Headless Image
|
|
||||||
|
|
||||||
.. _LinuxServer's Universal Cron mod: https://github.com/linuxserver/docker-mods/tree/universal-cron
|
|
||||||
|
|
||||||
The first step is to ensure you have `LinuxServer's Universal Cron mod`_ enabled via the environment variable. For the GUI image, this is already included (no need to add it).
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
services:
|
|
||||||
ytdl-sub:
|
|
||||||
image: ghcr.io/jmbannon/ytdl-sub:latest
|
|
||||||
container_name: ytdl-sub
|
|
||||||
environment:
|
|
||||||
- PUID=1000
|
|
||||||
- PGID=1000
|
|
||||||
- TZ=America/Los_Angeles
|
|
||||||
- DOCKER_MODS=linuxserver/mods:universal-cron # <-- Make sure you have this!
|
|
||||||
volumes:
|
|
||||||
# ensure directories have user permissions
|
|
||||||
- </path/to/ytdl-sub/config>:/config
|
|
||||||
- </path/to/ytdl-sub/tv_shows>:/tv_shows
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
This line will tell your container to install and enable cron on start.
|
|
||||||
|
|
||||||
If you had to add this line, you will need to restart your container.
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
docker compose restart
|
|
||||||
|
|
||||||
The script that will execute automatically is located at ``/config/run_cron``.
|
|
||||||
|
|
||||||
Access your container from the terminal by running:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
docker exec -itu abc ytdl-sub /bin/bash
|
|
||||||
|
|
||||||
then in the terminal run these commands:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
echo '#!/bin/bash' > /config/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-setup:
|
||||||
|
|
||||||
Linux
|
Linux
|
||||||
-----
|
-----
|
||||||
|
Must configure crontab manually, like so:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,6 @@ Docker Compose is an easy "set it and forget it" install method. Follow the inst
|
||||||
- PUID=1000
|
- PUID=1000
|
||||||
- PGID=1000
|
- PGID=1000
|
||||||
- TZ=America/Los_Angeles
|
- TZ=America/Los_Angeles
|
||||||
- DOCKER_MODS=linuxserver/mods:universal-cron
|
|
||||||
volumes:
|
volumes:
|
||||||
- <path/to/ytdl-sub/config>:/config
|
- <path/to/ytdl-sub/config>:/config
|
||||||
- <path/to/tv_shows>:/tv_shows # optional
|
- <path/to/tv_shows>:/tv_shows # optional
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
---------------
|
===============
|
||||||
|
|
||||||
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.
|
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
|
Example
|
||||||
~~~~~~~
|
-------
|
||||||
Must define ``tv_show_directory``. Available presets:
|
Must define ``tv_show_directory``. Available presets:
|
||||||
|
|
||||||
* ``"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``
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
|
@ -72,30 +67,68 @@ Must define ``tv_show_directory``. Available presets:
|
||||||
- "https://www.youtube.com/@rickbeato240"
|
- "https://www.youtube.com/@rickbeato240"
|
||||||
|
|
||||||
Advanced Usage
|
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``
|
__preset__:
|
||||||
* ``jellyfin_tv_show_by_date``
|
overrides:
|
||||||
* ``plex_tv_show_by_date``
|
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``
|
.. code-block:: yaml
|
||||||
* ``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.
|
"~Kids Toys Play":
|
||||||
* ``season_by_year__episode_by_download_index``
|
url: "https://www.youtube.com/@KidsToysPlayChannel"
|
||||||
|
tv_show_by_date_season_ordering: "upload-year-month"
|
||||||
|
tv_show_by_date_episode_ordering: "upload-day"
|
||||||
|
|
||||||
* 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.
|
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 Collection
|
||||||
------------------
|
==================
|
||||||
|
|
||||||
TV Show Collections set each URL as its own season. If a video belongs to multiple URLs
|
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
|
(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.
|
represents a separate channel/playlist.
|
||||||
|
|
||||||
Example
|
Example
|
||||||
~~~~~~~
|
-------
|
||||||
Must define ``tv_show_directory``. Available presets:
|
Must define ``tv_show_directory``. Available presets:
|
||||||
|
|
||||||
* ``"Kodi TV Show Collection"``
|
* ``Kodi TV Show Collection``
|
||||||
* ``"Jellyfin TV Show Collection"``
|
* ``Jellyfin TV Show Collection``
|
||||||
* ``"Plex TV Show Collection"``
|
* ``Plex TV Show Collection``
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
|
@ -132,21 +165,44 @@ Must define ``tv_show_directory``. Available presets:
|
||||||
s02_url: "https://www.youtube.com/playlist?list=PLE62gWlWZk5NWVAVuf0Lm9jdv_-_KXs0W"
|
s02_url: "https://www.youtube.com/playlist?list=PLE62gWlWZk5NWVAVuf0Lm9jdv_-_KXs0W"
|
||||||
|
|
||||||
Advanced Usage
|
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``
|
__preset__:
|
||||||
* ``jellyfin_tv_show_collection``
|
overrides:
|
||||||
* ``plex_tv_show_collection``
|
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``
|
.. code-block:: yaml
|
||||||
* ``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.
|
"~Beyond the Guitar":
|
||||||
* ``season_by_collection__episode_by_playlist_index_reversed``
|
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.
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ classifiers = [
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"yt-dlp[default]==2024.12.23",
|
"yt-dlp[default]==2025.5.22",
|
||||||
"colorama~=0.4",
|
"colorama~=0.4",
|
||||||
"mergedeep~=1.3",
|
"mergedeep~=1.3",
|
||||||
"mediafile~=0.12",
|
"mediafile~=0.12",
|
||||||
|
|
@ -48,8 +48,8 @@ test = [
|
||||||
]
|
]
|
||||||
lint = [
|
lint = [
|
||||||
"black==24.10.0",
|
"black==24.10.0",
|
||||||
"isort==5.13.2",
|
"isort==6.0.1",
|
||||||
"pylint==3.3.3",
|
"pylint==3.3.7",
|
||||||
]
|
]
|
||||||
docs = [
|
docs = [
|
||||||
"sphinx>=7,<9",
|
"sphinx>=7,<9",
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,6 @@ def main() -> List[Subscription]:
|
||||||
transaction_log_file_path=args.transaction_log,
|
transaction_log_file_path=args.transaction_log,
|
||||||
)
|
)
|
||||||
|
|
||||||
output_summary(subscriptions)
|
output_summary(subscriptions, suppress_colors=args.suppress_colors)
|
||||||
|
|
||||||
return subscriptions
|
return subscriptions
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,16 @@ from ytdl_sub.utils.logger import Logger
|
||||||
logger = Logger.get()
|
logger = Logger.get()
|
||||||
|
|
||||||
|
|
||||||
def _green(value: str) -> str:
|
def _green(value: str, suppress_colors: bool = False) -> str:
|
||||||
return Fore.GREEN + value + Fore.RESET
|
return value if suppress_colors else Fore.GREEN + value + Fore.RESET
|
||||||
|
|
||||||
|
|
||||||
def _red(value: str) -> str:
|
def _red(value: str, suppress_colors: bool = False) -> str:
|
||||||
return Fore.RED + value + Fore.RESET
|
return value if suppress_colors else Fore.RED + value + Fore.RESET
|
||||||
|
|
||||||
|
|
||||||
def _no_color(value: str) -> str:
|
def _no_color(value: str, suppress_colors: bool = False) -> str:
|
||||||
return Fore.RESET + value + Fore.RESET
|
return value if suppress_colors else Fore.RESET + value + Fore.RESET
|
||||||
|
|
||||||
|
|
||||||
def _str_int(value: int) -> str:
|
def _str_int(value: int) -> str:
|
||||||
|
|
@ -26,21 +26,23 @@ def _str_int(value: int) -> str:
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
def _color_int(value: int) -> str:
|
def _color_int(value: int, suppress_colors: bool = False) -> str:
|
||||||
str_int = _str_int(value)
|
str_int = _str_int(value)
|
||||||
if value > 0:
|
if value > 0:
|
||||||
return _green(str_int)
|
return _green(str_int, suppress_colors)
|
||||||
if value < 0:
|
if value < 0:
|
||||||
return _red(str_int)
|
return _red(str_int, suppress_colors)
|
||||||
return _no_color(str_int)
|
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
|
Parameters
|
||||||
----------
|
----------
|
||||||
subscriptions
|
subscriptions
|
||||||
Processed subscriptions
|
Processed subscriptions
|
||||||
|
suppress_colors
|
||||||
|
Whether to have color or not
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
|
@ -65,21 +67,21 @@ def output_summary(subscriptions: List[Subscription]) -> None:
|
||||||
|
|
||||||
# Initialize widths to 0
|
# Initialize widths to 0
|
||||||
width_sub_name: int = max(len(sub.name) for sub in subscriptions) + 4 # aesthetics
|
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_added: int = len(_color_int(total_added, suppress_colors))
|
||||||
width_num_entries_modified: int = len(_color_int(total_modified))
|
width_num_entries_modified: int = len(_color_int(total_modified, suppress_colors))
|
||||||
width_num_entries_removed: int = len(_color_int(total_removed))
|
width_num_entries_removed: int = len(_color_int(total_removed, suppress_colors))
|
||||||
width_num_entries: int = len(str(total_entries)) + 4 # aesthetics
|
width_num_entries: int = len(str(total_entries)) + 4 # aesthetics
|
||||||
|
|
||||||
# Build the summary
|
# Build the summary
|
||||||
for subscription in subscriptions:
|
for subscription in subscriptions:
|
||||||
num_entries_added = _color_int(subscription.num_entries_added)
|
num_entries_added = _color_int(subscription.num_entries_added, suppress_colors)
|
||||||
num_entries_modified = _color_int(subscription.num_entries_modified)
|
num_entries_modified = _color_int(subscription.num_entries_modified, suppress_colors)
|
||||||
num_entries_removed = _color_int(subscription.num_entries_removed * -1)
|
num_entries_removed = _color_int(subscription.num_entries_removed * -1, suppress_colors)
|
||||||
num_entries = str(subscription.num_entries)
|
num_entries = str(subscription.num_entries)
|
||||||
status = (
|
status = (
|
||||||
_red(subscription.exception.__class__.__name__)
|
_red(subscription.exception.__class__.__name__, suppress_colors)
|
||||||
if subscription.exception
|
if subscription.exception
|
||||||
else _green("✔")
|
else _green("✔", suppress_colors)
|
||||||
)
|
)
|
||||||
|
|
||||||
summary.append(
|
summary.append(
|
||||||
|
|
@ -92,14 +94,16 @@ def output_summary(subscriptions: List[Subscription]) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
total_errors_str = (
|
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(
|
summary.append(
|
||||||
f"{total_subs_str:<{width_sub_name}} "
|
f"{total_subs_str:<{width_sub_name}} "
|
||||||
f"{_color_int(total_added):>{width_num_entries_added}} "
|
f"{_color_int(total_added, suppress_colors):>{width_num_entries_added}} "
|
||||||
f"{_color_int(total_modified):>{width_num_entries_modified}} "
|
f"{_color_int(total_modified, suppress_colors):>{width_num_entries_modified}} "
|
||||||
f"{_color_int(total_removed):>{width_num_entries_removed}} "
|
f"{_color_int(total_removed * -1, suppress_colors):>{width_num_entries_removed}} "
|
||||||
f"{total_entries:>{width_num_entries}} "
|
f"{total_entries:>{width_num_entries}} "
|
||||||
f"{total_errors_str}"
|
f"{total_errors_str}"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ class MainArguments:
|
||||||
short="-m",
|
short="-m",
|
||||||
long="--match",
|
long="--match",
|
||||||
)
|
)
|
||||||
|
SUPPRESS_COLORS = CLIArgument(short="-nc", long="--suppress-colors")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def all(cls) -> List[CLIArgument]:
|
def all(cls) -> List[CLIArgument]:
|
||||||
|
|
@ -59,6 +60,7 @@ class MainArguments:
|
||||||
cls.TRANSACTION_LOG,
|
cls.TRANSACTION_LOG,
|
||||||
cls.SUPPRESS_TRANSACTION_LOG,
|
cls.SUPPRESS_TRANSACTION_LOG,
|
||||||
cls.MATCH,
|
cls.MATCH,
|
||||||
|
cls.SUPPRESS_COLORS,
|
||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@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",
|
help="do not output transaction logs to console or file",
|
||||||
default=argparse.SUPPRESS if suppress_defaults else False,
|
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(
|
arg_parser.add_argument(
|
||||||
MainArguments.MATCH.short,
|
MainArguments.MATCH.short,
|
||||||
MainArguments.MATCH.long,
|
MainArguments.MATCH.long,
|
||||||
|
|
|
||||||
|
|
@ -221,3 +221,12 @@ class Overrides(UnstructuredDictFormatterValidator, Scriptable):
|
||||||
return self._apply_to_resolvable(
|
return self._apply_to_resolvable(
|
||||||
formatter=formatter, entry=None, function_overrides=None
|
formatter=formatter, entry=None, function_overrides=None
|
||||||
).native
|
).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)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ from ytdl_sub.config.validators.options import OptionsValidatorT
|
||||||
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.utils.file_handler import FileMetadata
|
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 DownloadArchiver
|
||||||
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
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.
|
Returns True if enabled, False if disabled.
|
||||||
"""
|
"""
|
||||||
if isinstance(self.plugin_options, ToggleableOptionsDictValidator):
|
if isinstance(self.plugin_options, ToggleableOptionsDictValidator):
|
||||||
return ScriptUtils.bool_formatter_output(
|
return self.overrides.evaluate_boolean(self.plugin_options.enable)
|
||||||
self.overrides.apply_formatter(self.plugin_options.enable)
|
|
||||||
)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def ytdl_options_match_filters(self) -> Tuple[List[str], List[str]]:
|
def ytdl_options_match_filters(self) -> Tuple[List[str], List[str]]:
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,19 @@
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
from ytdl_sub.config.defaults import DEFAULT_DOWNLOAD_ARCHIVE_NAME
|
from ytdl_sub.config.defaults import DEFAULT_DOWNLOAD_ARCHIVE_NAME
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
|
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
||||||
|
from ytdl_sub.config.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 OverridesStringFormatterFilePathValidator
|
||||||
from ytdl_sub.validators.file_path_validators import StringFormatterFileNameValidator
|
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_datetime import StringDatetimeValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import OverridesIntegerFormatterValidator
|
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 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 StringFormatterValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import (
|
from ytdl_sub.validators.string_formatter_validators import (
|
||||||
UnstructuredOverridesDictFormatterValidator,
|
UnstructuredOverridesDictFormatterValidator,
|
||||||
|
|
@ -65,7 +69,7 @@ class YTDLOptions(UnstructuredOverridesDictFormatterValidator):
|
||||||
# pylint: disable=line-too-long
|
# pylint: disable=line-too-long
|
||||||
|
|
||||||
|
|
||||||
class OutputOptions(StrictDictValidator):
|
class OutputOptions(OptionsDictValidator):
|
||||||
"""
|
"""
|
||||||
Defines where to output files and thumbnails after all post-processing has completed.
|
Defines where to output files and thumbnails after all post-processing has completed.
|
||||||
|
|
||||||
|
|
@ -87,6 +91,8 @@ class OutputOptions(StrictDictValidator):
|
||||||
maintain_download_archive: True
|
maintain_download_archive: True
|
||||||
keep_files_before: now
|
keep_files_before: now
|
||||||
keep_files_after: 19000101
|
keep_files_after: 19000101
|
||||||
|
keep_max_files: 1000
|
||||||
|
keep_files_date_eval: "{upload_date_standardized}"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_required_keys = {"output_directory", "file_name"}
|
_required_keys = {"output_directory", "file_name"}
|
||||||
|
|
@ -99,6 +105,8 @@ class OutputOptions(StrictDictValidator):
|
||||||
"keep_files_before",
|
"keep_files_before",
|
||||||
"keep_files_after",
|
"keep_files_after",
|
||||||
"keep_max_files",
|
"keep_max_files",
|
||||||
|
"download_archive_standardized_date",
|
||||||
|
"keep_files_date_eval",
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -156,6 +164,11 @@ class OutputOptions(StrictDictValidator):
|
||||||
self._keep_max_files = self._validate_key_if_present(
|
self._keep_max_files = self._validate_key_if_present(
|
||||||
"keep_max_files", OverridesIntegerFormatterValidator
|
"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 (
|
if (
|
||||||
self._keep_files_before or self._keep_files_after or self._keep_max_files
|
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
|
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
|
@property
|
||||||
def keep_max_files(self) -> Optional[OverridesIntegerFormatterValidator]:
|
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``.
|
applied. Can be used in conjunction with ``keep_files_before`` and ``keep_files_after``.
|
||||||
"""
|
"""
|
||||||
return self._keep_max_files
|
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
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,13 +57,14 @@ def _add_dummy_overrides(overrides: Overrides) -> Dict[str, str]:
|
||||||
|
|
||||||
|
|
||||||
def _get_added_and_modified_variables(
|
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]]]:
|
) -> Iterable[Tuple[OptionsValidator, Set[str], Set[str]]]:
|
||||||
"""
|
"""
|
||||||
Iterates and returns the plugin options, added variables, modified variables
|
Iterates and returns the plugin options, added variables, modified variables
|
||||||
"""
|
"""
|
||||||
options: List[OptionsValidator] = plugins.plugin_options
|
options: List[OptionsValidator] = plugins.plugin_options
|
||||||
options.append(downloader_options)
|
options.append(downloader_options)
|
||||||
|
options.append(output_options)
|
||||||
|
|
||||||
for plugin_options in options:
|
for plugin_options in options:
|
||||||
added_variables: Set[str] = set()
|
added_variables: Set[str] = set()
|
||||||
|
|
@ -117,6 +118,7 @@ class VariableValidation:
|
||||||
) in _get_added_and_modified_variables(
|
) in _get_added_and_modified_variables(
|
||||||
plugins=self.plugins,
|
plugins=self.plugins,
|
||||||
downloader_options=self.downloader_options,
|
downloader_options=self.downloader_options,
|
||||||
|
output_options=self.output_options,
|
||||||
):
|
):
|
||||||
|
|
||||||
for added_variable in added_variables:
|
for added_variable in added_variables:
|
||||||
|
|
@ -183,6 +185,9 @@ class VariableValidation:
|
||||||
self._add_variables(PluginOperation.DOWNLOADER, options=self.downloader_options)
|
self._add_variables(PluginOperation.DOWNLOADER, options=self.downloader_options)
|
||||||
self._add_subscription_override_variables()
|
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
|
# Metadata variables to be added
|
||||||
for plugin_options in PluginMapping.order_options_by(
|
for plugin_options in PluginMapping.order_options_by(
|
||||||
self.plugins.zipped(), PluginOperation.MODIFY_ENTRY_METADATA
|
self.plugins.zipped(), PluginOperation.MODIFY_ENTRY_METADATA
|
||||||
|
|
|
||||||
|
|
@ -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.entries.script.variable_definitions import VariableDefinitions
|
||||||
from ytdl_sub.utils.file_handler import FileHandler
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
from ytdl_sub.utils.script import ScriptUtils
|
|
||||||
from ytdl_sub.utils.thumbnail import ThumbnailTypes
|
from ytdl_sub.utils.thumbnail import ThumbnailTypes
|
||||||
from ytdl_sub.utils.thumbnail import download_and_convert_url_thumbnail
|
from ytdl_sub.utils.thumbnail import download_and_convert_url_thumbnail
|
||||||
from ytdl_sub.utils.thumbnail import try_convert_download_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(
|
metadata_ytdl_options = self.metadata_ytdl_options(
|
||||||
ytdl_option_overrides=validator.ytdl_options.to_native_dict(self.overrides)
|
ytdl_option_overrides=validator.ytdl_options.to_native_dict(self.overrides)
|
||||||
)
|
)
|
||||||
download_reversed = ScriptUtils.bool_formatter_output(
|
download_reversed = self.overrides.evaluate_boolean(validator.download_reverse)
|
||||||
self.overrides.apply_formatter(validator.download_reverse)
|
include_sibling_metadata = self.overrides.evaluate_boolean(
|
||||||
)
|
validator.include_sibling_metadata
|
||||||
include_sibling_metadata = ScriptUtils.bool_formatter_output(
|
|
||||||
self.overrides.apply_formatter(validator.include_sibling_metadata)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
parents, orphan_entries = self._download_url_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 ..")
|
download_logger.info("Entry rejected by download match-filter, skipping ..")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
upload_date_idx = self._enhanced_download_archive.mapping.get_num_entries_with_upload_date(
|
upload_date_idx = self._enhanced_download_archive.mapping.get_num_entries_with_date(
|
||||||
upload_date_standardized=entry.get(v.upload_date_standardized, str)
|
standardized_date=entry.get(v.ytdl_sub_keep_files_date_eval, str)
|
||||||
)
|
)
|
||||||
download_idx = self._enhanced_download_archive.num_entries
|
download_idx = self._enhanced_download_archive.num_entries
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -823,6 +823,17 @@ class YtdlSubVariableDefinitions(ABC):
|
||||||
variable_name="upload_date_index_reversed_padded", pad=2
|
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):
|
class EntryVariableDefinitions(ABC):
|
||||||
@cached_property
|
@cached_property
|
||||||
|
|
@ -1121,6 +1132,7 @@ class VariableDefinitions(
|
||||||
self.ytdl_sub_input_url,
|
self.ytdl_sub_input_url,
|
||||||
self.ytdl_sub_input_url_index,
|
self.ytdl_sub_input_url_index,
|
||||||
self.ytdl_sub_input_url_count,
|
self.ytdl_sub_input_url_count,
|
||||||
|
self.ytdl_sub_keep_files_date_eval,
|
||||||
}
|
}
|
||||||
|
|
||||||
@cache
|
@cache
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ from typing import Tuple
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
||||||
from ytdl_sub.utils.datetime import to_date_str
|
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_datetime import StringDatetimeValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import OverridesBooleanFormatterValidator
|
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
|
date_validator=self.plugin_options.after, overrides=self.overrides
|
||||||
)
|
)
|
||||||
after_filter = f"upload_date >= {after_str}"
|
after_filter = f"upload_date >= {after_str}"
|
||||||
if ScriptUtils.bool_formatter_output(
|
if self.overrides.evaluate_boolean(self.plugin_options.breaks):
|
||||||
self.overrides.apply_formatter(self.plugin_options.breaks)
|
|
||||||
):
|
|
||||||
breaking_match_filters.append(after_filter)
|
breaking_match_filters.append(after_filter)
|
||||||
else:
|
else:
|
||||||
match_filters.append(after_filter)
|
match_filters.append(after_filter)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ from ytdl_sub.config.validators.options import OptionsValidator
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.utils.exceptions import StringFormattingException
|
from ytdl_sub.utils.exceptions import StringFormattingException
|
||||||
from ytdl_sub.utils.logger import Logger
|
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.validators.string_formatter_validators import ListFormatterValidator
|
||||||
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
||||||
|
|
||||||
|
|
@ -53,10 +52,9 @@ class FilterExcludePlugin(Plugin[FilterExcludeOptions]):
|
||||||
return entry
|
return entry
|
||||||
|
|
||||||
for formatter in self.plugin_options.list:
|
for formatter in self.plugin_options.list:
|
||||||
out = ScriptUtils.bool_formatter_output(
|
should_exclude = self.overrides.evaluate_boolean(formatter=formatter, entry=entry)
|
||||||
self.overrides.apply_formatter(formatter=formatter, entry=entry)
|
|
||||||
)
|
if should_exclude:
|
||||||
if bool(out):
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"Filtering '%s' from the filter %s evaluating to True",
|
"Filtering '%s' from the filter %s evaluating to True",
|
||||||
entry.title,
|
entry.title,
|
||||||
|
|
|
||||||
|
|
@ -61,10 +61,10 @@ class FilterIncludePlugin(Plugin[FilterIncludeOptions]):
|
||||||
return entry
|
return entry
|
||||||
|
|
||||||
for formatter in self.plugin_options.list:
|
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)
|
self.overrides.apply_formatter(formatter=formatter, entry=entry)
|
||||||
)
|
)
|
||||||
if not bool(out):
|
if not should_exclude:
|
||||||
logger.info(
|
logger.info(
|
||||||
"Filtering '%s' from the filter %s evaluating to False",
|
"Filtering '%s' from the filter %s evaluating to False",
|
||||||
entry.title,
|
entry.title,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from ytdl_sub.config.plugin.plugin import Plugin
|
from ytdl_sub.config.plugin.plugin import Plugin
|
||||||
from ytdl_sub.config.validators.options import ToggleableOptionsDictValidator
|
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.file_path_validators import StringFormatterFileNameValidator
|
||||||
from ytdl_sub.validators.nfo_validators import NfoTagsValidator
|
from ytdl_sub.validators.nfo_validators import NfoTagsValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator
|
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.string_formatter_validators import StringFormatterValidator
|
||||||
from ytdl_sub.validators.validators import BoolValidator
|
|
||||||
|
|
||||||
|
|
||||||
class SharedNfoTagsOptions(ToggleableOptionsDictValidator):
|
class SharedNfoTagsOptions(ToggleableOptionsDictValidator):
|
||||||
|
|
@ -54,8 +53,8 @@ class SharedNfoTagsOptions(ToggleableOptionsDictValidator):
|
||||||
)
|
)
|
||||||
self._tags = self._validate_key_if_present(key="tags", validator=NfoTagsValidator)
|
self._tags = self._validate_key_if_present(key="tags", validator=NfoTagsValidator)
|
||||||
self._kodi_safe = self._validate_key_if_present(
|
self._kodi_safe = self._validate_key_if_present(
|
||||||
key="kodi_safe", validator=BoolValidator, default=False
|
key="kodi_safe", validator=OverridesBooleanFormatterValidator, default="False"
|
||||||
).value
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nfo_name(self) -> StringFormatterFileNameValidator:
|
def nfo_name(self) -> StringFormatterFileNameValidator:
|
||||||
|
|
@ -81,9 +80,9 @@ class SharedNfoTagsOptions(ToggleableOptionsDictValidator):
|
||||||
return self._tags
|
return self._tags
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def kodi_safe(self) -> Optional[bool]:
|
def kodi_safe(self) -> OverridesBooleanFormatterValidator:
|
||||||
"""
|
"""
|
||||||
:expected type: Optional[Boolean]
|
:expected type: OverridesBooleanFormatterValidator
|
||||||
:description:
|
:description:
|
||||||
Defaults to False. Kodi does not support > 3-byte unicode characters, which include
|
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
|
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:
|
if not nfo_tags:
|
||||||
return
|
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_root = to_max_3_byte_utf8_string(nfo_root)
|
||||||
nfo_tags = {
|
nfo_tags = {
|
||||||
to_max_3_byte_utf8_string(key): [
|
to_max_3_byte_utf8_string(key): [
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,12 @@ class SubtitlesPlugin(Plugin[SubtitleOptions]):
|
||||||
plugin_options_type = SubtitleOptions
|
plugin_options_type = SubtitleOptions
|
||||||
|
|
||||||
def ytdl_options(self) -> Optional[Dict]:
|
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:
|
if self.plugin_options.embed_subtitles:
|
||||||
builder.add(
|
builder.add(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
|
from typing import Dict
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.config.overrides import Overrides
|
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})"
|
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:
|
def randomized_float(self) -> float:
|
||||||
"""
|
"""
|
||||||
Returns
|
Returns
|
||||||
|
|
@ -70,6 +87,9 @@ class ThrottleProtectionOptions(ToggleableOptionsDictValidator):
|
||||||
presets:
|
presets:
|
||||||
my_example_preset:
|
my_example_preset:
|
||||||
throttle_protection:
|
throttle_protection:
|
||||||
|
sleep_per_request_s:
|
||||||
|
min: 5.5
|
||||||
|
max: 10.4
|
||||||
sleep_per_download_s:
|
sleep_per_download_s:
|
||||||
min: 2.2
|
min: 2.2
|
||||||
max: 10.8
|
max: 10.8
|
||||||
|
|
@ -84,6 +104,7 @@ class ThrottleProtectionOptions(ToggleableOptionsDictValidator):
|
||||||
|
|
||||||
_optional_keys = {
|
_optional_keys = {
|
||||||
"enable",
|
"enable",
|
||||||
|
"sleep_per_request_s",
|
||||||
"sleep_per_download_s",
|
"sleep_per_download_s",
|
||||||
"sleep_per_subscription_s",
|
"sleep_per_subscription_s",
|
||||||
"max_downloads_per_subscription",
|
"max_downloads_per_subscription",
|
||||||
|
|
@ -93,6 +114,9 @@ class ThrottleProtectionOptions(ToggleableOptionsDictValidator):
|
||||||
def __init__(self, name, value):
|
def __init__(self, name, value):
|
||||||
super().__init__(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(
|
self._sleep_per_download_s = self._validate_key_if_present(
|
||||||
key="sleep_per_download_s", validator=RandomizedRangeValidator
|
key="sleep_per_download_s", validator=RandomizedRangeValidator
|
||||||
)
|
)
|
||||||
|
|
@ -106,6 +130,18 @@ class ThrottleProtectionOptions(ToggleableOptionsDictValidator):
|
||||||
key="subscription_download_probability", validator=ProbabilityValidator
|
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
|
@property
|
||||||
def sleep_per_download_s(self) -> Optional[RandomizedRangeValidator]:
|
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()
|
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:
|
def initialize_subscription(self) -> bool:
|
||||||
if self.plugin_options.subscription_download_probability:
|
if self.plugin_options.subscription_download_probability:
|
||||||
proba = self.plugin_options.subscription_download_probability.value
|
proba = self.plugin_options.subscription_download_probability.value
|
||||||
|
|
|
||||||
|
|
@ -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):
|
class TvShowCollectionPresets(PrebuiltPresets):
|
||||||
preset_names = {
|
preset_names = {
|
||||||
"Kodi TV Show Collection",
|
"Kodi TV Show Collection",
|
||||||
|
|
@ -48,24 +26,3 @@ class TvShowCollectionOldPresets(PrebuiltPresets):
|
||||||
"jellyfin_tv_show_collection",
|
"jellyfin_tv_show_collection",
|
||||||
"plex_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",
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ presets:
|
||||||
thumbnail_name: "{thumbnail_file_name}"
|
thumbnail_name: "{thumbnail_file_name}"
|
||||||
info_json_name: "{episode_file_path}.{info_json_ext}"
|
info_json_name: "{episode_file_path}.{info_json_ext}"
|
||||||
maintain_download_archive: True
|
maintain_download_archive: True
|
||||||
|
keep_files_date_eval: "{episode_date_standardized}"
|
||||||
|
|
||||||
ytdl_options:
|
ytdl_options:
|
||||||
break_on_existing: True
|
break_on_existing: True
|
||||||
|
|
@ -36,14 +37,11 @@ presets:
|
||||||
tv_show_genre: "{subscription_indent_1}"
|
tv_show_genre: "{subscription_indent_1}"
|
||||||
tv_show_content_rating: "{subscription_indent_2}"
|
tv_show_content_rating: "{subscription_indent_2}"
|
||||||
season_directory_name: "Season {season_number_padded}"
|
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_plot: "{webpage_url}\n\n{description}"
|
||||||
episode_year: "{upload_year}"
|
|
||||||
episode_content_rating: "{tv_show_content_rating}"
|
episode_content_rating: "{tv_show_content_rating}"
|
||||||
episode_date_standardized: "{upload_date_standardized}"
|
episode_date_standardized: "{upload_date_standardized}"
|
||||||
episode_file_name: "s{season_number_padded}.e{episode_number_padded} - {file_title}"
|
episode_file_name: "s{season_number_padded}.e{episode_number_padded} - {file_title}"
|
||||||
episode_file_path: "{season_directory_name_sanitized}/{episode_file_name_sanitized}"
|
episode_file_path: "{season_directory_name_sanitized}/{episode_file_name_sanitized}"
|
||||||
thumbnail_file_name: "{episode_file_path}-thumb.jpg"
|
thumbnail_file_name: "{episode_file_path}-thumb.jpg"
|
||||||
|
episode_year: "{%slice(episode_date_standardized, 0, 4)}"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,22 +35,125 @@ presets:
|
||||||
|
|
||||||
# TV show from one or more sources. Uses {url}'s avatar and banner as poster and fanart
|
# TV show from one or more sources. Uses {url}'s avatar and banner as poster and fanart
|
||||||
_tv_show_by_date:
|
_tv_show_by_date:
|
||||||
preset: "_multi_url_bilateral"
|
preset:
|
||||||
|
- "_multi_url_bilateral"
|
||||||
|
- "_tv_show_by_date_asserts"
|
||||||
overrides:
|
overrides:
|
||||||
avatar_uncropped_thumbnail_file_name: "{tv_show_poster_file_name}"
|
avatar_uncropped_thumbnail_file_name: "{tv_show_poster_file_name}"
|
||||||
banner_uncropped_thumbnail_file_name: "{tv_show_fanart_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:
|
_season_by_year:
|
||||||
|
preset: "_tv_show_by_date_season_episode_ordering"
|
||||||
overrides:
|
overrides:
|
||||||
season_number: "{upload_year}"
|
tv_show_by_date_season_ordering: "upload-year"
|
||||||
season_number_padded: "{season_number}"
|
|
||||||
|
|
||||||
_season_by_year_month:
|
_season_by_year_month:
|
||||||
|
preset: "_tv_show_by_date_season_episode_ordering"
|
||||||
overrides:
|
overrides:
|
||||||
season_number: "{upload_year}{upload_month_padded}"
|
tv_show_by_date_season_ordering: "upload-year-month"
|
||||||
season_number_padded: "{season_number}"
|
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
|
|
@ -58,26 +161,22 @@ presets:
|
||||||
preset:
|
preset:
|
||||||
- "_season_by_year_month"
|
- "_season_by_year_month"
|
||||||
overrides:
|
overrides:
|
||||||
episode_number: "{upload_day}{upload_date_index_padded}"
|
tv_show_by_date_episode_ordering: "upload-day"
|
||||||
episode_number_padded: "{upload_day_padded}{upload_date_index_padded}"
|
|
||||||
|
|
||||||
season_by_year__episode_by_month_day:
|
season_by_year__episode_by_month_day:
|
||||||
preset:
|
preset:
|
||||||
- "_season_by_year"
|
- "_season_by_year"
|
||||||
overrides:
|
overrides:
|
||||||
episode_number: "{upload_month}{upload_day_padded}{upload_date_index_padded}"
|
tv_show_by_date_episode_ordering: "upload-month-day"
|
||||||
episode_number_padded: "{upload_month_padded}{upload_day_padded}{upload_date_index_padded}"
|
|
||||||
|
|
||||||
season_by_year__episode_by_month_day_reversed:
|
season_by_year__episode_by_month_day_reversed:
|
||||||
preset:
|
preset:
|
||||||
- "_season_by_year"
|
- "_season_by_year"
|
||||||
overrides:
|
overrides:
|
||||||
episode_number: "{upload_day_of_year_reversed}{upload_date_index_reversed_padded}"
|
tv_show_by_date_episode_ordering: "upload-month-day-reversed"
|
||||||
episode_number_padded: "{upload_day_of_year_reversed_padded}{upload_date_index_reversed_padded}"
|
|
||||||
|
|
||||||
season_by_year__episode_by_download_index:
|
season_by_year__episode_by_download_index:
|
||||||
preset:
|
preset:
|
||||||
- "_season_by_year"
|
- "_season_by_year"
|
||||||
overrides:
|
overrides:
|
||||||
episode_number: "{download_index}"
|
tv_show_by_date_episode_ordering: "download-index"
|
||||||
episode_number_padded: "{download_index_padded6}"
|
|
||||||
|
|
|
||||||
|
|
@ -39,31 +39,68 @@ presets:
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
|
|
||||||
season_by_collection__episode_by_year_month_day:
|
_tv_show_collection_episode_ordering:
|
||||||
overrides:
|
overrides:
|
||||||
episode_number: "{upload_year_truncated}{upload_month_padded}{upload_day_padded}{upload_date_index_padded}"
|
tv_show_collection_episode_ordering: >-
|
||||||
episode_number_padded: "{episode_number}"
|
{ %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:
|
season_by_collection__episode_by_year_month_day_reversed:
|
||||||
|
preset: "_tv_show_collection_episode_ordering"
|
||||||
overrides:
|
overrides:
|
||||||
episode_number: "{upload_year_truncated_reversed}{upload_month_reversed_padded}{upload_day_reversed_padded}{upload_date_index_reversed_padded}"
|
tv_show_collection_episode_ordering: "upload-year-month-day-reversed"
|
||||||
episode_number_padded: "{episode_number}"
|
|
||||||
|
|
||||||
season_by_collection__episode_by_playlist_index:
|
season_by_collection__episode_by_playlist_index:
|
||||||
|
preset: "_tv_show_collection_episode_ordering"
|
||||||
overrides:
|
overrides:
|
||||||
episode_number: "{playlist_index}"
|
tv_show_collection_episode_ordering: "playlist-index"
|
||||||
episode_number_padded: "{playlist_index_padded6}"
|
|
||||||
|
|
||||||
season_by_collection__episode_by_playlist_index_reversed:
|
season_by_collection__episode_by_playlist_index_reversed:
|
||||||
|
preset: "_tv_show_collection_episode_ordering"
|
||||||
overrides:
|
overrides:
|
||||||
episode_number: "{playlist_index_reversed}"
|
tv_show_collection_episode_ordering: "playlist-index-reversed"
|
||||||
episode_number_padded: "{playlist_index_reversed_padded6}"
|
|
||||||
|
|
||||||
##############
|
##############
|
||||||
|
|
||||||
_tv_show_collection:
|
_tv_show_collection:
|
||||||
preset:
|
preset:
|
||||||
- "_tv_show_collection_bilateral"
|
- "_tv_show_collection_bilateral"
|
||||||
|
- "_tv_show_collection_asserts"
|
||||||
|
|
||||||
download:
|
download:
|
||||||
- url: "{collection_season_1_url}"
|
- url: "{collection_season_1_url}"
|
||||||
|
|
@ -1017,6 +1054,16 @@ presets:
|
||||||
ytdl_options:
|
ytdl_options:
|
||||||
playlist_items: "-1:0:-1"
|
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
|
# DEPRECATED SEASON PRESETS
|
||||||
|
|
|
||||||
|
|
@ -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.json_functions import JsonFunctions
|
||||||
from ytdl_sub.script.functions.map_functions import MapFunctions
|
from ytdl_sub.script.functions.map_functions import MapFunctions
|
||||||
from ytdl_sub.script.functions.numeric_functions import NumericFunctions
|
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.regex_functions import RegexFunctions
|
||||||
from ytdl_sub.script.functions.string_functions import StringFunctions
|
from ytdl_sub.script.functions.string_functions import StringFunctions
|
||||||
from ytdl_sub.script.types.resolvable import Resolvable
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
|
|
@ -26,6 +27,7 @@ class Functions(
|
||||||
RegexFunctions,
|
RegexFunctions,
|
||||||
DateFunctions,
|
DateFunctions,
|
||||||
JsonFunctions,
|
JsonFunctions,
|
||||||
|
PrintFunctions,
|
||||||
):
|
):
|
||||||
_custom_functions: Dict[str, Callable[..., Resolvable]] = {}
|
_custom_functions: Dict[str, Callable[..., Resolvable]] = {}
|
||||||
|
|
||||||
|
|
|
||||||
67
src/ytdl_sub/script/functions/print_functions.py
Normal file
67
src/ytdl_sub/script/functions/print_functions.py
Normal 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
|
||||||
|
|
@ -127,12 +127,12 @@ class StringFunctions:
|
||||||
return Array([String(split_val) for split_val in string.value.split(sep=sep.value)])
|
return Array([String(split_val) for split_val in string.value.split(sep=sep.value)])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def concat(*values: String) -> String:
|
def concat(*values: AnyArgument) -> String:
|
||||||
"""
|
"""
|
||||||
:description:
|
:description:
|
||||||
Concatenate multiple Strings into a single String.
|
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
|
@staticmethod
|
||||||
def pad(string: String, length: Integer, char: String) -> String:
|
def pad(string: String, length: Integer, char: String) -> String:
|
||||||
|
|
@ -176,3 +176,41 @@ class StringFunctions:
|
||||||
# World
|
# World
|
||||||
"""
|
"""
|
||||||
return String(string.value.encode("utf-8").decode("unicode_escape"))
|
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())
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ from ytdl_sub.downloaders.source_plugin import SourcePlugin
|
||||||
from ytdl_sub.downloaders.url.downloader import MultiUrlDownloader
|
from ytdl_sub.downloaders.url.downloader import MultiUrlDownloader
|
||||||
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
from ytdl_sub.downloaders.ytdl_options_builder import YTDLOptionsBuilder
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
||||||
from ytdl_sub.subscriptions.base_subscription import BaseSubscription
|
from ytdl_sub.subscriptions.base_subscription import BaseSubscription
|
||||||
from ytdl_sub.subscriptions.subscription_ytdl_options import SubscriptionYTDLOptions
|
from ytdl_sub.subscriptions.subscription_ytdl_options import SubscriptionYTDLOptions
|
||||||
from ytdl_sub.utils.datetime import to_date_range
|
from ytdl_sub.utils.datetime import to_date_range
|
||||||
|
|
@ -215,9 +216,23 @@ class SubscriptionDownload(BaseSubscription, ABC):
|
||||||
FileHandler.delete(entry.get_download_thumbnail_path())
|
FileHandler.delete(entry.get_download_thumbnail_path())
|
||||||
FileHandler.delete(entry.get_download_info_json_path())
|
FileHandler.delete(entry.get_download_info_json_path())
|
||||||
|
|
||||||
@classmethod
|
def _preprocess_entry(self, plugins: List[Plugin], entry: Entry) -> Optional[Entry]:
|
||||||
def _preprocess_entry(cls, plugins: List[Plugin], entry: Entry) -> Optional[Entry]:
|
|
||||||
maybe_entry: Optional[Entry] = 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(
|
for plugin in PluginMapping.order_plugins_by(
|
||||||
plugins, PluginOperation.MODIFY_ENTRY_METADATA
|
plugins, PluginOperation.MODIFY_ENTRY_METADATA
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -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 combine_filters
|
||||||
from ytdl_sub.plugins.match_filters import default_filters
|
from ytdl_sub.plugins.match_filters import default_filters
|
||||||
from ytdl_sub.plugins.subtitles import SubtitlesPlugin
|
from ytdl_sub.plugins.subtitles import SubtitlesPlugin
|
||||||
|
from ytdl_sub.plugins.throttle_protection import ThrottleProtectionPlugin
|
||||||
from ytdl_sub.utils.ffmpeg import FFMPEG
|
from ytdl_sub.utils.ffmpeg import FFMPEG
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
||||||
|
|
@ -175,6 +176,7 @@ class SubscriptionYTDLOptions:
|
||||||
self._global_options,
|
self._global_options,
|
||||||
self._output_options,
|
self._output_options,
|
||||||
self._plugin_match_filters,
|
self._plugin_match_filters,
|
||||||
|
self._plugin_ytdl_options(ThrottleProtectionPlugin),
|
||||||
self._plugin_ytdl_options(FormatPlugin),
|
self._plugin_ytdl_options(FormatPlugin),
|
||||||
self._plugin_ytdl_options(AudioExtractPlugin), # will override format
|
self._plugin_ytdl_options(AudioExtractPlugin), # will override format
|
||||||
self._user_ytdl_options, # user ytdl options...
|
self._user_ytdl_options, # user ytdl options...
|
||||||
|
|
|
||||||
|
|
@ -220,10 +220,17 @@ class Chapters:
|
||||||
# Timestamp captured, store it
|
# Timestamp captured, store it
|
||||||
if match := Timestamp.TIMESTAMP_REGEX.search(line):
|
if match := Timestamp.TIMESTAMP_REGEX.search(line):
|
||||||
timestamp_str = match.group(1)
|
timestamp_str = match.group(1)
|
||||||
timestamps.append(Timestamp.from_str(timestamp_str))
|
|
||||||
|
|
||||||
# Remove timestamp and surrounding whitespace from it
|
# Remove timestamp and surrounding whitespace from it
|
||||||
title_str = re.sub(f"\\s*{re.escape(timestamp_str)}\\s*", " ", line).strip()
|
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)
|
titles.append(title_str)
|
||||||
|
|
||||||
# If more than 3 timestamps were parsed, return it
|
# If more than 3 timestamps were parsed, return it
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
from datetime import datetime
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import Set
|
from typing import Set
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
@ -73,6 +74,20 @@ class StringFormatterValidator(StringValidator):
|
||||||
return resolved
|
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
|
# pylint: disable=line-too-long
|
||||||
class OverridesStringFormatterValidator(StringFormatterValidator):
|
class OverridesStringFormatterValidator(StringFormatterValidator):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ class DownloadMapping:
|
||||||
DownloadMapping for the entry
|
DownloadMapping for the entry
|
||||||
"""
|
"""
|
||||||
return DownloadMapping(
|
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,
|
extractor=entry.download_archive_extractor,
|
||||||
file_names=set(),
|
file_names=set(),
|
||||||
)
|
)
|
||||||
|
|
@ -248,20 +248,18 @@ class DownloadMappings:
|
||||||
del self._entry_mappings[entry_id]
|
del self._entry_mappings[entry_id]
|
||||||
return self
|
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
|
Parameters
|
||||||
----------
|
----------
|
||||||
upload_date_standardized
|
standardized_date
|
||||||
A standardized upload date
|
A standardized upload date
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
Number of entries in the mapping with this upload date
|
Number of entries in the mapping with this upload date
|
||||||
"""
|
"""
|
||||||
return len(
|
return len([_ for _ in self._entry_mappings.values() if _.upload_date == standardized_date])
|
||||||
[_ for _ in self._entry_mappings.values() if _.upload_date == upload_date_standardized]
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_num_entries(self) -> int:
|
def get_num_entries(self) -> int:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from typing import List
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from conftest import assert_logs
|
from conftest import assert_logs
|
||||||
from expected_download import assert_expected_downloads
|
from expected_download import assert_expected_downloads
|
||||||
|
|
@ -17,6 +19,7 @@ def subscription_dict(output_directory):
|
||||||
"subscription_indent_1": "Acoustic",
|
"subscription_indent_1": "Acoustic",
|
||||||
"music_directory": output_directory,
|
"music_directory": output_directory,
|
||||||
},
|
},
|
||||||
|
"throttle_protection": {"sleep_per_request_s": {"min": 0.1, "max": 0.5}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -34,6 +37,21 @@ class TestSoundcloudDiscography:
|
||||||
output_directory,
|
output_directory,
|
||||||
dry_run,
|
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(
|
discography_subscription = Subscription.from_dict(
|
||||||
preset_dict=subscription_dict,
|
preset_dict=subscription_dict,
|
||||||
preset_name="j_b",
|
preset_name="j_b",
|
||||||
|
|
@ -49,6 +67,7 @@ class TestSoundcloudDiscography:
|
||||||
output_directory=output_directory,
|
output_directory=output_directory,
|
||||||
dry_run=dry_run,
|
dry_run=dry_run,
|
||||||
expected_download_summary_file_name="soundcloud/test_soundcloud_discography.json",
|
expected_download_summary_file_name="soundcloud/test_soundcloud_discography.json",
|
||||||
|
ignore_md5_hashes_for=ignored_mp3s,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Ensure another invocation will hit ExistingVideoReached
|
# Ensure another invocation will hit ExistingVideoReached
|
||||||
|
|
@ -65,4 +84,5 @@ class TestSoundcloudDiscography:
|
||||||
output_directory=output_directory,
|
output_directory=output_directory,
|
||||||
dry_run=dry_run,
|
dry_run=dry_run,
|
||||||
expected_download_summary_file_name="soundcloud/test_soundcloud_discography.json",
|
expected_download_summary_file_name="soundcloud/test_soundcloud_discography.json",
|
||||||
|
ignore_md5_hashes_for=ignored_mp3s,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ from pathlib import Path
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
@ -53,6 +54,7 @@ def mock_entry_dict_factory(mock_downloaded_file_path) -> Callable:
|
||||||
is_youtube_channel: bool = False,
|
is_youtube_channel: bool = False,
|
||||||
mock_download_to_working_dir: bool = True,
|
mock_download_to_working_dir: bool = True,
|
||||||
is_extracted_audio: bool = False,
|
is_extracted_audio: bool = False,
|
||||||
|
release_date: Optional[str] = None,
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
entry_dict = {
|
entry_dict = {
|
||||||
v.uid.metadata_key: uid,
|
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",
|
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:
|
if is_youtube_channel:
|
||||||
entry_dict[v.playlist_metadata.metadata_key]["thumbnails"] = [
|
entry_dict[v.playlist_metadata.metadata_key]["thumbnails"] = [
|
||||||
{
|
{
|
||||||
|
|
@ -153,6 +159,7 @@ def mock_download_collection_entries(
|
||||||
mock_entry_dict_factory(
|
mock_entry_dict_factory(
|
||||||
uid="21-1",
|
uid="21-1",
|
||||||
upload_date="20210808",
|
upload_date="20210808",
|
||||||
|
release_date="20010808",
|
||||||
playlist_title="Download First",
|
playlist_title="Download First",
|
||||||
playlist_index=1,
|
playlist_index=1,
|
||||||
playlist_count=4,
|
playlist_count=4,
|
||||||
|
|
@ -163,6 +170,7 @@ def mock_download_collection_entries(
|
||||||
mock_entry_dict_factory(
|
mock_entry_dict_factory(
|
||||||
uid="20-1",
|
uid="20-1",
|
||||||
upload_date="20200808",
|
upload_date="20200808",
|
||||||
|
release_date="20000808",
|
||||||
playlist_title="Download First",
|
playlist_title="Download First",
|
||||||
playlist_index=2,
|
playlist_index=2,
|
||||||
playlist_count=4,
|
playlist_count=4,
|
||||||
|
|
@ -173,6 +181,7 @@ def mock_download_collection_entries(
|
||||||
mock_entry_dict_factory(
|
mock_entry_dict_factory(
|
||||||
uid="20-2",
|
uid="20-2",
|
||||||
upload_date="20200808",
|
upload_date="20200808",
|
||||||
|
release_date="20000808",
|
||||||
playlist_title="Download First",
|
playlist_title="Download First",
|
||||||
playlist_index=3,
|
playlist_index=3,
|
||||||
playlist_count=4,
|
playlist_count=4,
|
||||||
|
|
@ -183,6 +192,7 @@ def mock_download_collection_entries(
|
||||||
mock_entry_dict_factory(
|
mock_entry_dict_factory(
|
||||||
uid="20-3",
|
uid="20-3",
|
||||||
upload_date="20200807",
|
upload_date="20200807",
|
||||||
|
release_date="20000807",
|
||||||
playlist_title="Download First",
|
playlist_title="Download First",
|
||||||
playlist_index=4,
|
playlist_index=4,
|
||||||
playlist_count=4,
|
playlist_count=4,
|
||||||
|
|
@ -196,6 +206,7 @@ def mock_download_collection_entries(
|
||||||
mock_entry_dict_factory(
|
mock_entry_dict_factory(
|
||||||
uid="20-3",
|
uid="20-3",
|
||||||
upload_date="20200807",
|
upload_date="20200807",
|
||||||
|
release_date="20000807",
|
||||||
playlist_title="Download Second",
|
playlist_title="Download Second",
|
||||||
playlist_index=1,
|
playlist_index=1,
|
||||||
playlist_count=5,
|
playlist_count=5,
|
||||||
|
|
@ -206,6 +217,7 @@ def mock_download_collection_entries(
|
||||||
mock_entry_dict_factory(
|
mock_entry_dict_factory(
|
||||||
uid="20-4",
|
uid="20-4",
|
||||||
upload_date="20200806",
|
upload_date="20200806",
|
||||||
|
release_date="20000806",
|
||||||
playlist_title="Download Second",
|
playlist_title="Download Second",
|
||||||
playlist_index=2,
|
playlist_index=2,
|
||||||
playlist_count=5,
|
playlist_count=5,
|
||||||
|
|
@ -216,6 +228,7 @@ def mock_download_collection_entries(
|
||||||
mock_entry_dict_factory(
|
mock_entry_dict_factory(
|
||||||
uid="20-5",
|
uid="20-5",
|
||||||
upload_date="20200706",
|
upload_date="20200706",
|
||||||
|
release_date="20000706",
|
||||||
playlist_title="Download Second",
|
playlist_title="Download Second",
|
||||||
playlist_index=3,
|
playlist_index=3,
|
||||||
playlist_count=5,
|
playlist_count=5,
|
||||||
|
|
@ -226,6 +239,7 @@ def mock_download_collection_entries(
|
||||||
mock_entry_dict_factory(
|
mock_entry_dict_factory(
|
||||||
uid="20-6",
|
uid="20-6",
|
||||||
upload_date="20200706",
|
upload_date="20200706",
|
||||||
|
release_date="20000706",
|
||||||
playlist_title="Download Second",
|
playlist_title="Download Second",
|
||||||
playlist_index=4,
|
playlist_index=4,
|
||||||
playlist_count=5,
|
playlist_count=5,
|
||||||
|
|
@ -236,6 +250,7 @@ def mock_download_collection_entries(
|
||||||
mock_entry_dict_factory(
|
mock_entry_dict_factory(
|
||||||
uid="20-7",
|
uid="20-7",
|
||||||
upload_date="20200606",
|
upload_date="20200606",
|
||||||
|
release_date="20000606",
|
||||||
playlist_title="Download Second",
|
playlist_title="Download Second",
|
||||||
playlist_index=5,
|
playlist_index=5,
|
||||||
playlist_count=5,
|
playlist_count=5,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from unittest.mock import patch
|
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.downloaders.ytdlp import YTDLP
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.subscriptions.subscription import Subscription
|
from ytdl_sub.subscriptions.subscription import Subscription
|
||||||
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
from ytdl_sub.utils.file_handler import FileHandler
|
from ytdl_sub.utils.file_handler import FileHandler
|
||||||
from ytdl_sub.utils.thumbnail import try_convert_download_thumbnail
|
from ytdl_sub.utils.thumbnail import try_convert_download_thumbnail
|
||||||
|
|
||||||
|
|
@ -223,3 +225,35 @@ class TestOutputOptions:
|
||||||
dry_run=False,
|
dry_run=False,
|
||||||
expected_download_summary_file_name="plugins/output_options/test_missing_thumb.json",
|
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)
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,30 @@
|
||||||
|
import re
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from expected_download import assert_expected_downloads
|
from expected_download import assert_expected_downloads
|
||||||
from expected_transaction_log import assert_transaction_log_matches
|
from expected_transaction_log import assert_transaction_log_matches
|
||||||
|
|
||||||
from ytdl_sub.config.config_file import ConfigFile
|
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.prebuilt_presets.tv_show import TvShowByDatePresets
|
||||||
|
from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError
|
||||||
from ytdl_sub.subscriptions.subscription import Subscription
|
from ytdl_sub.subscriptions.subscription import Subscription
|
||||||
|
|
||||||
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS = {
|
DEFAULT_SEASON_ORDERING = "upload-year"
|
||||||
"Kodi TV Show by Date": "kodi_tv_show_by_date",
|
DEFAULT_EPISODE_ORDERING = "upload-month-day"
|
||||||
"Jellyfin TV Show by Date": "jellyfin_tv_show_by_date",
|
|
||||||
"Plex TV Show by Date": "plex_tv_show_by_date",
|
|
||||||
}
|
|
||||||
|
|
||||||
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:
|
class TestPrebuiltTVShowPresets:
|
||||||
|
|
@ -24,24 +35,28 @@ class TestPrebuiltTVShowPresets:
|
||||||
subscription_name: str,
|
subscription_name: str,
|
||||||
output_directory: str,
|
output_directory: str,
|
||||||
tv_show_preset: str,
|
tv_show_preset: str,
|
||||||
episode_ordering_preset: str,
|
season_ordering: str,
|
||||||
|
episode_ordering: str,
|
||||||
is_youtube_channel: bool = True,
|
is_youtube_channel: bool = True,
|
||||||
is_many_urls: bool = False,
|
is_many_urls: bool = False,
|
||||||
):
|
):
|
||||||
|
|
||||||
expected_summary_name = "unit/{}/{}/is_yt_{}{}".format(
|
expected_summary_name = "integration/by-date/{}/{}/{}/is_yt_{}{}".format(
|
||||||
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS[tv_show_preset],
|
tv_show_preset.split(" ")[0],
|
||||||
episode_ordering_preset,
|
season_ordering,
|
||||||
|
episode_ordering,
|
||||||
int(is_youtube_channel),
|
int(is_youtube_channel),
|
||||||
"_many_urls" if is_many_urls else "",
|
"_many_urls" if is_many_urls else "",
|
||||||
)
|
)
|
||||||
|
|
||||||
preset_dict = {
|
preset_dict = {
|
||||||
"preset": [tv_show_preset, episode_ordering_preset],
|
"preset": tv_show_preset,
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"url": "https://your.name.here",
|
"url": "https://your.name.here",
|
||||||
"tv_show_name": "Best Prebuilt TV Show by Date",
|
"tv_show_name": "Best Prebuilt TV Show by Date",
|
||||||
"tv_show_directory": output_directory,
|
"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:
|
if is_many_urls:
|
||||||
|
|
@ -67,16 +82,19 @@ class TestPrebuiltTVShowPresets:
|
||||||
)
|
)
|
||||||
|
|
||||||
###################################### Perform reformat
|
###################################### Perform reformat
|
||||||
reformatted_tv_show_structure_preset = "season_by_year__episode_by_download_index"
|
reformatted_season_ordering = "upload-year"
|
||||||
reformatted_expected_summary_name = "unit/{}/{}/is_yt_{}{}".format(
|
reformatted_episode_ordering = "download-index"
|
||||||
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS[tv_show_preset],
|
|
||||||
reformatted_tv_show_structure_preset,
|
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),
|
int(is_youtube_channel),
|
||||||
"_many_urls" if is_many_urls else "",
|
"_many_urls" if is_many_urls else "",
|
||||||
)
|
)
|
||||||
|
|
||||||
reformatted_preset_dict = {
|
reformatted_preset_dict = {
|
||||||
"preset": [tv_show_preset, reformatted_tv_show_structure_preset],
|
"preset": tv_show_preset,
|
||||||
"output_options": {
|
"output_options": {
|
||||||
"migrated_download_archive_name": ".ytdl-sub-{tv_show_name_sanitized}-download-archive.json"
|
"migrated_download_archive_name": ".ytdl-sub-{tv_show_name_sanitized}-download-archive.json"
|
||||||
},
|
},
|
||||||
|
|
@ -84,6 +102,8 @@ class TestPrebuiltTVShowPresets:
|
||||||
"url": "https://your.name.here",
|
"url": "https://your.name.here",
|
||||||
"tv_show_name": "Best Prebuilt TV Show by Date",
|
"tv_show_name": "Best Prebuilt TV Show by Date",
|
||||||
"tv_show_directory": output_directory,
|
"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:
|
if is_many_urls:
|
||||||
|
|
@ -98,7 +118,7 @@ class TestPrebuiltTVShowPresets:
|
||||||
output_directory=output_directory,
|
output_directory=output_directory,
|
||||||
transaction_log=reformatted_transaction_log,
|
transaction_log=reformatted_transaction_log,
|
||||||
transaction_log_summary_file_name=(
|
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(
|
assert_expected_downloads(
|
||||||
|
|
@ -123,11 +143,13 @@ class TestPrebuiltTVShowPresets:
|
||||||
subscription_name=subscription_name,
|
subscription_name=subscription_name,
|
||||||
output_directory=output_directory,
|
output_directory=output_directory,
|
||||||
tv_show_preset=tv_show_preset,
|
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(
|
@pytest.mark.parametrize(
|
||||||
"episode_ordering_preset", TvShowByDateEpisodeFormattingPresets.preset_names
|
"season_ordering, episode_ordering",
|
||||||
|
VALID_ORDERING_COMBOS,
|
||||||
)
|
)
|
||||||
def test_episode_ordering_presets(
|
def test_episode_ordering_presets(
|
||||||
self,
|
self,
|
||||||
|
|
@ -135,7 +157,8 @@ class TestPrebuiltTVShowPresets:
|
||||||
subscription_name,
|
subscription_name,
|
||||||
output_directory,
|
output_directory,
|
||||||
mock_download_collection_entries,
|
mock_download_collection_entries,
|
||||||
episode_ordering_preset: str,
|
season_ordering: str,
|
||||||
|
episode_ordering: str,
|
||||||
):
|
):
|
||||||
|
|
||||||
with mock_download_collection_entries(
|
with mock_download_collection_entries(
|
||||||
|
|
@ -146,5 +169,91 @@ class TestPrebuiltTVShowPresets:
|
||||||
subscription_name=subscription_name,
|
subscription_name=subscription_name,
|
||||||
output_directory=output_directory,
|
output_directory=output_directory,
|
||||||
tv_show_preset="Kodi TV Show by Date",
|
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,
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import re
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import List
|
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 expected_transaction_log import assert_transaction_log_matches
|
||||||
|
|
||||||
from ytdl_sub.config.config_file import ConfigFile
|
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.prebuilt_presets.tv_show import TvShowCollectionPresets
|
||||||
|
from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError
|
||||||
from ytdl_sub.subscriptions.subscription import Subscription
|
from ytdl_sub.subscriptions.subscription import Subscription
|
||||||
|
|
||||||
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS = {
|
DEFAULT_EPISODE_ORDERING = "upload-year-month-day"
|
||||||
"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"
|
|
||||||
|
|
||||||
|
|
||||||
class TestPrebuiltTvShowCollectionPresets:
|
class TestPrebuiltTvShowCollectionPresets:
|
||||||
|
|
@ -27,22 +22,19 @@ class TestPrebuiltTvShowCollectionPresets:
|
||||||
subscription_name: str,
|
subscription_name: str,
|
||||||
output_directory: str,
|
output_directory: str,
|
||||||
media_player_preset: str,
|
media_player_preset: str,
|
||||||
tv_show_structure_preset: str,
|
episode_ordering: str,
|
||||||
season_indices: List[int],
|
season_indices: List[int],
|
||||||
is_youtube_channel: bool = True,
|
is_youtube_channel: bool = True,
|
||||||
):
|
):
|
||||||
expected_summary_name = "unit/{}/{}/s_{}/is_yt_{}".format(
|
expected_summary_name = "integration/collection/{}/{}/s_{}/is_yt_{}".format(
|
||||||
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS[media_player_preset],
|
media_player_preset.split(" ")[0],
|
||||||
tv_show_structure_preset,
|
episode_ordering,
|
||||||
len(season_indices),
|
len(season_indices),
|
||||||
int(is_youtube_channel),
|
int(is_youtube_channel),
|
||||||
)
|
)
|
||||||
parent_presets: List[str] = [media_player_preset, tv_show_structure_preset]
|
|
||||||
|
|
||||||
overrides: Dict[str, str] = {}
|
overrides: Dict[str, str] = {}
|
||||||
for season_index in season_indices:
|
for season_index in season_indices:
|
||||||
parent_presets.append(f"collection_season_{season_index}")
|
|
||||||
|
|
||||||
overrides = dict(
|
overrides = dict(
|
||||||
overrides,
|
overrides,
|
||||||
**{
|
**{
|
||||||
|
|
@ -55,12 +47,13 @@ class TestPrebuiltTvShowCollectionPresets:
|
||||||
config=config,
|
config=config,
|
||||||
preset_name=subscription_name,
|
preset_name=subscription_name,
|
||||||
preset_dict={
|
preset_dict={
|
||||||
"preset": parent_presets,
|
"preset": media_player_preset,
|
||||||
"overrides": dict(
|
"overrides": dict(
|
||||||
overrides,
|
overrides,
|
||||||
**{
|
**{
|
||||||
"tv_show_name": "Best Prebuilt TV Show Collection",
|
"tv_show_name": "Best Prebuilt TV Show Collection",
|
||||||
"tv_show_directory": output_directory,
|
"tv_show_directory": output_directory,
|
||||||
|
"tv_show_collection_episode_ordering": episode_ordering,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -79,12 +72,10 @@ class TestPrebuiltTvShowCollectionPresets:
|
||||||
)
|
)
|
||||||
|
|
||||||
###################################### Perform reformat
|
###################################### Perform reformat
|
||||||
reformatted_tv_show_structure_preset = (
|
reformatted_tv_show_collection_episode_ordering = "playlist-index-reversed"
|
||||||
"season_by_collection__episode_by_playlist_index_reversed"
|
reformatted_expected_summary_name = "integration/collection/{}/{}/s_{}/is_yt_{}".format(
|
||||||
)
|
media_player_preset.split(" ")[0],
|
||||||
reformatted_expected_summary_name = "unit/{}/{}/s_{}/is_yt_{}".format(
|
reformatted_tv_show_collection_episode_ordering,
|
||||||
DEPRECATED_TV_SHOW_PRESET_EQUIVALENTS[media_player_preset],
|
|
||||||
reformatted_tv_show_structure_preset,
|
|
||||||
len(season_indices),
|
len(season_indices),
|
||||||
int(is_youtube_channel),
|
int(is_youtube_channel),
|
||||||
)
|
)
|
||||||
|
|
@ -93,7 +84,7 @@ class TestPrebuiltTvShowCollectionPresets:
|
||||||
config=config,
|
config=config,
|
||||||
preset_name=subscription_name,
|
preset_name=subscription_name,
|
||||||
preset_dict={
|
preset_dict={
|
||||||
"preset": parent_presets + [reformatted_tv_show_structure_preset],
|
"preset": media_player_preset,
|
||||||
"output_options": {
|
"output_options": {
|
||||||
"migrated_download_archive_name": ".ytdl-sub-{tv_show_name_sanitized}-download-archive.json"
|
"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_name": "Best Prebuilt TV Show Collection",
|
||||||
"tv_show_directory": output_directory,
|
"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,
|
output_directory=output_directory,
|
||||||
transaction_log=reformatted_transaction_log,
|
transaction_log=reformatted_transaction_log,
|
||||||
transaction_log_summary_file_name=(
|
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(
|
assert_expected_downloads(
|
||||||
|
|
@ -141,12 +133,20 @@ class TestPrebuiltTvShowCollectionPresets:
|
||||||
subscription_name=subscription_name,
|
subscription_name=subscription_name,
|
||||||
output_directory=output_directory,
|
output_directory=output_directory,
|
||||||
media_player_preset=media_player_preset,
|
media_player_preset=media_player_preset,
|
||||||
tv_show_structure_preset=DEFAULT_EPISODE_ORDERING_PRESET,
|
episode_ordering=DEFAULT_EPISODE_ORDERING,
|
||||||
season_indices=season_indices,
|
season_indices=season_indices,
|
||||||
)
|
)
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@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]])
|
@pytest.mark.parametrize("season_indices", [[1], [1, 2]])
|
||||||
def test_episode_ordering_presets(
|
def test_episode_ordering_presets(
|
||||||
|
|
@ -155,7 +155,7 @@ class TestPrebuiltTvShowCollectionPresets:
|
||||||
subscription_name,
|
subscription_name,
|
||||||
output_directory,
|
output_directory,
|
||||||
mock_download_collection_entries,
|
mock_download_collection_entries,
|
||||||
episode_ordering_preset: str,
|
episode_ordering: str,
|
||||||
season_indices: List[int],
|
season_indices: List[int],
|
||||||
):
|
):
|
||||||
|
|
||||||
|
|
@ -167,6 +167,32 @@ class TestPrebuiltTvShowCollectionPresets:
|
||||||
subscription_name=subscription_name,
|
subscription_name=subscription_name,
|
||||||
output_directory=output_directory,
|
output_directory=output_directory,
|
||||||
media_player_preset="Kodi TV Show Collection",
|
media_player_preset="Kodi TV Show Collection",
|
||||||
tv_show_structure_preset=episode_ordering_preset,
|
episode_ordering=episode_ordering,
|
||||||
season_indices=season_indices,
|
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],
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,18 @@
|
||||||
".ytdl-sub-subscription_test-download-archive.json": "76e202bd03ceef93daaffffee2cfa193",
|
".ytdl-sub-subscription_test-download-archive.json": "76e202bd03ceef93daaffffee2cfa193",
|
||||||
"JMC/Mock Entry 20-1.info.json": "INFO_JSON",
|
"JMC/Mock Entry 20-1.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 20-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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-1.nfo": "5d001a105d2380844db181911d5df5c6",
|
||||||
"JMC/Mock Entry 20-2.info.json": "INFO_JSON",
|
"JMC/Mock Entry 20-2.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 20-2.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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-2.nfo": "dccdded1ca7ebb38d2c9a0e5130bea33",
|
||||||
"JMC/Mock Entry 20-3.info.json": "INFO_JSON",
|
"JMC/Mock Entry 20-3.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 20-3.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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 20-3.nfo": "7b1eab48693161e83c21203b1308b64e",
|
||||||
"JMC/Mock Entry 21-1.info.json": "INFO_JSON",
|
"JMC/Mock Entry 21-1.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 21-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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"
|
"JMC/Mock Entry 21-1.nfo": "3b4b0e6820f80370d6738ce828f14a89"
|
||||||
}
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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 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.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.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 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/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
|
||||||
|
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
|
||||||
|
}
|
||||||
|
|
@ -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 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.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.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 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/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
|
||||||
|
"Best Prebuilt TV Show by Date/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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 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.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.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.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/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
|
||||||
|
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
|
||||||
|
}
|
||||||
|
|
@ -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 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.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.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.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 02/Season02.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||||
|
"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.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.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.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/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
|
||||||
|
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
|
||||||
|
}
|
||||||
|
|
@ -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 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.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.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.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/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
|
||||||
|
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
|
||||||
|
}
|
||||||
|
|
@ -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 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.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.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.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 02/Season02.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||||
|
"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.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.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.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/fanart.jpg": "15c9a67b554f415a662fdf7a3340cd61",
|
||||||
|
"Best Prebuilt TV Show Collection/poster.jpg": "0b0fdbe56bab3e3fdda18730588d742a"
|
||||||
|
}
|
||||||
|
|
@ -2,18 +2,18 @@
|
||||||
".ytdl-sub-subscription_test-download-archive.json": "76e202bd03ceef93daaffffee2cfa193",
|
".ytdl-sub-subscription_test-download-archive.json": "76e202bd03ceef93daaffffee2cfa193",
|
||||||
"JMC/Mock Entry 20-1.info.json": "INFO_JSON",
|
"JMC/Mock Entry 20-1.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 20-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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-1.nfo": "fefcf0b3e4f4ff80ad636584d50dadec",
|
||||||
"JMC/Mock Entry 20-2.info.json": "INFO_JSON",
|
"JMC/Mock Entry 20-2.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 20-2.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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-2.nfo": "025c0b631da5ff5470382b38fce78d2d",
|
||||||
"JMC/Mock Entry 20-3.info.json": "INFO_JSON",
|
"JMC/Mock Entry 20-3.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 20-3.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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 20-3.nfo": "618b0ff948d9de2e10cf1da8c0dd6615",
|
||||||
"JMC/Mock Entry 21-1.info.json": "INFO_JSON",
|
"JMC/Mock Entry 21-1.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 21-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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"
|
"JMC/Mock Entry 21-1.nfo": "e5c715749efc1603a6e2f59244d87aba"
|
||||||
}
|
}
|
||||||
|
|
@ -2,18 +2,18 @@
|
||||||
".ytdl-sub-subscription_test-download-archive.json": "19cf39d57914ba9cbd1e57ba6f1e0683",
|
".ytdl-sub-subscription_test-download-archive.json": "19cf39d57914ba9cbd1e57ba6f1e0683",
|
||||||
"JMC/Mock Entry 20-1.info.json": "INFO_JSON",
|
"JMC/Mock Entry 20-1.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 20-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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-1.nfo": "fefcf0b3e4f4ff80ad636584d50dadec",
|
||||||
"JMC/Mock Entry 20-2.info.json": "INFO_JSON",
|
"JMC/Mock Entry 20-2.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 20-2.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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-2.nfo": "025c0b631da5ff5470382b38fce78d2d",
|
||||||
"JMC/Mock Entry 20-3.info.json": "INFO_JSON",
|
"JMC/Mock Entry 20-3.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 20-3.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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 20-3.nfo": "618b0ff948d9de2e10cf1da8c0dd6615",
|
||||||
"JMC/Mock Entry 21-1.info.json": "INFO_JSON",
|
"JMC/Mock Entry 21-1.info.json": "INFO_JSON",
|
||||||
"JMC/Mock Entry 21-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
"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"
|
"JMC/Mock Entry 21-1.nfo": "e5c715749efc1603a6e2f59244d87aba"
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
".ytdl-sub-subscription_test-download-archive.json": "7c6fbd0631d7d02025f3da457ba203e3",
|
".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.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.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 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",
|
"Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
|
||||||
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
|
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
|
||||||
}
|
}
|
||||||
|
|
@ -2,19 +2,19 @@
|
||||||
".ytdl-sub-JMC-migrated-download-archive.json": "456d8882fc5e35d74f19b386d1d9a059",
|
".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-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||||
"Season 2020/s2020.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
|
"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.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-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||||
"Season 2020/s2020.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
|
"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.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-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||||
"Season 2020/s2020.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
|
"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 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-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||||
"Season 2021/s2021.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
|
"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",
|
"Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
|
||||||
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
|
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
|
||||||
}
|
}
|
||||||
|
|
@ -2,19 +2,19 @@
|
||||||
".ytdl-sub-subscription_test-download-archive.json": "456d8882fc5e35d74f19b386d1d9a059",
|
".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-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||||
"Season 2020/s2020.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
|
"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.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-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||||
"Season 2020/s2020.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
|
"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.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-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||||
"Season 2020/s2020.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
|
"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 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-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
|
||||||
"Season 2021/s2021.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
|
"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",
|
"Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
|
||||||
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
|
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
|
||||||
}
|
}
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
{
|
{
|
||||||
".ytdl-sub-subscription_test-download-archive.json": "e049068ba7f5bdc27c474b18f4c6b402",
|
".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.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.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.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.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.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 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.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",
|
"Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
|
||||||
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
|
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
|
||||||
}
|
}
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
{
|
{
|
||||||
".ytdl-sub-j_b-download-archive.json": "1a99156e9ece62539fb2608416a07200",
|
".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] 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/[2021] Purple Clouds/folder.jpg": "967892be44b8c47e1be73f055a7c6f08",
|
||||||
"j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3": "e737c2ba118920643cec9eac09a283ea",
|
"j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3": "10c925fc97629ca788c44ae8082ee889",
|
||||||
"j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3": "d5def3e4329b9b95c5354c838dd3bc91",
|
"j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3": "da0e8a7db660adbfef255ba1763c384c",
|
||||||
"j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3": "1694c4a2889aa7dacafc5f2fdb4fe1d7",
|
"j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3": "42284493f75a55bd1b1d3f1ac8d1ffe1",
|
||||||
"j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3": "9c8ddee6aaf88b38706ce6bbdf907878",
|
"j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3": "d660abefa257a10cbeae434c770bf3e5",
|
||||||
"j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3": "4bf9e700137cb1b58e730dd312e00bb4",
|
"j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3": "565d4dcf92e40e1485ed77fa79b52c17",
|
||||||
"j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3": "c1920254046eda0d84b36dd34f9bafdb",
|
"j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3": "7c5903693230ca9ac8b44b76ed004eb4",
|
||||||
"j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3": "26f2eb8395b23cecc4000e2fd58304bf",
|
"j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3": "dfec9909cb8156ec8d5c28cfce858f36",
|
||||||
"j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3": "e3ceb5ae25c115d037a298b4620bce9f",
|
"j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3": "2c8769a9de3d1033d0e152c642512e40",
|
||||||
"j_b/[2022] Acoustic Treats/09 - Finding Home.mp3": "f3dcfe7c8569853a02eb12ad21b0e248",
|
"j_b/[2022] Acoustic Treats/09 - Finding Home.mp3": "b3920d39deb847be938e03e3d74d4ac9",
|
||||||
"j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3": "4fb9a18b3fdd788ce9d9f4c8a07b6028",
|
"j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3": "759394ebe3db9ccef564fa9d7c0dfd09",
|
||||||
"j_b/[2022] Acoustic Treats/11 - Untold History.mp3": "ad186ee1d0029f8de02357e8b8712a4b",
|
"j_b/[2022] Acoustic Treats/11 - Untold History.mp3": "477af6c479263539f244db8d9de04201",
|
||||||
"j_b/[2022] Acoustic Treats/folder.jpg": "967892be44b8c47e1be73f055a7c6f08"
|
"j_b/[2022] Acoustic Treats/folder.jpg": "967892be44b8c47e1be73f055a7c6f08"
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue