821 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			821 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
	
	
import datetime
 | 
						||
import os
 | 
						||
import uuid
 | 
						||
 | 
						||
import mutagen.oggtheora
 | 
						||
import mutagen.oggvorbis
 | 
						||
import pytest
 | 
						||
 | 
						||
from funkwhale_api.music import metadata
 | 
						||
 | 
						||
DATA_DIR = os.path.dirname(os.path.abspath(__file__))
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "field,value",
 | 
						||
    [
 | 
						||
        ("title", "Peer Gynt Suite no. 1, op. 46: I. Morning"),
 | 
						||
        ("artist", "Edvard Grieg"),
 | 
						||
        ("album_artist", "Edvard Grieg; Musopen Symphony Orchestra"),
 | 
						||
        ("artists", "Edvard Grieg; Musopen Symphony Orchestra"),
 | 
						||
        ("album", "Peer Gynt Suite no. 1, op. 46"),
 | 
						||
        ("date", "2012-08-15"),
 | 
						||
        ("position", "1"),
 | 
						||
        ("disc_number", "1"),
 | 
						||
        ("musicbrainz_albumid", "a766da8b-8336-47aa-a3ee-371cc41ccc75"),
 | 
						||
        ("mbid", "bd21ac48-46d8-4e78-925f-d9cc2a294656"),
 | 
						||
        ("musicbrainz_artistid", "013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
 | 
						||
        (
 | 
						||
            "musicbrainz_albumartistid",
 | 
						||
            "013c8e5b-d72a-4cd3-8dee-6c64d6125823;5b4d7d2d-36df-4b38-95e3-a964234f520f",
 | 
						||
        ),
 | 
						||
        ("license", "Dummy license: http://creativecommons.org/licenses/by-sa/4.0/"),
 | 
						||
        ("copyright", "Someone"),
 | 
						||
        ("comment", "Hello there"),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_can_get_metadata_from_ogg_file(field, value):
 | 
						||
    path = os.path.join(DATA_DIR, "test.ogg")
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
 | 
						||
    assert data.get(field) == value
 | 
						||
 | 
						||
 | 
						||
def test_can_get_metadata_all():
 | 
						||
    path = os.path.join(DATA_DIR, "test.ogg")
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
 | 
						||
    expected = {
 | 
						||
        "title": "Peer Gynt Suite no. 1, op. 46: I. Morning",
 | 
						||
        "artist": "Edvard Grieg",
 | 
						||
        "album_artist": "Edvard Grieg; Musopen Symphony Orchestra",
 | 
						||
        "artists": "Edvard Grieg; Musopen Symphony Orchestra",
 | 
						||
        "album": "Peer Gynt Suite no. 1, op. 46",
 | 
						||
        "date": "2012-08-15",
 | 
						||
        "position": "1",
 | 
						||
        "disc_number": "1",
 | 
						||
        "musicbrainz_albumid": "a766da8b-8336-47aa-a3ee-371cc41ccc75",
 | 
						||
        "mbid": "bd21ac48-46d8-4e78-925f-d9cc2a294656",
 | 
						||
        "musicbrainz_artistid": "013c8e5b-d72a-4cd3-8dee-6c64d6125823",
 | 
						||
        "musicbrainz_albumartistid": "013c8e5b-d72a-4cd3-8dee-6c64d6125823;5b4d7d2d-36df-4b38-95e3-a964234f520f",
 | 
						||
        "license": "Dummy license: http://creativecommons.org/licenses/by-sa/4.0/",
 | 
						||
        "copyright": "Someone",
 | 
						||
        "genre": "Classical",
 | 
						||
        "comment": "Hello there",
 | 
						||
    }
 | 
						||
    assert data.all() == expected
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "field,value",
 | 
						||
    [
 | 
						||
        ("title", "Peer Gynt Suite no. 1, op. 46: I. Morning"),
 | 
						||
        ("artist", "Edvard Grieg"),
 | 
						||
        ("album_artist", "Edvard Grieg; Musopen Symphony Orchestra"),
 | 
						||
        ("artists", "Edvard Grieg; Musopen Symphony Orchestra"),
 | 
						||
        ("album", "Peer Gynt Suite no. 1, op. 46"),
 | 
						||
        ("date", "2012-08-15"),
 | 
						||
        ("position", "1"),
 | 
						||
        ("disc_number", "1"),
 | 
						||
        ("musicbrainz_albumid", "a766da8b-8336-47aa-a3ee-371cc41ccc75"),
 | 
						||
        ("mbid", "bd21ac48-46d8-4e78-925f-d9cc2a294656"),
 | 
						||
        ("musicbrainz_artistid", "013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
 | 
						||
        (
 | 
						||
            "musicbrainz_albumartistid",
 | 
						||
            "013c8e5b-d72a-4cd3-8dee-6c64d6125823;5b4d7d2d-36df-4b38-95e3-a964234f520f",
 | 
						||
        ),
 | 
						||
        ("license", "Dummy license: http://creativecommons.org/licenses/by-sa/4.0/"),
 | 
						||
        ("copyright", "Someone"),
 | 
						||
        ("comment", "Hello there"),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_can_get_metadata_from_opus_file(field, value):
 | 
						||
    path = os.path.join(DATA_DIR, "test.opus")
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
 | 
						||
    assert data.get(field) == value
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "field,value",
 | 
						||
    [
 | 
						||
        ("title", "Drei Kreuze (dass wir hier sind)"),
 | 
						||
        ("artist", "Die Toten Hosen"),
 | 
						||
        ("album_artist", "Die Toten Hosen"),
 | 
						||
        ("album", "Ballast der Republik"),
 | 
						||
        ("date", "2012-05-04"),
 | 
						||
        ("position", "1/16"),
 | 
						||
        ("disc_number", "1/2"),
 | 
						||
        ("musicbrainz_albumid", "1f0441ad-e609-446d-b355-809c445773cf"),
 | 
						||
        ("mbid", "124d0150-8627-46bc-bc14-789a3bc960c8"),
 | 
						||
        ("musicbrainz_artistid", "c3bc80a6-1f4a-4e17-8cf0-6b1efe8302f1"),
 | 
						||
        ("musicbrainz_albumartistid", "c3bc80a6-1f4a-4e17-8cf0-6b1efe8302f1"),
 | 
						||
        ("comment", "Hello there"),
 | 
						||
        # somehow, I cannot successfully create an ogg theora file
 | 
						||
        # with the proper license field
 | 
						||
        # ("license", "Dummy license: http://creativecommons.org/licenses/by-sa/4.0/"),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_can_get_metadata_from_ogg_theora_file(field, value):
 | 
						||
    path = os.path.join(DATA_DIR, "test_theora.ogg")
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
 | 
						||
    assert data.get(field) == value
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "field,value",
 | 
						||
    [
 | 
						||
        ("title", "Bend"),
 | 
						||
        ("artist", "Binärpilot"),
 | 
						||
        ("album_artist", "Binärpilot"),
 | 
						||
        ("artists", "Binärpilot; Another artist"),
 | 
						||
        ("album", "You Can't Stop Da Funk"),
 | 
						||
        ("date", "2006-02-07"),
 | 
						||
        ("position", "2/4"),
 | 
						||
        ("disc_number", "1/1"),
 | 
						||
        ("musicbrainz_albumid", "ce40cdb1-a562-4fd8-a269-9269f98d4124"),
 | 
						||
        ("mbid", "f269d497-1cc0-4ae4-a0c4-157ec7d73fcb"),
 | 
						||
        ("musicbrainz_artistid", "9c6bddde-6228-4d9f-ad0d-03f6fcb19e13"),
 | 
						||
        ("musicbrainz_albumartistid", "9c6bddde-6228-4d9f-ad0d-03f6fcb19e13"),
 | 
						||
        ("license", "https://creativecommons.org/licenses/by-nc-nd/2.5/"),
 | 
						||
        ("copyright", "Someone"),
 | 
						||
        ("comment", "Hello there"),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_can_get_metadata_from_id3_mp3_file(field, value):
 | 
						||
    path = os.path.join(DATA_DIR, "test.mp3")
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
 | 
						||
    assert str(data.get(field)) == value
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "field,value",
 | 
						||
    [
 | 
						||
        ("title", "Bend"),
 | 
						||
        ("artist", "Binärpilot"),
 | 
						||
        ("album_artist", "Binärpilot"),
 | 
						||
        # ("artists", "Binärpilot; Another artist"),  # FW does not properly extract multi-value artists from ID3
 | 
						||
        ("album", "You Can't Stop Da Funk"),
 | 
						||
        ("date", "2006-02-07"),
 | 
						||
        ("position", "2/4"),
 | 
						||
        ("disc_number", "1/1"),
 | 
						||
        ("musicbrainz_albumid", "ce40cdb1-a562-4fd8-a269-9269f98d4124"),
 | 
						||
        ("mbid", "f269d497-1cc0-4ae4-a0c4-157ec7d73fcb"),
 | 
						||
        ("musicbrainz_artistid", "9c6bddde-6228-4d9f-ad0d-03f6fcb19e13"),
 | 
						||
        ("musicbrainz_albumartistid", "9c6bddde-6228-4d9f-ad0d-03f6fcb19e13"),
 | 
						||
        ("license", "https://creativecommons.org/licenses/by-nc-nd/2.5/"),
 | 
						||
        ("copyright", "Someone"),
 | 
						||
        ("comment", "Hello there"),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_can_get_metadata_from_id3_aiff_file(field, value):
 | 
						||
    path = os.path.join(DATA_DIR, "test.aiff")
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
 | 
						||
    assert str(data.get(field)) == value
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "name",
 | 
						||
    [
 | 
						||
        "test.mp3",
 | 
						||
        "test.aiff",
 | 
						||
        "with_other_picture.mp3",
 | 
						||
        "sample.flac",
 | 
						||
        "with_cover.ogg",
 | 
						||
        "with_cover.opus",
 | 
						||
        "test.m4a",
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_can_get_pictures(name):
 | 
						||
    path = os.path.join(DATA_DIR, name)
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
 | 
						||
    pictures = data.get("pictures")
 | 
						||
    assert len(pictures) == 1
 | 
						||
    cover_data = data.get_picture("cover_front", "other")
 | 
						||
    assert cover_data["mimetype"].startswith("image/")
 | 
						||
    assert len(cover_data["content"]) > 0
 | 
						||
    assert type(cover_data["content"]) is bytes
 | 
						||
    assert type(cover_data["description"]) is str
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "field,value",
 | 
						||
    [
 | 
						||
        ("title", "999,999"),
 | 
						||
        ("artist", "Nine Inch Nails"),
 | 
						||
        ("album_artist", "Nine Inch Nails"),
 | 
						||
        ("album", "The Slip"),
 | 
						||
        ("date", "2008-05-05"),
 | 
						||
        ("position", "1"),
 | 
						||
        ("disc_number", "1"),
 | 
						||
        ("musicbrainz_albumid", "12b57d46-a192-499e-a91f-7da66790a1c1"),
 | 
						||
        ("mbid", "30f3f33e-8d0c-4e69-8539-cbd701d18f28"),
 | 
						||
        ("musicbrainz_artistid", "b7ffd2af-418f-4be2-bdd1-22f8b48613da"),
 | 
						||
        ("musicbrainz_albumartistid", "b7ffd2af-418f-4be2-bdd1-22f8b48613da"),
 | 
						||
        ("license", "http://creativecommons.org/licenses/by-nc-sa/3.0/us/"),
 | 
						||
        ("copyright", "2008 nin"),
 | 
						||
        ("comment", "Hello there"),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_can_get_metadata_from_flac_file(field, value):
 | 
						||
    path = os.path.join(DATA_DIR, "sample.flac")
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
 | 
						||
    assert data.get(field) == value
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "field,value",
 | 
						||
    [
 | 
						||
        ("title", "Peer Gynt Suite no. 1, op. 46: I. Morning"),
 | 
						||
        ("artist", "Edvard Grieg"),
 | 
						||
        ("album_artist", "Edvard Grieg; Musopen Symphony Orchestra"),
 | 
						||
        ("artists", "Edvard Grieg; Musopen Symphony Orchestra"),
 | 
						||
        ("album", "Peer Gynt Suite no. 1, op. 46"),
 | 
						||
        ("date", "2012-08-15"),
 | 
						||
        ("position", 1),
 | 
						||
        ("disc_number", 2),
 | 
						||
        ("musicbrainz_albumid", "a766da8b-8336-47aa-a3ee-371cc41ccc75"),
 | 
						||
        ("mbid", "bd21ac48-46d8-4e78-925f-d9cc2a294656"),
 | 
						||
        ("musicbrainz_artistid", "013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
 | 
						||
        (
 | 
						||
            "musicbrainz_albumartistid",
 | 
						||
            "013c8e5b-d72a-4cd3-8dee-6c64d6125823;5b4d7d2d-36df-4b38-95e3-a964234f520f",
 | 
						||
        ),
 | 
						||
        ("license", "Dummy license: http://creativecommons.org/licenses/by-sa/4.0/"),
 | 
						||
        ("copyright", "Someone"),
 | 
						||
        ("genre", "Dubstep"),
 | 
						||
        ("comment", "Hello there"),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_can_get_metadata_from_m4a_file(field, value):
 | 
						||
    path = os.path.join(DATA_DIR, "test.m4a")
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
 | 
						||
    assert data.get(field) == value
 | 
						||
 | 
						||
 | 
						||
def test_get_pictures_m4a_empty():
 | 
						||
    pictures = metadata.get_mp4_tag({}, "pictures")
 | 
						||
    assert metadata.clean_mp4_pictures(pictures) == []
 | 
						||
 | 
						||
 | 
						||
def test_can_get_metadata_from_flac_file_not_crash_if_empty():
 | 
						||
    path = os.path.join(DATA_DIR, "sample.flac")
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
 | 
						||
    with pytest.raises(metadata.TagNotFound):
 | 
						||
        data.get("test")
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "raw,expected",
 | 
						||
    [
 | 
						||
        ("2017", datetime.date(2017, 1, 1)),
 | 
						||
        ("2017-12-31", datetime.date(2017, 12, 31)),
 | 
						||
        ("2017-14-01 01:32", datetime.date(2017, 1, 14)),  # deezer format
 | 
						||
        ("2017-02", datetime.date(2017, 1, 1)),  # weird format that exists
 | 
						||
        ("0000", None),
 | 
						||
        ("", None),
 | 
						||
        ("nonsense", None),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_date_parsing(raw, expected):
 | 
						||
    assert metadata.PermissiveDateField().to_internal_value(raw) == expected
 | 
						||
 | 
						||
 | 
						||
def test_metadata_fallback_ogg_theora(mocker):
 | 
						||
    path = os.path.join(DATA_DIR, "with_cover.ogg")
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
 | 
						||
    assert isinstance(data._file, mutagen.oggtheora.OggTheora)
 | 
						||
    assert isinstance(data.fallback, metadata.Metadata)
 | 
						||
    assert isinstance(data.fallback._file, mutagen.oggvorbis.OggVorbis)
 | 
						||
 | 
						||
    expected_result = data.fallback.get("pictures")
 | 
						||
    fallback_get = mocker.spy(data.fallback, "get")
 | 
						||
 | 
						||
    assert expected_result is not None
 | 
						||
    assert data.get("pictures", "default") == expected_result
 | 
						||
 | 
						||
    fallback_get.assert_called_once_with("pictures", "default")
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "path, expected",
 | 
						||
    [
 | 
						||
        (
 | 
						||
            "test.mp3",
 | 
						||
            {
 | 
						||
                "title": "Bend",
 | 
						||
                "artist_credit": [
 | 
						||
                    {
 | 
						||
                        "credit": "Binärpilot",
 | 
						||
                        "mbid": uuid.UUID("9c6bddde-6228-4d9f-ad0d-03f6fcb19e13"),
 | 
						||
                        "joinphrase": "; ",
 | 
						||
                    },
 | 
						||
                    {
 | 
						||
                        "credit": "Another artist",
 | 
						||
                        "mbid": None,
 | 
						||
                        "joinphrase": "",
 | 
						||
                    },
 | 
						||
                ],
 | 
						||
                "album": {
 | 
						||
                    "title": "You Can't Stop Da Funk",
 | 
						||
                    "mbid": uuid.UUID("ce40cdb1-a562-4fd8-a269-9269f98d4124"),
 | 
						||
                    "release_date": datetime.date(2006, 2, 7),
 | 
						||
                    "artist_credit": [
 | 
						||
                        {
 | 
						||
                            "credit": "Binärpilot",
 | 
						||
                            "mbid": uuid.UUID("9c6bddde-6228-4d9f-ad0d-03f6fcb19e13"),
 | 
						||
                            "joinphrase": "; ",
 | 
						||
                        },
 | 
						||
                        {"credit": "Another artist", "mbid": None, "joinphrase": ""},
 | 
						||
                    ],
 | 
						||
                },
 | 
						||
                "position": 2,
 | 
						||
                "disc_number": 1,
 | 
						||
                "mbid": uuid.UUID("f269d497-1cc0-4ae4-a0c4-157ec7d73fcb"),
 | 
						||
                "license": "https://creativecommons.org/licenses/by-nc-nd/2.5/",
 | 
						||
                "copyright": "Someone",
 | 
						||
                "tags": ["Funk"],
 | 
						||
                "description": {"text": "Hello there", "content_type": "text/plain"},
 | 
						||
            },
 | 
						||
        ),
 | 
						||
        (
 | 
						||
            "test.ogg",
 | 
						||
            {
 | 
						||
                "title": "Peer Gynt Suite no. 1, op. 46: I. Morning",
 | 
						||
                "artist_credit": [
 | 
						||
                    {
 | 
						||
                        "credit": "Edvard Grieg",
 | 
						||
                        "mbid": uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
 | 
						||
                        "joinphrase": "; ",
 | 
						||
                    },
 | 
						||
                    {
 | 
						||
                        "credit": "Musopen Symphony Orchestra",
 | 
						||
                        "mbid": None,
 | 
						||
                        "joinphrase": "",
 | 
						||
                    },
 | 
						||
                ],
 | 
						||
                "album": {
 | 
						||
                    "title": "Peer Gynt Suite no. 1, op. 46",
 | 
						||
                    "mbid": uuid.UUID("a766da8b-8336-47aa-a3ee-371cc41ccc75"),
 | 
						||
                    "release_date": datetime.date(2012, 8, 15),
 | 
						||
                    "artist_credit": [
 | 
						||
                        {
 | 
						||
                            "credit": "Edvard Grieg",
 | 
						||
                            "mbid": uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
 | 
						||
                            "joinphrase": "; ",
 | 
						||
                        },
 | 
						||
                        {
 | 
						||
                            "credit": "Musopen Symphony Orchestra",
 | 
						||
                            "mbid": uuid.UUID("5b4d7d2d-36df-4b38-95e3-a964234f520f"),
 | 
						||
                            "joinphrase": "",
 | 
						||
                        },
 | 
						||
                    ],
 | 
						||
                },
 | 
						||
                "position": 1,
 | 
						||
                "disc_number": 1,
 | 
						||
                "mbid": uuid.UUID("bd21ac48-46d8-4e78-925f-d9cc2a294656"),
 | 
						||
                "license": "Dummy license: http://creativecommons.org/licenses/by-sa/4.0/",
 | 
						||
                "copyright": "Someone",
 | 
						||
                "tags": ["Classical"],
 | 
						||
                "description": {"text": "Hello there", "content_type": "text/plain"},
 | 
						||
            },
 | 
						||
        ),
 | 
						||
        (
 | 
						||
            "test.opus",
 | 
						||
            {
 | 
						||
                "title": "Peer Gynt Suite no. 1, op. 46: I. Morning",
 | 
						||
                "artist_credit": [
 | 
						||
                    {
 | 
						||
                        "credit": "Edvard Grieg",
 | 
						||
                        "mbid": uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
 | 
						||
                        "joinphrase": "; ",
 | 
						||
                    },
 | 
						||
                    {
 | 
						||
                        "credit": "Musopen Symphony Orchestra",
 | 
						||
                        "mbid": None,
 | 
						||
                        "joinphrase": "",
 | 
						||
                    },
 | 
						||
                ],
 | 
						||
                "album": {
 | 
						||
                    "title": "Peer Gynt Suite no. 1, op. 46",
 | 
						||
                    "mbid": uuid.UUID("a766da8b-8336-47aa-a3ee-371cc41ccc75"),
 | 
						||
                    "release_date": datetime.date(2012, 8, 15),
 | 
						||
                    "artist_credit": [
 | 
						||
                        {
 | 
						||
                            "credit": "Edvard Grieg",
 | 
						||
                            "mbid": uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
 | 
						||
                            "joinphrase": "; ",
 | 
						||
                        },
 | 
						||
                        {
 | 
						||
                            "credit": "Musopen Symphony Orchestra",
 | 
						||
                            "mbid": uuid.UUID("5b4d7d2d-36df-4b38-95e3-a964234f520f"),
 | 
						||
                            "joinphrase": "",
 | 
						||
                        },
 | 
						||
                    ],
 | 
						||
                },
 | 
						||
                "position": 1,
 | 
						||
                "disc_number": 1,
 | 
						||
                "mbid": uuid.UUID("bd21ac48-46d8-4e78-925f-d9cc2a294656"),
 | 
						||
                "license": "Dummy license: http://creativecommons.org/licenses/by-sa/4.0/",
 | 
						||
                "copyright": "Someone",
 | 
						||
                "tags": ["Classical"],
 | 
						||
                "description": {"text": "Hello there", "content_type": "text/plain"},
 | 
						||
            },
 | 
						||
        ),
 | 
						||
        (
 | 
						||
            "test_theora.ogg",
 | 
						||
            {
 | 
						||
                "title": "Drei Kreuze (dass wir hier sind)",
 | 
						||
                "artist_credit": [
 | 
						||
                    {
 | 
						||
                        "credit": "Die Toten Hosen",
 | 
						||
                        "mbid": uuid.UUID("c3bc80a6-1f4a-4e17-8cf0-6b1efe8302f1"),
 | 
						||
                        "joinphrase": "",
 | 
						||
                    }
 | 
						||
                ],
 | 
						||
                "album": {
 | 
						||
                    "title": "Ballast der Republik",
 | 
						||
                    "mbid": uuid.UUID("1f0441ad-e609-446d-b355-809c445773cf"),
 | 
						||
                    "release_date": datetime.date(2012, 5, 4),
 | 
						||
                    "artist_credit": [
 | 
						||
                        {
 | 
						||
                            "credit": "Die Toten Hosen",
 | 
						||
                            "mbid": uuid.UUID("c3bc80a6-1f4a-4e17-8cf0-6b1efe8302f1"),
 | 
						||
                            "joinphrase": "",
 | 
						||
                        }
 | 
						||
                    ],
 | 
						||
                },
 | 
						||
                "tags": ["Rock"],
 | 
						||
                "position": 1,
 | 
						||
                "disc_number": 1,
 | 
						||
                "mbid": uuid.UUID("124d0150-8627-46bc-bc14-789a3bc960c8"),
 | 
						||
                # somehow, I cannot successfully create an ogg theora file
 | 
						||
                # with the proper license field
 | 
						||
                # ("license", "Dummy license: http://creativecommons.org/licenses/by-sa/4.0/"),
 | 
						||
                "copyright": "℗ 2012 JKP GmbH & Co. KG",
 | 
						||
                "description": {"text": "Hello there", "content_type": "text/plain"},
 | 
						||
            },
 | 
						||
        ),
 | 
						||
        (
 | 
						||
            "sample.flac",
 | 
						||
            {
 | 
						||
                "title": "999,999",
 | 
						||
                "artist_credit": [
 | 
						||
                    {
 | 
						||
                        "credit": "Nine Inch Nails",
 | 
						||
                        "mbid": uuid.UUID("b7ffd2af-418f-4be2-bdd1-22f8b48613da"),
 | 
						||
                        "joinphrase": "",
 | 
						||
                    }
 | 
						||
                ],
 | 
						||
                "album": {
 | 
						||
                    "title": "The Slip",
 | 
						||
                    "mbid": uuid.UUID("12b57d46-a192-499e-a91f-7da66790a1c1"),
 | 
						||
                    "release_date": datetime.date(2008, 5, 5),
 | 
						||
                    "artist_credit": [
 | 
						||
                        {
 | 
						||
                            "credit": "Nine Inch Nails",
 | 
						||
                            "mbid": uuid.UUID("b7ffd2af-418f-4be2-bdd1-22f8b48613da"),
 | 
						||
                            "joinphrase": "",
 | 
						||
                        }
 | 
						||
                    ],
 | 
						||
                },
 | 
						||
                "position": 1,
 | 
						||
                "disc_number": 1,
 | 
						||
                "mbid": uuid.UUID("30f3f33e-8d0c-4e69-8539-cbd701d18f28"),
 | 
						||
                "license": "http://creativecommons.org/licenses/by-nc-sa/3.0/us/",
 | 
						||
                "copyright": "2008 nin",
 | 
						||
                "tags": ["Industrial"],
 | 
						||
                "description": {"text": "Hello there", "content_type": "text/plain"},
 | 
						||
            },
 | 
						||
        ),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_track_metadata_serializer(path, expected, mocker):
 | 
						||
    path = os.path.join(DATA_DIR, path)
 | 
						||
    data = metadata.Metadata(path)
 | 
						||
    get_picture = mocker.patch.object(data, "get_picture")
 | 
						||
    expected["album"]["cover_data"] = get_picture.return_value
 | 
						||
 | 
						||
    serializer = metadata.TrackMetadataSerializer(data=data)
 | 
						||
    assert serializer.is_valid(raise_exception=True) is True
 | 
						||
    assert serializer.validated_data == expected
 | 
						||
 | 
						||
    get_picture.assert_called_once_with("cover_front", "other")
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "raw, expected",
 | 
						||
    [
 | 
						||
        (
 | 
						||
            {
 | 
						||
                "names": "Hello; World",
 | 
						||
                "mbids": "f269d497-1cc0-4ae4-a0c4-157ec7d73fcb; f269d497-1cc0-4ae4-a0c4-157ec7d73fcd ",
 | 
						||
            },
 | 
						||
            [
 | 
						||
                {
 | 
						||
                    "credit": "Hello",
 | 
						||
                    "mbid": uuid.UUID("f269d497-1cc0-4ae4-a0c4-157ec7d73fcb"),
 | 
						||
                    "joinphrase": "; ",
 | 
						||
                },
 | 
						||
                {
 | 
						||
                    "credit": "World",
 | 
						||
                    "mbid": uuid.UUID("f269d497-1cc0-4ae4-a0c4-157ec7d73fcd"),
 | 
						||
                    "joinphrase": "",
 | 
						||
                },
 | 
						||
            ],
 | 
						||
        ),
 | 
						||
        (
 | 
						||
            {
 | 
						||
                "names": "Hello; World; Foo",
 | 
						||
                "mbids": "f269d497-1cc0-4ae4-a0c4-157ec7d73fcb; f269d497-1cc0-4ae4-a0c4-157ec7d73fcd ",
 | 
						||
            },
 | 
						||
            [
 | 
						||
                {
 | 
						||
                    "credit": "Hello",
 | 
						||
                    "mbid": uuid.UUID("f269d497-1cc0-4ae4-a0c4-157ec7d73fcb"),
 | 
						||
                    "joinphrase": "; ",
 | 
						||
                },
 | 
						||
                {
 | 
						||
                    "credit": "World",
 | 
						||
                    "mbid": uuid.UUID("f269d497-1cc0-4ae4-a0c4-157ec7d73fcd"),
 | 
						||
                    "joinphrase": "; ",
 | 
						||
                },
 | 
						||
                {"credit": "Foo", "mbid": None, "joinphrase": ""},
 | 
						||
            ],
 | 
						||
        ),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_artists_cleaning(raw, expected):
 | 
						||
    field = metadata.ArtistField()
 | 
						||
    assert field.to_internal_value(raw) == expected
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "data, errored_field",
 | 
						||
    [
 | 
						||
        ({"credit": "Hello", "mbid": "wrong-uuid"}, "mbid"),  # wrong uuid
 | 
						||
        ({"credit": "", "mbid": "f269d497-1cc0-4ae4-a0c4-157ec7d73fcd"}, "credit"),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_artist_serializer_validation(data, errored_field):
 | 
						||
    serializer = metadata.ArtistSerializer(data=data)
 | 
						||
    assert serializer.is_valid() is False
 | 
						||
 | 
						||
    assert len(serializer.errors) == 1
 | 
						||
    assert errored_field in serializer.errors
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "data, errored_field",
 | 
						||
    [
 | 
						||
        ({"title": "Hello", "mbid": "wrong"}, "mbid"),  # wrong uuid
 | 
						||
        (
 | 
						||
            {"title": "", "mbid": "f269d497-1cc0-4ae4-a0c4-157ec7d73fcd"},
 | 
						||
            "title",
 | 
						||
        ),  # empty title
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_album_serializer_validation(data, errored_field):
 | 
						||
    serializer = metadata.AlbumSerializer(data=data)
 | 
						||
    assert serializer.is_valid() is False
 | 
						||
 | 
						||
    assert len(serializer.errors) == 1
 | 
						||
    assert errored_field in serializer.errors
 | 
						||
 | 
						||
 | 
						||
def test_fake_metadata_with_serializer():
 | 
						||
    data = {
 | 
						||
        "title": "Peer Gynt Suite no. 1, op. 46: I. Morning",
 | 
						||
        "artist": "Edvard Grieg",
 | 
						||
        "album_artist": "Edvard Grieg; Musopen Symphony Orchestra",
 | 
						||
        "album": "Peer Gynt Suite no. 1, op. 46",
 | 
						||
        "date": "2012-08-15",
 | 
						||
        "position": "1",
 | 
						||
        "disc_number": "1",
 | 
						||
        "musicbrainz_albumid": "a766da8b-8336-47aa-a3ee-371cc41ccc75",
 | 
						||
        "mbid": "bd21ac48-46d8-4e78-925f-d9cc2a294656",
 | 
						||
        "musicbrainz_artistid": "013c8e5b-d72a-4cd3-8dee-6c64d6125823",
 | 
						||
        "musicbrainz_albumartistid": "013c8e5b-d72a-4cd3-8dee-6c64d6125823;5b4d7d2d-36df-4b38-95e3-a964234f520f",
 | 
						||
        "license": "Dummy license: http://creativecommons.org/licenses/by-sa/4.0/",
 | 
						||
        "copyright": "Someone",
 | 
						||
        "comment": "hello there",
 | 
						||
    }
 | 
						||
 | 
						||
    expected = {
 | 
						||
        "title": "Peer Gynt Suite no. 1, op. 46: I. Morning",
 | 
						||
        "description": {"text": "hello there", "content_type": "text/plain"},
 | 
						||
        "artist_credit": [
 | 
						||
            {
 | 
						||
                "credit": "Edvard Grieg",
 | 
						||
                "mbid": uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
 | 
						||
                "joinphrase": "",
 | 
						||
            }
 | 
						||
        ],
 | 
						||
        "album": {
 | 
						||
            "title": "Peer Gynt Suite no. 1, op. 46",
 | 
						||
            "mbid": uuid.UUID("a766da8b-8336-47aa-a3ee-371cc41ccc75"),
 | 
						||
            "release_date": datetime.date(2012, 8, 15),
 | 
						||
            "artist_credit": [
 | 
						||
                {
 | 
						||
                    "credit": "Edvard Grieg",
 | 
						||
                    "mbid": uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
 | 
						||
                    "joinphrase": "; ",
 | 
						||
                },
 | 
						||
                {
 | 
						||
                    "credit": "Musopen Symphony Orchestra",
 | 
						||
                    "mbid": uuid.UUID("5b4d7d2d-36df-4b38-95e3-a964234f520f"),
 | 
						||
                    "joinphrase": "",
 | 
						||
                },
 | 
						||
            ],
 | 
						||
            "cover_data": None,
 | 
						||
        },
 | 
						||
        "position": 1,
 | 
						||
        "disc_number": 1,
 | 
						||
        "mbid": uuid.UUID("bd21ac48-46d8-4e78-925f-d9cc2a294656"),
 | 
						||
        "license": "Dummy license: http://creativecommons.org/licenses/by-sa/4.0/",
 | 
						||
        "copyright": "Someone",
 | 
						||
    }
 | 
						||
    serializer = metadata.TrackMetadataSerializer(data=metadata.FakeMetadata(data))
 | 
						||
    assert serializer.is_valid(raise_exception=True) is True
 | 
						||
 | 
						||
    assert serializer.validated_data == expected
 | 
						||
 | 
						||
 | 
						||
def test_serializer_album_artist_missing():
 | 
						||
    data = {
 | 
						||
        "title": "Peer Gynt Suite no. 1, op. 46: I. Morning",
 | 
						||
        "artist": "Edvard Grieg",
 | 
						||
        "album": "Peer Gynt Suite no. 1, op. 46",
 | 
						||
    }
 | 
						||
 | 
						||
    expected = {
 | 
						||
        "title": "Peer Gynt Suite no. 1, op. 46: I. Morning",
 | 
						||
        "artist_credit": [{"credit": "Edvard Grieg", "mbid": None, "joinphrase": ""}],
 | 
						||
        "album": {
 | 
						||
            "title": "Peer Gynt Suite no. 1, op. 46",
 | 
						||
            "mbid": None,
 | 
						||
            "release_date": None,
 | 
						||
            "artist_credit": [],
 | 
						||
            "cover_data": None,
 | 
						||
        },
 | 
						||
    }
 | 
						||
    serializer = metadata.TrackMetadataSerializer(data=metadata.FakeMetadata(data))
 | 
						||
    assert serializer.is_valid(raise_exception=True) is True
 | 
						||
    assert serializer.validated_data == expected
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "data",
 | 
						||
    [
 | 
						||
        # no album tag
 | 
						||
        {"title": "Track", "artist": "Artist"},
 | 
						||
        # empty/null values
 | 
						||
        {"title": "Track", "artist": "Artist", "album": ""},
 | 
						||
        {"title": "Track", "artist": "Artist", "album": " "},
 | 
						||
        {"title": "Track", "artist": "Artist", "album": None},
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_serializer_album_default_title_when_missing_or_empty(data):
 | 
						||
    expected = {
 | 
						||
        "title": "Track",
 | 
						||
        "artist_credit": [{"credit": "Artist", "mbid": None, "joinphrase": ""}],
 | 
						||
        "album": {
 | 
						||
            "title": metadata.UNKNOWN_ALBUM,
 | 
						||
            "mbid": None,
 | 
						||
            "release_date": None,
 | 
						||
            "artist_credit": [],
 | 
						||
            "cover_data": None,
 | 
						||
        },
 | 
						||
    }
 | 
						||
    serializer = metadata.TrackMetadataSerializer(data=metadata.FakeMetadata(data))
 | 
						||
    assert serializer.is_valid(raise_exception=True) is True
 | 
						||
    assert serializer.validated_data == expected
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "field_name", ["copyright", "license", "mbid", "position", "disc_number"]
 | 
						||
)
 | 
						||
def test_serializer_empty_fields(field_name):
 | 
						||
    data = {
 | 
						||
        "title": "Track Title",
 | 
						||
        "artist": "Track Artist",
 | 
						||
        "album": "Track Album",
 | 
						||
        # empty copyright/license field shouldn't fail, cf #850
 | 
						||
        field_name: "",
 | 
						||
    }
 | 
						||
    expected = {
 | 
						||
        "title": "Track Title",
 | 
						||
        "artist_credit": [{"credit": "Track Artist", "mbid": None, "joinphrase": ""}],
 | 
						||
        "album": {
 | 
						||
            "title": "Track Album",
 | 
						||
            "mbid": None,
 | 
						||
            "release_date": None,
 | 
						||
            "artist_credit": [],
 | 
						||
            "cover_data": None,
 | 
						||
        },
 | 
						||
    }
 | 
						||
    serializer = metadata.TrackMetadataSerializer(data=metadata.FakeMetadata(data))
 | 
						||
    assert serializer.is_valid(raise_exception=True) is True
 | 
						||
    assert serializer.validated_data == expected
 | 
						||
 | 
						||
 | 
						||
def test_serializer_strict_mode_false():
 | 
						||
    data = {}
 | 
						||
    expected = {
 | 
						||
        "artist_credit": [],
 | 
						||
        "album": {
 | 
						||
            "title": "[Unknown Album]",
 | 
						||
            "mbid": None,
 | 
						||
            "release_date": None,
 | 
						||
            "artist_credit": [],
 | 
						||
            "cover_data": None,
 | 
						||
        },
 | 
						||
    }
 | 
						||
    serializer = metadata.TrackMetadataSerializer(
 | 
						||
        data=metadata.FakeMetadata(data), context={"strict": False}
 | 
						||
    )
 | 
						||
    assert serializer.is_valid(raise_exception=True) is True
 | 
						||
    assert serializer.validated_data == expected
 | 
						||
 | 
						||
 | 
						||
def test_serializer_strict_mode_true():
 | 
						||
    data = {}
 | 
						||
    serializer = metadata.TrackMetadataSerializer(
 | 
						||
        data=metadata.FakeMetadata(data), context={"strict": True}
 | 
						||
    )
 | 
						||
    with pytest.raises(metadata.serializers.ValidationError):
 | 
						||
        assert serializer.is_valid(raise_exception=True)
 | 
						||
 | 
						||
 | 
						||
def test_artist_field_featuring():
 | 
						||
    data = {
 | 
						||
        "artist": "Santana feat. Chris Cornell",
 | 
						||
        # here is the tricky bit, note the slash
 | 
						||
        "musicbrainz_artistid": "9a3bf45c-347d-4630-894d-7cf3e8e0b632/cbf9738d-8f81-4a92-bc64-ede09341652d",
 | 
						||
    }
 | 
						||
 | 
						||
    expected = [
 | 
						||
        {
 | 
						||
            "credit": "Santana",
 | 
						||
            "mbid": uuid.UUID("9a3bf45c-347d-4630-894d-7cf3e8e0b632"),
 | 
						||
            "joinphrase": " feat. ",
 | 
						||
        },
 | 
						||
        {
 | 
						||
            "credit": "Chris Cornell",
 | 
						||
            "mbid": uuid.UUID("cbf9738d-8f81-4a92-bc64-ede09341652d"),
 | 
						||
            "joinphrase": "",
 | 
						||
        },
 | 
						||
    ]
 | 
						||
 | 
						||
    field = metadata.ArtistField()
 | 
						||
    value = field.get_value(data)
 | 
						||
    assert field.to_internal_value(value) == expected
 | 
						||
 | 
						||
 | 
						||
@pytest.mark.parametrize(
 | 
						||
    "genre, expected_tags",
 | 
						||
    [
 | 
						||
        ("Pop", ["Pop"]),
 | 
						||
        ("pop", ["pop"]),
 | 
						||
        ("Soundtrack - Cute Anime", ["Soundtrack", "Cute Anime"]),
 | 
						||
        ("Pop, Rock", ["Pop", "Rock"]),
 | 
						||
        ("Chanson française", ["Chanson française"]),
 | 
						||
        (
 | 
						||
            "tag with non-breaking spaces",
 | 
						||
            ["tag\u202fwith\u202fnon-breaking\u202fspaces"],
 | 
						||
        ),
 | 
						||
    ],
 | 
						||
)
 | 
						||
def test_acquire_tags_from_genre(genre, expected_tags):
 | 
						||
    data = {
 | 
						||
        "title": "Track Title",
 | 
						||
        "artist": "Track Artist",
 | 
						||
        # "artist_credit": [{"credit": "Track Artist"}],
 | 
						||
        "album": "Track Album",
 | 
						||
        "genre": genre,
 | 
						||
    }
 | 
						||
    expected = {
 | 
						||
        "title": "Track Title",
 | 
						||
        "artist_credit": [{"credit": "Track Artist", "mbid": None, "joinphrase": ""}],
 | 
						||
        "album": {
 | 
						||
            "title": "Track Album",
 | 
						||
            "mbid": None,
 | 
						||
            "release_date": None,
 | 
						||
            "artist_credit": [],
 | 
						||
            "cover_data": None,
 | 
						||
        },
 | 
						||
    }
 | 
						||
    if expected_tags:
 | 
						||
        expected["tags"] = expected_tags
 | 
						||
    serializer = metadata.TrackMetadataSerializer(data=metadata.FakeMetadata(data))
 | 
						||
    assert serializer.is_valid(raise_exception=True) is True
 | 
						||
    assert serializer.validated_data == expected
 |