I've spent 2 hours troubleshooting why none of my music had genre tag.
It was because the single `genre`, without `s` doesn't seem to cover any
good ganre tags... at least it didn't on my opus files
looking at the code:
7ecd86101e/mediafile.py (L1669-L2167)
i don't honestly know why anyone created the single `ganre` field in the
first place
This utilises regex substitution in the substitute plugin. The previous
approach only used regex to match the pattern, then replaced it with a
static string. This change allows more complex substitutions, where the
output depends on the input.
### Example use case
Say we want to keep only the first artist of a multi-artist credit, as
in the following list:
```
Neil Young & Crazy Horse -> Neil Young
Michael Hurley, The Holy Modal Rounders, Jeffrey Frederick & The Clamtones -> Michael Hurley
James Yorkston and the Athletes -> James Yorkston
````
This would previously have required three separate rules, one for each
resulting artist. By using a regex substitution, we can get the desired
behaviour in a single rule:
```yaml
substitute:
^(.*?)(,| &| and).*: \1
```
(Capture the text until the first `,` ` &` or ` and`, then use that
capture group as the output)
### Notes
I've kept the previous behaviour of only applying the first matching
rule, but I'm not 100% sure it's the ideal approach.
I can imagine both cases where you want to apply several rules in
sequence and cases where you want to stop after the first match.
- Refactored Tekstowo backend to fetch lyrics directly from song pages.
- Added `encode` method to convert artist and title to their URL format,
where non-alphanumeric characters are replaced with underscores.
- Removed the now redundant search functionality and associated tests.
- Simplified `extract_lyrics` method to directly parse lyrics without
any checks.
## Description
This PR adds gracefully handling requests error in teh Deezer plugin. Right now, it errors out when it receives error:
```bash
Traceback (most recent call last):
File "/home/arsaboo/.local/bin/beet", line 8, in <module>
sys.exit(main())
^^^^^^
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/ui/__init__.py", line 1865, in main
_raw_main(args)
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/ui/__init__.py", line 1852, in _raw_main
subcommand.func(lib, suboptions, subargs)
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/ui/commands.py", line 1395, in import_func
import_files(lib, paths, query)
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/ui/commands.py", line 1326, in import_files
session.run()
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/importer.py", line 360, in run
pl.run_parallel(QUEUE_SIZE)
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/util/pipeline.py", line 447, in run_parallel
raise exc_info[1].with_traceback(exc_info[2])
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/util/pipeline.py", line 312, in run
out = self.coro.send(msg)
^^^^^^^^^^^^^^^^^^^
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/util/pipeline.py", line 195, in coro
func(*(args + (task,)))
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/importer.py", line 1497, in lookup_candidates
task.lookup_candidates()
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/importer.py", line 688, in lookup_candidates
artist, album, prop = autotag.tag_album(
^^^^^^^^^^^^^^^^^^
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/autotag/match.py", line 548, in tag_album
for matched_candidate in hooks.album_candidates(
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/plugins.py", line 593, in decorated
for v in generator(*args, **kwargs):
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/autotag/hooks.py", line 759, in album_candidates
yield from plugins.candidates(items, artist, album, va_likely, extra_tags)
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/plugins.py", line 390, in candidates
yield from plugin.candidates(
^^^^^^^^^^^^^^^^^^
File "/home/arsaboo/.local/lib/python3.12/site-packages/beets/plugins.py", line 772, in candidates
results = self._search_api(query_type="album", filters=query_filters)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/arsaboo/.local/lib/python3.12/site-packages/beetsplug/deezer.py", line 282, in _search_api
response.raise_for_status()
File "/home/arsaboo/.local/lib/python3.12/site-packages/requests/models.py", line 1024, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://api.deezer.com/search/album?q=album%3A%22Y+Hate+%3F%22+artist%3A%22Parmish+Verma%22
```
## To Do
- [ ] Documentation. (If you've added a new command-line flag, for example, find the appropriate page under `docs/` to describe it.)
- [x] 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.)
See my comment under #5406 for context
> The build on win32 is failing to install reflink because it's [only
supported until Python
3.7](https://gitlab.com/rubdos/pyreflink/-/blob/master/setup.py?ref_type=heads).
>
> I will address this in a separate PR and rebase this one accordingly
once the fix is merged.
>
> Note: this issue popped up now because I added a new requests-mock
dependency which invalidated cached dependencies.
As noted by 5bf4e3d92f, MusicBrainz
external IDs (`*_album_id`) were only saved for items and not albums.
This commit addresses that by copying `AlbumInfo` fields to the `Album`,
i.e. what's saved in the DB.
This is similar to how `TrackInfo` fields are copied to `Item` instances
except the copying is done at a different time since we only get an
`Album` much later in the import flow.
Fixes#4360
This PR enables querying albums by track fields and tracks by album
fields, and speeds up querying albums by `path` field.
It originally was part of #5240, however we found that the changes
related to the flexible attributes caused degradation in performance. So
this PR contains the first part of #5240 which joined `items` and
`albums` tables in queries.
## Description
This is a very simple PR, just removing the (apparently unused) `beet`
executable from the repository and substituting `bin/env python` for
`bin/python3` where possible.
Fixes#4604.
Migrate `beets` package configuration to Poetry which nowadays seems to
be the gold standard.
I have been using Poetry since 2019 and I have mostly been happy a happy
user: it makes local dev setup easy and has the tools I need to maintain
python packages day to day, including reliable dependency resolution,
versioning and publishing to Pypi.
It's a user-friendly tool, so it should make it more straightforward for
contributors to setup and navigate the codebase, and ultimately,
hopefully facilitate more frequent releases!
Since poetry manages local virtual environment, we do not have much need
for tox any more. Therefore, it was replaced by a task runner
`poethepoet`. Type `poe` in the project directory to see the available
commands.
- [x] Documentation. (If you've added a new command-line flag, for
example, find the appropriate page under `docs/` to describe it.)
- [x] Changelog. (Add an entry to `docs/changelog.rst` to the bottom of
one of the lists near the top of the document.)
- [x] Tests. (Very much encouraged but not strictly required.)
The docs say:
> The `auto` option uses reflinks when possible and falls back to plain
> copying when necessary.
I've been using this option for a while, and recently discovered that
despite the option, copying fails between two BTRFS filesystems with:
Error: OS/filesystem does not support reflinks. during link of paths /mnt/fs1/file, /mnt/fs2/file
I tracked this down to how the configuration is handled in the importer.
Additionally, update the 'in progress' header in the changelog: instead
of using a specific version number, simply say 'Unreleased' since we do
not know in advance what version will the changes be eventually
released.
This also simplifies latest changelog retrieval.
When unix tools make use of an external editor, they typically check the
environment variable VISUAL and fall back to EDITOR. This commit adds the
additional check for VISUAL to the existing EDITOR check (where VISUAL is
preferred over EDITOR).
Allow generating extm3u playlists so that they contain additional item fields such as the `id`.
The feature is required by the mgoltzsche/beets-webm3u plugin (M3U server) to transform playlists using a request based item URI template which may require additional fields such as the `id`, e.g. `beets:library:track;$id`.
External Python packages interfacing beets may want to use an in-memory
beets library instance for testing beets-related code.
The `TestHelper` class is very helpful for this purpose.
Previously `TestHelper` was located in the `test/` directory.
Now it is part of `beets` itself (`beets.test.helper.TestHelper`) and
can be easily imported.
Do not let the web plugin overwrite the Content-Length header with the full file length since flask/werkzeug sets the requested range's/chunk's size when handling a range request.
This allows to play large audio/opus files using e.g. a browser/firefox or gstreamer/mopidy without making a reverse-proxy/nginx emulate range request support and hide range-related headers from the backend.
Beets web API already allows remote players to access audio files but it doesn't provide a way to expose the playlists defined using the smartplaylist plugin.
Now the smartplaylist plugin provides an option to generate ID-based item URIs/URLs instead of paths.
Once playlists are generated this way, they can be served using a regular HTTP server such as nginx.
To provide sufficient flexibility for various ways of integrating beets remotely (e.g. beets API, beets API with context path, AURA API, mopidy resource URI, etc), the new option has been defined as a template with an `$id` placeholder (assuming each remote integration requires a different path schema but they all rely on using the beets item `id` as identifier/path segment).
To prevent local path-related plugin configuration from leaking into a HTTP URL-based playlist generation (invoked with CLI option in addition to the local playlists generated into another directory), setting the new option makes the plugin ignore the other path-related options `prefix`, `relative_to`, `forward_slash` and `urlencode`.
Usage examples:
* `beet splupdate --uri-format 'http://beets:8337/item/$id/file'` (for beets web API)
* `beet splupdate --uri-format 'http://beets:8337/aura/tracks/$id/audio'` (for AURA API)
(While it was already possible to generate playlists containing HTTP URLs previously using the `prefix` option, it did not allow to generate ID-based URLs pointing to the beets web API but required to expose the audio files using a web server directly and refer to them using their file system `$path`.)
Relates to #5037
The boolean flags `--extm3u` and `--no-extm3u` are replaced with a string option `--output=m3u|m3u8`.
This reduces the amount of options and allows to evolve the CLI to support more playlist output formats in the future (e.g. JSON) without polluting the CLI at that point.
- Set static path and css file in Sphinx config.
- Codebox style to black/white
- Secondary color to beetroot red
- Inline code color to beetroot green
- Leave primary color (pydata teal), difficult to read with beetroot
green. Works well with beetroot red actually.
- Leave some notes on colors in beets.css for reference.
- Sticky Nnavigation (default but make sure)
- Top left area white, to fit with beets logo background
- Title "beets"
- Logo only false, we want to see title
- Version true, we want to see which beets version we are looking at
- Issue: The latter two are invisible, would require custom CSS!!!
and rephrase a little if required. Often "our forums" was stated. Mostly
I tried to use the wording "discussion board" throughout and (almost) never used
the term "GitHub Discussions"
This plugin allows rewriting fields based on a given library query. This can be helpful, for example, when an artist was renamed but you'd like to keep their older releases under their old name, or if you have a single track from a Various Artists release and want to have it included with the original artist.
Instead of just stating config_default.yaml's values, provide a copy/paste-able
example that changes _all_ the values and still kind of works (visually).
This plugin uses librosa to automatically calculate the BPM for a track.
It is based on the keyfinder plugin, and rounds the BPM to an int.
Co-authored-by: Adrian Sampson <adrian@radbox.org>
This is a quickfix to get back the behaviour we previously had with the
readthedocs theme. There could be adjusted and fixed more, but postpone that
and do in a proper PR.
Adds the following fields with id3v2.4 multi-valued tag support to autotag:
- artists, artists_sort, artists_credit
- albumartists, albumartists_sort, albumartists_credit
- mb_artistids, mb_albumartistids
MusicBrainz support to populate + write the above multi-valued tags by default. Can be toggled to use id3v2.3 or id3v2.4 tags via the existing beets configuration option `id3v23`.
Big thanks to @JOJ0, @OxygenCobalt, @arsaboo for testing + @sampsyo for the initial code review .
on whether it modifies metadata or not. Let's also leave a link to the issue
here to make it superclear and researchable for anyone stumbling across it.
Also suggest the substitute plugin as an alternative.
While rebasing master into this feature branch I removed fdaniele85's
original version(s) of the changelog to make conflict resolvement
easier. This is a slightly extended version of the latest version I
found in the original commits.
and further clarify `mod -a` docs:
Even though e39dcfc002 and the linked discussion
already does a very good job on clarifying what is actually happening when `mod
-a` is issued, this commit adds further details about the difference between
the album query and what is actually modified.
The `ANTIALIAS` attribute has long been deprecated, and was finally
removed in pillow 10.0.
The recommendation is to migrate to `Resampling.LANCZOS` instead.
- New config option for the importer 'singleton_album_disambig' lets
users choose whether they want to display [album names] in the list of
candidates. Enabled by default but ony applicable if the candidate provides
an album attribute.
- Add docs describing the new option and which source plugins currently support
it.
beets does not currently store the "canonical" release group title,
only each release's title and disambiguation. Oddly, beets does store
the release group disambiguation.
Without this there is no way to determine a release group's title
without separately querying a data source.
Perform regex and `bareasc` lookups using SQL
- Define a custom function which performs regex lookups natively in SQL. This improves
performance of lookups like beet list path::hello.
- Define a SQL function which runs unidecode for the bareasc lookups
This slightly speeds up the queries and there's a nice side-effect where
`singleton:1` and `singleton:0` now work fine!
This is ultimately building towards replacing as many python-only
queries with SQL equivalents.