Ejemplo n.º 1
0
async def test_del_artist_from_release_bad_artist(db, graphql_query, snapshot):
    query = """
        mutation {
            delArtistFromRelease(releaseId: 2, artistId: 9999, role: MAIN) {
                release {
                    ...ReleaseFields
                }
                artist {
                    ...ArtistFields
                }
            }
        }
    """
    rls = release.from_id(2, db)
    assert rls is not None

    before_artists = release.artists(rls, db)

    success, data = await graphql_query(query)
    assert success is True
    snapshot.assert_match(data)

    after_artists = release.artists(rls, db)

    assert before_artists == after_artists
Ejemplo n.º 2
0
async def test_create_release(db, graphql_query, snapshot):
    query = """
        mutation {
            createRelease(
                title: "NewRelease"
                artists: [
                    {
                        artist_id: 2,
                        role: MAIN,
                    },
                    {
                        artist_id: 3,
                        role: MAIN,
                    },
                ]
                releaseType: ALBUM
                releaseYear: 2020
                releaseDate: "2020-10-23"
            ) {
                ...ReleaseFields
            }
        }
    """
    success, data = await graphql_query(query)
    assert success is True
    snapshot.assert_match(data)

    rls = release.from_id(data["data"]["createRelease"]["id"], db)
    assert rls is not None
    assert rls.title == "NewRelease"
    assert rls.release_type == ReleaseType.ALBUM
    assert rls.release_year == 2020
    assert rls.release_date == date(2020, 10, 23)

    assert {2, 3} == {a["artist"].id for a in release.artists(rls, db)}
Ejemplo n.º 3
0
def test_fix_album_artists_track_artists(factory: Factory, db: Connection):
    rls = factory.release(artists=[], conn=db)

    art1 = factory.artist(conn=db)
    art2 = factory.artist(conn=db)

    factory.track(
        release_id=rls.id,
        artists=[
            {
                "artist_id": art1.id,
                "role": ArtistRole.MAIN
            },
            {
                "artist_id": art2.id,
                "role": ArtistRole.FEATURE
            },
        ],
        conn=db,
    )

    _fix_album_artists(db)

    rls = release.from_id(rls.id, db)  # type: ignore
    assert rls is not None
    album_artists = release.artists(rls, db)
    assert len(album_artists) == 1
    assert album_artists[0]["artist"].id == art1.id
Ejemplo n.º 4
0
async def test_update_release(db, graphql_query, snapshot):
    query = """
        mutation {
            updateRelease(
                id: 2
                title: "aa"
                releaseType: SINGLE
                releaseYear: 2020
                releaseDate: "2020-10-23"
                rating: 1
            ) {
                ...ReleaseFields
            }
        }
    """
    success, data = await graphql_query(query)
    assert success is True
    snapshot.assert_match(data)

    rls = release.from_id(2, db)
    assert rls.title == "aa"
    assert rls.release_type == ReleaseType.SINGLE
    assert rls.release_year == 2020
    assert rls.release_date == date(2020, 10, 23)
    assert rls.rating == 1
Ejemplo n.º 5
0
def _fix_album_artists(conn: Connection) -> None:
    """
    Because not all albums contain the album artist tag, we look at all releases with no
    album artists and either assign them their track artists or assign them to the
    Unknown Artist.

    If the album's tracks have artists, then we conditionally assign the album artist
    based off the track's artists. See the code for the specific logic.

    :param conn: A connection to the database.
    """
    logger.info("Fixing album artists...")

    cursor = conn.execute("""
        SELECT rls.id
        FROM music__releases AS rls
        WHERE NOT EXISTS(
            SELECT 1 FROM music__releases_artists WHERE release_id = rls.id
        )
        """)
    release_ids = [row[0] for row in cursor]

    for rid in release_ids:
        rls = release.from_id(rid, conn)
        assert rls is not None

        tracks = release.tracks(rls, conn)
        amaps = chain.from_iterable(track.artists(trk, conn) for trk in tracks)
        artists = {
            amap["artist"]
            for amap in amaps if amap["role"] in MAIN_ROLES
        }

        for art in artists:
            release.add_artist(rls, art.id, ArtistRole.MAIN, conn)
Ejemplo n.º 6
0
def test_fetch_or_create_release_no_fetch(db: Connection):
    assert release.from_id(3, db) != _fetch_or_create_release(
        mock.Mock(
            album="Departure",
            artist_album=["Bacchus"],
            date=mock.Mock(year=2020, date="2020-01-01"),
            label=None,
            genre=[],
        ),
        db,
    )
Ejemplo n.º 7
0
def test_fetch_or_create_release_fetch(factory: Factory, db: Connection):
    rls = factory.release(conn=db)
    assert release.from_id(rls.id, db) == _fetch_or_create_release(
        tf=mock.Mock(
            album=rls.title,
            artist_album=[
                art["artist"].name for art in release.artists(rls, conn=db)
            ],
        ),
        conn=db,
    )
Ejemplo n.º 8
0
def resolve_del_release_from_collection(
    _,
    info: GraphQLResolveInfo,
    collectionId: int,
    releaseId: int,
) -> dict:
    col = collection.from_id(collectionId, info.context.db)
    if not col:
        raise NotFound(f"Collection {collectionId} does not exist.")

    col = collection.del_release(col, releaseId, info.context.db)
    rls = release.from_id(releaseId, info.context.db)

    return {"collection": col, "release": rls}
Ejemplo n.º 9
0
def resolve_del_artist_from_release(
    _,
    info: GraphQLResolveInfo,
    releaseId: int,
    artistId: int,
    role: ArtistRole,
) -> dict:
    rls = release.from_id(releaseId, info.context.db)
    if not rls:
        raise NotFound(f"Release {releaseId} does not exist.")

    rls = release.del_artist(rls, artistId, role, info.context.db)
    art = artist.from_id(artistId, info.context.db)

    return {"release": rls, "artist": art}
Ejemplo n.º 10
0
async def test_update_release_bad_date(db, graphql_query, snapshot):
    query = """
        mutation {
            updateRelease(
                id: 2
                releaseDate: "bbbbb"
            ) {
                ...ReleaseFields
            }
        }
    """
    success, data = await graphql_query(query)
    assert success is True
    snapshot.assert_match(data)

    rls = release.from_id(2, db)
    assert rls.release_date == date(1970, 2, 5)
Ejemplo n.º 11
0
def resolve_update_release(
    _,
    info: GraphQLResolveInfo,
    id: int,
    **changes,
) -> release.T:
    rls = release.from_id(id, info.context.db)
    if not rls:
        raise NotFound(f"Release {id} does not exist.")

    # Convert the "releaseDate" update from a string to a `date` object. If it is not in
    # the changes dict, do nothing.
    try:
        changes["releaseDate"] = date.fromisoformat(changes["releaseDate"])
    except ValueError:
        raise ParseError("Invalid release date.")
    except KeyError:
        pass

    return release.update(rls, info.context.db, **convert_keys_case(changes))
Ejemplo n.º 12
0
async def test_add_artist_to_release(db, graphql_query, snapshot):
    query = """
        mutation {
            addArtistToRelease(releaseId: 2, artistId: 5, role: MAIN) {
                release {
                    ...ReleaseFields
                }
                artist {
                    ...ArtistFields
                }
            }
        }
    """
    success, data = await graphql_query(query)
    assert success is True
    snapshot.assert_match(data)

    rls = release.from_id(2, db)
    assert rls is not None
    assert 5 in [a["artist"].id for a in release.artists(rls, db)]
Ejemplo n.º 13
0
def test_fix_release_types(factory: Factory, db: Connection, num_tracks,
                           release_type):
    rls = factory.release(release_type=ReleaseType.UNKNOWN, conn=db)

    for i in range(num_tracks):
        factory.track(
            title="a",
            filepath=Path(f"/lol{i}.flac"),
            sha256=bytes([i] * 32),
            release_id=rls.id,
            artists=[],
            duration=4,
            track_number="1",
            disc_number="1",
            conn=db,
        )

    _fix_release_types(db)

    new_rls = release.from_id(rls.id, db)
    assert new_rls is not None
    assert new_rls.release_type == release_type
Ejemplo n.º 14
0
async def test_del_artist_from_release(db, graphql_query, snapshot):
    query = """
        mutation {
            delArtistFromRelease(releaseId: 2, artistId: 2, role: MAIN) {
                release {
                    ...ReleaseFields
                }
                artist {
                    ...ArtistFields
                }
            }
        }
    """
    rls = release.from_id(2, db)
    assert rls is not None

    assert 2 in [a["artist"].id for a in release.artists(rls, db)]

    success, data = await graphql_query(query)
    assert success is True
    snapshot.assert_match(data)

    assert 2 not in [a["artist"].id for a in release.artists(rls, db)]
Ejemplo n.º 15
0
def _fetch_or_create_release(tf: TagFile, conn: Connection) -> release.T:
    """
    Try to match the album and album artist fields of the tagfile against the database.
    If a matching release is found, return it. Otherwise, create and return a new
    release. If the track has no album, return the Unknown Release (ID: 1).

    If a new release is created, add it to the inbox collection and relevant label/genre
    collections. We also flag the release for cover art extraction in the future (not as
    scary as it sounds!).

    :param tf: The track whose release we want to fetch.
    :param conn: A connection to the database.
    :return: The release the track belongs to.
    """
    if not tf.album:
        logger.debug(f"Fetched `Unknown Release` for track `{tf.path}`.")
        rls = release.from_id(1, conn)
        assert rls is not None
        return rls

    release_date: Optional[date] = None

    try:
        release_date = date.fromisoformat(tf.date.date)
    except (TypeError, ValueError):
        pass

    artist_ids = uniq_list(
        _fetch_or_create_artist(art, conn).id for art in tf.artist_album)
    artists = [{
        "artist_id": aid,
        "role": ArtistRole.MAIN
    } for aid in artist_ids]

    # Try to create a release with the given title and album artists. If it raises a
    # duplicate error, return the duplicate entity.
    try:
        rls = release.create(
            title=tf.album,
            # The tags might contain duplicate artists..
            artists=artists,
            release_type=_get_release_type(tf),
            release_year=tf.date.year,
            release_date=release_date,
            conn=conn,
            allow_duplicate=False,
        )
    except Duplicate as e:
        logger.debug(
            f"Return existing release {e.entity.id} for track `{tf.path}`.")
        return e.entity

    logger.debug(f"Created new release {rls.id} for track `{tf.path}`.")

    # Add release to the inbox and its label/genres.
    _insert_into_inbox_collections(rls, conn)
    _insert_into_label_collection(rls, tf.label, conn)
    _insert_into_genre_collections(rls, tf.genre, conn)

    # Flag the release to have its cover art extracted and stored.
    conn.execute(
        "INSERT INTO music__releases_images_to_fetch (release_id) VALUES (?)",
        (rls.id, ),
    )

    return rls
Ejemplo n.º 16
0
def resolve_release(_: Any, info: GraphQLResolveInfo, id: int) -> release.T:
    if rls := release.from_id(id, info.context.db):
        return rls
Ejemplo n.º 17
0
def test_fetch_or_create_release_unknown(db: Connection):
    assert release.from_id(1, db) == _fetch_or_create_release(
        mock.Mock(album=None), db)