feat: add album management endpoints (sections 2.1, 2.2, 2.3)

This commit is contained in:
Alexander
2026-04-29 13:34:20 +02:00
parent ff49403fd5
commit c307c68d88
6 changed files with 1275 additions and 0 deletions
+191
View File
@@ -416,3 +416,194 @@ func (db *DB) GetArtistMetadataByForeignID(ctx context.Context, foreignArtistID
}
return &a, nil
}
func (db *DB) GetAlbumByID(ctx context.Context, albumID uuid.UUID) (*AlbumRow, error) {
var a AlbumRow
err := db.pool.QueryRow(ctx, `
SELECT id, artist_metadata_id, foreign_album_id, title, album_type, release_date, monitored, added_at
FROM albums WHERE id = $1
`, albumID).Scan(&a.ID, &a.ArtistMetadataID, &a.ForeignAlbumID, &a.Title, &a.AlbumType, &a.ReleaseDate, &a.Monitored, &a.AddedAt)
if err != nil {
return nil, err
}
return &a, nil
}
type AlbumDetailRow struct {
ID uuid.UUID `json:"id"`
ArtistMetadataID uuid.UUID `json:"artist_metadata_id"`
ForeignAlbumID *string `json:"foreign_album_id"`
Title string `json:"title"`
AlbumType *string `json:"album_type"`
ReleaseDate *time.Time `json:"release_date"`
Monitored bool `json:"monitored"`
AddedAt time.Time `json:"added_at"`
ArtistName string `json:"artist_name"`
ForeignArtistID *string `json:"foreign_artist_id"`
}
func (db *DB) GetAlbumDetailByID(ctx context.Context, albumID uuid.UUID) (*AlbumDetailRow, error) {
var a AlbumDetailRow
err := db.pool.QueryRow(ctx, `
SELECT a.id, a.artist_metadata_id, a.foreign_album_id, a.title, a.album_type,
a.release_date, a.monitored, a.added_at, am.name, am.foreign_artist_id
FROM albums a
JOIN artist_metadata am ON a.artist_metadata_id = am.id
WHERE a.id = $1
`, albumID).Scan(&a.ID, &a.ArtistMetadataID, &a.ForeignAlbumID, &a.Title, &a.AlbumType,
&a.ReleaseDate, &a.Monitored, &a.AddedAt, &a.ArtistName, &a.ForeignArtistID)
if err != nil {
return nil, err
}
return &a, nil
}
func (db *DB) UpdateAlbumMonitored(ctx context.Context, albumID uuid.UUID, monitored bool) error {
_, err := db.pool.Exec(ctx, `
UPDATE albums SET monitored = $1 WHERE id = $2
`, monitored, albumID)
return err
}
func (db *DB) BulkUpdateAlbumsMonitored(ctx context.Context, artistMetadataID uuid.UUID, monitored bool) (int64, error) {
result, err := db.pool.Exec(ctx, `
UPDATE albums SET monitored = $1 WHERE artist_metadata_id = $2
`, monitored, artistMetadataID)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}
func (db *DB) GetMonitoredAlbumsByArtist(ctx context.Context, artistMetadataID uuid.UUID) ([]AlbumRow, error) {
rows, err := db.pool.Query(ctx, `
SELECT id, artist_metadata_id, foreign_album_id, title, album_type, release_date, monitored, added_at
FROM albums
WHERE artist_metadata_id = $1 AND monitored = true
ORDER BY release_date DESC NULLS LAST
`, artistMetadataID)
if err != nil {
return nil, err
}
defer rows.Close()
var albums []AlbumRow
for rows.Next() {
var a AlbumRow
err := rows.Scan(&a.ID, &a.ArtistMetadataID, &a.ForeignAlbumID, &a.Title, &a.AlbumType, &a.ReleaseDate, &a.Monitored, &a.AddedAt)
if err != nil {
return nil, err
}
albums = append(albums, a)
}
return albums, nil
}
type WantedAlbumRow struct {
ID uuid.UUID `json:"id"`
AlbumID uuid.UUID `json:"album_id"`
Priority int `json:"priority"`
SearchCount int `json:"search_count"`
LastSearchedAt *time.Time `json:"last_searched_at"`
AddedAt time.Time `json:"added_at"`
}
func (db *DB) AddToWantedAlbums(ctx context.Context, albumID uuid.UUID) error {
_, err := db.pool.Exec(ctx, `
INSERT INTO wanted_albums (album_id)
VALUES ($1)
ON CONFLICT (album_id) DO NOTHING
`, albumID)
return err
}
func (db *DB) RemoveFromWantedAlbums(ctx context.Context, albumID uuid.UUID) error {
_, err := db.pool.Exec(ctx, `
DELETE FROM wanted_albums WHERE album_id = $1
`, albumID)
return err
}
func (db *DB) IsAlbumWanted(ctx context.Context, albumID uuid.UUID) (bool, error) {
var count int64
err := db.pool.QueryRow(ctx, `
SELECT COUNT(*) FROM wanted_albums WHERE album_id = $1
`, albumID).Scan(&count)
return count > 0, err
}
func (db *DB) HasTrackFiles(ctx context.Context, albumID uuid.UUID) (bool, error) {
var count int64
err := db.pool.QueryRow(ctx, `
SELECT COUNT(*) FROM track_files WHERE album_id = $1
`, albumID).Scan(&count)
return count > 0, err
}
type BlocklistEntry struct {
ID uuid.UUID `json:"id"`
ArtistID uuid.UUID `json:"artist_id"`
AlbumID uuid.UUID `json:"album_id"`
SourceTitle string `json:"source_title"`
TorrentHash *string `json:"torrent_hash"`
Indexer *string `json:"indexer"`
Message *string `json:"message"`
}
func (db *DB) AddToBlocklist(ctx context.Context, artistID, albumID uuid.UUID, sourceTitle string, torrentHash, indexer *string) error {
_, err := db.pool.Exec(ctx, `
INSERT INTO blocklist (artist_id, album_id, source_title, torrent_hash, indexer)
VALUES ($1, $2, $3, $4, $5)
`, artistID, albumID, sourceTitle, torrentHash, indexer)
return err
}
func (db *DB) IsBlocklisted(ctx context.Context, sourceTitle string, torrentHash *string) (bool, error) {
var count int64
if torrentHash != nil && *torrentHash != "" {
err := db.pool.QueryRow(ctx, `
SELECT COUNT(*) FROM blocklist WHERE source_title = $1 OR torrent_hash = $2
`, sourceTitle, *torrentHash).Scan(&count)
return count > 0, err
}
err := db.pool.QueryRow(ctx, `
SELECT COUNT(*) FROM blocklist WHERE source_title = $1
`, sourceTitle).Scan(&count)
return count > 0, err
}
func (db *DB) ListBlocklist(ctx context.Context) ([]BlocklistEntry, error) {
rows, err := db.pool.Query(ctx, `
SELECT id, artist_id, album_id, source_title, torrent_hash, indexer, message
FROM blocklist ORDER BY date DESC
`)
if err != nil {
return nil, err
}
defer rows.Close()
var entries []BlocklistEntry
for rows.Next() {
var e BlocklistEntry
err := rows.Scan(&e.ID, &e.ArtistID, &e.AlbumID, &e.SourceTitle, &e.TorrentHash, &e.Indexer, &e.Message)
if err != nil {
return nil, err
}
entries = append(entries, e)
}
return entries, nil
}
func (db *DB) GetArtistIDByAlbum(ctx context.Context, albumID uuid.UUID) (*uuid.UUID, error) {
var artistID uuid.UUID
err := db.pool.QueryRow(ctx, `
SELECT ar.id FROM artists ar
JOIN artist_metadata am ON ar.metadata_id = am.id
JOIN albums a ON a.artist_metadata_id = am.id
WHERE a.id = $1
`, albumID).Scan(&artistID)
if err != nil {
return nil, err
}
return &artistID, nil
}