Files
silo-server/internal/userdb/library_playback_prefs.go
T

176 lines
5.7 KiB
Go

package userdb
import (
"database/sql"
"fmt"
"github.com/Silo-Server/silo-server/internal/userstore"
)
// LibraryPlaybackPreference is an alias for the canonical type in userstore.
type LibraryPlaybackPreference = userstore.LibraryPlaybackPreference
// UpsertLibraryPlaybackPreference creates or replaces a library playback preference
// for a given profile and library. Timestamps should be ISO 8601 UTC strings.
func UpsertLibraryPlaybackPreference(db *sql.DB, pref LibraryPlaybackPreference) error {
normalizeLibraryPlaybackPreference(&pref)
_, err := db.Exec(`
INSERT INTO library_playback_preferences (
profile_id, library_id, audio_language, subtitle_language,
subtitle_mode, show_forced_subtitles, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(profile_id, library_id) DO UPDATE SET
audio_language = excluded.audio_language,
subtitle_language = excluded.subtitle_language,
subtitle_mode = excluded.subtitle_mode,
show_forced_subtitles = excluded.show_forced_subtitles,
updated_at = excluded.updated_at`,
pref.ProfileID,
pref.LibraryID,
libraryPlaybackDBValue(pref.AudioLanguage, pref.HasAudioLanguage),
libraryPlaybackDBValue(pref.SubtitleLanguage, pref.HasSubtitleLanguage),
libraryPlaybackDBValue(pref.SubtitleMode, pref.HasSubtitleMode),
libraryPlaybackBoolDBValue(pref.ShowForcedSubtitles, pref.HasShowForcedSubtitles),
pref.UpdatedAt,
)
if err != nil {
return fmt.Errorf("upserting library playback preference for profile %q library %d: %w",
pref.ProfileID, pref.LibraryID, err)
}
return nil
}
// GetLibraryPlaybackPreference retrieves the library playback preference for a profile
// and library. Returns nil (not an error) if no preference exists.
func GetLibraryPlaybackPreference(db *sql.DB, profileID string, libraryID int) (*LibraryPlaybackPreference, error) {
var pref LibraryPlaybackPreference
var audioLanguage, subtitleLanguage, subtitleMode sql.NullString
var showForcedSubtitles sql.NullBool
err := db.QueryRow(`
SELECT profile_id, library_id, audio_language, subtitle_language,
subtitle_mode, show_forced_subtitles, updated_at
FROM library_playback_preferences
WHERE profile_id = ? AND library_id = ?`,
profileID, libraryID,
).Scan(
&pref.ProfileID,
&pref.LibraryID,
&audioLanguage,
&subtitleLanguage,
&subtitleMode,
&showForcedSubtitles,
&pref.UpdatedAt,
)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("getting library playback preference for profile %q library %d: %w",
profileID, libraryID, err)
}
pref.AudioLanguage, pref.HasAudioLanguage = stringValue(audioLanguage)
pref.SubtitleLanguage, pref.HasSubtitleLanguage = stringValue(subtitleLanguage)
pref.SubtitleMode, pref.HasSubtitleMode = stringValue(subtitleMode)
pref.ShowForcedSubtitles, pref.HasShowForcedSubtitles = boolValue(showForcedSubtitles)
return &pref, nil
}
// ListLibraryPlaybackPreferences retrieves all library playback preferences for a profile.
func ListLibraryPlaybackPreferences(db *sql.DB, profileID string) ([]LibraryPlaybackPreference, error) {
rows, err := db.Query(`
SELECT profile_id, library_id, audio_language, subtitle_language,
subtitle_mode, show_forced_subtitles, updated_at
FROM library_playback_preferences
WHERE profile_id = ?
ORDER BY library_id`,
profileID,
)
if err != nil {
return nil, fmt.Errorf("listing library playback preferences for profile %q: %w", profileID, err)
}
defer rows.Close()
prefs := make([]LibraryPlaybackPreference, 0)
for rows.Next() {
var pref LibraryPlaybackPreference
var audioLanguage, subtitleLanguage, subtitleMode sql.NullString
var showForcedSubtitles sql.NullBool
if err := rows.Scan(
&pref.ProfileID,
&pref.LibraryID,
&audioLanguage,
&subtitleLanguage,
&subtitleMode,
&showForcedSubtitles,
&pref.UpdatedAt,
); err != nil {
return nil, fmt.Errorf("listing library playback preferences for profile %q: %w", profileID, err)
}
pref.AudioLanguage, pref.HasAudioLanguage = stringValue(audioLanguage)
pref.SubtitleLanguage, pref.HasSubtitleLanguage = stringValue(subtitleLanguage)
pref.SubtitleMode, pref.HasSubtitleMode = stringValue(subtitleMode)
pref.ShowForcedSubtitles, pref.HasShowForcedSubtitles = boolValue(showForcedSubtitles)
prefs = append(prefs, pref)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("listing library playback preferences for profile %q: %w", profileID, err)
}
return prefs, nil
}
// DeleteLibraryPlaybackPreference removes the library playback preference for a profile and library.
func DeleteLibraryPlaybackPreference(db *sql.DB, profileID string, libraryID int) error {
_, err := db.Exec(
"DELETE FROM library_playback_preferences WHERE profile_id = ? AND library_id = ?",
profileID, libraryID,
)
if err != nil {
return fmt.Errorf("deleting library playback preference for profile %q library %d: %w",
profileID, libraryID, err)
}
return nil
}
func libraryPlaybackDBValue(value string, hasValue bool) any {
if !hasValue {
return nil
}
return value
}
func libraryPlaybackBoolDBValue(value bool, hasValue bool) any {
if !hasValue {
return nil
}
return value
}
func stringValue(value sql.NullString) (string, bool) {
if !value.Valid {
return "", false
}
return value.String, true
}
func boolValue(value sql.NullBool) (bool, bool) {
if !value.Valid {
return false, false
}
return value.Bool, true
}
func normalizeLibraryPlaybackPreference(pref *LibraryPlaybackPreference) {
if pref.AudioLanguage != "" {
pref.HasAudioLanguage = true
}
if pref.SubtitleLanguage != "" {
pref.HasSubtitleLanguage = true
}
if pref.SubtitleMode != "" {
pref.HasSubtitleMode = true
}
if pref.ShowForcedSubtitles {
pref.HasShowForcedSubtitles = true
}
}