Releases: linuxserver/docker-beets
Release list
nightly-c1dc7332-ls316
CI Report:
https://ci-tests.linuxserver.io/linuxserver/beets/nightly-c1dc7332-ls316/index.html
LinuxServer Changes:
Full Changelog: nightly-17d67980-ls315...nightly-c1dc7332-ls316
Remote Changes:
Fix logging in tests (#6853)
Summary
- Add a CLI logging handler that resolves
sys.stderrwhen each log
record is emitted. - Keep CLI logs attached to the current stderr stream when callers
temporarily replace it for capture or redirection. - Avoid retaining pytest's closed per-test capture stream across
repeated CLI invocations.
Problem
The issue is that the first CLI command run under pytest can install a
StreamHandler bound to pytest's temporary stderr capture stream.
Pytest later closes that stream, but the global beets logger keeps the
handler around for the next CLI invocation.
This was introduced by #6755, which removed logging setup as an import
side effect and moved CLI logging bootstrap into command startup.
Before #6755, the handler was created when beets.ui was imported. In
tests, that usually happened before pytest swapped in its per-test
stderr capture stream. After #6755, the handler is created when
_raw_main() runs, which means it can be created while pytest capture
is active.
The important bit is that logging.StreamHandler() stores the stream it
sees at creation time. So it ends up holding on to pytest's temporary
stderr stream from the first command. Once pytest closes that stream,
later debug/info logs try to write to a closed file and Python's logging
module prints the huge --- Logging error --- blocks.
This keeps the useful part of #6755 - no logging setup as an import side
effect - but avoids retaining whichever stderr stream happened to be
active during the first CLI run.
Before
I include the output I'm seeing where I have two failing tests in
test_convert.py. See the amount of noise this generates - this also
hides the actual test failures under repeated logging-internal
tracebacks and captured debug logs.
very verbose output
Poe => uv run pytest -p no:cov test/plugins/test_convert.py --lf --maxfail=2
=============================================================================== test session starts ================================================================================
platform linux -- Python 3.10.18, pytest-9.0.3, pluggy-1.6.0
cachedir: /tmp/pytest_cache
rootdir: /home/sarunas/repo/beets
configfile: setup.cfg
plugins: factoryboy-2.8.1, requests-mock-1.12.1, Faker-40.15.0, flask-1.3.0, anyio-4.13.0, xdist-3.8.0
collected 36 items / 15 deselected / 21 selected
run-last-failure: rerun previous 21 failures
test/plugins/test_convert.py FF
===================================================================================== FAILURES =====================================================================================
___________________________________________________________________________ TestConvertCli.test_convert ____________________________________________________________________________
self = <test.plugins.test_convert.TestConvertCli object at 0x7efd27567df0>
def test_convert(self):
self.io.addinput("y")
self.run_convert()
> assert self.file_endswith(self.converted_mp3, "mp3")
test/plugins/test_convert.py:127:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <test.plugins.test_convert.TestConvertCli object at 0x7efd27567df0>, path = PosixPath('/tmp/tmpxyo_pvcw/convert_dest/converted.mp3'), tag = 'mp3'
def file_endswith(self, path: Path, tag: str):
"""Check the path is a file and if its content ends with `tag`."""
> assert path.exists()
E AssertionError: assert False
E + where False = exists()
E + where exists = PosixPath('/tmp/tmpxyo_pvcw/convert_dest/converted.mp3').exists
test/plugins/test_convert.py:48: AssertionError
-------------------------------------------------------------------------------- Captured log setup --------------------------------------------------------------------------------
DEBUG beets:plugins.py:376 plugin paths: []
DEBUG beets:plugins.py:458 Loading plugins: convert
DEBUG beets:plugins.py:622 Sending event: pluginload
DEBUG beets:plugins.py:622 Sending event: database_change
DEBUG beets:queries.py:50 Parsed query: AndQuery([NoneQuery('album_id', True)])
DEBUG beets:queries.py:51 Parsed sort: NullSort()
DEBUG beets:plugins.py:622 Sending event: item_copied
DEBUG beets:plugins.py:622 Sending event: database_change
DEBUG beets:plugins.py:622 Sending event: database_change
DEBUG beets:plugins.py:622 Sending event: database_change
DEBUG beets:plugins.py:622 Sending event: database_change
------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------
the artist - älbum - tïtle 0
Convert? (Y/n)
------------------------------------------------------------------------------- Captured stderr call -------------------------------------------------------------------------------
data directory: /tmp/tmpxyo_pvcw
Sending event: library_opened
Parsed query: AndQuery([PathQuery('path', b'Non-Album/the artist/t\xc3\xaftle 0.ogg', fast=True, case_sensitive=True)])
Parsed sort: NullSort()
convert: Encoding /tmp/tmpxyo_pvcw/libdir/Non-Album/the artist/tïtle 0.ogg
convert: Finished encoding /tmp/tmpxyo_pvcw/libdir/Non-Album/the artist/tïtle 0.ogg
Sending event: write
Sending event: after_write
Sending event: after_convert
Sending event: cli_exit
data directory: /tmp/tmpxyo_pvcw
Sending event: library_opened
Parsed query: AndQuery([PathQuery('path', b'Non-Album/the artist/t\xc3\xaftle 0.ogg', fast=True, case_sensitive=True)])
Parsed sort: NullSort()
convert: Encoding /tmp/tmpxyo_pvcw/libdir/Non-Album/the artist/tïtle 0.ogg
convert: Finished encoding /tmp/tmpxyo_pvcw/libdir/Non-Album/the artist/tïtle 0.ogg
Sending event: write
Sending event: after_write
Sending event: after_convert
Sending event: cli_exit
-------------------------------------------------------------------------------- Captured log call ---------------------------------------------------------------------------------
DEBUG beets:__init__.py:953 data directory: /tmp/tmpxyo_pvcw
DEBUG beets:plugins.py:622 Sending event: library_opened
DEBUG beets:queries.py:50 Parsed query: AndQuery([PathQuery('path', b'Non-Album/the artist/t\xc3\xaftle 0.ogg', fast=True, case_sensitive=True)])
DEBUG beets:queries.py:51 Parsed sort: NullSort()
INFO beets.convert:convert.py:318 Encoding /tmp/tmpxyo_pvcw/libdir/Non-Album/the artist/tïtle 0.ogg
INFO beets.convert:convert.py:354 Finished encoding /tmp/tmpxyo_pvcw/libdir/Non-Album/the artist/tïtle 0.ogg
DEBUG beets:plugins.py:622 Sending event: write
DEBUG beets:plugins.py:622 Sending event: after_write
DEBUG beets:plugins.py:622 Sending event: after_convert
DEBUG beets:plugins.py:622 Sending event: cli_exit
________________________________________________________________ TestConvertCli.test_convert_with_auto_confirmation ________________________________________________________________
self = <test.plugins.test_convert.TestConvertCli object at 0x7efd27565f30>
def test_convert_with_auto_confirmation(self):
self.run_convert("--yes")
> assert self.file_endswith(self.converted_mp3, "mp3")
test/plugins/test_convert.py:131:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <test.plugins.test_convert.TestConvertCli object at 0x7efd27565f30>, path = PosixPath('/tmp/tmpvslyu88g/convert_dest/converted.mp3'), tag = 'mp3'
def file_endswith(self, path: Path, tag: str):
"""Check the path is a file and if its content ends with `tag`."""
> assert path.exists()
E AssertionError: assert False
E + where False = exists()
E + where exists = PosixPath('/tmp/tmpvslyu88g/convert_dest/converted.mp3').exists
test/plugins/test_convert.py:48: AssertionError
------------------------------------------------------------------------------ Captured stderr setup -------------------------------------------------------------------------------
--- Logging error ---
Traceback (most recent call last):
File "/home/sarunas/.local/share/uv/python/cpython-3.10.18-linux-x86_64-gnu/lib/python3.10/logging/__init__.py", line 1103, in emit
stream.write(msg + self.terminator)
File "/media/poetry/virtualenvs/beets-yAypcYUQ-py3.10/lib/python3.10/site-packages/_pytest/capture.py", line 218, in write
super().write(s)
ValueError: I/O operation on closed file.
Call stack:
File "/media/poetry/virtualenvs/beets-yAypcYUQ-py3.10/bin/pytest", line 10, in <module>
sys.exit(console_main())
File "/media/poetry/virtualenvs/beets-yAypcYUQ-py3.10/lib/python3.10/site-packages/_pytest/config/__init__.py", line 223, in console_main
...
Another 1200 lines of this stuff
...
File "/media/poetry/virtualenvs/beets-yAypcYUQ-py3.10/lib/python3.10/site-packages/_pytest/fixtures.py", line 1202, in pytest_fixture_setup
result = call_fixture_func(fixturefunc, request, kwargs)
File "/media/poetry/virtualenvs/beets-yAypcYUQ-py3.10/lib/python3.10/site-packages/_pytest/fixtures.py", line 908, in call_fixture_func
fixture_result = next(generator)
File "/home/sarunas/repo/beets/beets/test/helper.py", line 209, in setup
self.setup_beets()
File "/home/sarunas/repo/beets/test/plugins/test_convert.py", line 107, in setup_beets
self.album = self.add_album_fixture(ext="ogg")
File "/home/sarunas/repo/beets/beets/test/helper.py", line 376, in add_album_fixture
return self.lib.add...
nightly-8778d0ef-ls317
CI Report:
https://ci-tests.linuxserver.io/linuxserver/beets/nightly-8778d0ef-ls317/index.html
LinuxServer Changes:
Full Changelog: nightly-c1dc7332-ls316...nightly-8778d0ef-ls317
Remote Changes:
use pathlib in tests: use only Path-based attributes on PathsMixin/TestHelper (#6847)
Part of #6807
-
This change standardizes the test helper path API around
pathlib.Path. Main shared helpers now usetemp_path,lib_path, and
import_pathinstead of older mixed names liketemp_dir,
temp_dir_path,libdir, andimport_dir. -
Architecturally, path handling is pushed toward one clear model: use
Pathobjects inside helpers and tests, and only encode to bytes at
boundaries that still require it, like importer session setup. -
beets.dbcore.typesalso now acceptsPathvalues foritem.path,
so code can passPathobjects directly without manual conversion. -
High-level impact: the test infrastructure becomes more consistent,
path-related code gets easier to read, and there is less
bytes/string/path conversion scattered across the suite. This is mostly
a cleanup and API consistency change, not a behavior change.
2.12.0-ls341
CI Report:
https://ci-tests.linuxserver.io/linuxserver/beets/2.12.0-ls341/index.html
LinuxServer Changes:
Full Changelog: 2.12.0-ls340...2.12.0-ls341
Remote Changes:
Updating PIP version of beets to 2.12.0
nightly-db9e0441-ls315
CI Report:
https://ci-tests.linuxserver.io/linuxserver/beets/nightly-db9e0441-ls315/index.html
LinuxServer Changes:
Full Changelog: nightly-35e48114-ls314...nightly-db9e0441-ls315
Remote Changes:
typing: add types to beets.dbcore (#6820)
What changed
- This PR is mainly a typing pass over
beets.dbcore, especially in
db.py,query.py,sort.py, andtypes.py. - The main architecture change is in
db.py: model materialization is
now centralized inDatabase._make_model(), whileResultsonly
handles lazy row iteration and uses a materializer callback. - Reloading is also cleaner now:
Model.get_fresh_from_db()goes
throughDatabase._reload(), which keeps database lookup logic in the
database layer and preserves the model's concrete type. - Along the way, a few runtime mismatches found by typing were corrected
instead of just adjusting annotations.
Why
- The goal is to make the typed API match the real behavior of
dbcore. - This improves separation of responsibilities: querying and result
iteration stay inResults, while row-to-model construction and reload
behavior live inDatabase.
High-level impact
dbcorehas a clearer internal structure and a more explicit API
surface.- Type information is more accurate across queries, sorting, models, and
field types, which should make future refactors safer. - A few small correctness fixes are included:
DurationType.format()now always returnsstr.
PathType.from_sql()only expands paths when the normalized value is
actuallybytes.- Several
__eq__implementations now use explicitisinstance(...)
checks. - Reload behavior now has regression coverage in
test/dbcore/test_db.py. - Overall, this is a low-risk cleanup: mostly typing and API-shape
improvements, with a few small behavior fixes discovered during the
work.
nightly-86f0f0a7-ls315
CI Report:
https://ci-tests.linuxserver.io/linuxserver/beets/nightly-86f0f0a7-ls315/index.html
LinuxServer Changes:
No changes
Remote Changes:
Ignore empty deprecated genres (#6848)
While testing my custom out of date soundcloud autotagger which still
sets genre instead of genres, I realised that empty (genre = '')
is converted to genres = [''] list by
Info._get_list_from_string_value.
nightly-4e3884a6-ls315
CI Report:
https://ci-tests.linuxserver.io/linuxserver/beets/nightly-4e3884a6-ls315/index.html
LinuxServer Changes:
No changes
Remote Changes:
Document art_set event (#6851)
Document art_set event
Summary
Documents the missing art_set plugin event in the developer event
reference. The entry records that the event fires after album cover art
is copied or moved into place and that handlers receive the affected
album.
Fixes #6845
AI assistance disclosure
This contribution was produced by an autonomous AI coding agent (Claude
Code) that @Dodothereal operates and monitors. @Dodothereal is
accountable for it, will address review feedback promptly, and will
close this PR immediately if this kind of contribution is unwelcome in
this project. Commits carry an Assisted-by: Claude Code trailer.
nightly-311662bd-ls315
CI Report:
https://ci-tests.linuxserver.io/linuxserver/beets/nightly-311662bd-ls315/index.html
LinuxServer Changes:
No changes
Remote Changes:
typing: type beets.library (#6825)
-
This PR finishes a broad typing pass across
beets.library, mainly in
beets/library/models.pyandbeets/library/library.py, and tightens a
few related plugin and dbcore interfaces. -
Architecturally, the change makes the
Library,Item,Album,
query parsing, and template helper layers agree on clearer contracts:
nullable values are explicit, collection and query return types are
defined, and cross-layer APIs now use more precise types. -
The main behavioral surface is still the same, but several weak spots
are now modeled directly in the code, such as optional albums on items,
optional art paths, library-backed template memoization, and query
objects flowing throughLibrary._fetch(). -
The PR also cleans up how template uniqueness helpers work by giving
_memotableand related keys a stable shape, and by tightening the
logic around album-aware formatting and disambiguation. -
A small architectural rename in
dbcorechangesDatabase._fetch()
toDatabase.get_results(), which makes the lower-level database API
clearer and avoids confusion withLibrary._fetch(). -
High-level impact: better static type safety, clearer boundaries
between database, library, model, and templating code, and less
ambiguity for future refactors without intentionally changing
user-facing behavior.
nightly-2cf20aa6-ls315
CI Report:
https://ci-tests.linuxserver.io/linuxserver/beets/nightly-2cf20aa6-ls315/index.html
LinuxServer Changes:
No changes
Remote Changes:
discogs: refactor _coalesce_tracks around more specific track types (#6818)
-
beetsplug/discogs/types.pynow models Discogs tracklist entries as
distinct shapes:AudioTrack,IndexTrack, andHeadingTrack. This
shifts the plugin from "guessing byposition" to handling each entry
by its declaredtype_. -
beetsplug/discogs/__init__.pyrefactors_coalesce_tracks()into
smaller helpers for flat subtracks and index tracks. The normalization
flow is now type-driven, which makes the rules for "one physical track"
vs "many physical tracks" more explicit. -
beetsplug/discogs/states.pynow advances track state only for real
audio entries (type_ == "track"), so structural entries no longer
affect track counting through indirectpositionchecks. -
Tests now use dedicated Discogs track factories and add coverage for
logical index tracks. This gives the refactor a clearer test model and
protects the new coalescing behavior. -
High-level impact: Discogs imports should now treat headings, index
containers, and subtracks more consistently, especially for releases
where one displayed work contains multiple logical parts but maps to a
single playable track.
This change is based on the following research (thanks, Codex!):
Discogs track coalescing
DiscogsPlugin._coalesce_tracks() handles three distinct notions all
called
"subtracks." This is the main source of its complexity.
Discogs distinguishes:
track: an audio entry.index: a titled container whosesub_tracksare parts or movements.heading: descriptive text applying to following tracks.
That distinction is documented in the current
Discogs tracklisting
guidelines.
Positions such as 3.1, 3.2 or 3a, 3b separately indicate
multiple
musical pieces inside one physical track.
Observed input shapes
| Case | API shape | Current result | Example |
|---|---|---|---|
| Normal track | type_="track", nonempty position |
Passed through | |
| Most releases | |||
| Flat virtual subtracks | Multiple top-level track entries with |
||
1.1, 1.2 or 22a, 22b |
Merged into a copy of the first track | ||
| This Is Not, [Eclectic Beatz | |||
| 8](https://www.discogs.com/release/2885582) | |||
| Nested logical subtracks | index with nested children sharing one |
||
| physical position | Parent index becomes the physical track; children | ||
| discarded | [Defqon.1 Weekend | ||
| Festival](https://www.discogs.com/release/7168134) | |||
| Nested physical subtracks | index with children numbered as |
||
| independent tracks | Index discarded; children promoted | [Classical | |
| Hollywood III](https://www.discogs.com/release/3647530) | |||
| Heading | heading, empty position, no sub_tracks |
Passed through | |
| as structural metadata | Defqon.1 CD headings | ||
| Ambiguous/nonstandard index | index with positions the regex cannot |
||
| classify | Usually promoted incorrectly as separate tracks | [King | |
| Crimson - Lizard](https://www.discogs.com/release/1156598) |
Flat virtual subtracks
This Is Not returns nine top-level entries:
{"type_": "track", "position": "1.1", "title": "Intro", "duration": "1:49"}
{"type_": "track", "position": "1.2", "title": "Untitled", "duration": "6:31"}
# ...
{"type_": "track", "position": "1.9", "title": "2 Bad ...", "duration": "10:18"}There is no index container. _coalesce_tracks() detects the suffixes
and
_add_merged_subtracks() produces:
{
"type_": "track",
"position": "1.1",
"title": "Intro / Untitled / ... / 2 Bad ...",
"duration": "1:49",
"artists": ["Unknown Artist"],
}It copies all metadata from the first entry and only combines titles.
This
explains the incorrect duration and artist.
Eclectic Beatz 8 has the same flat shape:
{"type_": "track", "position": "22a", "title": "Amplifier", "artists": ["Fedde Le Grand"]}
{"type_": "track", "position": "22b", "title": "Autograph ...", "artists": ["Hatiras", "MC Flipside"]}Those become one track, retaining only the first artist.
Nested logical subtracks
Defqon.1 contains:
{
"type_": "index",
"position": "",
"title": "Eat This / God! What The Hell!",
"duration": "3:06",
"sub_tracks": [
{"type_": "track", "position": "2-20A", "title": "Eat This"},
{"type_": "track", "position": "2-20B", "title": "God! What The Hell!"},
],
}Because 2-20A has a parsed subindex, the helper changes the parent to:
{
"type_": "index",
"position": "2-20",
"title": "Eat This / God! What The Hell!",
"duration": "3:06",
}The children disappear. Downstream code treats this as audio solely
because
its position is now nonempty. It never checks that type_ remains
"index".
Nested physical subtracks
Classical Hollywood III contains index containers such as:
{
"type_": "index",
"position": "",
"title": "Auld Lang Syne Variations For Piano Quartet",
"sub_tracks": [
{"type_": "track", "position": "1", "title": "Eine Kleine Nichtmusik ..."},
{"type_": "track", "position": "2", "title": "L.V.B. - Adagio"},
{"type_": "track", "position": "3", "title": "Chaconne ..."},
{"type_": "track", "position": "4", "title": "Homage ..."},
],
}Because position 1 has no subindex:
- the index container is removed;
- its children become top-level physical tracks;
- parent artists are copied to children missing artists;
- when
index_tracksis enabled, the parent title prefixes every child
title.
This behavior was added for
issue #2318 by
PR #2355.
Headings
Defqon.1 also contains:
{
"type_": "heading",
"position": "",
"title": "CD2 ⚡ Mixed By Partyraiser",
"duration": "",
}This is not coalesced. It passes through, but TracklistState
subsequently
treats every positionless object as structural metadata without checking
type_.
The code therefore cannot distinguish:
position == "" and type_ == "heading"
position == "" and type_ == "index"Worse, _add_merged_subtracks() identifies a parent using only:
tracklist and not tracklist[-1]["position"]A heading can therefore theoretically be mistaken for an index parent.
History
- Issue #1543 reported
flat
positions such as22aand22brepresenting one CD track. - PR #2222 added both flat
and
nested subtrack support. Its author explicitly noted thattype_might
identify index tracks robustly, but avoided the larger refactor. - Issue #2318
demonstrated that
nestedsub_trackscan instead be independent physical tracks. - PR #2355 added the current heuristic:
- parsed child subindex means logical fragments of one physical track;
- no parsed child subindex means independent physical tracks.
- That PR documented the heuristic as imperfect.
Lizard, withBa,
Bb,
Bc, and related positions, was already a known failure.
Test data does not match the API shapes
The current test helper always creates:
"type_": "track"Consequently, test inputs such as:
_track("TRACK GROUP TITLE", sub_tracks=[...])are not realistic. Real API data uses:
"type_": "index"Likewise, test medium titles are manufactured as positionless track
objects
rather than heading or index objects.
Recommended direction
Before refactoring production code, introduce accurate input types and
factories:
TrackEntry = AudioTrack | IndexTrack | HeadingTrackWith approximate shapes:
class AudioTrack(TypedDict):
type_: Literal["track"]
position: str
title: str
duration: str
artists: NotRequired[list[Artist]]
class IndexTrack(TypedDict):
type_: Literal["index"]
position: Literal[""]
title: str
duration: str
sub_tracks: list[AudioTrack]
artists: NotRequired[list[Artist]]
class HeadingTrack(TypedDict):
type_: Literal["heading"]
position: Literal[""]
title: str
duration: strThen test using _track(), _index(), and _heading() factories.
The eventual normalization can dispatch structurally:
trackwithout subindex: pass through.- Flat subindexed
trackgroup: apply the flat-fragment policy. index: normalize its children as logical or physical.heading: preserve as structural metadata.- Never infer an index merely from
position == "".
This removes the most dangerous ambiguity while preserving the
positional
heuristic where Discogs genuinely requires it.
nightly-26b26c4b-ls315
CI Report:
https://ci-tests.linuxserver.io/linuxserver/beets/nightly-26b26c4b-ls315/index.html
LinuxServer Changes:
No changes
Remote Changes:
lastgenre: Fix whitelist/tree some disco/funk genres (#6841)
Description
Fixes two issues in whitelist and genre tree.
nightly-17d67980-ls315
CI Report:
https://ci-tests.linuxserver.io/linuxserver/beets/nightly-17d67980-ls315/index.html
LinuxServer Changes:
No changes
Remote Changes:
replaygain: add metaflac backend (#6800)
Fixes #1203.
The replaygain plugin can't compute ReplayGain when metaflac is the only
tool available. The existing backends (command, gstreamer, audiotools,
ffmpeg) each need something heavier installed, which doesn't work on
minimal setups like a NAS where those won't install. Issue #1203 asks
for a metaflac based option so FLAC users on those setups can still tag
ReplayGain.
This adds a metaflac backend for that case. It runs metaflac --add-replay-gain to compute the gain and reads the values back with
metaflac --show-tag. I modeled it on the existing CommandBackend
since both wrap an external tool. It only handles FLAC, skips other
formats, and shifts the gain to the configured targetlevel like the
other backends.
One limitation: metaflac scans a whole album in one pass, so the files
of an album need the same sample rate and channel layout.
Before, selecting the metaflac backend failed:
$ beet replaygain
UserError: Selected ReplayGain backend metaflac is not supported.
After, the backend works and the plugin tests pass:
$ python -m pytest test/plugins/test_replaygain.py
7 passed, 4 skipped
The 4 skipped are the Opus R128 cases, which don't apply to the metaflac
path.