beginnings of artist grid and artist details view
This commit is contained in:
@@ -30,3 +30,11 @@ DELETE FROM artists;
|
||||
-- name: GetAllArtists :many
|
||||
SELECT * FROM artists
|
||||
ORDER BY name;
|
||||
|
||||
-- name: GetAlbumArtists :many
|
||||
SELECT DISTINCT a.id, a.name
|
||||
FROM artists a
|
||||
JOIN artist_credit_artist aca ON aca.artist_id = a.id
|
||||
JOIN artist_credit ac ON ac.id = aca.credit_id
|
||||
JOIN release_groups rg ON rg.album_artist_credit_id = ac.id
|
||||
ORDER BY a.name;
|
||||
|
||||
@@ -63,3 +63,24 @@ LEFT JOIN (
|
||||
GROUP BY rgr.release_group_id
|
||||
) fallback_ac ON fallback_ac.release_group_id = rg.id
|
||||
ORDER BY rg.name;
|
||||
|
||||
-- name: GetAlbumsByArtist :many
|
||||
SELECT
|
||||
rg.id,
|
||||
rg.name,
|
||||
rg.year,
|
||||
COALESCE(ac.text, fallback_ac.text, '') as artist_name,
|
||||
COALESCE(ca.file_path, '') as cover_art_path
|
||||
FROM release_groups rg
|
||||
JOIN artist_credit ac ON rg.album_artist_credit_id = ac.id
|
||||
JOIN artist_credit_artist aca ON aca.credit_id = ac.id
|
||||
LEFT JOIN cover_art ca ON rg.cover_art_id = ca.id
|
||||
LEFT JOIN (
|
||||
SELECT rgr.release_group_id, ac2.text
|
||||
FROM release_group_recordings rgr
|
||||
JOIN recordings rec ON rec.id = rgr.recording_id
|
||||
JOIN artist_credit ac2 ON ac2.id = rec.artist_credit_id
|
||||
GROUP BY rgr.release_group_id
|
||||
) fallback_ac ON fallback_ac.release_group_id = rg.id
|
||||
WHERE aca.artist_id = ?
|
||||
ORDER BY rg.name;
|
||||
|
||||
@@ -40,6 +40,38 @@ func (q *Queries) DeleteArtist(ctx context.Context, id int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
const getAlbumArtists = `-- name: GetAlbumArtists :many
|
||||
SELECT DISTINCT a.id, a.name
|
||||
FROM artists a
|
||||
JOIN artist_credit_artist aca ON aca.artist_id = a.id
|
||||
JOIN artist_credit ac ON ac.id = aca.credit_id
|
||||
JOIN release_groups rg ON rg.album_artist_credit_id = ac.id
|
||||
ORDER BY a.name
|
||||
`
|
||||
|
||||
func (q *Queries) GetAlbumArtists(ctx context.Context) ([]Artist, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getAlbumArtists)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Artist
|
||||
for rows.Next() {
|
||||
var i Artist
|
||||
if err := rows.Scan(&i.ID, &i.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getAllArtists = `-- name: GetAllArtists :many
|
||||
SELECT id, name FROM artists
|
||||
ORDER BY name
|
||||
|
||||
@@ -87,6 +87,65 @@ func (q *Queries) DeleteReleaseGroup(ctx context.Context, id int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
const getAlbumsByArtist = `-- name: GetAlbumsByArtist :many
|
||||
SELECT
|
||||
rg.id,
|
||||
rg.name,
|
||||
rg.year,
|
||||
COALESCE(ac.text, fallback_ac.text, '') as artist_name,
|
||||
COALESCE(ca.file_path, '') as cover_art_path
|
||||
FROM release_groups rg
|
||||
JOIN artist_credit ac ON rg.album_artist_credit_id = ac.id
|
||||
JOIN artist_credit_artist aca ON aca.credit_id = ac.id
|
||||
LEFT JOIN cover_art ca ON rg.cover_art_id = ca.id
|
||||
LEFT JOIN (
|
||||
SELECT rgr.release_group_id, ac2.text
|
||||
FROM release_group_recordings rgr
|
||||
JOIN recordings rec ON rec.id = rgr.recording_id
|
||||
JOIN artist_credit ac2 ON ac2.id = rec.artist_credit_id
|
||||
GROUP BY rgr.release_group_id
|
||||
) fallback_ac ON fallback_ac.release_group_id = rg.id
|
||||
WHERE aca.artist_id = ?
|
||||
ORDER BY rg.name
|
||||
`
|
||||
|
||||
type GetAlbumsByArtistRow struct {
|
||||
ID int64
|
||||
Name string
|
||||
Year sql.NullInt64
|
||||
ArtistName string
|
||||
CoverArtPath string
|
||||
}
|
||||
|
||||
func (q *Queries) GetAlbumsByArtist(ctx context.Context, artistID int64) ([]GetAlbumsByArtistRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getAlbumsByArtist, artistID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetAlbumsByArtistRow
|
||||
for rows.Next() {
|
||||
var i GetAlbumsByArtistRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.Year,
|
||||
&i.ArtistName,
|
||||
&i.CoverArtPath,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getAllAlbumsWithDetails = `-- name: GetAllAlbumsWithDetails :many
|
||||
SELECT
|
||||
rg.id,
|
||||
|
||||
@@ -43,6 +43,12 @@ func splitGenres(concatenated string) []string {
|
||||
return strings.Split(concatenated, genreDelimiter)
|
||||
}
|
||||
|
||||
// Artist represents an artist in the library.
|
||||
type Artist struct {
|
||||
ID int64
|
||||
Name string
|
||||
}
|
||||
|
||||
// Album represents an album for the cover grid display.
|
||||
type Album struct {
|
||||
ID int64
|
||||
@@ -177,3 +183,90 @@ func (l *Library) GetAllAlbums() ([]Album, error) {
|
||||
|
||||
return albums, nil
|
||||
}
|
||||
|
||||
// GetAllArtists returns artists that are credited as album artists, ordered by name.
|
||||
func (l *Library) GetAllArtists() ([]Artist, error) {
|
||||
rows, err := l.db.Queries.GetAlbumArtists(l.ctx)
|
||||
if err != nil {
|
||||
l.logger.Error(
|
||||
"could not retrieve artists",
|
||||
"error", err,
|
||||
)
|
||||
|
||||
return nil, fmt.Errorf(
|
||||
"could not get artists: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
l.logger.Info("artist list", "count", len(rows))
|
||||
|
||||
artists := make([]Artist, 0, len(rows))
|
||||
|
||||
for _, row := range rows {
|
||||
artists = append(artists, Artist{
|
||||
ID: row.ID,
|
||||
Name: row.Name,
|
||||
})
|
||||
}
|
||||
|
||||
return artists, nil
|
||||
}
|
||||
|
||||
// GetAlbumsByArtist returns all albums where the given artist is the album artist.
|
||||
func (l *Library) GetAlbumsByArtist(
|
||||
artistID int64,
|
||||
) ([]Album, error) {
|
||||
rows, err := l.db.Queries.GetAlbumsByArtist(
|
||||
l.ctx,
|
||||
artistID,
|
||||
)
|
||||
if err != nil {
|
||||
l.logger.Error(
|
||||
"could not retrieve albums for artist",
|
||||
"artistID", artistID,
|
||||
"error", err,
|
||||
)
|
||||
|
||||
return nil, fmt.Errorf(
|
||||
"could not get albums for artist: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
l.logger.Info(
|
||||
"albums for artist",
|
||||
"artistID", artistID,
|
||||
"count", len(rows),
|
||||
)
|
||||
|
||||
albums := make([]Album, 0, len(rows))
|
||||
|
||||
for _, row := range rows {
|
||||
album := Album{
|
||||
ID: row.ID,
|
||||
Name: row.Name,
|
||||
ArtistName: row.ArtistName,
|
||||
}
|
||||
|
||||
if row.Year.Valid {
|
||||
album.Year = row.Year.Int64
|
||||
}
|
||||
|
||||
// Convert filesystem path to URL path for the asset handler.
|
||||
if row.CoverArtPath != "" {
|
||||
base := filepath.Base(row.CoverArtPath)
|
||||
album.CoverArtPath = "/covers/" + base
|
||||
album.CoverArtSmall = "/covers/" +
|
||||
SizedFilename(base, "_sm")
|
||||
album.CoverArtMedium = "/covers/" +
|
||||
SizedFilename(base, "_md")
|
||||
album.CoverArtLarge = "/covers/" +
|
||||
SizedFilename(base, "_lg")
|
||||
}
|
||||
|
||||
albums = append(albums, album)
|
||||
}
|
||||
|
||||
return albums, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user