Files
Guides/CONTRIBUTING.md
T
Robert Dailey c1b52c317d feat(starr): Add machine-readable conflict declarations for mutually exclusive CFs (#2681)
* feat(conflicts): add machine-readable CF conflict declarations

Add conflicts.json files for Radarr and Sonarr defining
mutually exclusive custom format pairs:

- SDR vs SDR (no WEBDL)
- x265 (HD) vs x265 (no HDR/DV)

Enables tooling to warn users about conflicting combinations.

Includes new JSON schema and metadata schema updates.

* refactor(conflicts): use id-as-key pattern

Restructure conflicts.json files to use trash IDs as object keys instead
of nested properties. This establishes the structural pattern for future
file migrations across the repository.

- Change custom_formats array items from arrays of objects to objects
  with trash ID keys
- Add name (required) and desc (optional) as value fields for each
  conflict entry
- Update schema to use patternProperties with hex regex for key
  validation
- Set minProperties: 2 on conflict groups to ensure at least 2
  conflicting CFs

* docs(contributing): document conflicts.json files

Adds documentation for the new conflicts.json files so contributors know
how to declare mutually exclusive Custom Formats when working with sync
app data.

- Add index entry and file references for conflicts.json
- Document the conflicts.json schema and format
- Explain how sync tools use conflict declarations
2026-04-08 14:11:31 +10:00

20 KiB

Contributing Guidelines

👍🎉 First off, thanks for taking the time to contribute! 🎉👍

Here you will find guidelines for contributing to TRaSH Guides. These are mostly guidelines, not rules. Use your best judgment and feel free to propose changes to this document in a pull request.

Guidelines

  • Ensure you're editing the latest version.
  • If you suggest changes, ensure they don't cause any issues, inconsistencies or breakages elsewhere in the guides.
  • After the modifications, verify that you do not receive any markdownlint errors.
  • If the metadata.json and metadata.schema.json require changes, announce it first in the Discord #development channel and ping voidpointer and nitsua to prevent disruption to third-party apps ‼️

Index

Branch naming

Important

We're trying to be as consistent as possible because of the automation of the changelog.

  • feat/xxx Commits that adds a new feature
  • fix/xxx Commits that fixes a bug/issue
  • style/xxx Commits that do not affect the meaning (white-space, formatting, missing semi-colons, grammar, etc.)
  • chore/xxx Miscellaneous commits (administrative, cleanup, backend, etc.)

Note

Where xxx can stand for the main Guide Categories in the guide.

Examples:

  • feat/Starr-ELEANOR-to-Scene-CF
  • feat/radarr-CiNEPHiLES-to-Remux-Tier-02
  • style/radarr minor-grammar corrections
  • fix/starr-dv-hdr10-cf-should-match-dv-hdr10+

Pull Request naming

Important

Because the changelog is created automatically, we want to make the PR name as clear and consistent as possible.

The PR naming consists of 3 parts.

part1(part2): part3 => type(guide category): short detailed descriptions

Types

Source

  • feat(xxx): Commits that adds a new feature
  • fix(xxx): Commits that fixes a bug/issue
  • style(xxx): Commits that do not affect the meaning (white-space, formatting, missing semi-colons, grammar, etc)
  • chore(xxx): Miscellaneous commits (administrative, cleanup, backend, etc)

Note

Where xxx can stand for the main Guide Categories in the guide.

Guide categories

The following Guide categories can be used for the PR name.

- type(radarr): #Radarr related
- type(radarr-german): #Radarr related but for the German guides
- type(radarr-french): #Radarr related but for the French guides
- type(radarr-anime): #Radarr related but for the Anime guides
- type(sonarr): #Sonarr related
- type(sonarr-german): #Sonarr related but for the German guides
- type(sonarr-french): #Sonarr related but for the French guides
- type(sonarr-anime): #Sonarr related but for the Anime guides
- type(starr): #Sonarr and Radarr related
- type(starr-german): #Sonarr and Radarr related but for the German guides
- type(starr-french): #Sonarr and Radarr related but for the French guides
- type(starr-anime): #Sonarr and Radarr related but for the Anime guides
- type(prowlarr): #Prowlarr related
- type(lidarr): #Lidarr related
- type(bazarr): #Bazarr related
- type(hardlinks): #Hardlinks/File and Folder Structure related
- type(downloaders): #Downloaders related
- type(plex): #Plex related
- type(guide-sync): # Officially supported third-party party Guide Sync Tools related
- type(misc): #Miscellaneous guides that do not fit in any other categories but are still related to Radarr/Sonarr, etc
- type(glossary): #Any additions/changes to the glossary page

Examples:

  • feat(guide-sync): Add more groups to give the user more personal options
  • feat(guide-sync): Add new Quality Profiles for Radarr/Sonarr
  • feat(starr): [NEW Guide] How does the current rank logic work
  • feat(downloaders): [NZBGet] Updated the guide to reflect the recent changes with v24.5

When doing a PR that is WIP

Tip

When doing a PR that is in progress and not yet complete/ready for review or not yet done fully, please ensure it is a DRAFT Pull Request

Radarr/Sonarr Custom Format (JSON)

Release Group Reclassifications, Removals, or Additions

Warning

When adding a release group to a Custom Format, please explain why it's added/removed/moved in the PR.

General Guidelines

Caution

  • The names of the Custom Format and the JSON must be identical. ‼️
  • No hashcode can exist multiple times ‼️
  • Tiers only hold release groups that have at least done several dozen objectively high-quality releases or are added for a specific reason. (If they do mainly niche stuff and/or foreign stuff, they won't be added)
  • All Tier Groups must use retail sources. Fanres and upscaled groups are forbidden. This is due to the high effort required and the near impossibility of systematically guaranteeing quality without manually checking every single movie.
  • JSON file format shall consist of the following TRaSH-specific data appended to the JSON exported from Starr
{
    "trash_id": "HASHCODE",
    "trash_scores": {
        "default": 50,
        "some_other_profile": 100
    },
    "trash_regex": "https://regex101.com/r/pADWJD/5",
STARRJSONEXPORT
}

General Structure

  • JSON file name - the name of the json file
  • trash_id - Generated HashCode for the Custom Format
  • trash_scores - JSON object of score(s) for the Custom Format. Note that Custom Formats with Default Scores of 0 should NOT have a trash_scores.default
  • trash_regex - Link to regex test cases for regex
  • STARRJSONEXPORT - The exported custom format created within Starr. Note that this will have a leading { that will need to have the trash-specific regex added after it.

File Naming

Caution

JSON file names are always written in lowercase. Spaces must be replaced by dashes, plus should be used instead of the + symbol, and no spaces or special characters should be used except for dashes. ‼️

Hashcode

  • When adding the hashcode for Radarr, use the following naming convention: CF_name e.g., the Custom Format BR-DISK would be the hash of BR-DISK When adding the hashcode for Radarr Anime, use the following naming convention: Radarr Anime CF_name. For example, the Custom Format BR-DISK would be the hash of Radarr Anime BR-DISK.
  • When adding the hashcode for Sonarr, use the following naming convention: Sonarr CF_name e.g. the Custom Format BR-DISK would be the hash of Sonarr BR-DISK.
  • When adding the hashcode for Sonarr Anime, use the following naming convention: Sonarr Anime CF_name e.g. the Custom Format BR-DISK would be the hash of Sonarr Anime BR-DISK.

Regex Test Cases

  • Provide a link to your regex example of your Custom Format using the following Template.

When adding a regex test case:

  • Replace the actual movie name with Movie.
  • Replace the actual Series name/title with Series.
  • Replace the actual group name with RlsGrp

When updating or adding a new CF, the test case URL (trash_regex) needs to be prepended to the exported from Starr JSON.

{
    "trash_regex": "https://regex101.com/r/pADWJD/5"
}

Scoring

  • Scores must be added as JSON objects under trash_scores, for example:
{
    "trash_scores": {
        "default": 50,
        "some_other_profile": 100
    }
}
  • This allows for Custom Formats to be assigned different scores for different profiles
  • Default Scores of 0 (e.g., as in trash_scores.default) are FORBIDDEN

YAML file naming

  • YAML file names are always written in lowercase. Spaces must be replaced by dashes, plus should be used instead of the + symbol, and no spaces or special characters should be used except for dashes. ‼️

Caution

  • If a hashcode is needed No hashcode can exist multiple times ‼️

Quality Profiles and 3rd party sync apps

Important

When creating a new quality profile or editing an existing one, it's mandatory to ensure that these settings are updated/added to the following locations for the third-party sync apps.

  • Radarr: docs/json/radarr/quality-profiles

    • docs/json/radarr/cf-groups
    • docs/json/radarr/quality-profile-groups/groups.json
    • docs/json/radarr/conflicts.json
  • Sonarr: docs/json/sonarr/quality-profiles

    • docs/json/sonarr/cf-groups
    • docs/json/sonarr/quality-profile-groups/groups.json
    • docs/json/sonarr/conflicts.json
  • docs/json/xxxarr/quality-profiles = The base quality profile with all the mandatory Custom Formats.

  • docs/json/xxxarr/cf-groups = The optional/User choices that wouldn't break the Quality Profile.

  • docs/json/xxxarr/quality-profile-groups = The groups.json file contains an array of groups. The order of groups determines display order, and profiles within each group are sorted alphabetically by their name.

  • docs/json/xxxarr/conflicts.json = Declares mutually exclusive Custom Formats so sync tools can warn users about conflicting selections.

quality-profiles

The quality-profiles hold the basic quality profile settings that you also see in the Radarr/Sonarr GUI.

image

Tip

Use one of the existing quality-profiles.json files as your base.

  • JSON file name - use the name of the quality profile that you used in the `"name":' in the JSON

Caution

JSON file names are always written in lowercase, spaces are replaced by a dash, and no spaces or special characters except a dash ‼️

  • trash_id - Generated HashCode for the profile name you used for the `"name":' in the JSON
  • name - Quality Profile name.
    • If the profile is for a foreign language, start with [Language] => example: [German] HD Bluray + WEB.
    • If the profile is for anime, start with [Anime] => example: [Anime] Something.
  • trash_description - Description of what the quality profile covers => example: Quality Profile that covers:<br>- WEBDL: 1080p<br>- Bluray: 720p, 1080p
    • The following HTML code is allowed in the description: <b>, </b>, <br> and <a href="link-here" target="_blank">text-here</a>.
  • group — Sort order to ensure the quality profiles stay together. The default public guide will always be the first.
    • [1-9] English/International Public Guides (None Anime).
    • [11-19] German Guides (Incl. Anime).
    • [21-29] French Guides (Incl. Anime).
    • [81-89] English/International Public Guides (Anime).
    • [91-99] Restricted Use.
  • upgradeAllowed - Upgrades Allowed.
  • cutoff - Upgrade Until.
  • minFormatScore - Minimum Custom Format Score.
  • cutoffFormatScore - Upgrade Until Custom Format Score.
  • minUpgradeFormatScore - Minimum Custom Format Score Increment.
  • language - Language. (This is only for Radarr)
  • items - Qualities. => The allowed quality sources are in reverse order, meaning that the highest quality allowed in your profile is at the bottom of the list.
  • formatItems - Custom Formats. => The mandatory Custom Formats that are needed for this quality profiles, excluding the ones that are added with the cf-groups

cf-groups

The cf-groups can hold several Custom Formats. Depending on the chosen profile, the end user gets a selection of groups where certain groups are enabled by default with certain Custom Formats or some groups holding Custom Formats that the end user can choose if they want to have it enabled or disabled.

The cf-group.json exists of two properties.

  • Green is the group properties.
  • Blue is the Custom Format properties.

image

Tip

Use one of the existing cf-groups.json files as an example.

Group Specific settings

Note

  • All Groups are optional and by default disabled. The user can enable or disable the group (If the CF should always be enabled, put it in the quality profile)
  • If you want the group to be enabled by default, add "default": "true", above "custom_formats": [. (If the group does not have to be enabled by default, there is no need to add "default": "false",)
  • JSON file name - use the name of the quality profile that you used in the `"name":' in the JSON

Caution

JSON file names are always written in lowercase, spaces are replaced by a dash, and no spaces or special characters except a dash ‼️

  • trash_id - Generated HashCode for the group name you used for the `"name":' in the JSON
  • name - Group name.
    • If the group is for a foreign language, start with [Language] => example: [German] HD Bluray + WEB.
    • If the group is for anime, start with [Anime] => example: [Anime] Something.
  • trash_description - Description of what the group covers => example: Collection of UK Streaming Services for Radarr
    • The following HTML code is allowed in the description: <b>, </b>, <br> and <a href="link-here" target="_blank">text-here</a>.
  • default": "true" - [OPTIONAL] If you want the group to be enabled by default.

Group Custom Format specific settings

Note

  • required: true => If the group is enabled, all the CF in that group are enabled, but the end user can still disable the full group (no individual choosing possible).
  • required: false => If the group is enabled, the end user can choose which CF he wants to be added individually, and they are not checked by default.
  • default: true/required: false => If the group is enabled, the end user can choose which CF he wants to be added individually, and they are checked by default.
  • custom_formats -
    • name - CF name found in the JSON.
    • trash_id - CF trash_id found in the JSON.
    • required - [true|false] See the above note for a description
    • default": "true" - [OPTIONAL] If you want the CF to be enabled by default.
  • quality_profiles
    • include - Quality profiles that receive this CF group, using the profile name and trash_id.

quality-profile-groups

Quality profile groups organize quality profiles into logical categories for easier discovery and selection.

  • Radarr: docs/json/radarr/quality-profile-groups/groups.json
  • Sonarr: docs/json/sonarr/quality-profile-groups/groups.json

The groups.json file contains an array of groups. The order of groups determines display order, and profiles within each group are sorted alphabetically by their name.

[
    {
        "name": "Standard",
        "profiles": ["trash_id_1", "trash_id_2"]
    },
    {
        "name": "Anime",
        "profiles": ["trash_id_3"]
    }
]
  • name - Display name for the profile group
  • profiles - Array of quality profile trash_id values belonging to this group

Important

All trash_id values in the profiles array must correspond to existing quality profiles in the quality-profiles directory. Each quality profile should belong to exactly one group.

conflicts

The conflicts file declares Custom Formats that are mutually exclusive. Sync tools read this to warn users when they pick CFs that don't make sense together (for example, two SDR variants in the same profile).

  • Radarr: docs/json/radarr/conflicts.json
  • Sonarr: docs/json/sonarr/conflicts.json

Each file has a custom_formats array, and each entry in that array is one conflict group. Inside a group, the trash_id is the object key and the value holds name and desc:

{
    "custom_formats": [
        {
            "9c38ebb7384dada637be8899efa68e6f": {
                "name": "SDR",
                "desc": ""
            },
            "25c12f78430a3a23413652cbd1d48d77": {
                "name": "SDR (no WEBDL)",
                "desc": ""
            }
        }
    ]
}
  • All CFs within a group are mutually exclusive with each other. A group must have at least 2 entries.
  • name is a human-readable comment. It has no functional effect; keep it in sync with the real CF name so you can tell at a glance which trash_id is which.
  • desc is an optional free-text field for longer maintainer notes. No formatting rules.
  • The schema (schemas/conflicts.schema.json) validates that keys are 32-character hex strings.
  • When you add a new CF that conflicts with an existing one, add or update the conflict group in the relevant conflicts.json file.

Recommendations

Pre-commit (autofix)

This repo uses pre-commit to automatically fix common issues (markdown formatting, table alignment, YAML lint, etc.) before you commit.

pip install pre-commit
pre-commit install

Once installed, pre-commit runs automatically on git commit and will auto-fix what it can. If files are modified by the hooks, simply git add the changes and commit again.

VS Code

Use VSCode for editing. VS Code should recommend extensions to you based on the .vscode/extensions.json file, you should install all of them.

Preview Docs Locally

Prerequisites

These prerequisites are taken from the mkdocs installation instructions.

  • Install a recent version of Python 3.
  • pip is also required, but it should come with Python. Run pip --version to check if it's available and working. See the installation instructions.

Alternatively, you can check out the Docker container and instructions maintained by zakkarry specifically for developing the guides here. The documentation in the README explains the installation process.

Mkdocs Installation

First, install mkdocs:

pip install mkdocs

Then, you can install dependent modules using the command below. This command should be run in the repository's root directory (i.e., where the requirements.txt file is). If the pip command does If it doesn't work, please check the mkdocs installation page linked in the Prerequisite section above.

pip install -r docs/requirements.txt

Once everything is installed, run the command below to start a local dev server to preview your changes to mkdocs:

mkdocs serve

Preview after Pull Request

After the Pull Request is pushed to GitHub and clears all checks, you can now get a Branch Preview URL.