Commit graph

13136 commits

Author SHA1 Message Date
Alok Saboo
56e132f352 more lint 2025-09-21 07:07:14 +02:00
Alok Saboo
95b35ded4a Lint 2025-09-21 07:07:14 +02:00
Alok Saboo
84986dc42d Enhance lastgenre plugin: add item.try_write() for write operations and improve documentation clarity 2025-09-21 07:07:14 +02:00
Alok Saboo
a57ef2cb3b Add --pretend option to lastgenre plugin for previewing genre changes 2025-09-21 07:07:14 +02:00
henry
0dc774c65d
Merge branch 'master' into discogs-disambiguation-fix 2025-09-20 14:08:43 -07:00
Sebastian Mohr
dc4e4e5020
Move art.py to beetsplug._utils package to avoid polluting core namespace (#6013)
This PR moves the `art.py` module, which is only used by the plugin
architecture, to avoid polluting the main beets namespace.
2025-09-20 14:09:58 +02:00
Sebastian Mohr
73dc8f2bc7 fix test by changing patch 2025-09-20 14:04:48 +02:00
Sebastian Mohr
4ab1bb4df4 Added changelog and git blame ignore rev 2025-09-20 14:02:25 +02:00
Sebastian Mohr
a796d6d799 New import location for art.py 2025-09-20 14:01:38 +02:00
Sebastian Mohr
28aee0fde4 Moved arts.py file into beetsplug namespace as it is not used in core. 2025-09-20 14:01:38 +02:00
Henry
8a21bacd14 Add type check 2025-09-19 21:00:37 -07:00
Henry
dda265dc77 Disambiguation fix implemented & tested 2025-09-19 20:46:07 -07:00
Henry Oberholtzer
24fbc566f6 initial changes, changelog adjusted, TODO: test for various artists and update docs 2025-09-20 01:58:56 +02:00
Henry Oberholtzer
23e46315e3 Remove Discogs Disambiguation stripping from metadata_plugins 2025-09-20 01:52:53 +02:00
Šarūnas Nejus
c56cb69e32
fix: enable tracebacks for "user"/custom sqlite functions (#5383)
A bit niche but I tried setting my bareasc prefix to an empty string,
and was getting an obtuse error. This should help make clearer what is
happening when queries fail.

The exception is not properly raised up the stack in the first place
because it happens across 2 FFI boundaries: the DB query
(Python -> SQLite), and the custom DB function (SQLite -> Python).
Thus Python cannot forwarded it back to itself through SQLite, and it's
treated as an "unraisable" exception.

We could override `sys.unraisablehook` to not print anything for the
original exception, and store it in a global for the outer Python
interpreter to fetch and raise properly, but that's pretty hacky,
limited to a single DB instance and query at once, and risks swallowing
other "unraisable" exceptions.
Instead we just tell the user to look above for what Python prints.

Sample output:
```
Exception ignored in: <function unidecode_expect_ascii at 0x7f7fa20bb060>
Traceback (most recent call last):
  File "site-packages/unidecode/__init__.py", line 60, in unidecode_expect_ascii
    bytestring = string.encode('ASCII')
                 ^^^^^^^^^^^^^
AttributeError: 'bytes' object has no attribute 'encode'
Traceback (most recent call last):
  File "site-packages/beets/dbcore/db.py", line 988, in query
    cursor = self.db._connection().execute(statement, subvals)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.OperationalError: user-defined function raised exception

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "site-packages/beets/__main__.py", line 9, in <module>
    sys.exit(main())
             ^^^^^^
  File "site-packages/beets/ui/__init__.py", line 1865, in main
    _raw_main(args)
  File "site-packages/beets/ui/__init__.py", line 1852, in _raw_main
    subcommand.func(lib, suboptions, subargs)
  File "site-packages/beets/ui/commands.py", line 1599, in list_func
    list_items(lib, decargs(args), opts.album)
  File "site-packages/beets/ui/commands.py", line 1594, in list_items
    for item in lib.items(query):
                ^^^^^^^^^^^^^^^^
  File "site-packages/beets/library.py", line 1695, in items
    return self._fetch(Item, query, sort or self.get_default_item_sort())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/beets/library.py", line 1673, in _fetch
    return super()._fetch(model_cls, query, sort)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/beets/dbcore/db.py", line 1301, in _fetch
    rows = tx.query(sql, subvals)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/beets/dbcore/db.py", line 991, in query
    raise DBCustomFunctionError()
beets.dbcore.db.DBCustomFunctionError: beets defined custom SQLite function failed; see the other errors above for details
```
2025-09-19 21:16:38 +01:00
ThinkChaos
eb83058b13 style: remove extraneous pass statements 2025-09-19 21:11:51 +01:00
ThinkChaos
e7e22ebb3d feat: mark SQLite custom functions as deterministic to allow caching 2025-09-19 21:11:51 +01:00
ThinkChaos
b0caac871a fix: enable tracebacks for "user"/custom sqlite functions
A bit niche but I tried setting my bareasc prefix to an empty string,
and was getting an obtuse error. This should help make clearer what is
happening when queries fail.

The exception is not properly raised up the stack in the first place
because it happens across 2 FFI boundaries: the DB query
(Python -> SQLite), and the custom DB function (SQLite -> Python).
Thus Python cannot forwarded it back to itself through SQLite, and it's
treated as an "unraisable" exception.

We could override `sys.unraisablehook` to not print anything for the
original exception, and store it in a global for the outer Python
interpreter to fetch and raise properly, but that's pretty hacky,
limited to a single DB instance and query at once, and risks swallowing
other "unraisable" exceptions.
Instead we just tell the user to look above for what Python prints.

Sample output:
```
Exception ignored in: <function unidecode_expect_ascii at
0x7f7fa20bb060>
Traceback (most recent call last):
  File "site-packages/unidecode/__init__.py", line 60, in
unidecode_expect_ascii
    bytestring = string.encode('ASCII')
                 ^^^^^^^^^^^^^
AttributeError: 'bytes' object has no attribute 'encode'
Traceback (most recent call last):
  File "site-packages/beets/dbcore/db.py", line 988, in query
    cursor = self.db._connection().execute(statement, subvals)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.OperationalError: user-defined function raised exception

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "site-packages/beets/__main__.py", line 9, in <module>
    sys.exit(main())
             ^^^^^^
  File "site-packages/beets/ui/__init__.py", line 1865, in main
    _raw_main(args)
  File "site-packages/beets/ui/__init__.py", line 1852, in _raw_main
    subcommand.func(lib, suboptions, subargs)
  File "site-packages/beets/ui/commands.py", line 1599, in list_func
    list_items(lib, decargs(args), opts.album)
  File "site-packages/beets/ui/commands.py", line 1594, in list_items
    for item in lib.items(query):
                ^^^^^^^^^^^^^^^^
  File "site-packages/beets/library.py", line 1695, in items
    return self._fetch(Item, query, sort or
self.get_default_item_sort())

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/beets/library.py", line 1673, in _fetch
    return super()._fetch(model_cls, query, sort)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/beets/dbcore/db.py", line 1301, in _fetch
    rows = tx.query(sql, subvals)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/beets/dbcore/db.py", line 991, in query
    raise DBCustomFunctionError()
beets.dbcore.db.DBCustomFunctionError: beets defined SQLite function
failed; see the other errors above for details
```
2025-09-19 21:11:51 +01:00
Sebastian Mohr
b65d773c8e
fix incorrect matches when album is missing or empty in spotify plugin search filter (#6012)
Only include non-empty artist and album filters in Spotify track
search and metadata candidate queries to prevent incorrect matches when
the album field is missing or empty.

closes #5189
2025-09-19 17:26:52 +02:00
Sebastian Mohr
efbfc23931 Removed config options and fixed a bug with beet spotify command 2025-09-19 17:20:51 +02:00
Sebastian Mohr
c7ba399dd1 fix incorrect matches when album is missing or empty
closes #5189
2025-09-19 17:20:51 +02:00
Vrihub
0ac7fb42f5
Merge branch 'master' into ffnp 2025-09-19 12:49:22 +02:00
Sebastian Mohr
c265bd7727
fromfilename: Don't crash if title is missing (#5907)
Prevent crash if title is removed from database by black magic.
2025-09-18 15:03:56 +02:00
Rebecca Turner
a302b6d9c2 fromfilename: Don't crash if title is missing
Prevents this crash:

```
$ beet import ~/Music/Music/_/[1405]/00.mp3
Traceback (most recent call last):
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/bin/.beet-wrapped", line 9, in <module>
    sys.exit(main())
             ~~~~^^
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/ui/__init__.py", line 1859, in main
    _raw_main(args)
    ~~~~~~~~~^^^^^^
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/ui/__init__.py", line 1838, in _raw_main
    subcommand.func(lib, suboptions, subargs)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/ui/commands.py", line 1390, in import_func
    import_files(lib, byte_paths, query)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/ui/commands.py", line 1330, in import_files
    session.run()
    ~~~~~~~~~~~^^
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/importer/session.py", line 234, in run
    pl.run_parallel(QUEUE_SIZE)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/util/pipeline.py", line 471, in run_parallel
    raise exc_info[1].with_traceback(exc_info[2])
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/util/pipeline.py", line 336, in run
    out = self.coro.send(msg)
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/util/pipeline.py", line 219, in coro
    func(*(args + (task,)))
    ~~~~^^^^^^^^^^^^^^^^^^^
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/importer/stages.py", line 141, in lookup_candidates
    plugins.send("import_task_start", session=session, task=task)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/plugins.py", line 505, in send
    result = handler(**arguments)
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beets/plugins.py", line 200, in wrapper
    return func(*args, **kwargs)
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beetsplug/fromfilename.py", line 165, in filename_task
    apply_matches(d, self._log)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^
  File "/nix/store/lfv9ns20hz2bg6d44js378vcxjfm9261-beets-2.3.1/lib/python3.13/site-packages/beetsplug/fromfilename.py", line 124, in apply_matches
    item.title = str(d[item][title_field])
                     ~~~~~~~^^^^^^^^^^^^^
KeyError: 'title'
```
2025-09-18 14:57:48 +02:00
henry
3336b68d08
Fix musicbrainz plugin documentation (#6024)
Add several lines to documentation to clear up possible confusion on
musicbrainz plugin being disabled when plugin list is modified.

closes #6020
2025-09-18 11:33:55 +02:00
Vrihub
ae9489cb92 Fix formatting to make poe format-docs happy 2025-09-16 20:48:40 +02:00
Vrihub
da08978eca Add entry to changelog.rst 2025-09-16 20:20:43 +02:00
Vrihub
c30f9603eb Fix format and lint errors 2025-09-16 17:31:42 +02:00
Vrihub
6b1c3bc582 Merge remote-tracking branch 'upstream/master' into ffnp 2025-09-16 16:01:25 +02:00
neofright
394d78de97
Replace flowery language (#6002)
Simplify wording by replacing flowery or pretentious terms throughout the project. 

A bouquet refers to trees or flowers. The etymology is pretty clear on
the Latin root via French.

Co-authored-by: Sebastian Mohr <sebastian@mohrenclan.de>
2025-09-15 09:02:22 +00:00
JOJ0
e837598e79 Increment version to 2.4.0 2025-09-13 16:47:21 +00:00
Šarūnas Nejus
2b4758d440
Improve default pretty diff colors (#5949)
- Switch default `text_diff_added` color from bold **red** to bold
**green**; unify all diff/case comparisons to use `text_diff_added` and
`text_diff_removed` colors consistently.
- Simplify color handling and setup: introduce cached color config
(validation + legacy normalization), consolidate regexes
- Remove unused colors names
- Update `ui` configuration docs.

### `beet write -p year:2000..2005`

#### Before
<img width="1261" height="460" alt="image"
src="https://github.com/user-attachments/assets/70207350-6d9a-48d8-a314-457ac07c5ad1"
/>

#### After
<img width="1257" height="536" alt="image"
src="https://github.com/user-attachments/assets/efcf3453-016a-490f-84ab-dedfb2aca97b"
/>

### `beet move -p albumtype:broadcast`

#### Before
<img width="1103" height="505" alt="image"
src="https://github.com/user-attachments/assets/9e76c5d6-d878-4535-9da3-a949e6c0830c"
/>

#### After
<img width="1134" height="508" alt="image"
src="https://github.com/user-attachments/assets/3dc03988-8011-4072-8840-6f0a0d12350f"
/>

## Summary by Sourcery

Improve default diff colors from red to green and streamline color
handling by refactoring ANSI code management, removing legacy logic, and
unifying diff highlighting. Also extract a cached changed_prefix
property and update UI config documentation.

Enhancements:
- Introduce cached get_color_config and consolidate ANSI escape regex
patterns to simplify color configuration parsing
- Refactor diff highlighting to consistently use text_diff_added and
text_diff_removed and simplify _colordiff implementation
- Add ChangeRepresentation.changed_prefix cached property for consistent
‘not equal’ prefix formatting

Documentation:
- Update UI configuration documentation to reflect new default colors
and removed settings

Chores:
- Remove unused color names and legacy normalization code
2025-09-13 12:57:13 +01:00
Šarūnas Nejus
30093c517e
Define color regex patterns once 2025-09-13 11:24:57 +01:00
Šarūnas Nejus
841c49d494
Update ui configuration docs 2025-09-13 11:24:57 +01:00
Šarūnas Nejus
f816f894d3
Use default red/green for case differences 2025-09-13 11:24:56 +01:00
Šarūnas Nejus
f8c2008f29
Dedupe "changed" colorize calls 2025-09-13 11:24:56 +01:00
Šarūnas Nejus
04380676e1
Slightly simplify colors setup
This replaces the funky color setup based on a global `COLORS` variable
with a cached function `get_color_config`.
2025-09-13 11:24:56 +01:00
Šarūnas Nejus
0818505334
Fix diff coloring for added and removed text in field diffs
- Update default `text_diff_added` value: red -> green
- Use `text_diff_removed` and `text_diff_added` instead of `text_error`
  in UI
2025-09-13 11:24:55 +01:00
Šarūnas Nejus
e7c12988bc
Remove unused colors 2025-09-13 11:24:44 +01:00
J0J0 Todos
160d4074b2
lastgenre: Some whitelist and genres-tree updates (#5977)
Addresses some fixes and additions mentioned here #5915 and some I
collected myself over the years.

Of course genres and sub-genres classifications always are rather
opinionated, but I consider them useful for others too. Critical
feedback is welcome.
2025-09-13 12:14:37 +02:00
J0J0 Todos
d24a85121b Changelog for #5977 lastgenre whitelist/tree 2025-09-13 09:30:20 +02:00
J0J0 Todos
e59521e375 lastgenre: tree/whitelist: Remove experimental
experimental, even though a tag last.fm very often returns (in top 20
tag charts!), it is too broad of a term to be pinned downed with any
particular genre, thus can't really be used for canonicalization.
2025-09-13 09:29:43 +02:00
J0J0 Todos
a98ba061e8 lastgenre: tree/whitelist: UK/Breakbeat Hardcore
Also changes decided during PR discussions and more research.
2025-09-13 09:29:43 +02:00
J0J0 Todos
9f442dcf75 lastgenre: tree/whitelist: Contributor feedback
that came up in the pull request comments and other discussions.
2025-09-13 09:29:43 +02:00
J0J0 Todos
4949f44e82 lastgenre: tree/whitlist: Jojo's essential fixes
Fixes to the beets default tree and whitlist files I collected over the
years; Includes Tags last.fm returns quite often; Also the
chart.getTopTags API endpoint was checked to make sure the top 100
charts are included in beets default tree and whitelist.
2025-09-13 09:29:43 +02:00
J0J0 Todos
3faa1af858
lastgenre: Move file loading to helpers (#5979)
I split out this refactor from #5744 to make the blacklist PR just a
little bit easier to read.

- Separate _load methods for whitelist and canonicalization tree file
loading.
- Add return type hints for those methods.
- Use `pathlib.Path()` instead of `normpath()`
- Additionally respect None value to fall back to built-in settings for
`canonical` and `whitelist` files (was only `""` before) - this code
exists for backwards compatibility (see
233f71a457),
and might be better sanity checked and vanish in the future... (a None
value is set eg. `canoncial:`) -> #5994
2025-09-10 08:30:53 +02:00
J0J0 Todos
7a5cfa8f46 lastgerne: Update wl/tree load methods docstrings 2025-09-10 07:36:47 +02:00
J0J0 Todos
d2caed3971 lastgenre: Also log which whitelist file is loading 2025-09-10 07:36:47 +02:00
J0J0 Todos
6601cbf8c0 lastgenre: canonical/whitelist setting None load default files 2025-09-10 07:36:47 +02:00
J0J0 Todos
6bc30eaf18 lastgenre: Add docstrings to file load methods 2025-09-10 07:36:47 +02:00