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.
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>
Adds a `userid` config option for the `embyupdate` plugin. When the
`userid` is provided, the Emby user lookup is bypassed. This avoids a
failure to get the user ID for private users.
Closes: #4402
by using store(inherit=False) for the creation of a new "ipfs album" as well as
when test_ipfs creates album+items to compare with.
Or put differently: Make ipfs and test_ipfs keep the old store() behaviour for
which the plugin initially was built for.
- Trigger subsonicupdate on database_change event instead of only at import
event.
- Send a new event from smartplaylist plugin whenever lists are updated/created
and have subsonicupdate plugin listen to it.
- Make sure the both events register a new listener that launches the actual
subsonic library update at the very end of a beets run (cli_exit) instead of
during each change (similar to how mpdupdate plugin does it).
by adding files which are not completely silent, thus hitting a different
code path in some calculations
The sample files were generated using
> sox -n whitenoise.flac synth 00:00:02 whitenoise
> ffmpeg -i whitenoise.flac whitenoise.opus
> ffmpeg -i whitenoise.flac whitenoise.mp3
This is a preparation for moving the Gst calculation to multiprocessing
worker threads. Passing only the file paths to the worker threads instead of
synchronizing the entire `Item`s (i.e. minimizing the data that is
shared between the processes) hopefully helps to prevent any issues with
this approach.
...album gains. This is in preparation for parallelizing the track
analysis, and computing the album values in the plugin's "main thread"
once all items are done.
tricky...
- the only way I found to express the concept of the "associated type"
(in Rust lingo) model_type was by making Type generic over its value
and null types.
- in addition, the class hierarchy of Integer and Float types had to be
modified, since previously some of them would have conflicting null
types relative to their super class (this required a change to the
edit plugin; hopefully no more breakage is caused by these changes)
- don't import the query module, but only the relevant Query's to avoid
confusing the module query and the class variable query
As far as I can tell, the fast SQL path was never used before, since a
query would use the default `clause()` implementation. It is only the
`FieldQuery.clause()` that could delegate to `col_clause()`, but
`PlaylistQuery` is not a `FieldQuery`.
- Add NamedQuery abstract class to be able to express the expectation
that a query should be such a query (and have a specific constructor
signature) in construct_query_part
- slightly (and probably completely irrelevantly) improve Query.__hash__
- also, sprinkle some ABC/abstractmethod around to clarify things
fanart.tv uses a string to output the number of likes (see https://fanart.tv/api-docs/api-v3/). In order to sort numerically we need to convert the string into an int.
cf. @arogl's comment 254bb297c8 (commitcomment-111922347)
> Now that this has been merged, external plugins that add to the fetchart plugin now fail with:
>
> ```AttributeError: module 'beetsplug.fetchart' has no attribute 'SOURCES_ALL'``
cf. https://github.com/pallets/werkzeug/issues/2506
didn't check when part_isolating was introduced, but presumably, it
should be harmless to set this attribute for old werkzeug versions that
didn't have it yet
- Remove initial comment around playlist entry condition (which is better
suited for user docs anyway, and stated there already)
- Add explanation above the items_paths playlist contents creation list
comprehension.
Make sure we stay with the beets standard of handling everything internally as
bytes.
- M3UFile.write() method writes in wb mode.
- Playlist contents and EXTM3U header is handled as bytes.
- item.destination() gives us unicode string paths, we tranlate to bytes
using util.bytestring_path().
- Fix test_playlist*write* tests to encode UTF-8 assert strings as bytes using
bytestring_path() before comparision.
- Move the creation of the playlist file to the very end, right after
self._parallel_convert, in the convert plugin's main function.
- In the test code, the destination directory is created when the
conversion happens, thus this fixes test_playlist and doesn't hurt the
feature - The playlist creation can as well be the very last step in
the process.
Use Item.destination method for generation of relative paths to media
files in playlist. The fragment keyword enables returning the path as
unicode instead of bytes, let's keep that in mind.
- Improve --help text
- Use unicode instead of bytes when adding media file paths to the
playlist file.
- The "standard" (?) of m3u8 defines that unicode should ensure support
of special characters in media file names. util.displayable_path() is
used to do the conversion from bytes. We save everything in bytes in
the config since it seemes to be the way this plugin or beets in
general likes to save paths.
- Join dest and playlist in the config reader method already to have it
ready in both methods that require the full path to the playlist file.
- Similar to what the Spotify plugin does, on imports we save to a field
`..._album_id` (spotify_album_id, deezer_album_id, beatport_album_id)
- It would be good to submit such a change to the 3rd-party plugins beetcamp
and beatport4 as well (beatport_album_id, bandcamp_album_id).
- We might need to investigate why none of these
flex attr fields get populated to the beets album level (`beet info -a`,
album_attributes db table), it is only available at the item level (`beet
info`, item_attributes db table). This should be tackled in a future
issue/PR.
from MetadataSourcePlugin and save beatport_id_regex in id_extractors module.
This streamlines the Beatport release ID extraction magic with plugins Deezer
and Spotify.
and put to use in Spotify plugin.
- Make _get_id() a staticmethod usable from outside a metadata source plugin.
- id_regex now has to be passed as an argument instead of assuming it is
accessible via an instance variable (self.id_regex).
- In the Spotify plugin, import spotify_id_regex from util.id_extractors
- We introduce a new submodule of beets.util named id_extractors.
- Parts of the ID extraction utilites required by metadata source plugins
should live there.
- Also this enables future usage of those utilities from the "outside" of
metadata source plugins.
- Move Discogs ID extractor to the new module and change test_discogs to use
the new location.
- Add spotify_id_regex variable to the new module.
Fixes#4627.
AcousticBrainz is shutting down as of early 2023. Deprecate the absubmit
plugin and update the acousticbrainz plugin to require configuration of
an AcousticBrainz server instance.
PR #3748 changed the way cover art is fetched from the cover art
archive, but the manual addition of a `-` to the width suffix that was
needed when the image URI was being constructed manually was not
removed. Because of this the plugin would try to look up the property
under `thumbnails` that didn't exist (for example `-1200` instead of
`1200`), which would fail.
This guards the os.chmod calls so it's only called IF the
permissions need changing. This guards against an exception in
certain complex library setups.
This was a helper for situations when Python 2 and 3 APIs returned bytes
and unicode, respectively. In these situation, we should nowadays know
which of the two we receive, so there's no need to wrap & hide the
`bytes.decode()` anymore (when it is still required).
Detailed justification:
beets/ui/__init__.py:
- command line options are always parsed to str
beets/ui/commands.py:
- confuse's config.dump always returns str
- open(...) defaults to text mode, read()ing str
beetsplug/keyfinder.py:
- ...
beetsplug/web/__init__.py:
- internally, paths are always bytestrings
- additionally, I took the liberty to slighlty re-arrange the code: it
makes sense to split off the basename first, since we're only
interested in the unicode conversion of that part.
test/helper.py:
- capture_stdout() gives a StringIO, which yields str
test/test_ui.py:
- self.io, from _common.TestCase, ultimately contains a
_common.DummyOut, which appears to be dealing with str (cf.
DummyOut.get)
The idea in this PR is to converge on Python's `fsdecode` and `fsencode`
for argument manipulation. This seems to match up with the Python
standard library's assumptions: namely, on Windows, we use `fsdecode` to
get back to Unicode strings:
54bbb5e336/Lib/subprocess.py (L561)
So let's start by dropping this utility and going straight for
`fsdecode` here to match.
The parallelism strategy in #3478, in retrospect, used a pretty funky
way to deal with exceptions in the asynchronous work---since
`apply_async` has an `error_callback` parameter that's meant for exactly
this. The problem is that the wrapped function would correctly log the
exception *and then return `None`*, confusing any downstream code.
Instead of just adding `None`-awareness to the callback, let's just
avoid running the callback altogether in the case of an error.