When the lib music dir is under a symlinked parent and reimported using not the realpath, the duplicate prompt will wrongly appear. And if import.move is on and choosing remove old, this will cause the music file be deleted.
FYI: on mac the /tmp is just a symlink to /private/tmp. This is stably reproducable as long as the music dir is under any symlinked dir.
Possible reason: we don't resolve symlinks here.
|
task_paths = {i.path for i in self.items if i} |
|
|
|
duplicates = [] |
|
for album in lib.albums(dup_query): |
|
# Check whether the album paths are all present in the task |
|
# i.e. album is being completely re-imported by the task, |
|
# in which case it is not a duplicate (will be replaced). |
|
album_paths = {i.path for i in album.items()} |
|
if not (album_paths <= task_paths): |
|
duplicates.append(album) |
|
|
|
return duplicates |
Problem
Running this command in verbose (-vv) mode:
/tmp/beets_test $ beet -vv imp -s ./music/Non-Album/Aimer/蝶々結び.mp3
Led to this problem:
configuration sources (highest → lowest priority):
YamlSource /tmp/beets_test/config.yaml
YamlSource /Users/proitheus/.cache/uv/archive-v0/glF2ru6xwIPcyNHl/lib/python3.14/site-packages/beets/config_default.yaml
data directory: /tmp/beets_test
plugin paths: []
Loading plugins: musicbrainz
Sending event: pluginload
library database: /tmp/beets_test/library.db
library directory: /tmp/beets_test/music
Sending event: library_opened
Sending event: import_begin
Sending event: import_task_created
Sending event: import_task_start
Looking up: /private/tmp/beets_test/music/Non-Album/Aimer/蝶々結び.mp3
Searching for track IDs: c13ab0f2-dd84-4d18-8ec4-fc6c53232b22
Sending event: mb_track_extract
Sending event: trackinfo_received
Track ID match.
/private/tmp/beets_test/music/Non-Album/Aimer/蝶々結び.mp3
Sending event: before_choose_candidate
Match (100.0%):
Aimer - 蝶々結び
MusicBrainz, Index None, Track None,
https://musicbrainz.org/recording/c13ab0f2-dd84-4d18-8ec4-fc6c53232b22
* Artist: Aimer
* Track: 蝶々結び
Sending event: import_task_choice
found duplicates: [1]
default action for duplicates: a
This item is already in the library!
Old: MP3, 175kbps, 5:05, 6.5 MiB
New: MP3, 175kbps, 5:07, 6.5 MiB
➜ [S]kip new, Merge all, Remove old, Keep all? r
Sending event: import_task_apply
0 of 1 items replaced
Sending event: database_change
removing 1 old duplicated items
Sending event: database_change
Sending event: item_removed
deleting duplicate /tmp/beets_test/music/Non-Album/Aimer/蝶々結び.mp3
Parsed query: AndQuery([NoneQuery('album_id', True)])
Parsed sort: NullSort()
Moving: file not found at /private/tmp/beets_test/music/Non-Album/Aimer/蝶々結び.mp3, skipping
Sending event: write
error reading /private/tmp/beets_test/music/Non-Album/Aimer/蝶々結び.mp3: [Errno 2] No such file or directory: '/private/tmp/beets_test/music/Non-Album/Aimer/蝶々結び.mp3'
Sending event: database_change
Sending event: import_task_files
Sending event: item_imported
Sending event: import
Sending event: cli_exit
Now the file has been DELETED, maybe causing real data loss.
Here's a link to the music files that trigger the bug (if relevant):
not relevant
Full Repro
This is done via BEETSDIR envvar isolation. The music file is pre-imported into the lib. From which path the music is initially imported is not much relevant, since it doesn't change the bug behaviour.
$ cd /tmp/beets_test
$ export BEETSDIR=$(pwd)
$ beet imp -s music/Non-Album/Aimer/蝶々結び.mp3 <- the -vv cmd above, cause trouble
$ cd /private/tmp/beets_test <- note the difference, here is the realpath
$ export BEETSDIR=$(pwd)
$ beet imp -s music/Non-Album/Aimer/蝶々結び.mp3 <- No prompts appear, beets correctly detects this is a reimport, nothing strange happens
Using absolute path under /tmp will also trigger this bug, while under /private/tmp, the realpath, will not.
Setup
- OS: macOS Tahoe 26.5.2
- Python version: 3.14.3
- beets version: 2.13.1
- Turning off plugins made problem go away (yes/no): no
My configuration (output of beet config) is:
import:
move: yes
directory: music
disabled_plugins: []
musicbrainz:
search_limit: 5
data_source_mismatch_penalty: 0.5
search_query_ascii: no
genres: no
genres_tag: genre
external_ids:
discogs: no
bandcamp: no
spotify: no
deezer: no
tidal: no
extra_tags: []
aliases_as_credits: no
When the lib music dir is under a symlinked parent and reimported using not the realpath, the duplicate prompt will wrongly appear. And if
import.moveis on and choosing remove old, this will cause the music file be deleted.FYI: on mac the
/tmpis just a symlink to/private/tmp. This is stably reproducable as long as the music dir is under any symlinked dir.Possible reason: we don't resolve symlinks here.
beets/beets/importer/tasks.py
Lines 582 to 593 in b7993d1
Problem
Running this command in verbose (
-vv) mode:Led to this problem:
Now the file has been DELETED, maybe causing real data loss.
Here's a link to the music files that trigger the bug (if relevant):
not relevant
Full Repro
This is done via
BEETSDIRenvvar isolation. The music file is pre-imported into the lib. From which path the music is initially imported is not much relevant, since it doesn't change the bug behaviour.Using absolute path under
/tmpwill also trigger this bug, while under/private/tmp, the realpath, will not.Setup
My configuration (output of
beet config) is: