1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
|
# This file is part of beets.
# Copyright 2016, Adrian Sampson.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
"""Tests for discogs plugin."""
from unittest.mock import Mock, patch
import pytest
from beets import config
from beets.test._common import Bag
from beets.test.helper import BeetsTestCase, capture_log
from beetsplug.discogs import DiscogsPlugin
@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock())
class DGAlbumInfoTest(BeetsTestCase):
def _make_release(self, tracks=None):
"""Returns a Bag that mimics a discogs_client.Release. The list
of elements on the returned Bag is incomplete, including just
those required for the tests on this class."""
data = {
"id": "ALBUM ID",
"uri": "https://www.discogs.com/release/release/13633721",
"title": "ALBUM TITLE",
"year": "3001",
"artists": [
{"name": "ARTIST NAME", "id": "ARTIST ID", "join": ","}
],
"formats": [
{
"descriptions": ["FORMAT DESC 1", "FORMAT DESC 2"],
"name": "FORMAT",
"qty": 1,
}
],
"styles": ["STYLE1", "STYLE2"],
"genres": ["GENRE1", "GENRE2"],
"labels": [
{
"name": "LABEL NAME",
"catno": "CATALOG NUMBER",
}
],
"tracklist": [],
}
if tracks:
for recording in tracks:
data["tracklist"].append(recording)
return Bag(
data=data,
# Make some fields available as properties, as they are
# accessed by DiscogsPlugin methods.
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
def _make_track(self, title, position="", duration="", type_=None):
track = {"title": title, "position": position, "duration": duration}
if type_ is not None:
# Test samples on discogs_client do not have a 'type_' field, but
# the API seems to return it. Values: 'track' for regular tracks,
# 'heading' for descriptive texts (ie. not real tracks - 12.13.2).
track["type_"] = type_
return track
def _make_release_from_positions(self, positions):
"""Return a Bag that mimics a discogs_client.Release with a
tracklist where tracks have the specified `positions`."""
tracks = [
self._make_track(f"TITLE{i}", position)
for (i, position) in enumerate(positions, start=1)
]
return self._make_release(tracks)
def test_parse_media_for_tracks(self):
tracks = [
self._make_track("TITLE ONE", "1", "01:01"),
self._make_track("TITLE TWO", "2", "02:02"),
]
release = self._make_release(tracks=tracks)
d = DiscogsPlugin().get_album_info(release)
t = d.tracks
assert d.media == "FORMAT"
assert t[0].media == d.media
assert t[1].media == d.media
def test_parse_medium_numbers_single_medium(self):
release = self._make_release_from_positions(["1", "2"])
d = DiscogsPlugin().get_album_info(release)
t = d.tracks
assert d.mediums == 1
assert t[0].medium == 1
assert t[0].medium_total == 2
assert t[1].medium == 1
assert t[0].medium_total == 2
def test_parse_medium_numbers_two_mediums(self):
release = self._make_release_from_positions(["1-1", "2-1"])
d = DiscogsPlugin().get_album_info(release)
t = d.tracks
assert d.mediums == 2
assert t[0].medium == 1
assert t[0].medium_total == 1
assert t[1].medium == 2
assert t[1].medium_total == 1
def test_parse_medium_numbers_two_mediums_two_sided(self):
release = self._make_release_from_positions(["A1", "B1", "C1"])
d = DiscogsPlugin().get_album_info(release)
t = d.tracks
assert d.mediums == 2
assert t[0].medium == 1
assert t[0].medium_total == 2
assert t[0].medium_index == 1
assert t[1].medium == 1
assert t[1].medium_total == 2
assert t[1].medium_index == 2
assert t[2].medium == 2
assert t[2].medium_total == 1
assert t[2].medium_index == 1
def test_parse_track_indices(self):
release = self._make_release_from_positions(["1", "2"])
d = DiscogsPlugin().get_album_info(release)
t = d.tracks
assert t[0].medium_index == 1
assert t[0].index == 1
assert t[0].medium_total == 2
assert t[1].medium_index == 2
assert t[1].index == 2
assert t[1].medium_total == 2
def test_parse_track_indices_several_media(self):
release = self._make_release_from_positions(
["1-1", "1-2", "2-1", "3-1"]
)
d = DiscogsPlugin().get_album_info(release)
t = d.tracks
assert d.mediums == 3
assert t[0].medium_index == 1
assert t[0].index == 1
assert t[0].medium_total == 2
assert t[1].medium_index == 2
assert t[1].index == 2
assert t[1].medium_total == 2
assert t[2].medium_index == 1
assert t[2].index == 3
assert t[2].medium_total == 1
assert t[3].medium_index == 1
assert t[3].index == 4
assert t[3].medium_total == 1
def test_parse_tracklist_without_sides(self):
"""Test standard Discogs position 12.2.9#1: "without sides"."""
release = self._make_release_from_positions(["1", "2", "3"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
def test_parse_tracklist_with_sides(self):
"""Test standard Discogs position 12.2.9#2: "with sides"."""
release = self._make_release_from_positions(["A1", "A2", "B1", "B2"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1 # 2 sides = 1 LP
assert len(d.tracks) == 4
def test_parse_tracklist_multiple_lp(self):
"""Test standard Discogs position 12.2.9#3: "multiple LP"."""
release = self._make_release_from_positions(["A1", "A2", "B1", "C1"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 2 # 3 sides = 1 LP + 1 LP
assert len(d.tracks) == 4
def test_parse_tracklist_multiple_cd(self):
"""Test standard Discogs position 12.2.9#4: "multiple CDs"."""
release = self._make_release_from_positions(
["1-1", "1-2", "2-1", "3-1"]
)
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 3
assert len(d.tracks) == 4
def test_parse_tracklist_non_standard(self):
"""Test non standard Discogs position."""
release = self._make_release_from_positions(["I", "II", "III", "IV"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 4
def test_parse_tracklist_subtracks_dot(self):
"""Test standard Discogs position 12.2.9#5: "sub tracks, dots"."""
release = self._make_release_from_positions(["1", "2.1", "2.2", "3"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
release = self._make_release_from_positions(
["A1", "A2.1", "A2.2", "A3"]
)
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
def test_parse_tracklist_subtracks_letter(self):
"""Test standard Discogs position 12.2.9#5: "sub tracks, letter"."""
release = self._make_release_from_positions(["A1", "A2a", "A2b", "A3"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
release = self._make_release_from_positions(
["A1", "A2.a", "A2.b", "A3"]
)
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
def test_parse_tracklist_subtracks_extra_material(self):
"""Test standard Discogs position 12.2.9#6: "extra material"."""
release = self._make_release_from_positions(["1", "2", "Video 1"])
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 2
assert len(d.tracks) == 3
def test_parse_tracklist_subtracks_indices(self):
"""Test parsing of subtracks that include index tracks."""
release = self._make_release_from_positions(["", "", "1.1", "1.2"])
# Track 1: Index track with medium title
release.data["tracklist"][0]["title"] = "MEDIUM TITLE"
# Track 2: Index track with track group title
release.data["tracklist"][1]["title"] = "TRACK GROUP TITLE"
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert d.tracks[0].disctitle == "MEDIUM TITLE"
assert len(d.tracks) == 1
assert d.tracks[0].title == "TRACK GROUP TITLE"
def test_parse_tracklist_subtracks_nested_logical(self):
"""Test parsing of subtracks defined inside a index track that are
logical subtracks (ie. should be grouped together into a single track).
"""
release = self._make_release_from_positions(["1", "", "3"])
# Track 2: Index track with track group title, and sub_tracks
release.data["tracklist"][1]["title"] = "TRACK GROUP TITLE"
release.data["tracklist"][1]["sub_tracks"] = [
self._make_track("TITLE ONE", "2.1", "01:01"),
self._make_track("TITLE TWO", "2.2", "02:02"),
]
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 3
assert d.tracks[1].title == "TRACK GROUP TITLE"
def test_parse_tracklist_subtracks_nested_physical(self):
"""Test parsing of subtracks defined inside a index track that are
physical subtracks (ie. should not be grouped together).
"""
release = self._make_release_from_positions(["1", "", "4"])
# Track 2: Index track with track group title, and sub_tracks
release.data["tracklist"][1]["title"] = "TRACK GROUP TITLE"
release.data["tracklist"][1]["sub_tracks"] = [
self._make_track("TITLE ONE", "2", "01:01"),
self._make_track("TITLE TWO", "3", "02:02"),
]
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 1
assert len(d.tracks) == 4
assert d.tracks[1].title == "TITLE ONE"
assert d.tracks[2].title == "TITLE TWO"
def test_parse_tracklist_disctitles(self):
"""Test parsing of index tracks that act as disc titles."""
release = self._make_release_from_positions(
["", "1-1", "1-2", "", "2-1"]
)
# Track 1: Index track with medium title (Cd1)
release.data["tracklist"][0]["title"] = "MEDIUM TITLE CD1"
# Track 4: Index track with medium title (Cd2)
release.data["tracklist"][3]["title"] = "MEDIUM TITLE CD2"
d = DiscogsPlugin().get_album_info(release)
assert d.mediums == 2
assert d.tracks[0].disctitle == "MEDIUM TITLE CD1"
assert d.tracks[1].disctitle == "MEDIUM TITLE CD1"
assert d.tracks[2].disctitle == "MEDIUM TITLE CD2"
assert len(d.tracks) == 3
def test_parse_minimal_release(self):
"""Test parsing of a release with the minimal amount of information."""
data = {
"id": 123,
"uri": "https://www.discogs.com/release/123456-something",
"tracklist": [self._make_track("A", "1", "01:01")],
"artists": [{"name": "ARTIST NAME", "id": 321, "join": ""}],
"title": "TITLE",
}
release = Bag(
data=data,
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
d = DiscogsPlugin().get_album_info(release)
assert d.artist == "ARTIST NAME"
assert d.album == "TITLE"
assert len(d.tracks) == 1
def test_parse_release_without_required_fields(self):
"""Test parsing of a release that does not have the required fields."""
release = Bag(data={}, refresh=lambda *args: None)
with capture_log() as logs:
d = DiscogsPlugin().get_album_info(release)
assert d is None
assert "Release does not contain the required fields" in logs[0]
def test_default_genre_style_settings(self):
"""Test genre default settings, genres to genre, styles to style"""
release = self._make_release_from_positions(["1", "2"])
d = DiscogsPlugin().get_album_info(release)
assert d.genre == "GENRE1, GENRE2"
assert d.style == "STYLE1, STYLE2"
def test_append_style_to_genre(self):
"""Test appending style to genre if config enabled"""
config["discogs"]["append_style_genre"] = True
release = self._make_release_from_positions(["1", "2"])
d = DiscogsPlugin().get_album_info(release)
assert d.genre == "GENRE1, GENRE2, STYLE1, STYLE2"
assert d.style == "STYLE1, STYLE2"
def test_append_style_to_genre_no_style(self):
"""Test nothing appended to genre if style is empty"""
config["discogs"]["append_style_genre"] = True
release = self._make_release_from_positions(["1", "2"])
release.data["styles"] = []
d = DiscogsPlugin().get_album_info(release)
assert d.genre == "GENRE1, GENRE2"
assert d.style is None
def test_strip_disambiguation(self):
"""Test removing disambiguation from all disambiguated fields."""
data = {
"id": 123,
"uri": "https://www.discogs.com/release/123456-something",
"tracklist": [
{
"title": "track",
"position": "A",
"type_": "track",
"duration": "5:44",
"artists": [
{"name": "TEST ARTIST (5)", "tracks": "", "id": 11146}
],
}
],
"artists": [
{"name": "ARTIST NAME (2)", "id": 321, "join": "&"},
{"name": "OTHER ARTIST (5)", "id": 321, "join": ""},
],
"title": "title",
"labels": [
{
"name": "LABEL NAME (5)",
"catno": "catalog number",
}
],
}
release = Bag(
data=data,
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
d = DiscogsPlugin().get_album_info(release)
assert d.artist == "ARTIST NAME & OTHER ARTIST"
assert d.tracks[0].artist == "TEST ARTIST"
assert d.label == "LABEL NAME"
def test_strip_disambiguation_false(self):
"""Test disabling disambiguation removal from all disambiguated fields."""
config["discogs"]["strip_disambiguation"] = False
data = {
"id": 123,
"uri": "https://www.discogs.com/release/123456-something",
"tracklist": [
{
"title": "track",
"position": "A",
"type_": "track",
"duration": "5:44",
"artists": [
{"name": "TEST ARTIST (5)", "tracks": "", "id": 11146}
],
}
],
"artists": [
{"name": "ARTIST NAME (2)", "id": 321, "join": "&"},
{"name": "OTHER ARTIST (5)", "id": 321, "join": ""},
],
"title": "title",
"labels": [
{
"name": "LABEL NAME (5)",
"catno": "catalog number",
}
],
}
release = Bag(
data=data,
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
d = DiscogsPlugin().get_album_info(release)
assert d.artist == "ARTIST NAME (2) & OTHER ARTIST (5)"
assert d.tracks[0].artist == "TEST ARTIST (5)"
assert d.label == "LABEL NAME (5)"
config["discogs"]["strip_disambiguation"] = True
@pytest.mark.parametrize(
"track_artist_anv,track_artist",
[(False, "ARTIST Feat. PERFORMER"), (True, "VARIATION Feat. VARIATION")],
)
@pytest.mark.parametrize(
"album_artist_anv,album_artist",
[(False, "ARTIST & SOLOIST"), (True, "VARIATION & VARIATION")],
)
@pytest.mark.parametrize(
"artist_credit_anv,track_artist_credit,album_artist_credit",
[
(False, "ARTIST Feat. PERFORMER", "ARTIST & SOLOIST"),
(True, "VARIATION Feat. VARIATION", "VARIATION & VARIATION"),
],
)
@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock())
def test_anv(
track_artist_anv,
track_artist,
album_artist_anv,
album_artist,
artist_credit_anv,
track_artist_credit,
album_artist_credit,
):
"""Test using artist name variations."""
data = {
"id": 123,
"uri": "https://www.discogs.com/release/123456-something",
"tracklist": [
{
"title": "track",
"position": "A",
"type_": "track",
"duration": "5:44",
"artists": [
{
"name": "ARTIST",
"tracks": "",
"anv": "VARIATION",
"id": 11146,
}
],
"extraartists": [
{
"name": "PERFORMER",
"role": "Featuring",
"anv": "VARIATION",
"id": 787,
}
],
}
],
"artists": [
{"name": "ARTIST (4)", "anv": "VARIATION", "id": 321, "join": "&"},
{"name": "SOLOIST", "anv": "VARIATION", "id": 445, "join": ""},
],
"title": "title",
}
release = Bag(
data=data,
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
config["discogs"]["anv"]["album_artist"] = album_artist_anv
config["discogs"]["anv"]["artist"] = track_artist_anv
config["discogs"]["anv"]["artist_credit"] = artist_credit_anv
r = DiscogsPlugin().get_album_info(release)
assert r.artist == album_artist
assert r.artist_credit == album_artist_credit
assert r.tracks[0].artist == track_artist
assert r.tracks[0].artist_credit == track_artist_credit
@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock())
def test_anv_album_artist():
"""Test using artist name variations when the album artist
is the same as the track artist, but only the track artist
should use the artist name variation."""
data = {
"id": 123,
"uri": "https://www.discogs.com/release/123456-something",
"tracklist": [
{
"title": "track",
"position": "A",
"type_": "track",
"duration": "5:44",
}
],
"artists": [
{"name": "ARTIST (4)", "anv": "VARIATION", "id": 321},
],
"title": "title",
}
release = Bag(
data=data,
title=data["title"],
artists=[Bag(data=d) for d in data["artists"]],
)
config["discogs"]["anv"]["album_artist"] = False
config["discogs"]["anv"]["artist"] = True
config["discogs"]["anv"]["artist_credit"] = False
r = DiscogsPlugin().get_album_info(release)
assert r.artist == "ARTIST"
assert r.artist_credit == "ARTIST"
assert r.tracks[0].artist == "VARIATION"
assert r.tracks[0].artist_credit == "ARTIST"
@pytest.mark.parametrize(
"track, expected_artist",
[
(
{
"type_": "track",
"title": "track",
"position": "1",
"duration": "5:00",
"artists": [
{"name": "NEW ARTIST", "tracks": "", "id": 11146},
{"name": "VOCALIST", "tracks": "", "id": 344, "join": "&"},
],
"extraartists": [
{
"name": "SOLOIST",
"id": 3,
"role": "Featuring",
},
{
"name": "PERFORMER (1)",
"id": 5,
"role": "Other Role, Featuring",
},
{
"name": "RANDOM",
"id": 8,
"role": "Written-By",
},
{
"name": "MUSICIAN",
"id": 10,
"role": "Featuring [Uncredited]",
},
],
},
"NEW ARTIST, VOCALIST Feat. SOLOIST, PERFORMER, MUSICIAN",
),
],
)
@patch("beetsplug.discogs.DiscogsPlugin.setup", Mock())
def test_parse_featured_artists(track, expected_artist):
"""Tests the plugins ability to parse a featured artist.
Initial check with one featured artist, two featured artists,
and three. Ignores artists that are not listed as featured."""
t = DiscogsPlugin().get_track_info(
track, 1, 1, ("ARTIST", "ARTIST CREDIT", 2)
)
assert t.artist == expected_artist
@pytest.mark.parametrize(
"formats, expected_media, expected_albumtype",
[
(None, None, None),
(
[
{
"descriptions": ['7"', "Single", "45 RPM"],
"name": "Vinyl",
"qty": 1,
}
],
"Vinyl",
'7", Single, 45 RPM',
),
],
)
def test_get_media_and_albumtype(formats, expected_media, expected_albumtype):
result = DiscogsPlugin.get_media_and_albumtype(formats)
assert result == (expected_media, expected_albumtype)
@pytest.mark.parametrize(
"position, medium, index, subindex",
[
("1", None, "1", None),
("A12", "A", "12", None),
("12-34", "12-", "34", None),
("CD1-1", "CD1-", "1", None),
("1.12", None, "1", "12"),
("12.a", None, "12", "A"),
("12.34", None, "12", "34"),
("1ab", None, "1", "AB"),
# Non-standard
("IV", "IV", None, None),
],
)
def test_get_track_index(position, medium, index, subindex):
assert DiscogsPlugin.get_track_index(position) == (medium, index, subindex)
|