mirror of
https://github.com/beetbox/beets.git
synced 2026-01-30 12:02:41 +01:00
Remove duplicate tracks
This commit is contained in:
parent
ebec90e8ac
commit
71f4cc1814
2 changed files with 67 additions and 5 deletions
|
|
@ -277,16 +277,26 @@ class SmartPlaylistPlugin(BeetsPlugin):
|
|||
items = []
|
||||
|
||||
# Handle tuple/list of queries (preserves order)
|
||||
# Track seen items to avoid duplicates when an item matches
|
||||
# multiple queries
|
||||
seen_ids = set()
|
||||
|
||||
if isinstance(query, (list, tuple)):
|
||||
for q, sort in query:
|
||||
items.extend(lib.items(q, sort))
|
||||
for item in lib.items(q, sort):
|
||||
if item.id not in seen_ids:
|
||||
items.append(item)
|
||||
seen_ids.add(item.id)
|
||||
elif query:
|
||||
items.extend(lib.items(query, q_sort))
|
||||
|
||||
if isinstance(album_query, (list, tuple)):
|
||||
for q, sort in album_query:
|
||||
for album in lib.albums(q, sort):
|
||||
items.extend(album.items())
|
||||
for item in album.items():
|
||||
if item.id not in seen_ids:
|
||||
items.append(item)
|
||||
seen_ids.add(item.id)
|
||||
elif album_query:
|
||||
for album in lib.albums(album_query, a_q_sort):
|
||||
items.extend(album.items())
|
||||
|
|
|
|||
|
|
@ -350,11 +350,11 @@ class SmartPlaylistTest(BeetsTestCase):
|
|||
spl = SmartPlaylistPlugin()
|
||||
|
||||
# Create three mock items
|
||||
i1 = Mock(path=b"/item1.mp3")
|
||||
i1 = Mock(path=b"/item1.mp3", id=1)
|
||||
i1.evaluate_template.return_value = "ordered.m3u"
|
||||
i2 = Mock(path=b"/item2.mp3")
|
||||
i2 = Mock(path=b"/item2.mp3", id=2)
|
||||
i2.evaluate_template.return_value = "ordered.m3u"
|
||||
i3 = Mock(path=b"/item3.mp3")
|
||||
i3 = Mock(path=b"/item3.mp3", id=3)
|
||||
i3.evaluate_template.return_value = "ordered.m3u"
|
||||
|
||||
lib = Mock()
|
||||
|
|
@ -405,6 +405,58 @@ class SmartPlaylistTest(BeetsTestCase):
|
|||
# Items should be in order: i1, i2, i3
|
||||
assert content == b"/item1.mp3\n/item2.mp3\n/item3.mp3\n"
|
||||
|
||||
def test_playlist_update_multiple_queries_no_duplicates(self):
|
||||
"""Test that items matching multiple queries only appear once."""
|
||||
spl = SmartPlaylistPlugin()
|
||||
|
||||
# Create two mock items
|
||||
i1 = Mock(path=b"/item1.mp3", id=1)
|
||||
i1.evaluate_template.return_value = "dedup.m3u"
|
||||
i2 = Mock(path=b"/item2.mp3", id=2)
|
||||
i2.evaluate_template.return_value = "dedup.m3u"
|
||||
|
||||
lib = Mock()
|
||||
lib.replacements = CHAR_REPLACE
|
||||
lib.albums.return_value = []
|
||||
|
||||
# Set up lib.items so both queries return overlapping items
|
||||
q1 = Mock()
|
||||
q2 = Mock()
|
||||
|
||||
def items_side_effect(query, sort):
|
||||
if query == q1:
|
||||
return [i1, i2] # Both items match q1
|
||||
elif query == q2:
|
||||
return [i2] # Only i2 matches q2
|
||||
return []
|
||||
|
||||
lib.items.side_effect = items_side_effect
|
||||
|
||||
# Create playlist with multiple queries (stored as tuple)
|
||||
queries_and_sorts = ((q1, None), (q2, None))
|
||||
pl = "dedup.m3u", (queries_and_sorts, None), (None, None)
|
||||
spl._matched_playlists = [pl]
|
||||
|
||||
dir = mkdtemp()
|
||||
config["smartplaylist"]["relative_to"] = False
|
||||
config["smartplaylist"]["playlist_dir"] = str(dir)
|
||||
try:
|
||||
spl.update_playlists(lib)
|
||||
except Exception:
|
||||
rmtree(syspath(dir))
|
||||
raise
|
||||
|
||||
m3u_filepath = Path(dir, "dedup.m3u")
|
||||
assert m3u_filepath.exists()
|
||||
content = m3u_filepath.read_bytes()
|
||||
rmtree(syspath(dir))
|
||||
|
||||
# i2 should only appear once even though it matches both queries
|
||||
# Order should be: i1 (from q1), i2 (from q1, skipped in q2)
|
||||
assert content == b"/item1.mp3\n/item2.mp3\n"
|
||||
# Verify i2 is not duplicated
|
||||
assert content.count(b"/item2.mp3") == 1
|
||||
|
||||
|
||||
class SmartPlaylistCLITest(PluginTestCase):
|
||||
plugin = "smartplaylist"
|
||||
|
|
|
|||
Loading…
Reference in a new issue