Skip to content

Add %tunique{} path template function for track disambiguation within albums#6722

Open
arsaboo wants to merge 7 commits into
beetbox:masterfrom
arsaboo:tunique
Open

Add %tunique{} path template function for track disambiguation within albums#6722
arsaboo wants to merge 7 commits into
beetbox:masterfrom
arsaboo:tunique

Conversation

@arsaboo

@arsaboo arsaboo commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Adds a new %tunique{} path template function (analogous to %aunique{} for albums and %sunique{} for singletons) that disambiguates tracks within the same album that would otherwise produce identical filenames (e.g., two tracks with the same title on the same album or across different discs). This follows the structure and logic used in aunique or sunique.

Fixes #5950

Default configuration:

tunique:
    keys: title
    disambiguators: track disc artist
    bracket: '[]'

The function first finds all sibling items (same album_id) with matching key values (default: same title). If duplicates exist, it iterates through the disambiguator fields looking for one that uniquely separates all duplicates. If no field suffices, the stable database ID is used as a fallback. For items without a duplicate, no suffix is added.

This solves the problem where beet move would non-deterministically append .1/.2 suffixes via unique_path() for duplicate-titled tracks, which would change every time the command was re-run.

Example usage in path config:

paths:
    default: $albumartist/$album/$album ($year) - $title%tunique{}

For an album with two identically-titled tracks:

- Artist/Album/Album (1993) - Common Title [07].mp3
- Artist/Album/Album (1993) - Common Title [11].mp3

To Do

  • Documentation. (If you've added a new command-line flag, for example, find the appropriate page under docs/ to describe it.)
  • Changelog. (Add an entry to docs/changelog.rst to the bottom of one of the lists near the top of the document.)
  • Tests. (Very much encouraged but not strictly required.)

Copilot AI review requested due to automatic review settings June 8, 2026 18:36
@arsaboo arsaboo requested a review from a team as a code owner June 8, 2026 18:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a new %tunique{} path template and configuration to disambiguate tracks with identical titles within the same album.

Changes:

  • Introduces tmpl_tunique and a query override hook in _tmpl_unique to scope ambiguity checks to an album.
  • Adds defaults for tunique in config_default.yaml and documents the new template/config.
  • Adds a new test suite covering %tunique{} behavior and edge cases.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
test/test_library.py Adds %tunique{} test coverage for album-scoped track title collisions and formatting options.
docs/reference/pathformat.rst Documents the new %tunique{} template and its default identifiers/disambiguators.
docs/reference/config.rst Documents new tunique config keys and defaults.
docs/changelog.rst Adds changelog entry announcing %tunique{}.
beets/library/models.py Implements tmpl_tunique and extends _tmpl_unique with an optional pre-built query.
beets/config_default.yaml Adds default configuration for tunique.

Comment thread test/test_library.py
Comment thread test/test_library.py
Comment thread beets/library/models.py
Comment thread beets/library/models.py Outdated
Comment thread beets/library/models.py Outdated
@codecov

codecov Bot commented Jun 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.63%. Comparing base (6f8d55d) to head (5695d9a).

Files with missing lines Patch % Lines
beets/library/models.py 80.00% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6722      +/-   ##
==========================================
- Coverage   75.63%   75.63%   -0.01%     
==========================================
  Files         162      162              
  Lines       20820    20835      +15     
  Branches     3298     3302       +4     
==========================================
+ Hits        15747    15758      +11     
- Misses       4292     4294       +2     
- Partials      781      783       +2     
Files with missing lines Coverage Δ
beets/library/models.py 87.44% <80.00%> (-0.33%) ⬇️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants