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 .
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.
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 replaces assertions of the form
self.assertTrue(os.path.exists(syspath(path)))
by
self.assertExists(path)
which includes the syspath conversion and is much easier to read.
Occurences where located using
git grep -E 'assert(True|False).*(isdir|isfile|exist)'
these are mostly in the tests, which didn't cause issues since the
affected directories usually have nice ASCII paths. For consistency, it
is nicer to always invoke syspath. That also avoids deprecation warnings
for the bytestring interfaces on Python <= 3.5. The bytestring
interfaces were undeprecated with PEP 529 in Python 3.6, such that we
didn't observe any actual failures.
- 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
A small change, as discussed in #4798, to avoid depending on the reflink
library to run *all* tests. The library seems to be unmaintained and it
may be annoying to install.
and shorten second and third test a little by providing -y cli flag. Enough to
test with interactive input once. Move all 3 tests to the very bottom of the
test class.
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.
- M3UFile.read() method reads in rb mode.
- M3UFile.read() method handles removal of (platform specific) line endings.
- Playlist contents and EXTM3U header is handled as bytes.
- Fix test_playlist*read* tests to encode playlist UTF-8 assert strings to
bytes using bytestring_path() before comparision.
- Fixture playlist_windows.m3u8 is now actually Windows formatted (\r\n + BOM)
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.
Add test_playlist_write_and_read_unicode_windows: Writes 2 media file
paths containing unicode characters, reads them in using M3UFile class
again and tests if the contents is correct.
- Add and Exception class called EmptyPlaylistError ought to be raised
when playlists without files are loaded or saved.
- Add a test for it in test_m3ufile
- Fix media_files vs. media_list attribute name.
- 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.
- samefile exists on all platforms for recent python
- don't rely on monkey-patching os/os.path and on specifics on the
implementation: as a result of doing so, the tests start failing in
obscure ways as soon as the implementation (and its usage of
os.path.exists and os.path.samefile) is changed
- move tests for case_sensitive to test_util.py, since this is not
really the concern of PathQueryTest
- removes part of the tests, since the tests that patch os.path.samefile
and os.path.exists are super brittle since they test the
implementation rather than the functionality of case_sensitive().
This is a prepartory step for actually changing the implementation,
which would otherwise break the tests in a confusing way...
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)
used to work due to inconsistent mediafile implementation, but with
https://github.com/beetbox/mediafile/pull/64 (in mediafile >= 0.11.0)
list fields are None if non-existent, not the empty list
On Windows, converting command-line arguments (hopefully!!!) only needs
to deal with valid strings from the OS. So it is not really relevant to
test with non-UTF-8, non-surrogate bytes.
Unidecode 1.3.5 (a yanked PyPI version) changed the behavior of
Unidecode for some specific characters:
> Remove trailing space in replacements for vulgar fractions.
As luck would have it, our tests used the 1/2 character specifically to
test the behavior when these characters decoded to contain slashes. We
now pin a sufficiently recent version of Unidecode and adapt the tests
to match the new behavior.
Quoth the responses documentation:
> querystring is matched by default
Not sure how recent this is, unfortunately---but probably 0.17.0, since
that's the version where `match_querystring` was deprecated.
Makes the dispatch to the chosen backend simpler in the thumbnails
plugin. Given that ArtResizer is not only about resizing art anymore,
these methods fit there quite nicely.
- Adds a configuration that, when enabled, will append the style to genre
- Rationale is to have more verbose genres in genre tag of players that only support genre
This didn't cause any issues since we only use the shared instance
anyway, but logically it doesn't make a lot of sense for the backends
always using ArtResizer.shared (which they should be oblivious of).
Uses a custom assertion to have more detailed output (which should help
with getting an idea what the difference between expected and actual
lyrics is), and use `subTest` to clearly associate test failure to a
backend.
In addition, this strip parenthesis from the lyrics' words. That helps
with the currently failing Tekstowo test, but doesn't entirely fix it.
Requires Python 3.4 for subTest.
Test more combinations of tags that might initially be present and
expected tags. The R128 codepath and the case of having the wrong type
of tags wasn't really tested before.
Another incorrect py2 -> py3 translation. Since python 3 attached the
traceback to the exception, this should preserve the traceback without
needing to resort to sys.exc_info
This is an incorrect translation of a python 2 reraise to python 3.
With python 3, however, we can just rely on exception chaining to get
the traceback, so get rid of the complicated re-raising entirely, with
the additional benefit that the exception from the tear-down is also
shown.
When the delete_originals was set, beets would print the following, regardless
of the presence of the quiet parameter:
convert: Removing original file /path/to/file.ext
This commit ensures that the log is only printed when quiet is not present.
Unit test may fails when path to temprorary library contains `.`; to
garantue that bug wasn't here, it forces to use one more `.` inside path.
Fixes: https://github.com/beetbox/beets/issues/4151
remove interlacing by default when resizing/down-scaling, the
`deinterlace` option is to remove interlace when otherwise no processing
would have happened.
This allows for the use of differing replacements for destinations other than
the library, which is useful for beets-alternatives in the case where
filesystem requirements differ between the two paths.
Signed-off-by: Christopher Larson <kergoth@gmail.com>
Some of these tests load plugins using beets' normal plugin loader, but
didn't call unload_plugins to tidy up afterwards. This led to any future
plugin loads being ignored until the next unload_plugins call.
This commit changes the config tests so that we always call load_plugins
on setup (to store the default beets state) and unload_plugins on
teardown (to restore the previously stored state).
This changes greatly improves the speed of `beet export` and `beet info`
when the `--include-keys` option is used. It also removes the globbing
feature of `--include-keys` that was added in #1295. (See #3762 for
discussion).
Listing all fields for an item requires querying the database to find
any flex attributes. This is slow when done for every item being
exported. We already have a way for the user to specify a fixed set
of keys, but we previously queried everything and filtered it afterwards.
The new approach is more efficient.
Code that iterates through all fields now have to handle invalid field
names. The export and info plugins output invalid fields as None.
Timings before:
> /usr/bin/time beet export -i title,path,artist -l Bob Dylan
13.26user 20.22system 0:34.01elapsed 98%CPU (0avgtext+0avgdata 52544maxresident)k
> /usr/bin/time beet export -l Bob Dylan
12.93user 20.15system 0:33.58elapsed 98%CPU (0avgtext+0avgdata 53632maxresident)k
Timings after:
> /usr/bin/time beet export -l Bob Dylan
13.33user 20.17system 0:34.02elapsed 98%CPU (0avgtext+0avgdata 53500maxresident)k
> /usr/bin/time beet export -i title,path,artist -l Bob Dylan
0.49user 0.07system 0:00.56elapsed 98%CPU (0avgtext+0avgdata 50496maxresident)k
Notice the dramatic speedup in the last example!
Squashed from the PR, relevant commit messages follow below:
Added file size option to artresizer
- In line with comments on PR, adjusted the ArtResizer API to add
functionality to "resize to X bytes" through `max_filesize` arg
- Adjustment to changelog.rst to include max_filesize change to ArtResizer
and addition of new plugin.
Added explicit tests for PIL & Imagemagick Methods
- Checks new resizing functions do reduce the filesize of images
Expose max_filesize logic to fetchart plugin
- Add syspath escaping for OS cross compatibility
- Return smaller PIL image even if max filesize not reached.
- Test resize logic against known smaller filesize (//2)
- Pass integer (not float) quality argument to PIL
- Remove Pillow from dependencies
- Implement "max_filesize" fetchart option, including
logic to resize and rescale if maxwidth is also set.
Added tests & documentation for fetchart additions.
Tests now check that a target filesize is reached with a
higher initial quality (a difficult check to pass).
With a starting quality of 95% PIL takes 4 iterations to succeed
in lowering the example cover image to 90% its original size.
To cover all bases, the PIL loop has been changed to 5 iterations
in the worst case, and the documentation altered to reflect the
50% loss in quality this implies. This seems reasonable as users
concerned about performance would most likely be persuaded to
install ImageMagick, or remove the maximum filesize constraint.
The previous 30% figure was arbitrary.
Also simplified the setup of the `readonly` value in the tests which
fixes a test ordering issue found using --random-order.
Signed-off-by: Graham R. Cobb <g+beets@cobb.uk.net>
Track item paths and album artpaths should be removed from results unless
INCLUDE_PATHS is set. This works for items but for albums the artpath is always
removed.
This patch makes the artpath removal conditional on INCLUDE_PATHS not being set
and includes a regression test. Note: the default value for INCLUDE_PATHS is
False so no changes will be seen by users unless they already have
INCLUDE_PATHS set.
Signed-off-by: Graham R. Cobb <g+beets@cobb.uk.net>
Added a test (test_get_stats) for the /stats web API.
This involved adding another item so that we can check both items and albums
are being counted correctly, which required a few small changes to some item
tests.
Signed-off-by: Graham R. Cobb <g+beets@cobb.uk.net>
Documentation says that ?expand does not need a value (i.e. ?expand=1 is wrong),
so the test is changed to reflect that syntax.
Signed-off-by: Graham R. Cobb <g+beets@cobb.uk.net>
Added test_get_album_details to test fetching /album/2?expand=1.
Also changed second album name to make tests more robust.
Signed-off-by: Graham R. Cobb <g+beets@cobb.uk.net>
self.lib.add ignores the "id" field from the entry being added and overwrites
it with the next free number. So remove the misleading id fields.
Add a test to confirm that the album query response contains the expected
album id number.
Signed-off-by: Graham R. Cobb <g+beets@cobb.uk.net>
References in the documentation to this plugin were removed in
beetbox/beets#3127 (beetbox/beets#3130) but no actual code
changes were made.
This PR removes support for this dependency entirely.
This adds support for the JSON Lines format as documented at
https://jsonlines.org/.
In this mode the data is output incrementally, whereas the other
modes load every item into memory and don't produce output until
the end.
* fetchart: Improve Cover Art Archive source.
Instead of blindly selecting the first image, we now treat all "front"
images as candidates.
This is useful where some digital releases have both an animated cover
and a still image and the animated image is the first image returned
from the API.
The previous test worked (on my machine, and on Github CI and AppVeyor),
but it is not obvious whether the order is really guaranteed (given that
the full beets database stack and sqlite are involved). Thus, to prevent
this from exploding at some point, only verify the number of deletions
for now.
MPD keeps the current track in the queue when stopping, so it's not
really like a skip, and I use it so that I can stop the music, and later
start at the beginning of a track.
I do this by keeping track of the current song id, and then comparing
them when we receive a stop signal.
* If import move is true, files will be deleted after converting.
Fixes#2947
* Removed trailing whitespace to comply with W293, fixing build
* Add period to the end of the comment
Co-Authored-By: Adrian Sampson <adrian@radbox.org>
* Added changelog entry for this fix.
* Added delete_originals option to remove source files after transcode
* Added unit test, removed redundant syspath call
Co-authored-by: Logan Arens <logan-arens@users.noreply.github.com>
Co-authored-by: Logan Arens <heresmygithub@protonmail.com>
Co-authored-by: Adrian Sampson <adrian@radbox.org>
Co-authored-by: Logan Arens <logan.arens@protonmail.com>
* clean-up code & add tests for genius lyrics backend
* add genius fetch tests
* organize imports: standard lib -> pip -> local
* check in sample genius lyrics page
* fix mock import
* force utf-8 encoding for opened files
* use io.open to force utf-8 encoding w/ python2.7
- renamed test test_format_fixed_field to test_format_fixed_field_string
- test_format_fixed_field_string not tests `field_two` with string values
- added new test_format_fixed_field_integer to test field `field_one` as INTEGER
- added new test_format_fixed_field_integer_normalized to test rounding float values
* safer version comparison
* regex bytes directly
* handle b'\x08 ...' case
* test_replaygain.py: injected command output should match the type of the actual output
* Fix unspecified `gain_adjustment` when method defined in config
* Fix difference between dB and LUFS values in case of mismatched `target_level`/`method`:
```
db_to_lufs( target_level <dB> ) - lufs_to_dB( -23 <LUFS> )
```
* Ignore single assertion in case of bs1770gain
(cherry picked from commit 2395bf224032c44f1ea5d28e0c63af96a92b96df)
Assert that the replaygain plugin does not write REPLAYGAIN_* tags but R128_*
tags, when instructed to do so.
This test is skipped for the `command` backend as it does not support OPUS.