Skip to content

tidal: Add flexible attributes and tidalsync command for popularity data#6744

Merged
semohr merged 29 commits into
beetbox:masterfrom
arsaboo:tidal
Jun 19, 2026
Merged

tidal: Add flexible attributes and tidalsync command for popularity data#6744
semohr merged 29 commits into
beetbox:masterfrom
arsaboo:tidal

Conversation

@arsaboo

@arsaboo arsaboo commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

This PR adds six typed flexible attributes to the Tidal plugin that are populated during album/track imports, and introduces a new beet tidalsync command to refresh popularity data post-import.

cc: @semohr

Flexible Attributes (item_types)

  • tidal_track_id, tidal_album_id, tidal_artist_id — INTEGER fields for Tidal entity IDs.
  • tidal_track_popularity, tidal_alb_popularity — INTEGER (0–100) normalized popularity scores.
  • tidal_updated — DATE timestamp of last sync.

Import population

  • _get_album_info() and _get_track_info() pass the new fields through to AlbumInfo / TrackInfo, which store them as flexattrs on the item.
  • _popularity() helper normalizes float/int/None from the Tidal API.

Reimport support

  • All Tidal fields added to REIMPORT_FRESH_FIELDS_ITEM so they refresh on reimport.

beet tidalsync command

  • Iterates library items, looks up each track by tidal_track_id, and updates tidal_track_popularity + tidal_updated.
  • --force/-f — re-fetch even if data already exists.
  • --write/-w — write updated tags to media files.
  • Accepts an optional query to filter items (e.g., beet tidalsync artist:Miles).

Documentation & Tests

  • Attribute reference table and command usage examples in
    docs/plugins/tidal.rst.

  • Flexattr assertions in existing tests, new TestPopularity and
    TestTidalsync test classes.

  • 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.)

arsaboo added 2 commits June 14, 2026 13:44
- Add item_types ClassVar with tidal_track_id, tidal_album_id,
  tidal_artist_id, tidal_track_popularity, tidal_alb_popularity,
  tidal_updated fields
- Populate flexattrs during album/track import via AlbumInfo/TrackInfo
  kwargs
- Add beet tidalsync command to refresh popularity data post-import
- Add tidal fields to REIMPORT_FRESH_FIELDS_ITEM for reimport support
- Add tests for flexattr population and tidalsync behavior
- Update tidal plugin docs with attribute reference and tidalsync usage
@arsaboo arsaboo requested review from a team and semohr as code owners June 14, 2026 20:13
@semohr semohr self-assigned this Jun 14, 2026
@codecov

codecov Bot commented Jun 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.23529% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.68%. Comparing base (162913f) to head (4e60f86).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
beetsplug/tidal/__init__.py 88.23% 4 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6744      +/-   ##
==========================================
+ Coverage   74.61%   74.68%   +0.06%     
==========================================
  Files         163      163              
  Lines       20852    20893      +41     
  Branches     3289     3294       +5     
==========================================
+ Hits        15559    15603      +44     
+ Misses       4540     4536       -4     
- Partials      753      754       +1     
Files with missing lines Coverage Δ
beets/importer/tasks.py 91.16% <ø> (ø)
beetsplug/tidal/__init__.py 89.38% <88.23%> (+3.97%) ⬆️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- Use self.add_item() instead of self.lib.add_item() in tests
- Fix mypy: add isinstance(val, int) check in _popularity()
- Apply ruff formatting
Comment thread beetsplug/tidal/__init__.py Outdated
Comment thread beetsplug/tidal/__init__.py
Comment thread docs/plugins/tidal.rst Outdated
Comment thread beetsplug/tidal/__init__.py Outdated
Comment thread beetsplug/tidal/__init__.py Outdated
Comment thread beetsplug/tidal/__init__.py Outdated
@semohr semohr added the tidal label Jun 15, 2026
Comment thread beetsplug/tidal/__init__.py Outdated
@semohr

This comment was marked as outdated.

@arsaboo

This comment was marked as resolved.

Comment thread beetsplug/tidal/__init__.py Outdated
@semohr

semohr commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

We have tidal_album_popularity to be explicit and avoid any confusion. Updated the parsing based on your comments.

Im not entirely sure how the best UX should look like here tbh. Both variants (with and without prefix) come with tradeoffs 🤔

@arsaboo

arsaboo commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

We have tidal_album_popularity to be explicit and avoid any confusion. Updated the parsing based on your comments.

Im not entirely sure how the best UX should look like here tbh. Both variants (with and without prefix) come with tradeoffs 🤔

We are not currently exposing popularity information in UI. This is mostly for the DB so that we can use it for other smart things (playlists)

@semohr

semohr commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

We are not currently exposing popularity information in UI. This is mostly for the DB so that we can use it for other smart things (playlists)

I mean the query syntax with UX. The question is whether users should have separate fields per entity, such as:

beet ls tidal_album_popularity:5..20

or a single generic field whose meaning depends on the search scope, for example:

beet ls tidal_popularity:5..50 -a

The latter is shorter and more flexible, but the former is more explicit and consistent across entity types.

@arsaboo

arsaboo commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

We are not currently exposing popularity information in UI. This is mostly for the DB so that we can use it for other smart things (playlists)

I mean the query syntax with UX. The question is whether users should have separate fields per entity, such as:

beet ls tidal_album_popularity:5..20

or a single generic field whose meaning depends on the search scope, for example:

beet ls tidal_popularity:5..50 -a

The latter is shorter and more flexible, but the former is more explicit and consistent across entity types.

I would (strongly) prefer the former, just to be explicit.

Replace tidalsync() with sync_item_popularity() / sync_album_popularity()
backed by a shared _sync_popularity() helper.

Split the `tidal` command into `tidal` (auth-only) and `tidalsync`
(popularity sync with --item, --album, --force, --write flags). While
I liked the tidal [auth|sync] it is currently not well supported in beets
and e.g. help pages are lacking.

Accept int IDs throughout the search pipeline to avoid unnecessary
str conversions.
@semohr

semohr commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

@arsaboo Just enhanced the sync logic a bit. Make sure to pull ;) Please have a look! Am mostly happy with the changes but ofcourse if you see something or have a better idea, lets discuss.

@arsaboo

arsaboo commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@semohr Excellent. Updated the other parts of the code. Everything is green.

@semohr

semohr commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Neat I will have another iteration at it tomorrow. Mainly tests and docs as I have not checked these in detail yet but than we should be good to go 👍

Comment thread beetsplug/tidal/__init__.py Outdated
@arsaboo

arsaboo commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

@semohr and @snejus, aside from the popularity issue, everything else should be addressed. I have kept both album and track popularity for now (but can update it if it is a blocker).

@semohr semohr 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.

Lets get rid of the unrelated changes please 😆

Comment thread beetsplug/tidal/__init__.py Outdated
Comment thread beetsplug/tidal/__init__.py Outdated
Comment thread beetsplug/tidal/__init__.py Outdated
Comment thread beetsplug/tidal/__init__.py Outdated
Comment thread beetsplug/tidal/__init__.py
Comment thread docs/changelog.rst Outdated
@arsaboo

arsaboo commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

Lets get rid of the unrelated changes please 😆

Most of the changes are to prevent the build from failing. Notice they are material changes, just reorganization to ensure that line length is less than 80.

Comment thread beetsplug/tidal/__init__.py Outdated
Comment thread beetsplug/tidal/api.py Outdated
Comment thread beetsplug/tidal/api_types.py
@snejus

snejus commented Jun 17, 2026

Copy link
Copy Markdown
Member

@arsaboo are you going to undo unrelated changes or shall I commit that instead?

Comment thread beetsplug/tidal/__init__.py Outdated
@arsaboo

arsaboo commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

@arsaboo are you going to undo unrelated changes or shall I commit that instead?

It will be great if you can do it. I am stepping out for a few and will complete the remaining issues.

@semohr semohr requested a review from snejus June 19, 2026 08:52
@semohr semohr merged commit 2bf0adf into beetbox:master Jun 19, 2026
18 checks passed
@semohr

semohr commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Thanks for the discussions and progress here!

@arsaboo

arsaboo commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, @semohr and @snejus, for patiently working on this and all the discussions.

@arsaboo arsaboo deleted the tidal branch June 19, 2026 15:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants