From 783609d2e371190f431f26d1fcde8164116e9d8e Mon Sep 17 00:00:00 2001 From: Johan Date: Sat, 10 Jan 2026 17:51:12 +0200 Subject: [PATCH] Prevent missing regex_patterns (#15) --- .github/workflows/generate.yml | 25 +- .github/workflows/lint.yml | 28 ++ .gitignore | 3 + README.md | 51 ++- custom_formats/Radarr - 1.0 Mono.yml | 6 +- custom_formats/Radarr - 2.0 Stereo.yml | 8 +- custom_formats/Radarr - 3.0 Sound.yml | 8 +- custom_formats/Radarr - 4.0 Sound.yml | 8 +- custom_formats/Radarr - 7.1 Surround.yml | 2 +- custom_formats/Radarr - AAC.yml | 14 +- custom_formats/Radarr - ATMOS (undefined).yml | 12 +- custom_formats/Radarr - Anime Dual Audio.yml | 2 +- ...darr - Anime Web Tier 02 (Top FanSubs).yml | 2 +- ...rr - Anime Web Tier 03 (Official Subs).yml | 2 +- custom_formats/Radarr - Bad Dual Groups.yml | 2 +- custom_formats/Radarr - DD+ ATMOS.yml | 14 +- custom_formats/Radarr - DD+.yml | 10 +- custom_formats/Radarr - DD.yml | 12 +- custom_formats/Radarr - DTS X.yml | 14 +- custom_formats/Radarr - DTS-ES.yml | 16 +- custom_formats/Radarr - DTS-HD HRA.yml | 20 +- custom_formats/Radarr - DTS-HD MA.yml | 18 +- custom_formats/Radarr - DTS.yml | 18 +- custom_formats/Radarr - DV (Disk).yml | 4 +- .../Radarr - DV (w-o HDR fallback).yml | 4 +- custom_formats/Radarr - DV Boost.yml | 2 +- custom_formats/Radarr - Dubs Only.yml | 4 +- custom_formats/Radarr - FLAC.yml | 14 +- custom_formats/Radarr - FR WEB Tier 02.yml | 2 +- custom_formats/Radarr - FraMeSToR.yml | 2 +- .../Radarr - Generated Dynamic HDR.yml | 2 +- .../Radarr - German Bluray Tier 02.yml | 2 +- .../Radarr - German Remux Tier 01.yml | 4 +- .../Radarr - German Web Tier 01.yml | 4 +- .../Radarr - German Web Tier 02.yml | 2 +- .../Radarr - German Web Tier 03.yml | 2 +- custom_formats/Radarr - German.yml | 2 +- custom_formats/Radarr - HD Bluray Tier 01.yml | 4 +- custom_formats/Radarr - HDR.yml | 4 +- custom_formats/Radarr - HDR10+ Boost.yml | 2 +- custom_formats/Radarr - Hybrid.yml | 2 +- .../Radarr - LQ (Release Title).yml | 2 +- custom_formats/Radarr - LQ.yml | 10 +- custom_formats/Radarr - MAX.yml | 2 +- custom_formats/Radarr - MULTi.yml | 2 +- .../Radarr - Not German or English.yml | 2 +- custom_formats/Radarr - Opus.yml | 2 +- custom_formats/Radarr - PCM.yml | 14 +- custom_formats/Radarr - Remaster.yml | 2 +- custom_formats/Radarr - Remux Tier 01.yml | 2 +- custom_formats/Radarr - Repack-Proper.yml | 2 +- custom_formats/Radarr - Repack2.yml | 2 +- custom_formats/Radarr - SiC.yml | 4 +- custom_formats/Radarr - TrueHD ATMOS.yml | 16 +- custom_formats/Radarr - TrueHD.yml | 8 +- custom_formats/Radarr - VFF.yml | 2 +- custom_formats/Radarr - VFQ.yml | 2 +- custom_formats/Radarr - WEB Tier 01.yml | 2 +- custom_formats/Radarr - WEB Tier 02.yml | 4 +- custom_formats/Radarr - x265 (HD).yml | 2 +- custom_formats/Radarr - x265 (no HDR-DV).yml | 4 +- custom_formats/Radarr - x265.yml | 2 +- custom_formats/Sonarr - 1.0 Mono.yml | 6 +- custom_formats/Sonarr - 2.0 Stereo.yml | 8 +- custom_formats/Sonarr - 3.0 Sound.yml | 8 +- custom_formats/Sonarr - 4.0 Sound.yml | 8 +- custom_formats/Sonarr - 7.1 Surround.yml | 2 +- custom_formats/Sonarr - AAC.yml | 14 +- custom_formats/Sonarr - ATMOS (undefined).yml | 12 +- custom_formats/Sonarr - Anime Dual Audio.yml | 2 +- ...narr - Anime Web Tier 02 (Top FanSubs).yml | 2 +- ...rr - Anime Web Tier 03 (Official Subs).yml | 2 +- custom_formats/Sonarr - Bad Dual Groups.yml | 2 +- custom_formats/Sonarr - DD+ ATMOS.yml | 14 +- custom_formats/Sonarr - DD+.yml | 10 +- custom_formats/Sonarr - DD.yml | 12 +- custom_formats/Sonarr - DTS X.yml | 14 +- custom_formats/Sonarr - DTS-ES.yml | 16 +- custom_formats/Sonarr - DTS-HD HRA.yml | 20 +- custom_formats/Sonarr - DTS-HD MA.yml | 18 +- custom_formats/Sonarr - DTS.yml | 18 +- custom_formats/Sonarr - DV (Disk).yml | 4 +- .../Sonarr - DV (w-o HDR fallback).yml | 6 +- custom_formats/Sonarr - DV Boost.yml | 2 +- custom_formats/Sonarr - Dubs Only.yml | 4 +- custom_formats/Sonarr - FLAC.yml | 14 +- custom_formats/Sonarr - FR WEB Tier 02.yml | 2 +- .../Sonarr - German Remux Tier 01.yml | 4 +- .../Sonarr - German Web Tier 01.yml | 2 +- custom_formats/Sonarr - German.yml | 2 +- custom_formats/Sonarr - HD Bluray Tier 01.yml | 2 +- custom_formats/Sonarr - HDR.yml | 4 +- custom_formats/Sonarr - HDR10+ Boost.yml | 2 +- custom_formats/Sonarr - Hybrid.yml | 2 +- custom_formats/Sonarr - LQ.yml | 2 +- custom_formats/Sonarr - MAX.yml | 2 +- custom_formats/Sonarr - MULTi.yml | 2 +- .../Sonarr - Not German or English.yml | 2 +- custom_formats/Sonarr - Opus.yml | 2 +- custom_formats/Sonarr - PCM.yml | 14 +- custom_formats/Sonarr - Remaster.yml | 2 +- custom_formats/Sonarr - Remux Tier 01.yml | 2 +- custom_formats/Sonarr - Repack-Proper.yml | 2 +- custom_formats/Sonarr - Repack2.yml | 2 +- custom_formats/Sonarr - TrueHD ATMOS.yml | 12 +- custom_formats/Sonarr - TrueHD.yml | 8 +- custom_formats/Sonarr - VFF.yml | 2 +- custom_formats/Sonarr - VFQ.yml | 2 +- custom_formats/Sonarr - WEB Tier 01.yml | 2 +- custom_formats/Sonarr - WEB Tier 02.yml | 6 +- custom_formats/Sonarr - x265 (HD).yml | 2 +- custom_formats/Sonarr - x265 (no HDR-DV).yml | 4 +- custom_formats/Sonarr - x265.yml | 2 +- pyproject.toml | 74 ++++ regex_patterns/{Not 3.0ch.yml => 3.0ch.yml} | 2 +- .../{Not 4K Remaster.yml => 4K Remaster.yml} | 2 +- regex_patterns/6.1 Surround (1).yml | 7 + regex_patterns/{Not AAC.yml => AAC.yml} | 2 +- regex_patterns/ATMOS (1).yml | 7 + .../{Not Basic DTS.yml => Basic DTS.yml} | 2 +- ...by Digital.yml => Basic Dolby Digital.yml} | 2 +- regex_patterns/Chotab (1).yml | 7 + regex_patterns/{Not DTS X.yml => DTS X.yml} | 2 +- regex_patterns/DTS-ES (1).yml | 7 + ...ot DTS-HD HRA-ES.yml => DTS-HD HRA-ES.yml} | 2 +- .../{Not DTS-HD.yml => DTS-HD MA.yml} | 2 +- regex_patterns/{Not DTS.yml => DTS.yml} | 2 +- regex_patterns/{Dolby Vision.yml => DV.yml} | 2 +- regex_patterns/Dae (1).yml | 7 + ...al Plus.yml => Dolby Digital Plus (1).yml} | 2 +- regex_patterns/Dolby Digital Plus.yml | 7 + regex_patterns/{Not FLAC.yml => FLAC.yml} | 2 +- regex_patterns/Feranki1980 (1).yml | 7 + regex_patterns/FraMeSToR (1).yml | 7 + ...erman in Title.yml => German in Title.yml} | 2 +- regex_patterns/HDR (1).yml | 7 + regex_patterns/{Not HDR-DV.yml => HDR-DV.yml} | 2 +- regex_patterns/{Not HDR.yml => HDR.yml} | 2 +- regex_patterns/HDR10+ (1).yml | 7 + ...annel Count.yml => High Channel Count.yml} | 2 +- ...r.yml => Higher Version Repack-Proper.yml} | 2 +- regex_patterns/Hybrid Release Group (1).yml | 7 + ...ase Group.yml => Hybrid Release Group.yml} | 2 +- ...ot Dual Audio).yml => KS (Dual Audio).yml} | 2 +- ...al Audio).yml => KaiDubs (Dual Audio).yml} | 2 +- ...hannel Count.yml => Low Channel Count.yml} | 2 +- regex_patterns/{Max.yml => Max (1).yml} | 2 +- regex_patterns/{Not Mono.yml => Mono.yml} | 2 +- regex_patterns/{Multi.yml => Multi (1).yml} | 2 +- regex_patterns/{NoNe.yml => NoNe (1).yml} | 2 +- ...lease Group.yml => OPUS Release Group.yml} | 2 +- regex_patterns/QfG (1).yml | 7 + regex_patterns/Radarr - 1XBET (1).yml | 6 + regex_patterns/Radarr - ATMOS (2).yml | 6 + regex_patterns/Radarr - D-Z0N3 (1).yml | 6 + regex_patterns/Radarr - E (1).yml | 6 + regex_patterns/Radarr - GalaxyRG (1).yml | 6 + .../{HDR10+.yml => Radarr - HDR10+.yml} | 3 +- regex_patterns/Radarr - NIMA4K (1).yml | 6 + regex_patterns/{QfG.yml => Radarr - QfG.yml} | 3 +- regex_patterns/Radarr - RobertDeNiro (1).yml | 6 + regex_patterns/{SiC.yml => Radarr - SiC.yml} | 3 +- regex_patterns/Radarr - TEKNO3D (1).yml | 6 + regex_patterns/Radarr - TrueHD (1).yml | 6 + regex_patterns/Radarr - TvR (1).yml | 6 + regex_patterns/Radarr - VECTOR (1).yml | 6 + regex_patterns/Radarr - jennaortega (1).yml | 6 + .../{pmHD.yml => Radarr - pmHD.yml} | 3 +- ...epack-Proper 3.yml => Repack-Proper 3.yml} | 2 +- regex_patterns/{Not RlsGrp.yml => RlsGrp.yml} | 2 +- regex_patterns/{SbR.yml => SbR (1).yml} | 2 +- regex_patterns/SiC (1).yml | 7 + ...uage Only.yml => Single Language Only.yml} | 2 +- regex_patterns/{Not Stereo.yml => Stereo.yml} | 2 +- regex_patterns/{Not Subbed.yml => Subbed.yml} | 2 +- regex_patterns/TrueHD-ATMOS (1).yml | 7 + ...{Not TrueHD-ATMOS.yml => TrueHD-ATMOS.yml} | 2 +- regex_patterns/VF2 (1).yml | 7 + regex_patterns/ZR (1).yml | 7 + regex_patterns/ZigZag (1).yml | 7 + regex_patterns/{dB.yml => dB (1).yml} | 2 +- regex_patterns/pmHD (1).yml | 7 + regex_patterns/{x|h265.yml => x265-HEVC.yml} | 2 +- renovate.json | 38 +- scripts/generate.py | 20 +- scripts/utils/custom_formats.py | 132 +++---- scripts/utils/file_utils.py | 29 ++ scripts/utils/media_management.py | 26 +- scripts/utils/profiles.py | 35 +- scripts/utils/regex_patterns.py | 225 ++++++++---- scripts/utils/strings.py | 16 +- tests/__init__.py | 11 + tests/test_custom_formats.py | 98 +++++ tests/test_profiles.py | 100 ++++++ uv.lock | 340 ++++++++++++++++++ 195 files changed, 1617 insertions(+), 562 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 pyproject.toml rename regex_patterns/{Not 3.0ch.yml => 3.0ch.yml} (82%) rename regex_patterns/{Not 4K Remaster.yml => 4K Remaster.yml} (73%) create mode 100644 regex_patterns/6.1 Surround (1).yml rename regex_patterns/{Not AAC.yml => AAC.yml} (83%) create mode 100644 regex_patterns/ATMOS (1).yml rename regex_patterns/{Not Basic DTS.yml => Basic DTS.yml} (78%) rename regex_patterns/{Not Basic Dolby Digital.yml => Basic Dolby Digital.yml} (75%) create mode 100644 regex_patterns/Chotab (1).yml rename regex_patterns/{Not DTS X.yml => DTS X.yml} (86%) create mode 100644 regex_patterns/DTS-ES (1).yml rename regex_patterns/{Not DTS-HD HRA-ES.yml => DTS-HD HRA-ES.yml} (79%) rename regex_patterns/{Not DTS-HD.yml => DTS-HD MA.yml} (85%) rename regex_patterns/{Not DTS.yml => DTS.yml} (83%) rename regex_patterns/{Dolby Vision.yml => DV.yml} (83%) create mode 100644 regex_patterns/Dae (1).yml rename regex_patterns/{Not Dolby Digital Plus.yml => Dolby Digital Plus (1).yml} (76%) create mode 100644 regex_patterns/Dolby Digital Plus.yml rename regex_patterns/{Not FLAC.yml => FLAC.yml} (82%) create mode 100644 regex_patterns/Feranki1980 (1).yml create mode 100644 regex_patterns/FraMeSToR (1).yml rename regex_patterns/{Not German in Title.yml => German in Title.yml} (74%) create mode 100644 regex_patterns/HDR (1).yml rename regex_patterns/{Not HDR-DV.yml => HDR-DV.yml} (87%) rename regex_patterns/{Not HDR.yml => HDR.yml} (83%) create mode 100644 regex_patterns/HDR10+ (1).yml rename regex_patterns/{Not High Channel Count.yml => High Channel Count.yml} (74%) rename regex_patterns/{Not Higher Version Repack-Proper.yml => Higher Version Repack-Proper.yml} (75%) create mode 100644 regex_patterns/Hybrid Release Group (1).yml rename regex_patterns/{Not Hybrid Release Group.yml => Hybrid Release Group.yml} (68%) rename regex_patterns/{KS (Not Dual Audio).yml => KS (Dual Audio).yml} (83%) rename regex_patterns/{KaiDubs (Not Dual Audio).yml => KaiDubs (Dual Audio).yml} (82%) rename regex_patterns/{Not Low Channel Count.yml => Low Channel Count.yml} (79%) rename regex_patterns/{Max.yml => Max (1).yml} (88%) rename regex_patterns/{Not Mono.yml => Mono.yml} (86%) rename regex_patterns/{Multi.yml => Multi (1).yml} (85%) rename regex_patterns/{NoNe.yml => NoNe (1).yml} (81%) rename regex_patterns/{Not OPUS Release Group.yml => OPUS Release Group.yml} (68%) create mode 100644 regex_patterns/QfG (1).yml create mode 100644 regex_patterns/Radarr - 1XBET (1).yml create mode 100644 regex_patterns/Radarr - ATMOS (2).yml create mode 100644 regex_patterns/Radarr - D-Z0N3 (1).yml create mode 100644 regex_patterns/Radarr - E (1).yml create mode 100644 regex_patterns/Radarr - GalaxyRG (1).yml rename regex_patterns/{HDR10+.yml => Radarr - HDR10+.yml} (76%) create mode 100644 regex_patterns/Radarr - NIMA4K (1).yml rename regex_patterns/{QfG.yml => Radarr - QfG.yml} (75%) create mode 100644 regex_patterns/Radarr - RobertDeNiro (1).yml rename regex_patterns/{SiC.yml => Radarr - SiC.yml} (75%) create mode 100644 regex_patterns/Radarr - TEKNO3D (1).yml create mode 100644 regex_patterns/Radarr - TrueHD (1).yml create mode 100644 regex_patterns/Radarr - TvR (1).yml create mode 100644 regex_patterns/Radarr - VECTOR (1).yml create mode 100644 regex_patterns/Radarr - jennaortega (1).yml rename regex_patterns/{pmHD.yml => Radarr - pmHD.yml} (74%) rename regex_patterns/{Not Repack-Proper 3.yml => Repack-Proper 3.yml} (81%) rename regex_patterns/{Not RlsGrp.yml => RlsGrp.yml} (81%) rename regex_patterns/{SbR.yml => SbR (1).yml} (82%) create mode 100644 regex_patterns/SiC (1).yml rename regex_patterns/{Not Single Language Only.yml => Single Language Only.yml} (70%) rename regex_patterns/{Not Stereo.yml => Stereo.yml} (84%) rename regex_patterns/{Not Subbed.yml => Subbed.yml} (85%) create mode 100644 regex_patterns/TrueHD-ATMOS (1).yml rename regex_patterns/{Not TrueHD-ATMOS.yml => TrueHD-ATMOS.yml} (79%) create mode 100644 regex_patterns/VF2 (1).yml create mode 100644 regex_patterns/ZR (1).yml create mode 100644 regex_patterns/ZigZag (1).yml rename regex_patterns/{dB.yml => dB (1).yml} (83%) create mode 100644 regex_patterns/pmHD (1).yml rename regex_patterns/{x|h265.yml => x265-HEVC.yml} (84%) create mode 100644 scripts/utils/file_utils.py create mode 100644 tests/__init__.py create mode 100644 tests/test_custom_formats.py create mode 100644 tests/test_profiles.py create mode 100644 uv.lock diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 0b6cf59..7a49319 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -3,6 +3,8 @@ name: Generate on: schedule: - cron: "31 7 * * *" + pull_request: + types: [opened, synchronize] workflow_dispatch: jobs: @@ -27,11 +29,32 @@ jobs: git config --global user.name "Github Actions" git clone https://github.com/TRaSH-Guides/Guides.git TRaSH-Guides + - name: Install dependencies` + run: uv sync --extra dev + - name: Run Python script run: | uv run scripts/generate.py TRaSH-Guides/docs/json . - - name: Check for changes + - name: Run tests + run: | + uv run pytest tests + + - name: Check for uncommitted changes (PR) + if: github.event_name == 'pull_request' + run: | + git add regex_patterns/ custom_formats/ profiles/ + if ! git diff --staged --quiet; then + echo "❌ Error: Generated files have changes that are not committed." + echo "Please run the generation script locally and commit the changes:" + echo " uv run scripts/generate.py TRaSH-Guides/docs/json ." + git diff --staged --stat + exit 1 + fi + echo "✅ No uncommitted changes detected" + + - name: Commit and push changes (Scheduled/Manual) + if: github.event_name != 'pull_request' run: | git add regex_patterns/ custom_formats/ profiles/ git commit -m "Automated update from GitHub Actions" || echo "No changes to commit" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..43e062a --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,28 @@ +name: Lint and Format Check + +on: + pull_request: + types: [opened, synchronize] + workflow_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.14" + + - name: Install uv + run: pip install uv + + - name: Install dev dependencies + run: uv sync --extra dev + + - name: Run pylint on scripts + run: uv run pylint scripts tests diff --git a/.gitignore b/.gitignore index 895b4f6..176086a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ __pycache__ TRaSH-Guides + +.mypy_cache +.pytest_cache diff --git a/README.md b/README.md index d5525e8..d8a9c6d 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,11 @@ The repository a script to generate the specification based on the TRaSH-Guide d ### Requirements -The scripts utilize UV for easy package management, ensure it's installed by following the [official instructions](https://github.com/astral-sh/uv?tab=readme-ov-file#installation). +- **Python 3.13+** +- **UV** for package management - install via [official instructions](https://github.com/astral-sh/uv?tab=readme-ov-file#installation) +- **TRaSH-Guides data** - a local clone with JSON data in `docs/json/` (not automatically cloned) -Additionally it's expected that you have a local folder with a TRaSH-Guides clone containing the JSON data ([docs/json within the TRaSH-Guides repository](https://github.com/TRaSH-Guides/Guides/tree/master/docs/json)). The script does not pull any data. +Dependencies are defined in `pyproject.toml` and managed by UV. ### Running the script @@ -30,3 +32,48 @@ uv run scripts/generate.py /path/to/trash-guides/docs/json . ``` It will clear any potentially pre-existing output and generate new output based on the provided TRaSH-Guides folder. + +## Testing + +This project includes automated tests to validate the integrity of generated output files. + +### Running Tests + +The test suite validates that: +- Every pattern referenced in custom formats exists as a regex pattern file +- Every custom format referenced in profiles exists as a custom format file + +```bash +# Install dev dependencies +uv sync --extra dev + +# Run all tests +uv run pytest tests/ -v + +# Run specific test files +uv run pytest tests/test_custom_formats.py -v +uv run pytest tests/test_profiles.py -v + +# Run with coverage report +uv run pytest tests/ --cov=scripts --cov-report=term +``` + +### Test Validation + +The tests ensure data integrity across the generated output: +- **Custom Format Tests** - Validates all pattern references in `custom_formats/` exist in `regex_patterns/` +- **Profile Tests** - Validates all custom format references in `profiles/` exist in `custom_formats/` + +If a test fails, it will clearly indicate which files contain broken references, making it easy to identify and fix issues. + +## Code Quality + +This project uses **pylint** for static code analysis and quality checks. + +```bash +# Install dev tools +uv sync --extra dev + +# Run linting +uv run pylint scripts tests +``` diff --git a/custom_formats/Radarr - 1.0 Mono.yml b/custom_formats/Radarr - 1.0 Mono.yml index b9b8d1c..a61cabd 100644 --- a/custom_formats/Radarr - 1.0 Mono.yml +++ b/custom_formats/Radarr - 1.0 Mono.yml @@ -8,12 +8,12 @@ conditions: negate: false required: true type: release_title - pattern: Not Mono + pattern: Mono - name: Radarr - Not 3.0ch negate: true required: true type: release_title - pattern: Not 3.0ch + pattern: 3.0ch - name: Radarr - Not 4.0ch negate: true required: true @@ -23,5 +23,5 @@ conditions: negate: true required: true type: release_title - pattern: Not High Channel Count + pattern: High Channel Count tests: [] diff --git a/custom_formats/Radarr - 2.0 Stereo.yml b/custom_formats/Radarr - 2.0 Stereo.yml index ce06bb5..9f4ce26 100644 --- a/custom_formats/Radarr - 2.0 Stereo.yml +++ b/custom_formats/Radarr - 2.0 Stereo.yml @@ -8,12 +8,12 @@ conditions: negate: false required: true type: release_title - pattern: Not Stereo + pattern: Stereo - name: Radarr - Not 3.0ch negate: true required: true type: release_title - pattern: Not 3.0ch + pattern: 3.0ch - name: Radarr - Not 4.0ch negate: true required: true @@ -23,10 +23,10 @@ conditions: negate: true required: true type: release_title - pattern: Not High Channel Count + pattern: High Channel Count - name: Radarr - Not Mono negate: true required: true type: release_title - pattern: Not Mono + pattern: Mono tests: [] diff --git a/custom_formats/Radarr - 3.0 Sound.yml b/custom_formats/Radarr - 3.0 Sound.yml index 579b353..8131cce 100644 --- a/custom_formats/Radarr - 3.0 Sound.yml +++ b/custom_formats/Radarr - 3.0 Sound.yml @@ -8,17 +8,17 @@ conditions: negate: false required: true type: release_title - pattern: Not 3.0ch + pattern: 3.0ch - name: Radarr - Not Mono negate: true required: true type: release_title - pattern: Not Mono + pattern: Mono - name: Radarr - Not Stereo negate: true required: true type: release_title - pattern: Not Stereo + pattern: Stereo - name: Radarr - Not 4.0ch negate: true required: true @@ -28,5 +28,5 @@ conditions: negate: true required: true type: release_title - pattern: Not High Channel Count + pattern: High Channel Count tests: [] diff --git a/custom_formats/Radarr - 4.0 Sound.yml b/custom_formats/Radarr - 4.0 Sound.yml index 0beee6b..1550213 100644 --- a/custom_formats/Radarr - 4.0 Sound.yml +++ b/custom_formats/Radarr - 4.0 Sound.yml @@ -13,20 +13,20 @@ conditions: negate: true required: true type: release_title - pattern: Not Mono + pattern: Mono - name: Radarr - Not Stereo negate: true required: true type: release_title - pattern: Not Stereo + pattern: Stereo - name: Radarr - Not 3.0ch negate: true required: true type: release_title - pattern: Not 3.0ch + pattern: 3.0ch - name: Radarr - Not High Channel Count negate: true required: true type: release_title - pattern: Not High Channel Count + pattern: High Channel Count tests: [] diff --git a/custom_formats/Radarr - 7.1 Surround.yml b/custom_formats/Radarr - 7.1 Surround.yml index cdaa26d..b866aaa 100644 --- a/custom_formats/Radarr - 7.1 Surround.yml +++ b/custom_formats/Radarr - 7.1 Surround.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Not Low Channel Count + pattern: Low Channel Count tests: [] diff --git a/custom_formats/Radarr - AAC.yml b/custom_formats/Radarr - AAC.yml index 22885fb..24a2e5b 100644 --- a/custom_formats/Radarr - AAC.yml +++ b/custom_formats/Radarr - AAC.yml @@ -8,22 +8,22 @@ conditions: negate: false required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Radarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS -- name: 'Radarr - Not Dolby Digital Plus ' + pattern: DTS +- name: Radarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Radarr - Not PCM negate: true required: true @@ -33,10 +33,10 @@ conditions: negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS tests: [] diff --git a/custom_formats/Radarr - ATMOS (undefined).yml b/custom_formats/Radarr - ATMOS (undefined).yml index d1352b0..3afd024 100644 --- a/custom_formats/Radarr - ATMOS (undefined).yml +++ b/custom_formats/Radarr - ATMOS (undefined).yml @@ -13,27 +13,27 @@ conditions: negate: true required: true type: release_title - pattern: Not AAC -- name: 'Radarr - Not Basic Dolby Digital ' + pattern: AAC +- name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Radarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Radarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not PCM negate: true required: true diff --git a/custom_formats/Radarr - Anime Dual Audio.yml b/custom_formats/Radarr - Anime Dual Audio.yml index 2a56a78..7e3d98f 100644 --- a/custom_formats/Radarr - Anime Dual Audio.yml +++ b/custom_formats/Radarr - Anime Dual Audio.yml @@ -14,7 +14,7 @@ conditions: negate: true required: true type: release_title - pattern: Not Single Language Only + pattern: Single Language Only - name: Radarr - Japanese Language negate: false required: false diff --git a/custom_formats/Radarr - Anime Web Tier 02 (Top FanSubs).yml b/custom_formats/Radarr - Anime Web Tier 02 (Top FanSubs).yml index 31fffa4..3ac9a4f 100644 --- a/custom_formats/Radarr - Anime Web Tier 02 (Top FanSubs).yml +++ b/custom_formats/Radarr - Anime Web Tier 02 (Top FanSubs).yml @@ -39,7 +39,7 @@ conditions: negate: false required: false type: release_title - pattern: Radarr - Dae + pattern: Dae (1) - name: Radarr - Foxtrot negate: false required: false diff --git a/custom_formats/Radarr - Anime Web Tier 03 (Official Subs).yml b/custom_formats/Radarr - Anime Web Tier 03 (Official Subs).yml index c5f92eb..46c7109 100644 --- a/custom_formats/Radarr - Anime Web Tier 03 (Official Subs).yml +++ b/custom_formats/Radarr - Anime Web Tier 03 (Official Subs).yml @@ -29,5 +29,5 @@ conditions: negate: false required: false type: release_title - pattern: Radarr - ZR + pattern: ZR (1) tests: [] diff --git a/custom_formats/Radarr - Bad Dual Groups.yml b/custom_formats/Radarr - Bad Dual Groups.yml index 7c4e523..afa4090 100644 --- a/custom_formats/Radarr - Bad Dual Groups.yml +++ b/custom_formats/Radarr - Bad Dual Groups.yml @@ -143,7 +143,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - ZigZag + pattern: ZigZag (1) - name: Radarr - ZNM negate: false required: false diff --git a/custom_formats/Radarr - DD+ ATMOS.yml b/custom_formats/Radarr - DD+ ATMOS.yml index 77c23b9..add28e8 100644 --- a/custom_formats/Radarr - DD+ ATMOS.yml +++ b/custom_formats/Radarr - DD+ ATMOS.yml @@ -8,12 +8,12 @@ conditions: negate: false required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Radarr - ATMOS negate: false required: true type: release_title - pattern: Radarr - ATMOS + pattern: ATMOS (1) - name: Radarr - Not TrueHD negate: true required: true @@ -23,22 +23,22 @@ conditions: negate: true required: true type: release_title - pattern: Not DTS -- name: 'Radarr - Not Basic Dolby Digital ' + pattern: DTS +- name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Radarr - Not PCM negate: true required: true diff --git a/custom_formats/Radarr - DD+.yml b/custom_formats/Radarr - DD+.yml index 1ecdf6f..4ec1aff 100644 --- a/custom_formats/Radarr - DD+.yml +++ b/custom_formats/Radarr - DD+.yml @@ -8,27 +8,27 @@ conditions: negate: false required: true type: release_title - pattern: Dolby Digital Plus + pattern: Dolby Digital Plus (1) - name: Radarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Radarr - TrueHD-ATMOS + pattern: TrueHD-ATMOS (1) - name: Radarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Radarr - Not PCM negate: true required: true diff --git a/custom_formats/Radarr - DD.yml b/custom_formats/Radarr - DD.yml index e88e568..09a3ef4 100644 --- a/custom_formats/Radarr - DD.yml +++ b/custom_formats/Radarr - DD.yml @@ -8,32 +8,32 @@ conditions: negate: false required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Radarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Radarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Radarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Radarr - Not PCM negate: true required: true diff --git a/custom_formats/Radarr - DTS X.yml b/custom_formats/Radarr - DTS X.yml index c329132..9dd459d 100644 --- a/custom_formats/Radarr - DTS X.yml +++ b/custom_formats/Radarr - DTS X.yml @@ -8,37 +8,37 @@ conditions: negate: false required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Radarr - Not Basic DTS negate: true required: true type: release_title - pattern: Not Basic DTS + pattern: Basic DTS - name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Radarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Radarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Radarr - Not PCM negate: true required: true diff --git a/custom_formats/Radarr - DTS-ES.yml b/custom_formats/Radarr - DTS-ES.yml index ff7a329..c5b99a7 100644 --- a/custom_formats/Radarr - DTS-ES.yml +++ b/custom_formats/Radarr - DTS-ES.yml @@ -13,37 +13,37 @@ conditions: negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Radarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Radarr - Not Basic DTS negate: true required: true type: release_title - pattern: Not Basic DTS -- name: 'Radarr - Not Basic Dolby Digital ' + pattern: Basic DTS +- name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Radarr - Not DTS X negate: true required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Radarr - Not PCM negate: true required: true diff --git a/custom_formats/Radarr - DTS-HD HRA.yml b/custom_formats/Radarr - DTS-HD HRA.yml index 8f36388..f38304e 100644 --- a/custom_formats/Radarr - DTS-HD HRA.yml +++ b/custom_formats/Radarr - DTS-HD HRA.yml @@ -13,37 +13,37 @@ conditions: negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Radarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Radarr - Not Basic DTS negate: true required: true type: release_title - pattern: Not Basic DTS -- name: 'Radarr - Not Basic Dolby Digital ' + pattern: Basic DTS +- name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Radarr - Not DTS X negate: true required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Radarr - Not PCM negate: true required: true @@ -53,10 +53,10 @@ conditions: negate: true required: true type: release_title - pattern: Radarr - DTS-ES + pattern: DTS-ES (1) - name: Radarr - Not 6.1 Surround negate: true required: true type: release_title - pattern: Radarr - 6.1 Surround + pattern: 6.1 Surround (1) tests: [] diff --git a/custom_formats/Radarr - DTS-HD MA.yml b/custom_formats/Radarr - DTS-HD MA.yml index 1f6c21a..7e64297 100644 --- a/custom_formats/Radarr - DTS-HD MA.yml +++ b/custom_formats/Radarr - DTS-HD MA.yml @@ -8,37 +8,37 @@ conditions: negate: false required: true type: release_title - pattern: Not DTS-HD + pattern: DTS-HD MA - name: Radarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Radarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus -- name: 'Radarr - Not Basic Dolby Digital ' + pattern: Dolby Digital Plus +- name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Radarr - Not DTS X negate: true required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Radarr - Not PCM negate: true required: true @@ -48,5 +48,5 @@ conditions: negate: true required: true type: release_title - pattern: Not DTS-HD HRA-ES + pattern: DTS-HD HRA-ES tests: [] diff --git a/custom_formats/Radarr - DTS.yml b/custom_formats/Radarr - DTS.yml index 20396c2..393728d 100644 --- a/custom_formats/Radarr - DTS.yml +++ b/custom_formats/Radarr - DTS.yml @@ -8,47 +8,47 @@ conditions: negate: false required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Radarr - Not DTS-HD negate: true required: true type: release_title - pattern: Not DTS-HD + pattern: DTS-HD MA - name: Radarr - Not DTS-HD HRA-ES negate: true required: true type: release_title - pattern: Not DTS-HD HRA-ES + pattern: DTS-HD HRA-ES - name: Radarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Radarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Radarr - Not DTS X negate: true required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Radarr - Not PCM negate: true required: true diff --git a/custom_formats/Radarr - DV (Disk).yml b/custom_formats/Radarr - DV (Disk).yml index b5816d0..a84a767 100644 --- a/custom_formats/Radarr - DV (Disk).yml +++ b/custom_formats/Radarr - DV (Disk).yml @@ -14,7 +14,7 @@ conditions: negate: false required: true type: release_title - pattern: Dolby Vision + pattern: DV - name: Radarr - No FANRES negate: true required: true @@ -29,5 +29,5 @@ conditions: negate: true required: true type: release_title - pattern: Not Hybrid Release Group + pattern: Hybrid Release Group tests: [] diff --git a/custom_formats/Radarr - DV (w-o HDR fallback).yml b/custom_formats/Radarr - DV (w-o HDR fallback).yml index 4ea5f44..b1a2b14 100644 --- a/custom_formats/Radarr - DV (w-o HDR fallback).yml +++ b/custom_formats/Radarr - DV (w-o HDR fallback).yml @@ -25,12 +25,12 @@ conditions: negate: true required: true type: release_group - pattern: Not RlsGrp + pattern: RlsGrp - name: Radarr - Not HDR negate: true required: true type: release_title - pattern: Not HDR + pattern: HDR - name: Radarr - Not Hulu negate: true required: true diff --git a/custom_formats/Radarr - DV Boost.yml b/custom_formats/Radarr - DV Boost.yml index 8f53478..8ec79c8 100644 --- a/custom_formats/Radarr - DV Boost.yml +++ b/custom_formats/Radarr - DV Boost.yml @@ -8,5 +8,5 @@ conditions: negate: false required: false type: release_title - pattern: Dolby Vision + pattern: DV tests: [] diff --git a/custom_formats/Radarr - Dubs Only.yml b/custom_formats/Radarr - Dubs Only.yml index babc069..6e2aef3 100644 --- a/custom_formats/Radarr - Dubs Only.yml +++ b/custom_formats/Radarr - Dubs Only.yml @@ -18,7 +18,7 @@ conditions: negate: false required: false type: release_title - pattern: KaiDubs (Not Dual Audio) + pattern: KaiDubs (Dual Audio) - name: Radarr - KamiFS negate: false required: false @@ -28,7 +28,7 @@ conditions: negate: false required: false type: release_title - pattern: KS (Not Dual Audio) + pattern: KS (Dual Audio) - name: Radarr - torenter69 negate: false required: false diff --git a/custom_formats/Radarr - FLAC.yml b/custom_formats/Radarr - FLAC.yml index 3df8b1e..0c9eb40 100644 --- a/custom_formats/Radarr - FLAC.yml +++ b/custom_formats/Radarr - FLAC.yml @@ -8,7 +8,7 @@ conditions: negate: false required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not PCM negate: true required: true @@ -18,25 +18,25 @@ conditions: negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Radarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Radarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital -- name: 'Radarr - Not Dolby Digital Plus ' + pattern: Basic Dolby Digital +- name: Radarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus tests: [] diff --git a/custom_formats/Radarr - FR WEB Tier 02.yml b/custom_formats/Radarr - FR WEB Tier 02.yml index f496a21..eea0772 100644 --- a/custom_formats/Radarr - FR WEB Tier 02.yml +++ b/custom_formats/Radarr - FR WEB Tier 02.yml @@ -39,7 +39,7 @@ conditions: negate: false required: false type: release_group - pattern: NoNe + pattern: NoNe (1) - name: Radarr - ONLYMOViE negate: false required: false diff --git a/custom_formats/Radarr - FraMeSToR.yml b/custom_formats/Radarr - FraMeSToR.yml index 8e7dae8..ab56ef5 100644 --- a/custom_formats/Radarr - FraMeSToR.yml +++ b/custom_formats/Radarr - FraMeSToR.yml @@ -8,5 +8,5 @@ conditions: negate: false required: true type: release_group - pattern: Radarr - FraMeSToR + pattern: FraMeSToR (1) tests: [] diff --git a/custom_formats/Radarr - Generated Dynamic HDR.yml b/custom_formats/Radarr - Generated Dynamic HDR.yml index 70ca49b..be0effd 100644 --- a/custom_formats/Radarr - Generated Dynamic HDR.yml +++ b/custom_formats/Radarr - Generated Dynamic HDR.yml @@ -54,5 +54,5 @@ conditions: negate: false required: false type: release_title - pattern: Dolby Vision + pattern: DV tests: [] diff --git a/custom_formats/Radarr - German Bluray Tier 02.yml b/custom_formats/Radarr - German Bluray Tier 02.yml index 5316ee4..8fc9cb4 100644 --- a/custom_formats/Radarr - German Bluray Tier 02.yml +++ b/custom_formats/Radarr - German Bluray Tier 02.yml @@ -10,7 +10,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - VECTOR + pattern: Radarr - VECTOR (1) - name: Radarr - MULTiPLEX negate: false required: false diff --git a/custom_formats/Radarr - German Remux Tier 01.yml b/custom_formats/Radarr - German Remux Tier 01.yml index a3c1855..03749aa 100644 --- a/custom_formats/Radarr - German Remux Tier 01.yml +++ b/custom_formats/Radarr - German Remux Tier 01.yml @@ -9,7 +9,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - TvR + pattern: Radarr - TvR (1) - name: Radarr - pmHD negate: false required: false @@ -19,7 +19,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - NIMA4K + pattern: Radarr - NIMA4K (1) - name: Radarr - QfG negate: false required: false diff --git a/custom_formats/Radarr - German Web Tier 01.yml b/custom_formats/Radarr - German Web Tier 01.yml index bd5a6cf..1fe0926 100644 --- a/custom_formats/Radarr - German Web Tier 01.yml +++ b/custom_formats/Radarr - German Web Tier 01.yml @@ -49,7 +49,7 @@ conditions: negate: false required: false type: release_group - pattern: QfG + pattern: QfG (1) - name: Radarr - CNY negate: false required: false @@ -84,7 +84,7 @@ conditions: negate: false required: false type: release_group - pattern: pmHD + pattern: pmHD (1) - name: Radarr - WebDL negate: false required: false diff --git a/custom_formats/Radarr - German Web Tier 02.yml b/custom_formats/Radarr - German Web Tier 02.yml index 3f82759..7b39503 100644 --- a/custom_formats/Radarr - German Web Tier 02.yml +++ b/custom_formats/Radarr - German Web Tier 02.yml @@ -9,7 +9,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - VECTOR + pattern: Radarr - VECTOR (1) - name: Radarr - MULTiPLEX negate: false required: false diff --git a/custom_formats/Radarr - German Web Tier 03.yml b/custom_formats/Radarr - German Web Tier 03.yml index 8f76a35..fd86201 100644 --- a/custom_formats/Radarr - German Web Tier 03.yml +++ b/custom_formats/Radarr - German Web Tier 03.yml @@ -9,7 +9,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - RobertDeNiro + pattern: Radarr - RobertDeNiro (1) - name: Radarr - BALENCiAGA negate: false required: false diff --git a/custom_formats/Radarr - German.yml b/custom_formats/Radarr - German.yml index ad94ab0..3f5c08a 100644 --- a/custom_formats/Radarr - German.yml +++ b/custom_formats/Radarr - German.yml @@ -29,5 +29,5 @@ conditions: negate: true required: true type: release_title - pattern: Not Subbed + pattern: Subbed tests: [] diff --git a/custom_formats/Radarr - HD Bluray Tier 01.yml b/custom_formats/Radarr - HD Bluray Tier 01.yml index 4dd08ac..0b9cb2f 100644 --- a/custom_formats/Radarr - HD Bluray Tier 01.yml +++ b/custom_formats/Radarr - HD Bluray Tier 01.yml @@ -41,7 +41,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - Chotab + pattern: Chotab (1) - name: Radarr - CRiSC negate: false required: false @@ -56,7 +56,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - D-Z0N3 + pattern: Radarr - D-Z0N3 (1) - name: Radarr - Dariush negate: false required: false diff --git a/custom_formats/Radarr - HDR.yml b/custom_formats/Radarr - HDR.yml index d911abf..a2151c9 100644 --- a/custom_formats/Radarr - HDR.yml +++ b/custom_formats/Radarr - HDR.yml @@ -13,7 +13,7 @@ conditions: negate: false required: false type: release_title - pattern: Radarr - HDR + pattern: HDR (1) - name: Radarr - HDR10 negate: false required: false @@ -23,7 +23,7 @@ conditions: negate: false required: false type: release_title - pattern: HDR10+ + pattern: HDR10+ (1) - name: Radarr - HLG negate: false required: false diff --git a/custom_formats/Radarr - HDR10+ Boost.yml b/custom_formats/Radarr - HDR10+ Boost.yml index 69d6200..e41aadc 100644 --- a/custom_formats/Radarr - HDR10+ Boost.yml +++ b/custom_formats/Radarr - HDR10+ Boost.yml @@ -8,5 +8,5 @@ conditions: negate: false required: false type: release_title - pattern: HDR10+ + pattern: HDR10+ (1) tests: [] diff --git a/custom_formats/Radarr - Hybrid.yml b/custom_formats/Radarr - Hybrid.yml index 8784953..afc8aaa 100644 --- a/custom_formats/Radarr - Hybrid.yml +++ b/custom_formats/Radarr - Hybrid.yml @@ -15,7 +15,7 @@ conditions: negate: true required: true type: release_group - pattern: Radarr - Hybrid Release Group + pattern: Hybrid Release Group (1) - name: Radarr - Bluray negate: false required: false diff --git a/custom_formats/Radarr - LQ (Release Title).yml b/custom_formats/Radarr - LQ (Release Title).yml index e43c4b3..07508db 100644 --- a/custom_formats/Radarr - LQ (Release Title).yml +++ b/custom_formats/Radarr - LQ (Release Title).yml @@ -8,7 +8,7 @@ conditions: negate: false required: false type: release_title - pattern: Radarr - 1XBET + pattern: Radarr - 1XBET (1) - name: Radarr - BEN THE MEN negate: false required: false diff --git a/custom_formats/Radarr - LQ.yml b/custom_formats/Radarr - LQ.yml index 11aed26..5ec54ce 100644 --- a/custom_formats/Radarr - LQ.yml +++ b/custom_formats/Radarr - LQ.yml @@ -138,7 +138,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - E + pattern: Radarr - E (1) - name: Radarr - EPiC negate: false required: false @@ -158,7 +158,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - Feranki1980 + pattern: Feranki1980 (1) - name: Radarr - FGT negate: false required: false @@ -183,7 +183,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - GalaxyRG + pattern: Radarr - GalaxyRG (1) - name: Radarr - GHD negate: false required: false @@ -238,7 +238,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - jennaortega + pattern: Radarr - jennaortega (1) - name: Radarr - JFF negate: false required: false @@ -438,7 +438,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - TEKNO3D + pattern: Radarr - TEKNO3D (1) - name: Radarr - Tigole negate: false required: false diff --git a/custom_formats/Radarr - MAX.yml b/custom_formats/Radarr - MAX.yml index f872283..4c01069 100644 --- a/custom_formats/Radarr - MAX.yml +++ b/custom_formats/Radarr - MAX.yml @@ -9,7 +9,7 @@ conditions: negate: false required: false type: release_title - pattern: Max + pattern: Max (1) - name: Radarr - MAX Rename negate: false required: false diff --git a/custom_formats/Radarr - MULTi.yml b/custom_formats/Radarr - MULTi.yml index 79d14ee..a956c4a 100644 --- a/custom_formats/Radarr - MULTi.yml +++ b/custom_formats/Radarr - MULTi.yml @@ -8,5 +8,5 @@ conditions: negate: false required: true type: release_title - pattern: Multi + pattern: Multi (1) tests: [] diff --git a/custom_formats/Radarr - Not German or English.yml b/custom_formats/Radarr - Not German or English.yml index b4cadcf..9966a06 100644 --- a/custom_formats/Radarr - Not German or English.yml +++ b/custom_formats/Radarr - Not German or English.yml @@ -19,5 +19,5 @@ conditions: negate: true required: true type: release_title - pattern: Not German in Title + pattern: German in Title tests: [] diff --git a/custom_formats/Radarr - Opus.yml b/custom_formats/Radarr - Opus.yml index 849f22d..901e5b3 100644 --- a/custom_formats/Radarr - Opus.yml +++ b/custom_formats/Radarr - Opus.yml @@ -14,5 +14,5 @@ conditions: negate: true required: true type: release_group - pattern: Not OPUS Release Group + pattern: OPUS Release Group tests: [] diff --git a/custom_formats/Radarr - PCM.yml b/custom_formats/Radarr - PCM.yml index 833bc85..d19fa02 100644 --- a/custom_formats/Radarr - PCM.yml +++ b/custom_formats/Radarr - PCM.yml @@ -13,30 +13,30 @@ conditions: negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Radarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital -- name: 'Radarr - Not Dolby Digital Plus ' + pattern: Basic Dolby Digital +- name: Radarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus tests: [] diff --git a/custom_formats/Radarr - Remaster.yml b/custom_formats/Radarr - Remaster.yml index 64e8c57..b30dba0 100644 --- a/custom_formats/Radarr - Remaster.yml +++ b/custom_formats/Radarr - Remaster.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Not 4K Remaster + pattern: 4K Remaster tests: [] diff --git a/custom_formats/Radarr - Remux Tier 01.yml b/custom_formats/Radarr - Remux Tier 01.yml index e565ef7..457e9e9 100644 --- a/custom_formats/Radarr - Remux Tier 01.yml +++ b/custom_formats/Radarr - Remux Tier 01.yml @@ -39,7 +39,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - FraMeSToR + pattern: FraMeSToR (1) - name: Radarr - PiRAMiDHEAD negate: false required: false diff --git a/custom_formats/Radarr - Repack-Proper.yml b/custom_formats/Radarr - Repack-Proper.yml index ed39998..62e02e3 100644 --- a/custom_formats/Radarr - Repack-Proper.yml +++ b/custom_formats/Radarr - Repack-Proper.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Not Higher Version Repack-Proper + pattern: Higher Version Repack-Proper tests: [] diff --git a/custom_formats/Radarr - Repack2.yml b/custom_formats/Radarr - Repack2.yml index 80e23ff..5a388a2 100644 --- a/custom_formats/Radarr - Repack2.yml +++ b/custom_formats/Radarr - Repack2.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Not Repack-Proper 3 + pattern: Repack-Proper 3 tests: [] diff --git a/custom_formats/Radarr - SiC.yml b/custom_formats/Radarr - SiC.yml index 0ba2cfa..ea446b1 100644 --- a/custom_formats/Radarr - SiC.yml +++ b/custom_formats/Radarr - SiC.yml @@ -25,10 +25,10 @@ conditions: negate: false required: true type: release_title - pattern: Not HDR + pattern: HDR - name: Radarr - DV negate: false required: true type: release_title - pattern: Dolby Vision + pattern: DV tests: [] diff --git a/custom_formats/Radarr - TrueHD ATMOS.yml b/custom_formats/Radarr - TrueHD ATMOS.yml index 5c09ac7..39f1d4b 100644 --- a/custom_formats/Radarr - TrueHD ATMOS.yml +++ b/custom_formats/Radarr - TrueHD ATMOS.yml @@ -8,35 +8,35 @@ conditions: negate: false required: true type: release_title - pattern: Radarr - TrueHD + pattern: Radarr - TrueHD (1) - name: Radarr - ATMOS negate: false required: true type: release_title - pattern: Radarr - ATMOS + pattern: Radarr - ATMOS (2) - name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital -- name: 'Radarr - Not Dolby Digital Plus ' + pattern: Basic Dolby Digital +- name: Radarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Radarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Radarr - Not DTS X negate: true required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC tests: [] diff --git a/custom_formats/Radarr - TrueHD.yml b/custom_formats/Radarr - TrueHD.yml index a3e912a..de31732 100644 --- a/custom_formats/Radarr - TrueHD.yml +++ b/custom_formats/Radarr - TrueHD.yml @@ -18,22 +18,22 @@ conditions: negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Radarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Radarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Radarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Radarr - Not RlsGrp (TrueHD only) negate: true required: true diff --git a/custom_formats/Radarr - VFF.yml b/custom_formats/Radarr - VFF.yml index cac9c59..92f2432 100644 --- a/custom_formats/Radarr - VFF.yml +++ b/custom_formats/Radarr - VFF.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Radarr - VF2 + pattern: VF2 (1) tests: [] diff --git a/custom_formats/Radarr - VFQ.yml b/custom_formats/Radarr - VFQ.yml index 4e17aa6..295711c 100644 --- a/custom_formats/Radarr - VFQ.yml +++ b/custom_formats/Radarr - VFQ.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Radarr - VF2 + pattern: VF2 (1) tests: [] diff --git a/custom_formats/Radarr - WEB Tier 01.yml b/custom_formats/Radarr - WEB Tier 01.yml index f2144f2..6f36953 100644 --- a/custom_formats/Radarr - WEB Tier 01.yml +++ b/custom_formats/Radarr - WEB Tier 01.yml @@ -104,7 +104,7 @@ conditions: negate: false required: false type: release_group - pattern: SiC + pattern: SiC (1) - name: Radarr - TEPES negate: false required: false diff --git a/custom_formats/Radarr - WEB Tier 02.yml b/custom_formats/Radarr - WEB Tier 02.yml index 82f36c1..69ff617 100644 --- a/custom_formats/Radarr - WEB Tier 02.yml +++ b/custom_formats/Radarr - WEB Tier 02.yml @@ -19,7 +19,7 @@ conditions: negate: false required: false type: release_group - pattern: dB + pattern: dB (1) - name: Radarr - Flights negate: false required: false @@ -54,7 +54,7 @@ conditions: negate: false required: false type: release_group - pattern: SbR + pattern: SbR (1) - name: Radarr - SMURF negate: false required: false diff --git a/custom_formats/Radarr - x265 (HD).yml b/custom_formats/Radarr - x265 (HD).yml index 43f84c9..15dbe41 100644 --- a/custom_formats/Radarr - x265 (HD).yml +++ b/custom_formats/Radarr - x265 (HD).yml @@ -9,7 +9,7 @@ conditions: negate: false required: true type: release_title - pattern: x|h265 + pattern: x265-HEVC - name: Radarr - Not 2160p negate: true required: true diff --git a/custom_formats/Radarr - x265 (no HDR-DV).yml b/custom_formats/Radarr - x265 (no HDR-DV).yml index 69e64cc..86f4604 100644 --- a/custom_formats/Radarr - x265 (no HDR-DV).yml +++ b/custom_formats/Radarr - x265 (no HDR-DV).yml @@ -9,12 +9,12 @@ conditions: negate: false required: true type: release_title - pattern: x|h265 + pattern: x265-HEVC - name: Radarr - Not HDR-DV negate: true required: true type: release_title - pattern: Not HDR-DV + pattern: HDR-DV - name: Radarr - Not 2160p negate: true required: true diff --git a/custom_formats/Radarr - x265.yml b/custom_formats/Radarr - x265.yml index 63d608d..fd51161 100644 --- a/custom_formats/Radarr - x265.yml +++ b/custom_formats/Radarr - x265.yml @@ -9,7 +9,7 @@ conditions: negate: false required: true type: release_title - pattern: x|h265 + pattern: x265-HEVC - name: Radarr - Not Remux negate: true required: true diff --git a/custom_formats/Sonarr - 1.0 Mono.yml b/custom_formats/Sonarr - 1.0 Mono.yml index ee26dcf..cb51404 100644 --- a/custom_formats/Sonarr - 1.0 Mono.yml +++ b/custom_formats/Sonarr - 1.0 Mono.yml @@ -8,12 +8,12 @@ conditions: negate: false required: true type: release_title - pattern: Not Mono + pattern: Mono - name: Sonarr - Not 3.0ch negate: true required: true type: release_title - pattern: Not 3.0ch + pattern: 3.0ch - name: Sonarr - Not 4.0ch negate: true required: true @@ -23,5 +23,5 @@ conditions: negate: true required: true type: release_title - pattern: Not High Channel Count + pattern: High Channel Count tests: [] diff --git a/custom_formats/Sonarr - 2.0 Stereo.yml b/custom_formats/Sonarr - 2.0 Stereo.yml index 21fae28..bf0b2d5 100644 --- a/custom_formats/Sonarr - 2.0 Stereo.yml +++ b/custom_formats/Sonarr - 2.0 Stereo.yml @@ -8,12 +8,12 @@ conditions: negate: false required: true type: release_title - pattern: Not Stereo + pattern: Stereo - name: Sonarr - Not 3.0ch negate: true required: true type: release_title - pattern: Not 3.0ch + pattern: 3.0ch - name: Sonarr - Not 4.0ch negate: true required: true @@ -23,10 +23,10 @@ conditions: negate: true required: true type: release_title - pattern: Not High Channel Count + pattern: High Channel Count - name: Sonarr - Not Mono negate: true required: true type: release_title - pattern: Not Mono + pattern: Mono tests: [] diff --git a/custom_formats/Sonarr - 3.0 Sound.yml b/custom_formats/Sonarr - 3.0 Sound.yml index 4311040..e814cfd 100644 --- a/custom_formats/Sonarr - 3.0 Sound.yml +++ b/custom_formats/Sonarr - 3.0 Sound.yml @@ -8,17 +8,17 @@ conditions: negate: false required: true type: release_title - pattern: Not 3.0ch + pattern: 3.0ch - name: Sonarr - Not Mono negate: true required: true type: release_title - pattern: Not Mono + pattern: Mono - name: Sonarr - Not Stereo negate: true required: true type: release_title - pattern: Not Stereo + pattern: Stereo - name: Sonarr - Not 4.0ch negate: true required: true @@ -28,5 +28,5 @@ conditions: negate: true required: true type: release_title - pattern: Not High Channel Count + pattern: High Channel Count tests: [] diff --git a/custom_formats/Sonarr - 4.0 Sound.yml b/custom_formats/Sonarr - 4.0 Sound.yml index 6b884e8..9144c5a 100644 --- a/custom_formats/Sonarr - 4.0 Sound.yml +++ b/custom_formats/Sonarr - 4.0 Sound.yml @@ -13,20 +13,20 @@ conditions: negate: true required: true type: release_title - pattern: Not Mono + pattern: Mono - name: Sonarr - Not Stereo negate: true required: true type: release_title - pattern: Not Stereo + pattern: Stereo - name: Sonarr - Not 3.0ch negate: true required: true type: release_title - pattern: Not 3.0ch + pattern: 3.0ch - name: Sonarr - Not High Channel Count negate: true required: true type: release_title - pattern: Not High Channel Count + pattern: High Channel Count tests: [] diff --git a/custom_formats/Sonarr - 7.1 Surround.yml b/custom_formats/Sonarr - 7.1 Surround.yml index 7197620..ef0ed13 100644 --- a/custom_formats/Sonarr - 7.1 Surround.yml +++ b/custom_formats/Sonarr - 7.1 Surround.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Not Low Channel Count + pattern: Low Channel Count tests: [] diff --git a/custom_formats/Sonarr - AAC.yml b/custom_formats/Sonarr - AAC.yml index 3c7488a..8d691d7 100644 --- a/custom_formats/Sonarr - AAC.yml +++ b/custom_formats/Sonarr - AAC.yml @@ -8,22 +8,22 @@ conditions: negate: false required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Sonarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS -- name: 'Sonarr - Not Dolby Digital Plus ' + pattern: DTS +- name: Sonarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Sonarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Sonarr - Not PCM negate: true required: true @@ -33,10 +33,10 @@ conditions: negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS tests: [] diff --git a/custom_formats/Sonarr - ATMOS (undefined).yml b/custom_formats/Sonarr - ATMOS (undefined).yml index 4816a52..2af9a38 100644 --- a/custom_formats/Sonarr - ATMOS (undefined).yml +++ b/custom_formats/Sonarr - ATMOS (undefined).yml @@ -13,27 +13,27 @@ conditions: negate: true required: true type: release_title - pattern: Not AAC -- name: 'Sonarr - Not Basic Dolby Digital ' + pattern: AAC +- name: Sonarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Sonarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Sonarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not PCM negate: true required: true diff --git a/custom_formats/Sonarr - Anime Dual Audio.yml b/custom_formats/Sonarr - Anime Dual Audio.yml index 50beddf..e00f99a 100644 --- a/custom_formats/Sonarr - Anime Dual Audio.yml +++ b/custom_formats/Sonarr - Anime Dual Audio.yml @@ -14,7 +14,7 @@ conditions: negate: true required: true type: release_title - pattern: Not Single Language Only + pattern: Single Language Only - name: Sonarr - Japanese Language negate: false required: false diff --git a/custom_formats/Sonarr - Anime Web Tier 02 (Top FanSubs).yml b/custom_formats/Sonarr - Anime Web Tier 02 (Top FanSubs).yml index a29f371..6724023 100644 --- a/custom_formats/Sonarr - Anime Web Tier 02 (Top FanSubs).yml +++ b/custom_formats/Sonarr - Anime Web Tier 02 (Top FanSubs).yml @@ -44,7 +44,7 @@ conditions: negate: false required: false type: release_title - pattern: Radarr - Dae + pattern: Dae (1) - name: Sonarr - Foxtrot negate: false required: false diff --git a/custom_formats/Sonarr - Anime Web Tier 03 (Official Subs).yml b/custom_formats/Sonarr - Anime Web Tier 03 (Official Subs).yml index 30cbae5..54f1c1e 100644 --- a/custom_formats/Sonarr - Anime Web Tier 03 (Official Subs).yml +++ b/custom_formats/Sonarr - Anime Web Tier 03 (Official Subs).yml @@ -34,5 +34,5 @@ conditions: negate: false required: false type: release_title - pattern: Radarr - ZR + pattern: ZR (1) tests: [] diff --git a/custom_formats/Sonarr - Bad Dual Groups.yml b/custom_formats/Sonarr - Bad Dual Groups.yml index 817cfeb..b55382a 100644 --- a/custom_formats/Sonarr - Bad Dual Groups.yml +++ b/custom_formats/Sonarr - Bad Dual Groups.yml @@ -138,7 +138,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - ZigZag + pattern: ZigZag (1) - name: Sonarr - ZNM negate: false required: false diff --git a/custom_formats/Sonarr - DD+ ATMOS.yml b/custom_formats/Sonarr - DD+ ATMOS.yml index 3146881..762a33c 100644 --- a/custom_formats/Sonarr - DD+ ATMOS.yml +++ b/custom_formats/Sonarr - DD+ ATMOS.yml @@ -8,12 +8,12 @@ conditions: negate: false required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Sonarr - ATMOS negate: false required: true type: release_title - pattern: Radarr - ATMOS + pattern: ATMOS (1) - name: Sonarr - Not TrueHD negate: true required: true @@ -23,22 +23,22 @@ conditions: negate: true required: true type: release_title - pattern: Not DTS -- name: 'Sonarr - Not Basic Dolby Digital ' + pattern: DTS +- name: Sonarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Sonarr - Not PCM negate: true required: true diff --git a/custom_formats/Sonarr - DD+.yml b/custom_formats/Sonarr - DD+.yml index 639779a..3c46f21 100644 --- a/custom_formats/Sonarr - DD+.yml +++ b/custom_formats/Sonarr - DD+.yml @@ -8,27 +8,27 @@ conditions: negate: false required: true type: release_title - pattern: Dolby Digital Plus + pattern: Dolby Digital Plus (1) - name: Sonarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Radarr - TrueHD-ATMOS + pattern: TrueHD-ATMOS (1) - name: Sonarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Sonarr - Not PCM negate: true required: true diff --git a/custom_formats/Sonarr - DD.yml b/custom_formats/Sonarr - DD.yml index 7d90d75..8481aea 100644 --- a/custom_formats/Sonarr - DD.yml +++ b/custom_formats/Sonarr - DD.yml @@ -8,32 +8,32 @@ conditions: negate: false required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Sonarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Sonarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Sonarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Sonarr - Not PCM negate: true required: true diff --git a/custom_formats/Sonarr - DTS X.yml b/custom_formats/Sonarr - DTS X.yml index f01b34a..d5be260 100644 --- a/custom_formats/Sonarr - DTS X.yml +++ b/custom_formats/Sonarr - DTS X.yml @@ -8,37 +8,37 @@ conditions: negate: false required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Sonarr - Not Basic DTS negate: true required: true type: release_title - pattern: Not Basic DTS + pattern: Basic DTS - name: Sonarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Sonarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Sonarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Sonarr - Not PCM negate: true required: true diff --git a/custom_formats/Sonarr - DTS-ES.yml b/custom_formats/Sonarr - DTS-ES.yml index 1f28722..36c7f41 100644 --- a/custom_formats/Sonarr - DTS-ES.yml +++ b/custom_formats/Sonarr - DTS-ES.yml @@ -13,37 +13,37 @@ conditions: negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Sonarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Sonarr - Not Basic DTS negate: true required: true type: release_title - pattern: Not Basic DTS -- name: 'Sonarr - Not Basic Dolby Digital ' + pattern: Basic DTS +- name: Sonarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Sonarr - Not DTS X negate: true required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Sonarr - Not PCM negate: true required: true diff --git a/custom_formats/Sonarr - DTS-HD HRA.yml b/custom_formats/Sonarr - DTS-HD HRA.yml index 40cde76..51473c5 100644 --- a/custom_formats/Sonarr - DTS-HD HRA.yml +++ b/custom_formats/Sonarr - DTS-HD HRA.yml @@ -13,37 +13,37 @@ conditions: negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Sonarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Sonarr - Not Basic DTS negate: true required: true type: release_title - pattern: Not Basic DTS -- name: 'Sonarr - Not Basic Dolby Digital ' + pattern: Basic DTS +- name: Sonarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Sonarr - Not DTS X negate: true required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Sonarr - Not PCM negate: true required: true @@ -53,10 +53,10 @@ conditions: negate: true required: true type: release_title - pattern: Radarr - DTS-ES + pattern: DTS-ES (1) - name: Sonarr - Not 6.1 Surround negate: true required: true type: release_title - pattern: Radarr - 6.1 Surround + pattern: 6.1 Surround (1) tests: [] diff --git a/custom_formats/Sonarr - DTS-HD MA.yml b/custom_formats/Sonarr - DTS-HD MA.yml index fb80a1e..da48a8f 100644 --- a/custom_formats/Sonarr - DTS-HD MA.yml +++ b/custom_formats/Sonarr - DTS-HD MA.yml @@ -8,37 +8,37 @@ conditions: negate: false required: true type: release_title - pattern: Not DTS-HD + pattern: DTS-HD MA - name: Sonarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Sonarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus -- name: 'Sonarr - Not Basic Dolby Digital ' + pattern: Dolby Digital Plus +- name: Sonarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Sonarr - Not DTS X negate: true required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Sonarr - Not PCM negate: true required: true @@ -48,5 +48,5 @@ conditions: negate: true required: true type: release_title - pattern: Not DTS-HD HRA-ES + pattern: DTS-HD HRA-ES tests: [] diff --git a/custom_formats/Sonarr - DTS.yml b/custom_formats/Sonarr - DTS.yml index 2393736..ca52971 100644 --- a/custom_formats/Sonarr - DTS.yml +++ b/custom_formats/Sonarr - DTS.yml @@ -8,47 +8,47 @@ conditions: negate: false required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Sonarr - Not DTS-HD negate: true required: true type: release_title - pattern: Not DTS-HD + pattern: DTS-HD MA - name: Sonarr - Not DTS-HD HRA-ES negate: true required: true type: release_title - pattern: Not DTS-HD HRA-ES + pattern: DTS-HD HRA-ES - name: Sonarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Sonarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Sonarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital - name: Sonarr - Not DTS X negate: true required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not AAC negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Sonarr - Not PCM negate: true required: true diff --git a/custom_formats/Sonarr - DV (Disk).yml b/custom_formats/Sonarr - DV (Disk).yml index b556129..bd74e12 100644 --- a/custom_formats/Sonarr - DV (Disk).yml +++ b/custom_formats/Sonarr - DV (Disk).yml @@ -14,7 +14,7 @@ conditions: negate: false required: true type: release_title - pattern: Dolby Vision + pattern: DV - name: Sonarr - No FANRES negate: true required: true @@ -29,5 +29,5 @@ conditions: negate: true required: true type: release_title - pattern: Not Hybrid Release Group + pattern: Hybrid Release Group tests: [] diff --git a/custom_formats/Sonarr - DV (w-o HDR fallback).yml b/custom_formats/Sonarr - DV (w-o HDR fallback).yml index 28f0fca..0dfe603 100644 --- a/custom_formats/Sonarr - DV (w-o HDR fallback).yml +++ b/custom_formats/Sonarr - DV (w-o HDR fallback).yml @@ -10,7 +10,7 @@ conditions: negate: false required: true type: release_title - pattern: Dolby Vision + pattern: DV - name: Sonarr - WEBDL negate: false required: false @@ -25,12 +25,12 @@ conditions: negate: true required: true type: release_group - pattern: Not RlsGrp + pattern: RlsGrp - name: Sonarr - Not HDR negate: true required: true type: release_title - pattern: Not HDR + pattern: HDR - name: Sonarr - Not Hulu negate: true required: true diff --git a/custom_formats/Sonarr - DV Boost.yml b/custom_formats/Sonarr - DV Boost.yml index ec87fe5..48e2279 100644 --- a/custom_formats/Sonarr - DV Boost.yml +++ b/custom_formats/Sonarr - DV Boost.yml @@ -8,5 +8,5 @@ conditions: negate: false required: false type: release_title - pattern: Dolby Vision + pattern: DV tests: [] diff --git a/custom_formats/Sonarr - Dubs Only.yml b/custom_formats/Sonarr - Dubs Only.yml index 8ed5b02..6bb3214 100644 --- a/custom_formats/Sonarr - Dubs Only.yml +++ b/custom_formats/Sonarr - Dubs Only.yml @@ -18,7 +18,7 @@ conditions: negate: false required: false type: release_title - pattern: KaiDubs (Not Dual Audio) + pattern: KaiDubs (Dual Audio) - name: Sonarr - KamiFS negate: false required: false @@ -28,7 +28,7 @@ conditions: negate: false required: false type: release_title - pattern: KS (Not Dual Audio) + pattern: KS (Dual Audio) - name: Sonarr - torenter69 negate: false required: false diff --git a/custom_formats/Sonarr - FLAC.yml b/custom_formats/Sonarr - FLAC.yml index 96dbd15..ee3d98c 100644 --- a/custom_formats/Sonarr - FLAC.yml +++ b/custom_formats/Sonarr - FLAC.yml @@ -8,7 +8,7 @@ conditions: negate: false required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not PCM negate: true required: true @@ -18,25 +18,25 @@ conditions: negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Sonarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Sonarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Sonarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital -- name: 'Sonarr - Not Dolby Digital Plus ' + pattern: Basic Dolby Digital +- name: Sonarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus tests: [] diff --git a/custom_formats/Sonarr - FR WEB Tier 02.yml b/custom_formats/Sonarr - FR WEB Tier 02.yml index f625d3d..f0635d9 100644 --- a/custom_formats/Sonarr - FR WEB Tier 02.yml +++ b/custom_formats/Sonarr - FR WEB Tier 02.yml @@ -39,7 +39,7 @@ conditions: negate: false required: false type: release_group - pattern: NoNe + pattern: NoNe (1) - name: Sonarr - pERsO negate: false required: false diff --git a/custom_formats/Sonarr - German Remux Tier 01.yml b/custom_formats/Sonarr - German Remux Tier 01.yml index 5c28e9f..164927e 100644 --- a/custom_formats/Sonarr - German Remux Tier 01.yml +++ b/custom_formats/Sonarr - German Remux Tier 01.yml @@ -14,7 +14,7 @@ conditions: negate: false required: false type: release_group - pattern: pmHD + pattern: pmHD (1) - name: Sonarr - NIMA4K negate: false required: false @@ -24,7 +24,7 @@ conditions: negate: false required: false type: release_group - pattern: QfG + pattern: QfG (1) - name: Sonarr - TSCC negate: false required: false diff --git a/custom_formats/Sonarr - German Web Tier 01.yml b/custom_formats/Sonarr - German Web Tier 01.yml index 4435f83..5c86baa 100644 --- a/custom_formats/Sonarr - German Web Tier 01.yml +++ b/custom_formats/Sonarr - German Web Tier 01.yml @@ -44,7 +44,7 @@ conditions: negate: false required: false type: release_group - pattern: QfG + pattern: QfG (1) - name: Sonarr - CNY negate: false required: false diff --git a/custom_formats/Sonarr - German.yml b/custom_formats/Sonarr - German.yml index 24a0c1c..0c29a37 100644 --- a/custom_formats/Sonarr - German.yml +++ b/custom_formats/Sonarr - German.yml @@ -29,5 +29,5 @@ conditions: negate: true required: true type: release_title - pattern: Not Subbed + pattern: Subbed tests: [] diff --git a/custom_formats/Sonarr - HD Bluray Tier 01.yml b/custom_formats/Sonarr - HD Bluray Tier 01.yml index 2637f92..a7baae0 100644 --- a/custom_formats/Sonarr - HD Bluray Tier 01.yml +++ b/custom_formats/Sonarr - HD Bluray Tier 01.yml @@ -25,7 +25,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - Chotab + pattern: Chotab (1) - name: Sonarr - CtrlHD negate: false required: false diff --git a/custom_formats/Sonarr - HDR.yml b/custom_formats/Sonarr - HDR.yml index 8fc5156..96a9f4b 100644 --- a/custom_formats/Sonarr - HDR.yml +++ b/custom_formats/Sonarr - HDR.yml @@ -13,7 +13,7 @@ conditions: negate: false required: false type: release_title - pattern: Radarr - HDR + pattern: HDR (1) - name: Sonarr - HDR10 negate: false required: false @@ -23,7 +23,7 @@ conditions: negate: false required: false type: release_title - pattern: HDR10+ + pattern: HDR10+ (1) - name: Sonarr - HLG negate: false required: false diff --git a/custom_formats/Sonarr - HDR10+ Boost.yml b/custom_formats/Sonarr - HDR10+ Boost.yml index 9fa5a5e..f318979 100644 --- a/custom_formats/Sonarr - HDR10+ Boost.yml +++ b/custom_formats/Sonarr - HDR10+ Boost.yml @@ -8,5 +8,5 @@ conditions: negate: false required: false type: release_title - pattern: HDR10+ + pattern: HDR10+ (1) tests: [] diff --git a/custom_formats/Sonarr - Hybrid.yml b/custom_formats/Sonarr - Hybrid.yml index 542b061..a7f35b0 100644 --- a/custom_formats/Sonarr - Hybrid.yml +++ b/custom_formats/Sonarr - Hybrid.yml @@ -15,7 +15,7 @@ conditions: negate: true required: true type: release_group - pattern: Radarr - Hybrid Release Group + pattern: Hybrid Release Group (1) - name: Sonarr - Remux negate: false required: false diff --git a/custom_formats/Sonarr - LQ.yml b/custom_formats/Sonarr - LQ.yml index 9a94235..cecd377 100644 --- a/custom_formats/Sonarr - LQ.yml +++ b/custom_formats/Sonarr - LQ.yml @@ -43,7 +43,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - Feranki1980 + pattern: Feranki1980 (1) - name: Sonarr - FGT negate: false required: false diff --git a/custom_formats/Sonarr - MAX.yml b/custom_formats/Sonarr - MAX.yml index 4603c06..cee1562 100644 --- a/custom_formats/Sonarr - MAX.yml +++ b/custom_formats/Sonarr - MAX.yml @@ -9,7 +9,7 @@ conditions: negate: false required: false type: release_title - pattern: Max + pattern: Max (1) - name: Sonarr - MAX Rename negate: false required: false diff --git a/custom_formats/Sonarr - MULTi.yml b/custom_formats/Sonarr - MULTi.yml index 4050495..a94237a 100644 --- a/custom_formats/Sonarr - MULTi.yml +++ b/custom_formats/Sonarr - MULTi.yml @@ -8,5 +8,5 @@ conditions: negate: false required: true type: release_title - pattern: Multi + pattern: Multi (1) tests: [] diff --git a/custom_formats/Sonarr - Not German or English.yml b/custom_formats/Sonarr - Not German or English.yml index dcce6ff..9e61102 100644 --- a/custom_formats/Sonarr - Not German or English.yml +++ b/custom_formats/Sonarr - Not German or English.yml @@ -19,5 +19,5 @@ conditions: negate: true required: true type: release_title - pattern: Not German in Title + pattern: German in Title tests: [] diff --git a/custom_formats/Sonarr - Opus.yml b/custom_formats/Sonarr - Opus.yml index 927bd57..0a7671a 100644 --- a/custom_formats/Sonarr - Opus.yml +++ b/custom_formats/Sonarr - Opus.yml @@ -14,5 +14,5 @@ conditions: negate: true required: true type: release_group - pattern: Not OPUS Release Group + pattern: OPUS Release Group tests: [] diff --git a/custom_formats/Sonarr - PCM.yml b/custom_formats/Sonarr - PCM.yml index 58e445e..67956c8 100644 --- a/custom_formats/Sonarr - PCM.yml +++ b/custom_formats/Sonarr - PCM.yml @@ -13,30 +13,30 @@ conditions: negate: true required: true type: release_title - pattern: Not AAC + pattern: AAC - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Sonarr - Not TrueHD-ATMOS negate: true required: true type: release_title - pattern: Not TrueHD-ATMOS + pattern: TrueHD-ATMOS - name: Sonarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital -- name: 'Sonarr - Not Dolby Digital Plus ' + pattern: Basic Dolby Digital +- name: Sonarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus tests: [] diff --git a/custom_formats/Sonarr - Remaster.yml b/custom_formats/Sonarr - Remaster.yml index d3c18cd..2e23447 100644 --- a/custom_formats/Sonarr - Remaster.yml +++ b/custom_formats/Sonarr - Remaster.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Not 4K Remaster + pattern: 4K Remaster tests: [] diff --git a/custom_formats/Sonarr - Remux Tier 01.yml b/custom_formats/Sonarr - Remux Tier 01.yml index 3846403..268f476 100644 --- a/custom_formats/Sonarr - Remux Tier 01.yml +++ b/custom_formats/Sonarr - Remux Tier 01.yml @@ -24,7 +24,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - FraMeSToR + pattern: FraMeSToR (1) - name: Sonarr - PmP negate: false required: false diff --git a/custom_formats/Sonarr - Repack-Proper.yml b/custom_formats/Sonarr - Repack-Proper.yml index 607f839..907e5a6 100644 --- a/custom_formats/Sonarr - Repack-Proper.yml +++ b/custom_formats/Sonarr - Repack-Proper.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Not Higher Version Repack-Proper + pattern: Higher Version Repack-Proper tests: [] diff --git a/custom_formats/Sonarr - Repack2.yml b/custom_formats/Sonarr - Repack2.yml index 99d37c0..eef4de3 100644 --- a/custom_formats/Sonarr - Repack2.yml +++ b/custom_formats/Sonarr - Repack2.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Not Repack-Proper 3 + pattern: Repack-Proper 3 tests: [] diff --git a/custom_formats/Sonarr - TrueHD ATMOS.yml b/custom_formats/Sonarr - TrueHD ATMOS.yml index 3aa87b9..25688ff 100644 --- a/custom_formats/Sonarr - TrueHD ATMOS.yml +++ b/custom_formats/Sonarr - TrueHD ATMOS.yml @@ -18,25 +18,25 @@ conditions: negate: true required: true type: release_title - pattern: Not Basic Dolby Digital -- name: 'Sonarr - Not Dolby Digital Plus ' + pattern: Basic Dolby Digital +- name: Sonarr - Not Dolby Digital Plus negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Sonarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Sonarr - Not DTS X negate: true required: true type: release_title - pattern: Not DTS X + pattern: DTS X - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC tests: [] diff --git a/custom_formats/Sonarr - TrueHD.yml b/custom_formats/Sonarr - TrueHD.yml index 99204e8..11eb94e 100644 --- a/custom_formats/Sonarr - TrueHD.yml +++ b/custom_formats/Sonarr - TrueHD.yml @@ -18,20 +18,20 @@ conditions: negate: true required: true type: release_title - pattern: Not Dolby Digital Plus + pattern: Dolby Digital Plus - name: Sonarr - Not DTS negate: true required: true type: release_title - pattern: Not DTS + pattern: DTS - name: Sonarr - Not FLAC negate: true required: true type: release_title - pattern: Not FLAC + pattern: FLAC - name: Sonarr - Not Basic Dolby Digital negate: true required: true type: release_title - pattern: Not Basic Dolby Digital + pattern: Basic Dolby Digital tests: [] diff --git a/custom_formats/Sonarr - VFF.yml b/custom_formats/Sonarr - VFF.yml index 60cf432..9db0d62 100644 --- a/custom_formats/Sonarr - VFF.yml +++ b/custom_formats/Sonarr - VFF.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Radarr - VF2 + pattern: VF2 (1) tests: [] diff --git a/custom_formats/Sonarr - VFQ.yml b/custom_formats/Sonarr - VFQ.yml index 725f2ac..6669238 100644 --- a/custom_formats/Sonarr - VFQ.yml +++ b/custom_formats/Sonarr - VFQ.yml @@ -13,5 +13,5 @@ conditions: negate: true required: true type: release_title - pattern: Radarr - VF2 + pattern: VF2 (1) tests: [] diff --git a/custom_formats/Sonarr - WEB Tier 01.yml b/custom_formats/Sonarr - WEB Tier 01.yml index be24289..2859cfc 100644 --- a/custom_formats/Sonarr - WEB Tier 01.yml +++ b/custom_formats/Sonarr - WEB Tier 01.yml @@ -94,7 +94,7 @@ conditions: negate: false required: false type: release_group - pattern: SiC + pattern: SiC (1) - name: Sonarr - T6D negate: false required: false diff --git a/custom_formats/Sonarr - WEB Tier 02.yml b/custom_formats/Sonarr - WEB Tier 02.yml index c0947ed..7a2781c 100644 --- a/custom_formats/Sonarr - WEB Tier 02.yml +++ b/custom_formats/Sonarr - WEB Tier 02.yml @@ -29,7 +29,7 @@ conditions: negate: false required: false type: release_group - pattern: Radarr - Chotab + pattern: Chotab (1) - name: Sonarr - Cinefeel negate: false required: false @@ -54,7 +54,7 @@ conditions: negate: false required: false type: release_group - pattern: dB + pattern: dB (1) - name: Sonarr - DEEP negate: false required: false @@ -179,7 +179,7 @@ conditions: negate: false required: false type: release_group - pattern: SbR + pattern: SbR (1) - name: Sonarr - SDCC negate: false required: false diff --git a/custom_formats/Sonarr - x265 (HD).yml b/custom_formats/Sonarr - x265 (HD).yml index 6313146..c2d6641 100644 --- a/custom_formats/Sonarr - x265 (HD).yml +++ b/custom_formats/Sonarr - x265 (HD).yml @@ -9,7 +9,7 @@ conditions: negate: false required: true type: release_title - pattern: x|h265 + pattern: x265-HEVC - name: Sonarr - Not 2160p negate: true required: true diff --git a/custom_formats/Sonarr - x265 (no HDR-DV).yml b/custom_formats/Sonarr - x265 (no HDR-DV).yml index 80a1c6e..6d1e63e 100644 --- a/custom_formats/Sonarr - x265 (no HDR-DV).yml +++ b/custom_formats/Sonarr - x265 (no HDR-DV).yml @@ -9,12 +9,12 @@ conditions: negate: false required: true type: release_title - pattern: x|h265 + pattern: x265-HEVC - name: Sonarr - Not HDR-DV negate: true required: true type: release_title - pattern: Not HDR-DV + pattern: HDR-DV - name: Sonarr - Not 2160p negate: true required: true diff --git a/custom_formats/Sonarr - x265.yml b/custom_formats/Sonarr - x265.yml index 54c64be..3f11dab 100644 --- a/custom_formats/Sonarr - x265.yml +++ b/custom_formats/Sonarr - x265.yml @@ -9,7 +9,7 @@ conditions: negate: false required: true type: release_title - pattern: x|h265 + pattern: x265-HEVC - name: Sonarr - Not Remux negate: true required: true diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d36afd5 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,74 @@ +[project] +name = "profilarr-trash-guides" +version = "0.1.0" +description = "Generates a Profilarr database from TRaSH-Guides data" +readme = "README.md" +requires-python = ">=3.13" +dependencies = [ + "pyyaml", + "markdownify", +] + +[project.optional-dependencies] +dev = [ + "pytest>=7.0", + "pytest-cov>=4.0", + "pytest-mock>=3.10", + "pylint>=3.0", +] + +[tool.pytest.ini_options] +testpaths = ["tests"] +python_files = "test_*.py" +python_functions = "test_*" +python_classes = "Test*" +addopts = "-v --tb=short --strict-markers" +filterwarnings = [ + "ignore::DeprecationWarning", +] + +[tool.pylint.main] +py-version = "3.13" +jobs = 4 + +[tool.pylint.messages_control] +disable = [ + "C0103", # invalid-name + "C0114", # missing-module-docstring + "C0115", # missing-class-docstring + "C0116", # missing-function-docstring + "W0212", # protected-access + "R0913", # too-many-arguments + "R0902", # too-many-instance-attributes + "C0301", # line-too-long (use max-line-length instead) + "W0511", # fixme + "W0621", # redefined-outer-name - doesn't work with pytest fixtures +] + +[tool.pylint.format] +max-line-length = 100 + +[tool.pylint.design] +max-attributes = 10 +max-args = 7 +max-locals = 15 + +[tool.pylint.basic] +good-names = ["i", "j", "k", "x", "y", "z", "_", "f", "df", "e"] +bad-names = ["l", "O", "I"] + +[tool.pylint.variables] +dummy-variables-rgx = "^_" + +[tool.pylint.typecheck] +ignored-modules = ["yaml", "pytest"] + +[tool.pylint.similarities] +min-similarity-lines = 5 +ignore-imports = true + +[tool.pylint.logging] +logging-format-style = "new" + +[tool.pylint.reports] +reports = false diff --git a/regex_patterns/Not 3.0ch.yml b/regex_patterns/3.0ch.yml similarity index 82% rename from regex_patterns/Not 3.0ch.yml rename to regex_patterns/3.0ch.yml index f212ba5..662ec03 100644 --- a/regex_patterns/Not 3.0ch.yml +++ b/regex_patterns/3.0ch.yml @@ -1,4 +1,4 @@ -name: Not 3.0ch +name: 3.0ch pattern: '[^0-9]3[ .]0\b' description: '' tags: diff --git a/regex_patterns/Not 4K Remaster.yml b/regex_patterns/4K Remaster.yml similarity index 73% rename from regex_patterns/Not 4K Remaster.yml rename to regex_patterns/4K Remaster.yml index 5dc843e..9d07bc8 100644 --- a/regex_patterns/Not 4K Remaster.yml +++ b/regex_patterns/4K Remaster.yml @@ -1,4 +1,4 @@ -name: Not 4K Remaster +name: 4K Remaster pattern: 4K description: '' tags: diff --git a/regex_patterns/6.1 Surround (1).yml b/regex_patterns/6.1 Surround (1).yml new file mode 100644 index 0000000..545f5f4 --- /dev/null +++ b/regex_patterns/6.1 Surround (1).yml @@ -0,0 +1,7 @@ +name: 6.1 Surround (1) +pattern: '[^0-9]6[ .][0-1]' +description: '' +tags: +- Radarr +- Sonarr +tests: [] diff --git a/regex_patterns/Not AAC.yml b/regex_patterns/AAC.yml similarity index 83% rename from regex_patterns/Not AAC.yml rename to regex_patterns/AAC.yml index b40b960..d75a269 100644 --- a/regex_patterns/Not AAC.yml +++ b/regex_patterns/AAC.yml @@ -1,4 +1,4 @@ -name: Not AAC +name: AAC pattern: \bAAC(\b|\d) description: '' tags: diff --git a/regex_patterns/ATMOS (1).yml b/regex_patterns/ATMOS (1).yml new file mode 100644 index 0000000..9e5218d --- /dev/null +++ b/regex_patterns/ATMOS (1).yml @@ -0,0 +1,7 @@ +name: ATMOS (1) +pattern: \b(ATMOS|DDPA)(\b|\d) +description: '' +tags: +- Radarr +- Sonarr +tests: [] diff --git a/regex_patterns/Not Basic DTS.yml b/regex_patterns/Basic DTS.yml similarity index 78% rename from regex_patterns/Not Basic DTS.yml rename to regex_patterns/Basic DTS.yml index a0be7c3..7ecb4aa 100644 --- a/regex_patterns/Not Basic DTS.yml +++ b/regex_patterns/Basic DTS.yml @@ -1,4 +1,4 @@ -name: Not Basic DTS +name: Basic DTS pattern: DTS[ .]?[1-9] description: '' tags: diff --git a/regex_patterns/Not Basic Dolby Digital.yml b/regex_patterns/Basic Dolby Digital.yml similarity index 75% rename from regex_patterns/Not Basic Dolby Digital.yml rename to regex_patterns/Basic Dolby Digital.yml index 0d171d7..3b396d9 100644 --- a/regex_patterns/Not Basic Dolby Digital.yml +++ b/regex_patterns/Basic Dolby Digital.yml @@ -1,4 +1,4 @@ -name: Not Basic Dolby Digital +name: Basic Dolby Digital pattern: \bDD[^a-z+]|(?=3.13" + }, + "packageRules": [ + { + "description": "Auto-merge patch and minor updates for dependencies", + "matchUpdateTypes": ["patch", "minor"], + "automerge": true, + "automergeType": "pr" + }, + { + "description": "Do not auto-merge major version updates", + "matchUpdateTypes": ["major"], + "automerge": false + }, + { + "description": "Group Python dependencies", + "matchDatasources": ["pypi"], + "groupName": "Python dependencies", + "groupSlug": "python-deps" + } + ], + "schedule": [ + "before 3am on Monday" + ], + "timezone": "UTC", + "semanticCommits": true, + "prConcurrentLimit": 5, + "vulnerabilityAlerts": { + "labels": ["security"], + "automerge": true } } diff --git a/scripts/generate.py b/scripts/generate.py index 073d4a8..32a83b7 100644 --- a/scripts/generate.py +++ b/scripts/generate.py @@ -1,18 +1,12 @@ -# /// script -# requires-python = ">=3.13" -# dependencies = [ -# "markdownify", -# "pyyaml", -# ] -# /// import os import sys -import yaml +import yaml from utils.custom_formats import collect_custom_formats -from utils.regex_patterns import collect_regex_patterns -from utils.profiles import collect_profiles from utils.media_management import collect_media_management +from utils.profiles import collect_profiles +from utils.regex_patterns import collect_regex_patterns + # Prevent aliases from showing up yaml.Dumper.ignore_aliases = lambda *args: True @@ -20,7 +14,7 @@ yaml.Dumper.ignore_aliases = lambda *args: True def clear_output_dir(output_dir): if not os.path.exists(output_dir): - print(f"Output directory does not exist, skipping clearing") + print("Output directory does not exist, skipping clearing") else: for filename in os.listdir(output_dir): file_path = os.path.join(output_dir, filename) @@ -58,7 +52,7 @@ def main(): f"Custom format directory {trash_custom_formats_dir} does not exist, skipping." ) continue - custom_regex_patterns = collect_regex_patterns( + regex_patterns = collect_regex_patterns( service, trash_custom_formats_dir, regex_patterns_dir, @@ -79,7 +73,7 @@ def main(): ) continue trash_id_to_scoring_mapping = collect_custom_formats( - service, trash_custom_formats_dir, custom_formats_dir, custom_regex_patterns + service, trash_custom_formats_dir, custom_formats_dir, regex_patterns ) collect_profiles( service, diff --git a/scripts/utils/custom_formats.py b/scripts/utils/custom_formats.py index c6d77d6..8bc063f 100644 --- a/scripts/utils/custom_formats.py +++ b/scripts/utils/custom_formats.py @@ -1,15 +1,16 @@ import os -import json -import yaml +import yaml from markdownify import markdownify -from utils.mappings.languages import LANGUAGE_MAPPING +from utils.file_utils import iterate_json_files from utils.mappings.indexer_flags import INDEXER_FLAG_MAPPING -from utils.mappings.release_type import RELEASE_TYPE_MAPPING +from utils.mappings.languages import LANGUAGE_MAPPING from utils.mappings.quality_modifiers import QUALITY_MODIFIER_MAPPING +from utils.mappings.release_type import RELEASE_TYPE_MAPPING from utils.mappings.source import SOURCE_MAPPING -from utils.strings import get_name, get_regex_pattern_name +from utils.strings import get_name + IMPLEMENTATION_TO_TAG_MAPPING = { "ReleaseTitleSpecification": "Release Title", @@ -39,54 +40,68 @@ SERVICE_TO_TRASH_GUIDES_URL = { } -def collect_custom_format( - service, file_name, input_json, output_dir, custom_regex_patterns +def _create_condition_base(service, spec): + """Create base condition structure from specification.""" + return { + "name": get_name(service, spec.get("name", "")), + "negate": spec.get("negate", False), + "required": spec.get("required", False), + "type": IMPLEMENTATION_TO_TYPE_MAPPING.get( + spec.get("implementation"), "unknown" + ), + } + + +def _add_condition_value( + condition, implementation, spec, *, service, regex_patterns, file_name +): + """Add implementation-specific value to condition.""" + fields = spec.get("fields", {}) + value = fields.get("value") + + if implementation in ["ReleaseTitleSpecification", "ReleaseGroupSpecification"]: + pattern_name = regex_patterns["by_pattern"].get(value)["name"] + if not pattern_name: + raise ValueError( + f"Pattern '{value}' not found in collected regex patterns " + f"for {service} in custom format {file_name}." + ) + condition["pattern"] = pattern_name + elif implementation == "ResolutionSpecification": + condition["resolution"] = f"{value}p" + elif implementation == "SourceSpecification": + condition["source"] = SOURCE_MAPPING[service][value] + elif implementation == "LanguageSpecification": + condition["language"] = LANGUAGE_MAPPING[service][value] + elif implementation == "IndexerFlagSpecification": + condition["flag"] = INDEXER_FLAG_MAPPING[service][value] + elif implementation == "QualityModifierSpecification": + condition["qualityModifier"] = QUALITY_MODIFIER_MAPPING[service][value] + elif implementation == "ReleaseTypeSpecification": + condition["releaseType"] = RELEASE_TYPE_MAPPING[service][value] + else: + return False + return True + + +def _collect_custom_format( + service, file_name, input_json, output_dir, regex_patterns ): conditions = [] implementation_tags = set() for spec in input_json.get("specifications", []): - condition = { - "name": get_name(service, spec.get("name", "")), - "negate": spec.get("negate", False), - "required": spec.get("required", False), - "type": IMPLEMENTATION_TO_TYPE_MAPPING.get( - spec.get("implementation"), "unknown" - ), - } - implementation = spec.get("implementation") - implementation_tags.add(IMPLEMENTATION_TO_TAG_MAPPING[implementation]) - if implementation in ["ReleaseTitleSpecification", "ReleaseGroupSpecification"]: - pattern = spec.get("fields", {}).get("value") - condition["pattern"] = custom_regex_patterns.get( - pattern, get_regex_pattern_name(service, spec.get("name", "")) - ) - elif implementation in ["ResolutionSpecification"]: - condition["resolution"] = f"{spec.get('fields', {}).get('value')}p" - elif implementation in ["SourceSpecification"]: - condition["source"] = SOURCE_MAPPING[service][ - spec.get("fields", {}).get("value") - ] - elif implementation in ["LanguageSpecification"]: - # TODO: exceptLanguage - condition["language"] = LANGUAGE_MAPPING[service][ - spec.get("fields", {}).get("value") - ] - elif implementation in ["IndexerFlagSpecification"]: - condition["flag"] = INDEXER_FLAG_MAPPING[service][ - spec.get("fields", {}).get("value") - ] - elif implementation in ["QualityModifierSpecification"]: - condition["qualityModifier"] = QUALITY_MODIFIER_MAPPING[service][ - spec.get("fields", {}).get("value") - ] - elif implementation in ["ReleaseTypeSpecification"]: - condition["releaseType"] = RELEASE_TYPE_MAPPING[service][ - spec.get("fields", {}).get("value") - ] - else: + condition = _create_condition_base(service, spec) + if not _add_condition_value( + condition, + implementation, + spec, + service=service, + regex_patterns=regex_patterns, + file_name=file_name, + ): print(f"Unrecognised implementation ({implementation}), skipping for now.") continue @@ -120,23 +135,14 @@ def collect_custom_format( def collect_custom_formats(service, input_dir, output_dir, custom_regex_patterns): trash_id_to_scoring_mapping = {} - for root, _, files in os.walk(input_dir): - for filename in sorted(files): - if not filename.endswith(".json"): - continue + for _, file_stem, data in iterate_json_files(input_dir): + trash_id = data.get("trash_id") + trash_scores = data.get("trash_scores", {}) + if trash_id: + trash_id_to_scoring_mapping[trash_id] = trash_scores - file_path = os.path.join(root, filename) - file_stem = os.path.splitext(filename)[0] # Filename without extension - with open(file_path, "r", encoding="utf-8") as f: - data = json.load(f) - - trash_id = data.get("trash_id") - trash_scores = data.get("trash_scores", {}) - if trash_id: - trash_id_to_scoring_mapping[trash_id] = trash_scores - - collect_custom_format( - service, file_stem, data, output_dir, custom_regex_patterns - ) + _collect_custom_format( + service, file_stem, data, output_dir, custom_regex_patterns + ) return trash_id_to_scoring_mapping diff --git a/scripts/utils/file_utils.py b/scripts/utils/file_utils.py new file mode 100644 index 0000000..e7207f5 --- /dev/null +++ b/scripts/utils/file_utils.py @@ -0,0 +1,29 @@ +import json +import os + + +def iterate_json_files(input_dir): + """ + Generator that yields (file_path, file_stem, data) tuples for all JSON files + in the input directory and its subdirectories. + + Args: + input_dir: Directory to search for JSON files + + Yields: + Tuple of (file_path, file_stem, data) where: + - file_path: Full path to the JSON file + - file_stem: Filename without extension + - data: Parsed JSON data + """ + for root, _, files in os.walk(input_dir): + for filename in sorted(files): + if not filename.endswith(".json"): + continue + + file_path = os.path.join(root, filename) + file_stem = os.path.splitext(filename)[0] + with open(file_path, encoding="utf-8") as f: + data = json.load(f) + + yield file_path, file_stem, data diff --git a/scripts/utils/media_management.py b/scripts/utils/media_management.py index 45dbc0d..ca3216f 100644 --- a/scripts/utils/media_management.py +++ b/scripts/utils/media_management.py @@ -1,9 +1,11 @@ -import os import json +import os + import yaml from utils.mappings.misc_media_management import MISC_MEDIA_MANAGEMENT + BASE_NAMING_CONFIG = { "radarr": { "rename": True, @@ -28,7 +30,7 @@ BASE_NAMING_CONFIG = { BASE_QUALITY_DEFINITIONS = {"qualityDefinitions": {"radarr": {}, "sonarr": {}}} -def collect_misc_config(output_dir): +def _collect_misc_config(output_dir): output_file = os.path.join(output_dir, "misc.yml") with open(output_file, "w", encoding="utf-8") as f: @@ -37,14 +39,14 @@ def collect_misc_config(output_dir): print(f"Generated: {output_file}") -def collect_naming_formats(input_dir, output_dir): - output_file = os.path.join(output_dir, f"naming.yml") +def _collect_naming_formats(input_dir, output_dir): + output_file = os.path.join(output_dir, "naming.yml") new_config = BASE_NAMING_CONFIG.copy() radarr_input_file_path = os.path.join( input_dir, "radarr", "naming", "radarr-naming.json" ) - with open(radarr_input_file_path, "r", encoding="utf-8") as f: + with open(radarr_input_file_path, encoding="utf-8") as f: input_json = json.load(f) new_config["radarr"]["movieFormat"] = input_json["file"]["standard"] new_config["radarr"]["movieFolderFormat"] = input_json["folder"]["default"] @@ -52,7 +54,7 @@ def collect_naming_formats(input_dir, output_dir): sonarr_input_file_path = os.path.join( input_dir, "sonarr", "naming", "sonarr-naming.json" ) - with open(sonarr_input_file_path, "r", encoding="utf-8") as f: + with open(sonarr_input_file_path, encoding="utf-8") as f: input_json = json.load(f) standard_episode_format = input_json["episodes"]["standard"]["default"] daily_episode_format = input_json["episodes"]["daily"]["default"] @@ -71,14 +73,14 @@ def collect_naming_formats(input_dir, output_dir): print(f"Generated: {output_file}") -def collect_quality_definitions(input_dir, output_dir): +def _collect_quality_definitions(input_dir, output_dir): output_structure = BASE_QUALITY_DEFINITIONS.copy() output_file = os.path.join(output_dir, "quality_definitions.yml") radarr_input_file_path = os.path.join( input_dir, "radarr", "quality-size", "movie.json" ) - with open(radarr_input_file_path, "r", encoding="utf-8") as f: + with open(radarr_input_file_path, encoding="utf-8") as f: radarr_data = json.load(f) for quality in reversed(radarr_data["qualities"]): profilarr_quality = { @@ -93,7 +95,7 @@ def collect_quality_definitions(input_dir, output_dir): sonarr_input_file_path = os.path.join( input_dir, "sonarr", "quality-size", "series.json" ) - with open(sonarr_input_file_path, "r", encoding="utf-8") as f: + with open(sonarr_input_file_path, encoding="utf-8") as f: sonarr_data = json.load(f) for quality in reversed(sonarr_data["qualities"]): profilarr_quality = { @@ -112,6 +114,6 @@ def collect_quality_definitions(input_dir, output_dir): def collect_media_management(input_dir, output_dir): - collect_misc_config(output_dir) - collect_naming_formats(input_dir, output_dir) - collect_quality_definitions(input_dir, output_dir) + _collect_misc_config(output_dir) + _collect_naming_formats(input_dir, output_dir) + _collect_quality_definitions(input_dir, output_dir) diff --git a/scripts/utils/profiles.py b/scripts/utils/profiles.py index e922a9c..da99b90 100644 --- a/scripts/utils/profiles.py +++ b/scripts/utils/profiles.py @@ -1,14 +1,14 @@ import os -import json -import yaml +import yaml from markdownify import markdownify +from utils.file_utils import iterate_json_files from utils.mappings.qualities import QUALITIES from utils.strings import get_name -def collect_profile_formats( +def _collect_profile_formats( service, trash_score_name, format_items, trash_id_to_scoring_mapping ): profile_formats = [] @@ -29,14 +29,14 @@ def collect_profile_formats( ) -def get_quality_id(quality_name): +def _get_quality_id(quality_name): return next( (quality["id"] for quality in QUALITIES if quality["name"] == quality_name), None, ) -def collect_qualities(items): +def _collect_qualities(items): qualities = [] quality_collection_id = -1 for item in items: @@ -44,7 +44,7 @@ def collect_qualities(items): continue quality = { - "id": get_quality_id(item.get("name", "")), + "id": _get_quality_id(item.get("name", "")), "name": item.get("name", ""), } if item.get("items") is not None: @@ -54,14 +54,14 @@ def collect_qualities(items): quality["qualities"] = [] for sub_item in item["items"]: quality["qualities"].append( - {"id": get_quality_id(sub_item), "name": sub_item} + {"id": _get_quality_id(sub_item), "name": sub_item} ) qualities.append(quality) return list(reversed(qualities)) -def get_upgrade_until(quality_name, profile_qualities): +def _get_upgrade_until(quality_name, profile_qualities): found_quality = next( quality for quality in profile_qualities if quality["name"] == quality_name ) @@ -73,10 +73,10 @@ def get_upgrade_until(quality_name, profile_qualities): return found_quality -def collect_profile(service, input_json, output_dir, trash_id_to_scoring_mapping): +def _collect_profile(service, input_json, output_dir, trash_id_to_scoring_mapping): # Compose YAML structure name = input_json.get("name", "") - profile_qualities = collect_qualities(input_json.get("items", [])) + profile_qualities = _collect_qualities(input_json.get("items", [])) yml_data = { "name": get_name(service, name), "description": f"""[Profile from TRaSH-Guides.](https://trash-guides.info/{service.capitalize()}/{service}-setup-quality-profiles) @@ -87,14 +87,14 @@ def collect_profile(service, input_json, output_dir, trash_id_to_scoring_mapping "minCustomFormatScore": input_json.get("minFormatScore", 0), "upgradeUntilScore": input_json.get("cutoffFormatScore", 0), "minScoreIncrement": input_json.get("minUpgradeFormatScore", 0), - "custom_formats": collect_profile_formats( + "custom_formats": _collect_profile_formats( service, input_json.get("trash_score_set"), input_json.get("formatItems", {}), trash_id_to_scoring_mapping, ), "qualities": profile_qualities, - "upgrade_until": get_upgrade_until(input_json.get("cutoff"), profile_qualities), + "upgrade_until": _get_upgrade_until(input_json.get("cutoff"), profile_qualities), "language": input_json.get("language", "any").lower(), } @@ -111,12 +111,5 @@ def collect_profiles( output_dir, trash_id_to_scoring_mapping, ): - for root, _, files in os.walk(input_dir): - for filename in sorted(files): - if not filename.endswith(".json"): - continue - - file_path = os.path.join(root, filename) - with open(file_path, "r", encoding="utf-8") as f: - data = json.load(f) - collect_profile(service, data, output_dir, trash_id_to_scoring_mapping) + for _, _, data in iterate_json_files(input_dir): + _collect_profile(service, data, output_dir, trash_id_to_scoring_mapping) diff --git a/scripts/utils/regex_patterns.py b/scripts/utils/regex_patterns.py index 855362d..9c66a46 100644 --- a/scripts/utils/regex_patterns.py +++ b/scripts/utils/regex_patterns.py @@ -1,16 +1,142 @@ import os -import json + import yaml -from utils.strings import get_regex_pattern_name, get_safe_name - -duplicate_regex_patterns = {} +from utils.file_utils import iterate_json_files +from utils.strings import get_name -def collect_regex_pattern(service, file_name, input_json, output_dir): - # Find the first pattern in specifications - pattern = None +regex_patterns = { + "by_name": {}, + "by_pattern": {}, +} + +def _update_existing_pattern_for_service(existing_data, service, output_dir): + """Update an existing pattern file to support multiple services.""" + existing_path = existing_data["file_path"] + if not os.path.exists(existing_path): + raise FileNotFoundError(f"Expected pattern file not found: {existing_path}") + + # Use the existing pattern name to preserve casing + existing_name = existing_data["name"] + + # Remove service prefix if present (e.g., "Radarr - " or "Sonarr - ") + # to get the base pattern name with original casing + for svc in ["Radarr", "Sonarr"]: + prefix = f"{svc} - " + if existing_name.startswith(prefix): + existing_name = existing_name[len(prefix):] + break + + # Use the existing (original) name with preserved casing + safe_name = existing_name + new_path = os.path.join(output_dir, f"{safe_name}.yml") + + # Rename file if needed (from service-specific to generic name) + if existing_path != new_path and not os.path.exists(new_path): + os.rename(existing_path, new_path) + # Update tracking data + old_name = existing_data["name"] + existing_data["file_path"] = new_path + existing_data["name"] = safe_name + # Update by_name dict with normalized keys + old_key = old_name.lower() + if old_key in regex_patterns["by_name"]: + regex_patterns["by_name"].pop(old_key) + regex_patterns["by_name"][safe_name.lower()] = existing_data + + # Update the file to add the new service tag + with open(new_path, "r+", encoding="utf-8") as f: + yml_data = yaml.safe_load(f) + if "tags" not in yml_data: + yml_data["tags"] = [] + if service.capitalize() not in yml_data["tags"]: + yml_data["tags"].append(service.capitalize()) + yml_data["name"] = safe_name + f.seek(0) + yaml.dump(yml_data, f, sort_keys=False, allow_unicode=True) + f.truncate() + + # Update services list in tracking + if service.capitalize() not in existing_data["services"]: + existing_data["services"].append(service.capitalize()) + + # Update name in tracking data + existing_data["name"] = safe_name + + print(f"Updated pattern for multiple services: {new_path}") + + +def _generate_unique_pattern_name(initial_name, pattern, output_dir): + """Generate a unique pattern name if there are collisions.""" + final_name = initial_name + counter = 1 + # Use lowercase for case-insensitive comparison + normalized_key = final_name.lower() + + while normalized_key in regex_patterns["by_name"]: + existing_pattern_data = regex_patterns["by_name"][normalized_key] + if existing_pattern_data["pattern"] == pattern: + print(f"Pattern with same name and pattern already exists: {final_name}") + return None + final_name = f"{initial_name} ({counter})" + normalized_key = final_name.lower() + counter += 1 + + # Also check for case-insensitive file system collisions + while _case_insensitive_file_exists(output_dir, f"{final_name}.yml"): + final_name = f"{initial_name} ({counter})" + normalized_key = final_name.lower() + counter += 1 + + return final_name + + +def _case_insensitive_file_exists(directory, filename): + """Check if a file exists with case-insensitive matching.""" + if not os.path.exists(directory): + return False + + filename_lower = filename.lower() + for existing_file in os.listdir(directory): + if existing_file.lower() == filename_lower: + return True + return False + + +def _create_new_pattern_file(service, pattern, final_name, output_dir): + """Create a new pattern file.""" + yml_data = { + "name": final_name, + "pattern": pattern, + "description": "", + "tags": [service.capitalize()], + "tests": [], + } + + output_path = os.path.join(output_dir, f"{final_name}.yml") + + with open(output_path, "w", encoding="utf-8") as f: + yaml.dump(yml_data, f, sort_keys=False, allow_unicode=True) + + # Store in dict (twice - by name and by pattern) + # Use lowercase keys for case-insensitive lookups + pattern_data = { + "name": final_name, + "pattern": pattern, + "services": [service.capitalize()], + "file_path": output_path, + } + regex_patterns["by_name"][final_name.lower()] = pattern_data + regex_patterns["by_pattern"][pattern] = pattern_data + + print(f"Generated: {output_path}") + return True + + +def _collect_regex_pattern(service, file_name, input_json, output_dir): + """Extract and collect regex patterns from specifications.""" for spec in input_json.get("specifications", []): implementation = spec.get("implementation") if implementation not in [ @@ -20,78 +146,37 @@ def collect_regex_pattern(service, file_name, input_json, output_dir): continue pattern = spec.get("fields", {}).get("value") - if not pattern: print(f"No pattern found in {file_name} for {implementation}") continue - # Compose YAML structure - name = spec.get("name", "") + spec_name = spec.get("name", "") - existing_pattern_name = duplicate_regex_patterns.get(pattern) - if existing_pattern_name: - existing_pattern_path = os.path.join( - output_dir, - f"{existing_pattern_name}.yml", + # Check if this exact pattern was already seen + if pattern in regex_patterns["by_pattern"]: + existing_data = regex_patterns["by_pattern"][pattern] + + # If previously seen for the same service with the same regex - Skip + if service.capitalize() in existing_data.get("services", []): + print(f"Pattern already exists for {service}: {spec_name}") + continue + + # If previously seen for a different service - update to support both + _update_existing_pattern_for_service( + existing_data, service, output_dir ) - if ( - os.path.exists(existing_pattern_path) - and service.capitalize() not in existing_pattern_path - ): - new_path = os.path.join( - output_dir, - f"{get_safe_name(name)}.yml", - ) - os.rename( - existing_pattern_path, - new_path, - ) - with open(new_path, "r+", encoding="utf-8") as f: - yml_data = yaml.safe_load(f) - yml_data["name"] = get_safe_name(name) - if service.capitalize() not in yml_data["tags"]: - yml_data["tags"].append(service.capitalize()) - f.seek(0) - yaml.dump(yml_data, f, sort_keys=False, allow_unicode=True) - f.truncate() - duplicate_regex_patterns[pattern] = get_safe_name(name) - continue - else: - duplicate_regex_patterns[pattern] = get_regex_pattern_name(service, name) - - yml_data = { - "name": get_regex_pattern_name(service, name), - "pattern": pattern, - "description": "", - "tags": [service.capitalize()], - "tests": [], - } - - # Output path - output_path = os.path.join( - output_dir, - f"{get_regex_pattern_name(service, name)}.yml", - ) - - if os.path.exists(output_path): - print(f"exists{output_path}, skipping") continue - with open(output_path, "w", encoding="utf-8") as f: - yaml.dump(yml_data, f, sort_keys=False, allow_unicode=True) - print(f"Generated: {output_path}") + # Pattern not seen before - check for name collisions + initial_name = get_name(service, spec_name, remove_not=True) + final_name = _generate_unique_pattern_name(initial_name, pattern, output_dir) + + if final_name: + _create_new_pattern_file(service, pattern, final_name, output_dir) def collect_regex_patterns(service, input_dir, output_dir): - for root, _, files in os.walk(input_dir): - for filename in sorted(files): - if not filename.endswith(".json"): - continue + for _, file_stem, data in iterate_json_files(input_dir): + _collect_regex_pattern(service, file_stem, data, output_dir) - file_path = os.path.join(root, filename) - file_stem = os.path.splitext(filename)[0] # Filename without extension - with open(file_path, "r", encoding="utf-8") as f: - data = json.load(f) - collect_regex_pattern(service, file_stem, data, output_dir) - - return duplicate_regex_patterns + return regex_patterns diff --git a/scripts/utils/strings.py b/scripts/utils/strings.py index 48972c5..bbae5fa 100644 --- a/scripts/utils/strings.py +++ b/scripts/utils/strings.py @@ -1,17 +1,17 @@ -def get_safe_name(name): +def _get_safe_name(name, remove_not=False): + result = name + if remove_not: + result = result.replace("Not ", "") return ( - name.replace("/", "-") + result.replace("/", "-") .replace("[", "(") .replace("]", ")") .replace("HDR10Plus", "HDR10+") .replace("10 bit", "10bit") .replace("Atmos", "ATMOS") + .strip() ) -def get_name(service, name): - return f"{service.capitalize()} - {get_safe_name(name)}" - - -def get_regex_pattern_name(service, regex_pattern_name): - return get_name(service, regex_pattern_name).replace("Not ", "") +def get_name(service, name, remove_not=False): + return f"{service.capitalize()} - {_get_safe_name(name, remove_not)}" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..d37419a --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,11 @@ +# Run tests on output data stored in regex_patterns, custom_formats and profiles +# Ensure al references are correct and no broken links have been generated. + +# Every custom format pattern should exist in regex_patterns by a file with the same name. +# Every profile custom format reference should exist in custom_formats by a file with the same name. +# If a file can not be found the test should fail. + +# Tests should cover all the files in the output directories, it can be assumed the data has been updated already. +# Instructions should exist in README on how to run the tests. +# Pytest framework is used for the tests +# Tests are run in github actions - after generation completion. diff --git a/tests/test_custom_formats.py b/tests/test_custom_formats.py new file mode 100644 index 0000000..3a9ef65 --- /dev/null +++ b/tests/test_custom_formats.py @@ -0,0 +1,98 @@ +"""Tests to ensure custom format patterns reference valid regex pattern files.""" + +from pathlib import Path + +import pytest +import yaml + + +# Get the project root directory +PROJECT_ROOT = Path(__file__).parent.parent +CUSTOM_FORMATS_DIR = PROJECT_ROOT / "custom_formats" +REGEX_PATTERNS_DIR = PROJECT_ROOT / "regex_patterns" + + +def get_all_custom_formats(): + """Get all custom format YAML files.""" + if not CUSTOM_FORMATS_DIR.exists(): + return [] + return list(CUSTOM_FORMATS_DIR.glob("*.yml")) + +@pytest.fixture(scope="module") +def available_regex_patterns_file_names(): + """Fixture to load all available regex pattern names once.""" + if not REGEX_PATTERNS_DIR.exists(): + return set() + + pattern_names = set() + for yml_file in REGEX_PATTERNS_DIR.glob("*.yml"): + # Use filename without extension as pattern name + pattern_names.add(yml_file.stem) + return pattern_names + + +@pytest.fixture(scope="module") +def available_regex_patterns_names(): + """Fixture to load all available regex pattern names once.""" + if not REGEX_PATTERNS_DIR.exists(): + return set() + + pattern_names = set() + for yml_file in REGEX_PATTERNS_DIR.glob("*.yml"): + # Read name from YAML file content + with open(yml_file, encoding="utf-8") as f: + data = yaml.safe_load(f) + if data and "name" in data: + pattern_names.add(data["name"]) + return pattern_names + + +@pytest.mark.parametrize("custom_format_file", get_all_custom_formats()) +def test_custom_format_patterns_exist( + custom_format_file, + available_regex_patterns_file_names, + available_regex_patterns_names, +): + """Test that every pattern referenced in a custom format exists in regex_patterns.""" + with open(custom_format_file, encoding="utf-8") as f: + data = yaml.safe_load(f) + + if not data or "conditions" not in data: + pytest.skip(f"No conditions found in {custom_format_file.name}") + + missing_patterns_files = [] + missing_patterns_names = [] + + for condition in data["conditions"]: + pattern_name = condition.get("pattern") + if not pattern_name: + continue + + # Check if the referenced pattern exists in regex_patterns + if pattern_name not in available_regex_patterns_file_names: + missing_patterns_files.append(pattern_name) + + if pattern_name not in available_regex_patterns_names: + missing_patterns_names.append(pattern_name) + + if missing_patterns_files: + pytest.fail( + f"Custom format '{custom_format_file.name}' references missing regex patterns:\n" + + "\n".join(f" - {pattern}" for pattern in missing_patterns_files) + ) + + if missing_patterns_names: + pytest.fail( + f"Custom format '{custom_format_file.name}' references missing regex patterns:\n" + + "\n".join(f" - {pattern}" for pattern in missing_patterns_names) + ) + + +def test_custom_formats_directory_exists(): + """Test that the custom_formats directory exists.""" + assert CUSTOM_FORMATS_DIR.exists(), f"Custom formats directory not found: {CUSTOM_FORMATS_DIR}" + + +def test_regex_patterns_directory_exists(): + """Test that the regex_patterns directory exists.""" + assert REGEX_PATTERNS_DIR.exists(), f"Regex patterns directory not found: {REGEX_PATTERNS_DIR}" diff --git a/tests/test_profiles.py b/tests/test_profiles.py new file mode 100644 index 0000000..57de326 --- /dev/null +++ b/tests/test_profiles.py @@ -0,0 +1,100 @@ +"""Tests to ensure profiles reference valid custom format files.""" + +from pathlib import Path + +import pytest +import yaml + + +# Get the project root directory +PROJECT_ROOT = Path(__file__).parent.parent +PROFILES_DIR = PROJECT_ROOT / "profiles" +CUSTOM_FORMATS_DIR = PROJECT_ROOT / "custom_formats" + + +def get_all_profiles(): + """Get all profile YAML files.""" + if not PROFILES_DIR.exists(): + return [] + return list(PROFILES_DIR.glob("*.yml")) + + +@pytest.fixture(scope="module") +def available_custom_formats_file_names(): + """Fixture to load all available custom format names once.""" + if not CUSTOM_FORMATS_DIR.exists(): + return set() + + format_names = set() + for yml_file in CUSTOM_FORMATS_DIR.glob("*.yml"): + # Use filename without extension as format name + format_names.add(yml_file.stem) + + return format_names + + +@pytest.fixture(scope="module") +def available_custom_formats_names(): + """Fixture to load all available custom format names once.""" + if not CUSTOM_FORMATS_DIR.exists(): + return set() + + format_names = set() + for yml_file in CUSTOM_FORMATS_DIR.glob("*.yml"): + # Read name from YAML file content + with open(yml_file, encoding="utf-8") as f: + data = yaml.safe_load(f) + if data and "name" in data: + format_names.add(data["name"]) + + return format_names + + +@pytest.mark.parametrize("profile_file", get_all_profiles()) +def test_profile_custom_formats_exist( + profile_file, available_custom_formats_file_names, available_custom_formats_names +): + """Test that every custom format referenced in a profile exists in custom_formats.""" + with open(profile_file, encoding="utf-8") as f: + data = yaml.safe_load(f) + + if not data or "custom_formats" not in data: + pytest.skip(f"No custom_formats found in {profile_file.name}") + + missing_formats_files = [] + missing_formats_names = [] + + for custom_format_ref in data["custom_formats"]: + format_name = custom_format_ref.get("name") + if not format_name: + continue + + # Check if the referenced custom format exists in custom_formats + if format_name not in available_custom_formats_file_names: + missing_formats_files.append(format_name) + + # Check if the referenced custom format exists in custom_formats + if format_name not in available_custom_formats_names: + missing_formats_names.append(format_name) + + if missing_formats_files: + pytest.fail( + f"Profile '{profile_file.name}' references missing custom formats:\n" + + "\n".join(f" - {format}" for format in missing_formats_files) + ) + + if missing_formats_names: + pytest.fail( + f"Profile '{profile_file.name}' references missing custom formats:\n" + + "\n".join(f" - {format}" for format in missing_formats_names) + ) + + +def test_profiles_directory_exists(): + """Test that the profiles directory exists.""" + assert PROFILES_DIR.exists(), f"Profiles directory not found: {PROFILES_DIR}" + + +def test_custom_formats_directory_exists(): + """Test that the custom_formats directory exists.""" + assert CUSTOM_FORMATS_DIR.exists(), f"Custom formats directory not found: {CUSTOM_FORMATS_DIR}" diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..e803bdf --- /dev/null +++ b/uv.lock @@ -0,0 +1,340 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" + +[[package]] +name = "astroid" +version = "4.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/c17d0f83016532a1ad87d1de96837164c99d47a3b6bbba28bd597c25b37a/astroid-4.0.3.tar.gz", hash = "sha256:08d1de40d251cc3dc4a7a12726721d475ac189e4e583d596ece7422bc176bda3", size = 406224, upload-time = "2026-01-03T22:14:26.096Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/66/686ac4fc6ef48f5bacde625adac698f41d5316a9753c2b20bb0931c9d4e2/astroid-4.0.3-py3-none-any.whl", hash = "sha256:864a0a34af1bd70e1049ba1e61cee843a7252c826d97825fcee9b2fcbd9e1b14", size = 276443, upload-time = "2026-01-03T22:14:24.412Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/f9/e92df5e07f3fc8d4c7f9a0f146ef75446bf870351cd37b788cf5897f8079/coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd", size = 825862, upload-time = "2025-12-28T15:42:56.969Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/a4/e98e689347a1ff1a7f67932ab535cef82eb5e78f32a9e4132e114bbb3a0a/coverage-7.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cb237bfd0ef4d5eb6a19e29f9e528ac67ac3be932ea6b44fb6cc09b9f3ecff78", size = 218951, upload-time = "2025-12-28T15:41:16.653Z" }, + { url = "https://files.pythonhosted.org/packages/32/33/7cbfe2bdc6e2f03d6b240d23dc45fdaf3fd270aaf2d640be77b7f16989ab/coverage-7.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1dcb645d7e34dcbcc96cd7c132b1fc55c39263ca62eb961c064eb3928997363b", size = 219325, upload-time = "2025-12-28T15:41:18.609Z" }, + { url = "https://files.pythonhosted.org/packages/59/f6/efdabdb4929487baeb7cb2a9f7dac457d9356f6ad1b255be283d58b16316/coverage-7.13.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3d42df8201e00384736f0df9be2ced39324c3907607d17d50d50116c989d84cd", size = 250309, upload-time = "2025-12-28T15:41:20.629Z" }, + { url = "https://files.pythonhosted.org/packages/12/da/91a52516e9d5aea87d32d1523f9cdcf7a35a3b298e6be05d6509ba3cfab2/coverage-7.13.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa3edde1aa8807de1d05934982416cb3ec46d1d4d91e280bcce7cca01c507992", size = 252907, upload-time = "2025-12-28T15:41:22.257Z" }, + { url = "https://files.pythonhosted.org/packages/75/38/f1ea837e3dc1231e086db1638947e00d264e7e8c41aa8ecacf6e1e0c05f4/coverage-7.13.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9edd0e01a343766add6817bc448408858ba6b489039eaaa2018474e4001651a4", size = 254148, upload-time = "2025-12-28T15:41:23.87Z" }, + { url = "https://files.pythonhosted.org/packages/7f/43/f4f16b881aaa34954ba446318dea6b9ed5405dd725dd8daac2358eda869a/coverage-7.13.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:985b7836931d033570b94c94713c6dba5f9d3ff26045f72c3e5dbc5fe3361e5a", size = 250515, upload-time = "2025-12-28T15:41:25.437Z" }, + { url = "https://files.pythonhosted.org/packages/84/34/8cba7f00078bd468ea914134e0144263194ce849ec3baad187ffb6203d1c/coverage-7.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ffed1e4980889765c84a5d1a566159e363b71d6b6fbaf0bebc9d3c30bc016766", size = 252292, upload-time = "2025-12-28T15:41:28.459Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/cffac66c7652d84ee4ac52d3ccb94c015687d3b513f9db04bfcac2ac800d/coverage-7.13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8842af7f175078456b8b17f1b73a0d16a65dcbdc653ecefeb00a56b3c8c298c4", size = 250242, upload-time = "2025-12-28T15:41:30.02Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/9a64d462263dde416f3c0067efade7b52b52796f489b1037a95b0dc389c9/coverage-7.13.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ccd7a6fca48ca9c131d9b0a2972a581e28b13416fc313fb98b6d24a03ce9a398", size = 250068, upload-time = "2025-12-28T15:41:32.007Z" }, + { url = "https://files.pythonhosted.org/packages/69/c8/a8994f5fece06db7c4a97c8fc1973684e178599b42e66280dded0524ef00/coverage-7.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0403f647055de2609be776965108447deb8e384fe4a553c119e3ff6bfbab4784", size = 251846, upload-time = "2025-12-28T15:41:33.946Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f7/91fa73c4b80305c86598a2d4e54ba22df6bf7d0d97500944af7ef155d9f7/coverage-7.13.1-cp313-cp313-win32.whl", hash = "sha256:549d195116a1ba1e1ae2f5ca143f9777800f6636eab917d4f02b5310d6d73461", size = 221512, upload-time = "2025-12-28T15:41:35.519Z" }, + { url = "https://files.pythonhosted.org/packages/45/0b/0768b4231d5a044da8f75e097a8714ae1041246bb765d6b5563bab456735/coverage-7.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:5899d28b5276f536fcf840b18b61a9fce23cc3aec1d114c44c07fe94ebeaa500", size = 222321, upload-time = "2025-12-28T15:41:37.371Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b8/bdcb7253b7e85157282450262008f1366aa04663f3e3e4c30436f596c3e2/coverage-7.13.1-cp313-cp313-win_arm64.whl", hash = "sha256:868a2fae76dfb06e87291bcbd4dcbcc778a8500510b618d50496e520bd94d9b9", size = 220949, upload-time = "2025-12-28T15:41:39.553Z" }, + { url = "https://files.pythonhosted.org/packages/70/52/f2be52cc445ff75ea8397948c96c1b4ee14f7f9086ea62fc929c5ae7b717/coverage-7.13.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67170979de0dacac3f3097d02b0ad188d8edcea44ccc44aaa0550af49150c7dc", size = 219643, upload-time = "2025-12-28T15:41:41.567Z" }, + { url = "https://files.pythonhosted.org/packages/47/79/c85e378eaa239e2edec0c5523f71542c7793fe3340954eafb0bc3904d32d/coverage-7.13.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f80e2bb21bfab56ed7405c2d79d34b5dc0bc96c2c1d2a067b643a09fb756c43a", size = 219997, upload-time = "2025-12-28T15:41:43.418Z" }, + { url = "https://files.pythonhosted.org/packages/fe/9b/b1ade8bfb653c0bbce2d6d6e90cc6c254cbb99b7248531cc76253cb4da6d/coverage-7.13.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f83351e0f7dcdb14d7326c3d8d8c4e915fa685cbfdc6281f9470d97a04e9dfe4", size = 261296, upload-time = "2025-12-28T15:41:45.207Z" }, + { url = "https://files.pythonhosted.org/packages/1f/af/ebf91e3e1a2473d523e87e87fd8581e0aa08741b96265730e2d79ce78d8d/coverage-7.13.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb3f6562e89bad0110afbe64e485aac2462efdce6232cdec7862a095dc3412f6", size = 263363, upload-time = "2025-12-28T15:41:47.163Z" }, + { url = "https://files.pythonhosted.org/packages/c4/8b/fb2423526d446596624ac7fde12ea4262e66f86f5120114c3cfd0bb2befa/coverage-7.13.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77545b5dcda13b70f872c3b5974ac64c21d05e65b1590b441c8560115dc3a0d1", size = 265783, upload-time = "2025-12-28T15:41:49.03Z" }, + { url = "https://files.pythonhosted.org/packages/9b/26/ef2adb1e22674913b89f0fe7490ecadcef4a71fa96f5ced90c60ec358789/coverage-7.13.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4d240d260a1aed814790bbe1f10a5ff31ce6c21bc78f0da4a1e8268d6c80dbd", size = 260508, upload-time = "2025-12-28T15:41:51.035Z" }, + { url = "https://files.pythonhosted.org/packages/ce/7d/f0f59b3404caf662e7b5346247883887687c074ce67ba453ea08c612b1d5/coverage-7.13.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d2287ac9360dec3837bfdad969963a5d073a09a85d898bd86bea82aa8876ef3c", size = 263357, upload-time = "2025-12-28T15:41:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b1/29896492b0b1a047604d35d6fa804f12818fa30cdad660763a5f3159e158/coverage-7.13.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0d2c11f3ea4db66b5cbded23b20185c35066892c67d80ec4be4bab257b9ad1e0", size = 260978, upload-time = "2025-12-28T15:41:54.589Z" }, + { url = "https://files.pythonhosted.org/packages/48/f2/971de1238a62e6f0a4128d37adadc8bb882ee96afbe03ff1570291754629/coverage-7.13.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:3fc6a169517ca0d7ca6846c3c5392ef2b9e38896f61d615cb75b9e7134d4ee1e", size = 259877, upload-time = "2025-12-28T15:41:56.263Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fc/0474efcbb590ff8628830e9aaec5f1831594874360e3251f1fdec31d07a3/coverage-7.13.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d10a2ed46386e850bb3de503a54f9fe8192e5917fcbb143bfef653a9355e9a53", size = 262069, upload-time = "2025-12-28T15:41:58.093Z" }, + { url = "https://files.pythonhosted.org/packages/88/4f/3c159b7953db37a7b44c0eab8a95c37d1aa4257c47b4602c04022d5cb975/coverage-7.13.1-cp313-cp313t-win32.whl", hash = "sha256:75a6f4aa904301dab8022397a22c0039edc1f51e90b83dbd4464b8a38dc87842", size = 222184, upload-time = "2025-12-28T15:41:59.763Z" }, + { url = "https://files.pythonhosted.org/packages/58/a5/6b57d28f81417f9335774f20679d9d13b9a8fb90cd6160957aa3b54a2379/coverage-7.13.1-cp313-cp313t-win_amd64.whl", hash = "sha256:309ef5706e95e62578cda256b97f5e097916a2c26247c287bbe74794e7150df2", size = 223250, upload-time = "2025-12-28T15:42:01.52Z" }, + { url = "https://files.pythonhosted.org/packages/81/7c/160796f3b035acfbb58be80e02e484548595aa67e16a6345e7910ace0a38/coverage-7.13.1-cp313-cp313t-win_arm64.whl", hash = "sha256:92f980729e79b5d16d221038dbf2e8f9a9136afa072f9d5d6ed4cb984b126a09", size = 221521, upload-time = "2025-12-28T15:42:03.275Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8e/ba0e597560c6563fc0adb902fda6526df5d4aa73bb10adf0574d03bd2206/coverage-7.13.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:97ab3647280d458a1f9adb85244e81587505a43c0c7cff851f5116cd2814b894", size = 218996, upload-time = "2025-12-28T15:42:04.978Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8e/764c6e116f4221dc7aa26c4061181ff92edb9c799adae6433d18eeba7a14/coverage-7.13.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8f572d989142e0908e6acf57ad1b9b86989ff057c006d13b76c146ec6a20216a", size = 219326, upload-time = "2025-12-28T15:42:06.691Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a6/6130dc6d8da28cdcbb0f2bf8865aeca9b157622f7c0031e48c6cf9a0e591/coverage-7.13.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d72140ccf8a147e94274024ff6fd8fb7811354cf7ef88b1f0a988ebaa5bc774f", size = 250374, upload-time = "2025-12-28T15:42:08.786Z" }, + { url = "https://files.pythonhosted.org/packages/82/2b/783ded568f7cd6b677762f780ad338bf4b4750205860c17c25f7c708995e/coverage-7.13.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3c9f051b028810f5a87c88e5d6e9af3c0ff32ef62763bf15d29f740453ca909", size = 252882, upload-time = "2025-12-28T15:42:10.515Z" }, + { url = "https://files.pythonhosted.org/packages/cd/b2/9808766d082e6a4d59eb0cc881a57fc1600eb2c5882813eefff8254f71b5/coverage-7.13.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f398ba4df52d30b1763f62eed9de5620dcde96e6f491f4c62686736b155aa6e4", size = 254218, upload-time = "2025-12-28T15:42:12.208Z" }, + { url = "https://files.pythonhosted.org/packages/44/ea/52a985bb447c871cb4d2e376e401116520991b597c85afdde1ea9ef54f2c/coverage-7.13.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:132718176cc723026d201e347f800cd1a9e4b62ccd3f82476950834dad501c75", size = 250391, upload-time = "2025-12-28T15:42:14.21Z" }, + { url = "https://files.pythonhosted.org/packages/7f/1d/125b36cc12310718873cfc8209ecfbc1008f14f4f5fa0662aa608e579353/coverage-7.13.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e549d642426e3579b3f4b92d0431543b012dcb6e825c91619d4e93b7363c3f9", size = 252239, upload-time = "2025-12-28T15:42:16.292Z" }, + { url = "https://files.pythonhosted.org/packages/6a/16/10c1c164950cade470107f9f14bbac8485f8fb8515f515fca53d337e4a7f/coverage-7.13.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:90480b2134999301eea795b3a9dbf606c6fbab1b489150c501da84a959442465", size = 250196, upload-time = "2025-12-28T15:42:18.54Z" }, + { url = "https://files.pythonhosted.org/packages/2a/c6/cd860fac08780c6fd659732f6ced1b40b79c35977c1356344e44d72ba6c4/coverage-7.13.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e825dbb7f84dfa24663dd75835e7257f8882629fc11f03ecf77d84a75134b864", size = 250008, upload-time = "2025-12-28T15:42:20.365Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/a8c58d3d38f82a5711e1e0a67268362af48e1a03df27c03072ac30feefcf/coverage-7.13.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:623dcc6d7a7ba450bbdbeedbaa0c42b329bdae16491af2282f12a7e809be7eb9", size = 251671, upload-time = "2025-12-28T15:42:22.114Z" }, + { url = "https://files.pythonhosted.org/packages/f0/bc/fd4c1da651d037a1e3d53e8cb3f8182f4b53271ffa9a95a2e211bacc0349/coverage-7.13.1-cp314-cp314-win32.whl", hash = "sha256:6e73ebb44dca5f708dc871fe0b90cf4cff1a13f9956f747cc87b535a840386f5", size = 221777, upload-time = "2025-12-28T15:42:23.919Z" }, + { url = "https://files.pythonhosted.org/packages/4b/50/71acabdc8948464c17e90b5ffd92358579bd0910732c2a1c9537d7536aa6/coverage-7.13.1-cp314-cp314-win_amd64.whl", hash = "sha256:be753b225d159feb397bd0bf91ae86f689bad0da09d3b301478cd39b878ab31a", size = 222592, upload-time = "2025-12-28T15:42:25.619Z" }, + { url = "https://files.pythonhosted.org/packages/f7/c8/a6fb943081bb0cc926499c7907731a6dc9efc2cbdc76d738c0ab752f1a32/coverage-7.13.1-cp314-cp314-win_arm64.whl", hash = "sha256:228b90f613b25ba0019361e4ab81520b343b622fc657daf7e501c4ed6a2366c0", size = 221169, upload-time = "2025-12-28T15:42:27.629Z" }, + { url = "https://files.pythonhosted.org/packages/16/61/d5b7a0a0e0e40d62e59bc8c7aa1afbd86280d82728ba97f0673b746b78e2/coverage-7.13.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:60cfb538fe9ef86e5b2ab0ca8fc8d62524777f6c611dcaf76dc16fbe9b8e698a", size = 219730, upload-time = "2025-12-28T15:42:29.306Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2c/8881326445fd071bb49514d1ce97d18a46a980712b51fee84f9ab42845b4/coverage-7.13.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:57dfc8048c72ba48a8c45e188d811e5efd7e49b387effc8fb17e97936dde5bf6", size = 220001, upload-time = "2025-12-28T15:42:31.319Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d7/50de63af51dfa3a7f91cc37ad8fcc1e244b734232fbc8b9ab0f3c834a5cd/coverage-7.13.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3f2f725aa3e909b3c5fdb8192490bdd8e1495e85906af74fe6e34a2a77ba0673", size = 261370, upload-time = "2025-12-28T15:42:32.992Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2c/d31722f0ec918fd7453b2758312729f645978d212b410cd0f7c2aed88a94/coverage-7.13.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ee68b21909686eeb21dfcba2c3b81fee70dcf38b140dcd5aa70680995fa3aa5", size = 263485, upload-time = "2025-12-28T15:42:34.759Z" }, + { url = "https://files.pythonhosted.org/packages/fa/7a/2c114fa5c5fc08ba0777e4aec4c97e0b4a1afcb69c75f1f54cff78b073ab/coverage-7.13.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:724b1b270cb13ea2e6503476e34541a0b1f62280bc997eab443f87790202033d", size = 265890, upload-time = "2025-12-28T15:42:36.517Z" }, + { url = "https://files.pythonhosted.org/packages/65/d9/f0794aa1c74ceabc780fe17f6c338456bbc4e96bd950f2e969f48ac6fb20/coverage-7.13.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:916abf1ac5cf7eb16bc540a5bf75c71c43a676f5c52fcb9fe75a2bd75fb944e8", size = 260445, upload-time = "2025-12-28T15:42:38.646Z" }, + { url = "https://files.pythonhosted.org/packages/49/23/184b22a00d9bb97488863ced9454068c79e413cb23f472da6cbddc6cfc52/coverage-7.13.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:776483fd35b58d8afe3acbd9988d5de592ab6da2d2a865edfdbc9fdb43e7c486", size = 263357, upload-time = "2025-12-28T15:42:40.788Z" }, + { url = "https://files.pythonhosted.org/packages/7d/bd/58af54c0c9199ea4190284f389005779d7daf7bf3ce40dcd2d2b2f96da69/coverage-7.13.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b6f3b96617e9852703f5b633ea01315ca45c77e879584f283c44127f0f1ec564", size = 260959, upload-time = "2025-12-28T15:42:42.808Z" }, + { url = "https://files.pythonhosted.org/packages/4b/2a/6839294e8f78a4891bf1df79d69c536880ba2f970d0ff09e7513d6e352e9/coverage-7.13.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd63e7b74661fed317212fab774e2a648bc4bb09b35f25474f8e3325d2945cd7", size = 259792, upload-time = "2025-12-28T15:42:44.818Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c3/528674d4623283310ad676c5af7414b9850ab6d55c2300e8aa4b945ec554/coverage-7.13.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:933082f161bbb3e9f90d00990dc956120f608cdbcaeea15c4d897f56ef4fe416", size = 262123, upload-time = "2025-12-28T15:42:47.108Z" }, + { url = "https://files.pythonhosted.org/packages/06/c5/8c0515692fb4c73ac379d8dc09b18eaf0214ecb76ea6e62467ba7a1556ff/coverage-7.13.1-cp314-cp314t-win32.whl", hash = "sha256:18be793c4c87de2965e1c0f060f03d9e5aff66cfeae8e1dbe6e5b88056ec153f", size = 222562, upload-time = "2025-12-28T15:42:49.144Z" }, + { url = "https://files.pythonhosted.org/packages/05/0e/c0a0c4678cb30dac735811db529b321d7e1c9120b79bd728d4f4d6b010e9/coverage-7.13.1-cp314-cp314t-win_amd64.whl", hash = "sha256:0e42e0ec0cd3e0d851cb3c91f770c9301f48647cb2877cb78f74bdaa07639a79", size = 223670, upload-time = "2025-12-28T15:42:51.218Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5f/b177aa0011f354abf03a8f30a85032686d290fdeed4222b27d36b4372a50/coverage-7.13.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eaecf47ef10c72ece9a2a92118257da87e460e113b83cc0d2905cbbe931792b4", size = 221707, upload-time = "2025-12-28T15:42:53.034Z" }, + { url = "https://files.pythonhosted.org/packages/cc/48/d9f421cb8da5afaa1a64570d9989e00fb7955e6acddc5a12979f7666ef60/coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573", size = 210722, upload-time = "2025-12-28T15:42:54.901Z" }, +] + +[[package]] +name = "dill" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "isort" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/53/4f3c058e3bace40282876f9b553343376ee687f3c35a525dc79dbd450f88/isort-7.0.0.tar.gz", hash = "sha256:5513527951aadb3ac4292a41a16cbc50dd1642432f5e8c20057d414bdafb4187", size = 805049, upload-time = "2025-10-11T13:30:59.107Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/ed/e3705d6d02b4f7aea715a353c8ce193efd0b5db13e204df895d38734c244/isort-7.0.0-py3-none-any.whl", hash = "sha256:1bcabac8bc3c36c7fb7b98a76c8abb18e0f841a3ba81decac7691008592499c1", size = 94672, upload-time = "2025-10-11T13:30:57.665Z" }, +] + +[[package]] +name = "markdownify" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3f/bc/c8c8eea5335341306b0fa7e1cb33c5e1c8d24ef70ddd684da65f41c49c92/markdownify-1.2.2.tar.gz", hash = "sha256:b274f1b5943180b031b699b199cbaeb1e2ac938b75851849a31fd0c3d6603d09", size = 18816, upload-time = "2025-11-16T19:21:18.565Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/ce/f1e3e9d959db134cedf06825fae8d5b294bd368aacdd0831a3975b7c4d55/markdownify-1.2.2-py3-none-any.whl", hash = "sha256:3f02d3cc52714084d6e589f70397b6fc9f2f3a8531481bf35e8cc39f975e186a", size = 15724, upload-time = "2025-11-16T19:21:17.622Z" }, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "profilarr-trash-guides" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "markdownify" }, + { name = "pyyaml" }, +] + +[package.optional-dependencies] +dev = [ + { name = "pylint" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-mock" }, +] + +[package.metadata] +requires-dist = [ + { name = "markdownify" }, + { name = "pylint", marker = "extra == 'dev'", specifier = ">=3.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0" }, + { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=4.0" }, + { name = "pytest-mock", marker = "extra == 'dev'", specifier = ">=3.10" }, + { name = "pyyaml" }, +] +provides-extras = ["dev"] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pylint" +version = "4.0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "astroid" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "dill" }, + { name = "isort" }, + { name = "mccabe" }, + { name = "platformdirs" }, + { name = "tomlkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/d2/b081da1a8930d00e3fc06352a1d449aaf815d4982319fab5d8cdb2e9ab35/pylint-4.0.4.tar.gz", hash = "sha256:d9b71674e19b1c36d79265b5887bf8e55278cbe236c9e95d22dc82cf044fdbd2", size = 1571735, upload-time = "2025-11-30T13:29:04.315Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/92/d40f5d937517cc489ad848fc4414ecccc7592e4686b9071e09e64f5e378e/pylint-4.0.4-py3-none-any.whl", hash = "sha256:63e06a37d5922555ee2c20963eb42559918c20bd2b21244e4ef426e7c43b92e0", size = 536425, upload-time = "2025-11-30T13:29:02.53Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "pytest-mock" +version = "3.15.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", size = 34036, upload-time = "2025-09-16T16:37:27.081Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", size = 10095, upload-time = "2025-09-16T16:37:25.734Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/89/23/adf3796d740536d63a6fbda113d07e60c734b6ed5d3058d1e47fc0495e47/soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350", size = 117856, upload-time = "2025-12-18T13:50:34.655Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/f3/b67d6ea49ca9154453b6d70b34ea22f3996b9fa55da105a79d8732227adc/soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434", size = 36710, upload-time = "2025-12-18T13:50:33.267Z" }, +] + +[[package]] +name = "tomlkit" +version = "0.13.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +]