Files
vibesonic/internal/database/subsonic_helpers2.go
T

92 lines
3.8 KiB
Go

package database
import "database/sql"
// ListVideoMediaFiles returns every media file the scanner identified as
// a video (as opposed to audio) track.
func ListVideoMediaFiles(db *sql.DB) ([]*MediaFile, error) {
rows, err := db.Query(mediaFileSelect + ` WHERE kind = 'video' AND missing = 0 ORDER BY relative_path`)
if err != nil {
return nil, err
}
defer rows.Close()
return scanMediaFiles(rows)
}
// FindArtistByName looks up an artist by exact, case-insensitive name —
// used by endpoints that take an artist name rather than ID (getTopSongs).
func FindArtistByName(db *sql.DB, name string) (*Artist, error) {
var id string
err := db.QueryRow(`SELECT id FROM artists WHERE name = ? COLLATE NOCASE LIMIT 1`, name).Scan(&id)
if err == sql.ErrNoRows {
return nil, ErrNotFound
}
if err != nil {
return nil, err
}
return GetArtist(db, id)
}
// TopSongsByArtist returns an artist's songs ordered by total play count
// (across all users) descending, falling back to any order for songs
// that have never been played, up to limit.
func TopSongsByArtist(db *sql.DB, artistID string, limit int) ([]*Song, error) {
rows, err := db.Query(`SELECT s.id, s.media_file_id, s.album_id, s.title, s.sort_title, s.track_number, s.track_total, s.disc_number, s.disc_total,
s.composer, s.conductor, s.isrc, s.bpm, s.musicbrainz_track_id, s.musicbrainz_recording_id,
s.replaygain_track_gain_db, s.replaygain_track_peak, s.replaygain_album_gain_db, s.replaygain_album_peak
FROM songs s
JOIN song_artists sa ON sa.song_id = s.id
LEFT JOIN (SELECT song_id, COUNT(*) AS plays FROM playback_history GROUP BY song_id) ph ON ph.song_id = s.id
WHERE sa.artist_id = ?
GROUP BY s.id
ORDER BY COALESCE(MAX(ph.plays), 0) DESC, s.title COLLATE NOCASE
LIMIT ?`, artistID, limit)
if err != nil {
return nil, err
}
defer rows.Close()
return scanSongs(rows)
}
// SimilarSongsByGenre returns up to limit random songs sharing at least
// one genre with seedSongID, excluding the seed itself. A simple,
// honest local substitute for an external recommendation service.
func SimilarSongsByGenre(db *sql.DB, seedSongID string, limit int) ([]*Song, error) {
rows, err := db.Query(`SELECT DISTINCT s.id, s.media_file_id, s.album_id, s.title, s.sort_title, s.track_number, s.track_total, s.disc_number, s.disc_total,
s.composer, s.conductor, s.isrc, s.bpm, s.musicbrainz_track_id, s.musicbrainz_recording_id,
s.replaygain_track_gain_db, s.replaygain_track_peak, s.replaygain_album_gain_db, s.replaygain_album_peak
FROM songs s
JOIN song_genres sg ON sg.song_id = s.id
WHERE sg.genre_id IN (SELECT genre_id FROM song_genres WHERE song_id = ?)
AND s.id != ?
ORDER BY RANDOM() LIMIT ?`, seedSongID, seedSongID, limit)
if err != nil {
return nil, err
}
defer rows.Close()
return scanSongs(rows)
}
// SimilarSongsByArtist returns up to limit random songs by the given
// artist (or sharing a genre with them if that artist has few songs),
// excluding none in particular — used for getSimilarSongs2's artist
// seed.
func SimilarSongsByArtist(db *sql.DB, artistID string, limit int) ([]*Song, error) {
rows, err := db.Query(`SELECT DISTINCT s.id, s.media_file_id, s.album_id, s.title, s.sort_title, s.track_number, s.track_total, s.disc_number, s.disc_total,
s.composer, s.conductor, s.isrc, s.bpm, s.musicbrainz_track_id, s.musicbrainz_recording_id,
s.replaygain_track_gain_db, s.replaygain_track_peak, s.replaygain_album_gain_db, s.replaygain_album_peak
FROM songs s
JOIN song_genres sg ON sg.song_id = s.id
WHERE sg.genre_id IN (
SELECT DISTINCT sg2.genre_id FROM song_artists sa2
JOIN song_genres sg2 ON sg2.song_id = sa2.song_id
WHERE sa2.artist_id = ?
)
ORDER BY RANDOM() LIMIT ?`, artistID, limit)
if err != nil {
return nil, err
}
defer rows.Close()
return scanSongs(rows)
}