-----------------------
This long overdue release of beets includes far too many exciting and useful
features than could ever be satisfactorily enumerated.
As a technical detail, it also introduces two new external libraries:
`MediaFile`_ and `Confuse`_ used to be part of beets but are now reusable
dependencies---packagers, please take note.
Finally, this is the last version of beets where we intend to support Python
2.x and 3.5; future releases will soon require Python 3.6.
One non-technical change is that we moved our official ``beets`` home
on IRC from freenode to `Libera.Chat`_.
.. _Libera.Chat: https://libera.chat/
Major new features:
* Fields in queries now fall back to an item's album and check its fields too.
Notably, this allows querying items by an album's attribute: in other words,
``beet list foo:bar`` will not only find tracks with the `foo` attribute; it
will also find tracks *on albums* that have the `foo` attribute. This may be
particularly useful in the :ref:`path-format-config`, which matches
individual items to decide which path to use.
Thanks to :user:`FichteFoll`.
:bug:`2797` :bug:`2988`
* A new :ref:`reflink` config option instructs the importer to create fast,
copy-on-write file clones on filesystems that support them. Thanks to
:user:`rubdos`.
* A new :doc:`/plugins/unimported` lets you find untracked files in your
library directory.
* The :doc:`/plugins/aura` has arrived! Try out the future of remote music
library access today.
* We now fetch information about `works`_ from MusicBrainz.
MusicBrainz matches provide the fields ``work`` (the title), ``mb_workid``
(the MBID), and ``work_disambig`` (the disambiguation string).
Thanks to :user:`dosoe`.
:bug:`2580` :bug:`3272`
* A new :doc:`/plugins/parentwork` gets information about the original work,
which is useful for classical music.
Thanks to :user:`dosoe`.
:bug:`2580` :bug:`3279`
* :doc:`/plugins/bpd`: BPD now supports most of the features of version 0.16
of the MPD protocol. This is enough to get it talking to more complicated
clients like ncmpcpp, but there are still some incompatibilities, largely due
to MPD commands we don't support yet. (Let us know if you find an MPD client
that doesn't get along with BPD!)
:bug:`3214` :bug:`800`
* A new :doc:`/plugins/deezer` can autotag tracks and albums using the
`Deezer`_ database.
Thanks to :user:`rhlahuja`.
:bug:`3355`
* A new :doc:`/plugins/bareasc` provides a new query type: "bare ASCII"
queries that ignore accented characters, treating them as though they
were plain ASCII characters. Use the ` prefix with :ref:`list-cmd` or
other commands. :bug:`3882`
* :doc:`/plugins/fetchart`: The plugin can now get album art from `last.fm`_.
:bug:`3530`
* :doc:`/plugins/web`: The API now supports the HTTP `DELETE` and `PATCH`
methods for modifying items.
They are disabled by default; set ``readonly: no`` in your configuration
file to enable modification via the API.
:bug:`3870`
Other new things:
* ``beet remove`` now also allows interactive selection of items from the query,
similar to ``beet modify``.
* Enable HTTPS for MusicBrainz by default and add configuration option
`https` for custom servers. See :ref:`musicbrainz-config` for more details.
* :doc:`/plugins/mpdstats`: Add a new `strip_path` option to help build the
right local path from MPD information.
* :doc:`/plugins/convert`: Conversion can now parallelize conversion jobs on
Python 3.
* :doc:`/plugins/lastgenre`: Add a new `title_case` config option to make
title-case formatting optional.
* There's a new message when running ``beet config`` when there's no available
configuration file.
:bug:`3779`
* When importing a duplicate album, the prompt now says "keep all" instead of
"keep both" to reflect that there may be more than two albums involved.
:bug:`3569`
* :doc:`/plugins/chroma`: The plugin now updates file metadata after
generating fingerprints through the `submit` command.
* :doc:`/plugins/lastgenre`: Added more heavy metal genres to the built-in
genre filter lists.
* A new :doc:`/plugins/subsonicplaylist` can import playlists from a Subsonic
server.
* :doc:`/plugins/subsonicupdate`: The plugin now automatically chooses between
token- and password-based authentication based on the server version.
* A new :ref:`extra_tags` configuration option lets you use more metadata in
MusicBrainz queries to further narrow the search.
* A new :doc:`/plugins/fish` adds `Fish shell`_ tab autocompletion to beets.
* :doc:`plugins/fetchart` and :doc:`plugins/embedart`: Added a new ``quality``
option that controls the quality of the image output when the image is
resized.
* :doc:`plugins/keyfinder`: Added support for `keyfinder-cli`_.
Thanks to :user:`BrainDamage`.
* :doc:`plugins/fetchart`: Added a new ``high_resolution`` config option to
allow downloading of higher resolution iTunes artwork (at the expense of
file size).
:bug:`3391`
* :doc:`plugins/discogs`: The plugin applies two new fields: `discogs_labelid`
and `discogs_artistid`.
:bug:`3413`
* :doc:`/plugins/export`: Added a new ``-f`` (``--format``) flag,
which can export your data as JSON, JSON lines, CSV, or XML.
Thanks to :user:`austinmm`.
:bug:`3402`
* :doc:`/plugins/convert`: Added a new ``-l`` (``--link``) flag and ``link``
option as well as the ``-H`` (``--hardlink``) flag and ``hardlink``
option, which symlink or hardlink files that do not need to
be converted (instead of copying them).
:bug:`2324`
* :doc:`/plugins/replaygain`: The plugin now supports a ``per_disc`` option
that enables calculation of album ReplayGain on disc level instead of album
level.
Thanks to :user:`samuelnilsson`.
:bug:`293`
* :doc:`/plugins/replaygain`: The new ``ffmpeg`` ReplayGain backend supports
``R128_`` tags.
:bug:`3056`
* :doc:`plugins/replaygain`: A new ``r128_targetlevel`` configuration option
defines the reference volume for files using ``R128_`` tags. ``targetlevel``
only configures the reference volume for ``REPLAYGAIN_`` files.
:bug:`3065`
* :doc:`/plugins/discogs`: The plugin now collects the "style" field.
Thanks to :user:`thedevilisinthedetails`.
:bug:`2579` :bug:`3251`
* :doc:`/plugins/absubmit`: By default, the plugin now avoids re-analyzing
files that already have AcousticBrainz data.
There are new ``force`` and ``pretend`` options to help control this new
behavior.
Thanks to :user:`SusannaMaria`.
:bug:`3318`
* :doc:`/plugins/discogs`: The plugin now also gets genre information and a
new ``discogs_albumid`` field from the Discogs API.
Thanks to :user:`thedevilisinthedetails`.
:bug:`465` :bug:`3322`
* :doc:`/plugins/acousticbrainz`: The plugin now fetches two more additional
fields: ``moods_mirex`` and ``timbre``.
Thanks to :user:`malcops`.
:bug:`2860`
* :doc:`/plugins/playlist` and :doc:`/plugins/smartplaylist`: A new
``forward_slash`` config option facilitates compatibility with MPD on
Windows.
Thanks to :user:`MartyLake`.
:bug:`3331` :bug:`3334`
* The `data_source` field, which indicates which metadata source was used
during an autotagging import, is now also applied as an album-level flexible
attribute.
:bug:`3350` :bug:`1693`
* :doc:`/plugins/beatport`: The plugin now gets the musical key, BPM, and
genre for each track.
:bug:`2080`
* A new :doc:`/plugins/bpsync` can synchronize metadata changes from the
Beatport database (like the existing :doc:`/plugins/mbsync` for MusicBrainz).
* :doc:`/plugins/hook`: The plugin now treats non-zero exit codes as errors.
:bug:`3409`
* :doc:`/plugins/subsonicupdate`: A new ``url`` configuration replaces the
older (and now deprecated) separate ``host``, ``port``, and ``contextpath``
config options. As a consequence, the plugin can now talk to Subsonic over
HTTPS.
Thanks to :user:`jef`.
:bug:`3449`
* :doc:`/plugins/discogs`: The new ``index_tracks`` option enables
incorporation of work names and intra-work divisions into imported track
titles.
Thanks to :user:`cole-miller`.
:bug:`3459`
* :doc:`/plugins/web`: The query API now interprets backslashes as path
separators to support path queries.
Thanks to :user:`nmeum`.
:bug:`3567`
* ``beet import`` now handles tar archives with bzip2 or gzip compression.
:bug:`3606`
* ``beet import`` *also* now handles 7z archives, via the `py7zr`_ library.
Thanks to :user:`arogl`.
:bug:`3906`
* :doc:`/plugins/plexupdate`: Added an option to use a secure connection to
Plex server, and to ignore certificate validation errors if necessary.
:bug:`2871`
* :doc:`/plugins/convert`: A new ``delete_originals`` configuration option can
delete the source files after conversion during import.
Thanks to :user:`logan-arens`.
:bug:`2947`
* There is a new ``--plugins`` (or ``-p``) CLI flag to specify a list of
plugins to load.
* A new :ref:`genres` option fetches genre information from MusicBrainz. This
functionality depends on functionality that is currently unreleased in the
`python-musicbrainzngs`_ library: see PR `266
<https://github.com/alastair/python-musicbrainzngs/pull/266>`_.
Thanks to :user:`aereaux`.
* :doc:`/plugins/replaygain`: Analysis now happens in parallel using the
``command`` and ``ffmpeg`` backends.
:bug:`3478`
* :doc:`plugins/replaygain`: The bs1770gain backend is removed.
Thanks to :user:`SamuelCook`.
* Added ``trackdisambig`` which stores the recording disambiguation from
MusicBrainz for each track.
:bug:`1904`
* :doc:`plugins/fetchart`: The new ``max_filesize`` configuration sets a
maximum target image file size.
* :doc:`/plugins/badfiles`: Checkers can now run during import with the
``check_on_import`` config option.
* :doc:`/plugins/export`: The plugin is now much faster when using the
`--include-keys` option is used.
Thanks to :user:`ssssam`.
* The importer's :ref:`set_fields` option now saves all updated fields to
on-disk metadata.
:bug:`3925` :bug:`3927`
* We now fetch ISRC identifiers from MusicBrainz.
Thanks to :user:`aereaux`.
* :doc:`/plugins/metasync`: The plugin now also fetches the "Date Added" field
from iTunes databases and stores it in the ``itunes_dateadded`` field.
Thanks to :user:`sandersantema`.
* :doc:`/plugins/lyrics`: Added a new Tekstowo.pl lyrics provider. Thanks to
various people for the implementation and for reporting issues with the
initial version.
:bug:`3344` :bug:`3904` :bug:`3905` :bug:`3994`
* ``beet update`` will now confirm that the user still wants to update if
their library folder cannot be found, preventing the user from accidentally
wiping out their beets database.
Thanks to user: `logan-arens`.
:bug:`1934`
Fixes:
* Adapt to breaking changes in Python's ``ast`` module in Python 3.8.
* :doc:`/plugins/beatport`: Fix the assignment of the `genre` field, and
rename `musical_key` to `initial_key`.
:bug:`3387`
* :doc:`/plugins/lyrics`: Fixed the Musixmatch backend for lyrics pages when
lyrics are divided into multiple elements on the webpage, and when the
lyrics are missing.
* :doc:`/plugins/web`: Allow use of the backslash character in regex queries.
:bug:`3867`
* :doc:`/plugins/web`: Fixed a small bug that caused the album art path to be
redacted even when ``include_paths`` option is set.
:bug:`3866`
* :doc:`/plugins/discogs`: Fixed a bug with the ``index_tracks`` option that
sometimes caused the index to be discarded. Also, remove the extra semicolon
that was added when there is no index track.
* :doc:`/plugins/subsonicupdate`: The API client was using the `POST` method
rather the `GET` method.
Also includes better exception handling, response parsing, and tests.
* :doc:`/plugins/the`: Fixed incorrect regex for "the" that matched any
3-letter combination of the letters t, h, e.
:bug:`3701`
* :doc:`/plugins/fetchart`: Fixed a bug that caused the plugin to not take
environment variables, such as proxy servers, into account when making
requests.
:bug:`3450`
* :doc:`/plugins/fetchart`: Temporary files for fetched album art that fail
validation are now removed.
* :doc:`/plugins/inline`: In function-style field definitions that refer to
flexible attributes, values could stick around from one function invocation
to the next. This meant that, when displaying a list of objects, later
objects could seem to reuse values from earlier objects when they were
missing a value for a given field. These values are now properly undefined.
:bug:`2406`
* :doc:`/plugins/bpd`: Seeking by fractions of a second now works as intended,
fixing crashes in MPD clients like mpDris2 on seek.
The ``playlistid`` command now works properly in its zero-argument form.
:bug:`3214`
* :doc:`/plugins/replaygain`: Fix a Python 3 incompatibility in the Python
Audio Tools backend.
:bug:`3305`
* :doc:`/plugins/importadded`: Fixed a crash that occurred when the
``after_write`` signal was emitted.
:bug:`3301`
* :doc:`plugins/replaygain`: Fix the storage format for R128 gain tags.
:bug:`3311` :bug:`3314`
* :doc:`/plugins/discogs`: Fixed a crash that occurred when the master URI
isn't set in the API response.
:bug:`2965` :bug:`3239`
* :doc:`/plugins/spotify`: Fix handling of year-only release dates
returned by the Spotify albums API.
Thanks to :user:`rhlahuja`.
:bug:`3343`
* Fixed a bug that caused the UI to display incorrect track numbers for tracks
with index 0 when the ``per_disc_numbering`` option was set.
:bug:`3346`
* ``none_rec_action`` does not import automatically when ``timid`` is enabled.
Thanks to :user:`RollingStar`.
:bug:`3242`
* Fix a bug that caused a crash when tagging items with the beatport plugin.
:bug:`3374`
* ``beet import`` now logs which files are ignored when in debug mode.
:bug:`3764`
* :doc:`/plugins/bpd`: Fix the transition to next track when in consume mode.
Thanks to :user:`aereaux`.
:bug:`3437`
* :doc:`/plugins/lyrics`: Fix a corner-case with Genius lowercase artist names
:bug:`3446`
* :doc:`/plugins/parentwork`: Don't save tracks when nothing has changed.
:bug:`3492`
* Added a warning when configuration files defined in the `include` directive
of the configuration file fail to be imported.
:bug:`3498`
* Added normalization to integer values in the database, which should avoid
problems where fields like ``bpm`` would sometimes store non-integer values.
:bug:`762` :bug:`3507` :bug:`3508`
* Fix a crash when querying for null values.
:bug:`3516` :bug:`3517`
* :doc:`/plugins/lyrics`: Tolerate a missing lyrics div in the Genius scraper.
Thanks to :user:`thejli21`.
:bug:`3535` :bug:`3554`
* :doc:`/plugins/lyrics`: Use the artist sort name to search for lyrics, which
can help find matches when the artist name has special characters.
Thanks to :user:`hashhar`.
:bug:`3340` :bug:`3558`
* :doc:`/plugins/replaygain`: Trying to calculate volume gain for an album
consisting of some formats using ``ReplayGain`` and some using ``R128``
will no longer crash; instead it is skipped and and a message is logged.
The log message has also been rewritten for to improve clarity.
Thanks to :user:`autrimpo`.
:bug:`3533`
* :doc:`/plugins/lyrics`: Adapt the Genius backend to changes in markup to
reduce the scraping failure rate.
:bug:`3535` :bug:`3594`
* :doc:`/plugins/lyrics`: Fix a crash when writing ReST files for a query
without results or fetched lyrics.
:bug:`2805`
* :doc:`/plugins/fetchart`: Attempt to fetch pre-resized thumbnails from Cover
Art Archive if the ``maxwidth`` option matches one of the sizes supported by
the Cover Art Archive API.
Thanks to :user:`trolley`.
:bug:`3637`
* :doc:`/plugins/ipfs`: Fix Python 3 compatibility.
Thanks to :user:`musoke`.
:bug:`2554`
* Fix a bug that caused metadata starting with something resembling a drive
letter to be incorrectly split into an extra directory after the colon.
:bug:`3685`
* :doc:`/plugins/mpdstats`: Don't record a skip when stopping MPD, as MPD keeps
the current track in the queue.
Thanks to :user:`aereaux`.
:bug:`3722`
* String-typed fields are now normalized to string values, avoiding an
occasional crash when using both the :doc:`/plugins/fetchart` and the
:doc:`/plugins/discogs` together.
:bug:`3773` :bug:`3774`
* Fix a bug causing PIL to generate poor quality JPEGs when resizing artwork.
:bug:`3743`
* :doc:`plugins/keyfinder`: Catch output from ``keyfinder-cli`` that is missing key.
:bug:`2242`
* :doc:`plugins/replaygain`: Disable parallel analysis on import by default.
:bug:`3819`
* :doc:`/plugins/mpdstats`: Fix Python 2/3 compatibility
:bug:`3798`
* :doc:`/plugins/discogs`: Replace the deprecated official `discogs-client`
library with the community supported `python3-discogs-client`_ library.
:bug:`3608`
* :doc:`/plugins/chroma`: Fixed submitting AcoustID information for tracks
that already have a fingerprint.
:bug:`3834`
* Allow equals within the value part of the ``--set`` option to the ``beet
import`` command.
:bug:`2984`
* Duplicates can now generate checksums. Thanks :user:`wisp3rwind`
for the pointer to how to solve. Thanks to :user:`arogl`.
:bug:`2873`
* Templates that use ``%ifdef`` now produce the expected behavior when used in
conjunction with non-string fields from the :doc:`/plugins/types`.
:bug:`3852`
* :doc:`/plugins/lyrics`: Fix crashes when a website could not be retrieved,
affecting at least the Genius source.
:bug:`3970`
* :doc:`/plugins/duplicates`: Fix a crash when running the ``dup`` command with
a query that returns no results.
:bug:`3943`
* :doc:`/plugins/beatport`: Fix the default assignment of the musical key.
:bug:`3377`
* :doc:`/plugins/lyrics`: Improved searching on the Genius backend when the
artist contains special characters.
:bug:`3634`
* :doc:`/plugins/parentwork`: Also get the composition date of the parent work,
instead of just the child work.
Thanks to :user:`aereaux`.
:bug:`3650`
* :doc:`/plugins/lyrics`: Fix a bug in the heuristic for detecting valid
lyrics in the Google source.
:bug:`2969`
* :doc:`/plugins/thumbnails`: Fix a crash due to an incorrect string type on
Python 3.
:bug:`3360`
* :doc:`/plugins/fetchart`: The Cover Art Archive source now iterates over
all front images instead of blindly selecting the first one.
* :doc:`/plugins/lyrics`: Removed the LyricWiki source (the site shut down on
21/09/2020).
* :doc:`/plugins/subsonicupdate`: The plugin is now functional again. A new
`auth` configuration option is required in the configuration to specify the
flavor of authentication to use.
:bug:`4002`
For plugin developers:
* `MediaFile`_ has been split into a standalone project. Where you used to do
``from beets import mediafile``, now just do ``import mediafile``. Beets
re-exports MediaFile at the old location for backwards-compatibility, but a
deprecation warning is raised if you do this since we might drop this wrapper
in a future release.
* Similarly, we've replaced beets' configuration library (previously called
Confit) with a standalone version called `Confuse`_. Where you used to do
``from beets.util import confit``, now just do ``import confuse``. The code
is almost identical apart from the name change. Again, we'll re-export at the
old location (with a deprecation warning) for backwards compatibility, but
we might stop doing this in a future release.
* ``beets.util.command_output`` now returns a named tuple containing both the
standard output and the standard error data instead of just stdout alone.
Client code will need to access the ``stdout`` attribute on the return
value.
Thanks to :user:`zsinskri`.
:bug:`3329`
* There were sporadic failures in ``test.test_player``. Hopefully these are
fixed. If they resurface, please reopen the relevant issue.
:bug:`3309` :bug:`3330`
* The ``beets.plugins.MetadataSourcePlugin`` base class has been added to
simplify development of plugins which query album, track, and search
APIs to provide metadata matches for the importer. Refer to the
:doc:`/plugins/spotify` and the :doc:`/plugins/deezer` for examples of using
this template class.
:bug:`3355`
* Accessing fields on an `Item` now falls back to the album's
attributes. So, for example, ``item.foo`` will first look for a field `foo` on
`item` and, if it doesn't exist, next tries looking for a field named `foo`
on the album that contains `item`. If you specifically want to access an
item's attributes, use ``Item.get(key, with_album=False)``. :bug:`2988`
* ``Item.keys`` also has a ``with_album`` argument now, defaulting to ``True``.
* A ``revision`` attribute has been added to ``Database``. It is increased on
every transaction that mutates it. :bug:`2988`
* The classes ``AlbumInfo`` and ``TrackInfo`` now convey arbitrary attributes
instead of a fixed, built-in set of field names (which was important to
address :bug:`1547`).
Thanks to :user:`dosoe`.
* Two new events, ``mb_album_extract`` and ``mb_track_extract``, let plugins
add new fields based on MusicBrainz data. Thanks to :user:`dosoe`.
For packagers:
* Beets' library for manipulating media file metadata has now been split to a
standalone project called `MediaFile`_, released as :pypi:`mediafile`. Beets
now depends on this new package. Beets now depends on Mutagen transitively
through MediaFile rather than directly, except in the case of one of beets'
plugins (in particular, the :doc:`/plugins/scrub`).
* Beets' library for configuration has been split into a standalone project
called `Confuse`_, released as :pypi:`confuse`. Beets now depends on this
package. Confuse has existed separately for some time and is used by
unrelated projects, but until now we've been bundling a copy within beets.
* We attempted to fix an unreliable test, so a patch to `skip <https://sources.debian.org/src/beets/1.4.7-2/debian/patches/skip-broken-test/>`_
or `repair <https://build.opensuse.org/package/view_file/openSUSE:Factory/beets/fix_test_command_line_option_relative_to_working_dir.diff?expand=1>`_
the test may no longer be necessary.
* This version drops support for Python 3.4.
* We have removed an optional dependency on bs1770gain.
.. _Fish shell: https://fishshell.com/
.. _MediaFile: https://github.com/beetbox/mediafile
.. _Confuse: https://github.com/beetbox/confuse
.. _works: https://musicbrainz.org/doc/Work
.. _Deezer: https://www.deezer.com
.. _keyfinder-cli: https://github.com/EvanPurkhiser/keyfinder-cli
.. _last.fm: https://last.fm
.. _python3-discogs-client: https://github.com/joalla/discogs_client
.. _py7zr: https://pypi.org/project/py7zr/