Skip to content

Sort initial_key harmonic (by circle of fiths)#6669

Draft
JOJ0 wants to merge 1 commit into
masterfrom
harmonic_sort_option
Draft

Sort initial_key harmonic (by circle of fiths)#6669
JOJ0 wants to merge 1 commit into
masterfrom
harmonic_sort_option

Conversation

@JOJ0
Copy link
Copy Markdown
Member

@JOJ0 JOJ0 commented May 25, 2026

Description

Enable sorting the initial_key field by the circle of fiths. For now, first major then minor keys (TBD make configurable?)

I even propose to set this as the default sorting behavior for this field. To disable it (revert back to alphabetical sorting the user can set sort_initial_key_harmonic: no

Solves the core part of #6241

To Do

  • Documentation.
  • Changelog.
  • Tests.

Copilot AI review requested due to automatic review settings May 25, 2026 07:58
@JOJ0 JOJ0 requested a review from a team as a code owner May 25, 2026 07:58
@JOJ0 JOJ0 marked this pull request as draft May 25, 2026 07:58
@github-actions
Copy link
Copy Markdown

Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 25, 2026

Codecov Report

❌ Patch coverage is 69.76744% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.51%. Comparing base (26ab08b) to head (edcd32c).
⚠️ Report is 9 commits behind head on master.

Files with missing lines Patch % Lines
beets/dbcore/sort.py 37.50% 10 Missing ⚠️
beets/util/musictheory.py 82.35% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6669      +/-   ##
==========================================
+ Coverage   72.50%   72.51%   +0.01%     
==========================================
  Files         161      163       +2     
  Lines       20766    20815      +49     
  Branches     3288     3291       +3     
==========================================
+ Hits        15056    15094      +38     
- Misses       4984     4996      +12     
+ Partials      726      725       -1     
Files with missing lines Coverage Δ
beets/dbcore/__init__.py 100.00% <100.00%> (ø)
beets/dbcore/types.py 96.96% <100.00%> (-0.08%) ⬇️
beets/library/models.py 87.36% <100.00%> (+0.32%) ⬆️
beets/util/musictheory.py 82.35% <82.35%> (ø)
beets/dbcore/sort.py 85.36% <37.50%> (-7.16%) ⬇️

... and 9 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@JOJ0 JOJ0 mentioned this pull request May 25, 2026
3 tasks
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

grug see PR want make initial_key sort harmonic (Circle of Fifths) instead of plain abc. this fit beets library sort system, so user can do better DJ / playlist flow.

Changes:

  • add beets.util.musictheory with key normalize + Circle-of-Fifths position function
  • add HarmonicKeySort and wire it as default sort handler for Item.initial_key (config gate sort_initial_key_harmonic)
  • move MusicalKey parsing to reuse shared normalize helper; add default config option enabled

Reviewed changes

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

Show a summary per file
File Description
beets/util/musictheory.py new shared key normalization + harmonic position mapping
beets/library/models.py register initial_key to use HarmonicKeySort
beets/dbcore/types.py reuse shared normalize helper for MusicalKey.parse()
beets/dbcore/sort.py implement config-gated harmonic sorting (python slow path)
beets/dbcore/init.py export HarmonicKeySort via __all__
beets/config_default.yaml add default sort_initial_key_harmonic: yes

Comment thread beets/dbcore/sort.py
Comment on lines +224 to +243
def is_slow(self) -> bool:
return self._harmonic_enabled()

def order_clause(self) -> str | None:
if self._harmonic_enabled():
return None # Python-level sort; no SQL ORDER BY fragment
return FixedFieldSort(
self.field, self.ascending, self.case_insensitive
).order_clause()

def sort(self, objs: list[AnyModel]) -> list[AnyModel]:
if not self._harmonic_enabled():
return FieldSort.sort(self, objs)
from beets.util.musictheory import harmonic_sort_key

return sorted(
objs,
key=lambda obj: harmonic_sort_key(obj.get(self.field)),
reverse=not self.ascending,
)
Comment thread beets/dbcore/sort.py
Comment on lines +208 to +243
class HarmonicKeySort(FieldSort):
"""Sort by musical key in Circle of Fifths order when
``sort_initial_key_harmonic`` is enabled; falls back to standard
case-insensitive alphabetical ordering otherwise.

Applies enharmonic normalization before lookup, so keys stored in either
flat or sharp notation sort correctly relative to each other. Keys not
present in the Circle of Fifths (or missing entirely) sort to the end.
"""

@staticmethod
def _harmonic_enabled() -> bool:
import beets

return beets.config["sort_initial_key_harmonic"].get(bool)

def is_slow(self) -> bool:
return self._harmonic_enabled()

def order_clause(self) -> str | None:
if self._harmonic_enabled():
return None # Python-level sort; no SQL ORDER BY fragment
return FixedFieldSort(
self.field, self.ascending, self.case_insensitive
).order_clause()

def sort(self, objs: list[AnyModel]) -> list[AnyModel]:
if not self._harmonic_enabled():
return FieldSort.sort(self, objs)
from beets.util.musictheory import harmonic_sort_key

return sorted(
objs,
key=lambda obj: harmonic_sort_key(obj.get(self.field)),
reverse=not self.ascending,
)
Comment thread beets/util/musictheory.py
"""Normalize a musical key string to canonical form.

Applies flat-to-sharp enharmonic conversion, handles ``minor``/``major``
suffixes, and capitalizes the result. Mirrors the logic in
Comment thread beets/dbcore/__init__.py
Comment on lines +33 to +40
from .sort import HarmonicKeySort
from .types import Type

__all__ = [
"AndQuery",
"Database",
"FieldQuery",
"HarmonicKeySort",
@JOJ0 JOJ0 force-pushed the harmonic_sort_option branch from 77243ea to edcd32c Compare May 25, 2026 08:08
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