mirror of
https://github.com/gabehf/Koito.git
synced 2026-03-08 23:18:15 -07:00
* add dev branch container to workflow * correctly set the default range of ActivityGrid * fix: set name/short_name to koito (#61) * fix dev container push workflow * fix: race condition with using getComputedStyle primary color for dynamic activity grid darkening (#76) * Fix race condition with using getComputedStyle primary color for dynamic activity grid darkening Instead just use the color from the current theme directly. Tested works on initial load and theme changes. Fixes https://github.com/gabehf/Koito/issues/75 * Rework theme provider to provide the actual Theme object throughtout the app, in addition to the name Split name out of the Theme struct to simplify custom theme saving/reading * fix: set first artist listed as primary by default (#81) * feat: add server-side configuration with default theme (#90) * docs: add example for usage of the main listenbrainz instance (#71) * docs: add example for usage of the main listenbrainz instance * Update scrobbler.md --------- Co-authored-by: Gabe Farrell <90876006+gabehf@users.noreply.github.com> * feat: add server-side cfg and default theme * fix: repair custom theme --------- Co-authored-by: m0d3rnX <jesper@posteo.de> * docs: add default theme cfg option to docs * feat: add ability to manually scrobble track (#91) * feat: add button to manually scrobble from ui * fix: ensure timestamp is in the past, log fix * test: add integration test * feat: add first listened to dates for media items (#92) * fix: ensure error checks for ErrNoRows * feat: add now playing endpoint and ui (#93) * wip * feat: add now playing * fix: set default theme when config is not set * feat: fetch images from subsonic server (#94) * fix: useQuery instead of useEffect for now playing * feat: custom artist separator regex (#95) * Fix race condition with using getComputedStyle primary color for dynamic activity grid darkening Instead just use the color from the current theme directly. Tested works on initial load and theme changes. Fixes https://github.com/gabehf/Koito/issues/75 * Rework theme provider to provide the actual Theme object throughtout the app, in addition to the name Split name out of the Theme struct to simplify custom theme saving/reading * feat: add server-side configuration with default theme (#90) * docs: add example for usage of the main listenbrainz instance (#71) * docs: add example for usage of the main listenbrainz instance * Update scrobbler.md --------- Co-authored-by: Gabe Farrell <90876006+gabehf@users.noreply.github.com> * feat: add server-side cfg and default theme * fix: repair custom theme --------- Co-authored-by: m0d3rnX <jesper@posteo.de> * fix: rebase errors --------- Co-authored-by: pet <128837728+againstpetra@users.noreply.github.com> Co-authored-by: mlandry <mike.landry@gmail.com> Co-authored-by: m0d3rnX <jesper@posteo.de>
440 lines
11 KiB
Go
440 lines
11 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.30.0
|
|
// source: artist.sql
|
|
|
|
package repository
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const countTopArtists = `-- name: CountTopArtists :one
|
|
SELECT COUNT(DISTINCT at.artist_id) AS total_count
|
|
FROM listens l
|
|
JOIN artist_tracks at ON l.track_id = at.track_id
|
|
WHERE l.listened_at BETWEEN $1 AND $2
|
|
`
|
|
|
|
type CountTopArtistsParams struct {
|
|
ListenedAt time.Time
|
|
ListenedAt_2 time.Time
|
|
}
|
|
|
|
func (q *Queries) CountTopArtists(ctx context.Context, arg CountTopArtistsParams) (int64, error) {
|
|
row := q.db.QueryRow(ctx, countTopArtists, arg.ListenedAt, arg.ListenedAt_2)
|
|
var total_count int64
|
|
err := row.Scan(&total_count)
|
|
return total_count, err
|
|
}
|
|
|
|
const deleteArtist = `-- name: DeleteArtist :exec
|
|
DELETE FROM artists WHERE id = $1
|
|
`
|
|
|
|
func (q *Queries) DeleteArtist(ctx context.Context, id int32) error {
|
|
_, err := q.db.Exec(ctx, deleteArtist, id)
|
|
return err
|
|
}
|
|
|
|
const deleteConflictingArtistReleases = `-- name: DeleteConflictingArtistReleases :exec
|
|
DELETE FROM artist_releases ar
|
|
WHERE ar.artist_id = $1
|
|
AND release_id IN (
|
|
SELECT ar.release_id FROM artist_releases ar WHERE ar.artist_id = $2
|
|
)
|
|
`
|
|
|
|
type DeleteConflictingArtistReleasesParams struct {
|
|
ArtistID int32
|
|
ArtistID_2 int32
|
|
}
|
|
|
|
func (q *Queries) DeleteConflictingArtistReleases(ctx context.Context, arg DeleteConflictingArtistReleasesParams) error {
|
|
_, err := q.db.Exec(ctx, deleteConflictingArtistReleases, arg.ArtistID, arg.ArtistID_2)
|
|
return err
|
|
}
|
|
|
|
const deleteConflictingArtistTracks = `-- name: DeleteConflictingArtistTracks :exec
|
|
DELETE FROM artist_tracks at
|
|
WHERE at.artist_id = $1
|
|
AND track_id IN (
|
|
SELECT at.track_id FROM artist_tracks at WHERE at.artist_id = $2
|
|
)
|
|
`
|
|
|
|
type DeleteConflictingArtistTracksParams struct {
|
|
ArtistID int32
|
|
ArtistID_2 int32
|
|
}
|
|
|
|
func (q *Queries) DeleteConflictingArtistTracks(ctx context.Context, arg DeleteConflictingArtistTracksParams) error {
|
|
_, err := q.db.Exec(ctx, deleteConflictingArtistTracks, arg.ArtistID, arg.ArtistID_2)
|
|
return err
|
|
}
|
|
|
|
const getArtist = `-- name: GetArtist :one
|
|
SELECT
|
|
a.id, a.musicbrainz_id, a.image, a.image_source, a.name,
|
|
array_agg(aa.alias)::text[] AS aliases
|
|
FROM artists_with_name a
|
|
LEFT JOIN artist_aliases aa ON a.id = aa.artist_id
|
|
WHERE a.id = $1
|
|
GROUP BY a.id, a.musicbrainz_id, a.image, a.image_source, a.name
|
|
`
|
|
|
|
type GetArtistRow struct {
|
|
ID int32
|
|
MusicBrainzID *uuid.UUID
|
|
Image *uuid.UUID
|
|
ImageSource pgtype.Text
|
|
Name string
|
|
Aliases []string
|
|
}
|
|
|
|
func (q *Queries) GetArtist(ctx context.Context, id int32) (GetArtistRow, error) {
|
|
row := q.db.QueryRow(ctx, getArtist, id)
|
|
var i GetArtistRow
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.ImageSource,
|
|
&i.Name,
|
|
&i.Aliases,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getArtistByImage = `-- name: GetArtistByImage :one
|
|
SELECT id, musicbrainz_id, image, image_source FROM artists WHERE image = $1 LIMIT 1
|
|
`
|
|
|
|
func (q *Queries) GetArtistByImage(ctx context.Context, image *uuid.UUID) (Artist, error) {
|
|
row := q.db.QueryRow(ctx, getArtistByImage, image)
|
|
var i Artist
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.ImageSource,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getArtistByMbzID = `-- name: GetArtistByMbzID :one
|
|
SELECT
|
|
a.id, a.musicbrainz_id, a.image, a.image_source, a.name,
|
|
array_agg(aa.alias)::text[] AS aliases
|
|
FROM artists_with_name a
|
|
LEFT JOIN artist_aliases aa ON a.id = aa.artist_id
|
|
WHERE a.musicbrainz_id = $1
|
|
GROUP BY a.id, a.musicbrainz_id, a.image, a.image_source, a.name
|
|
`
|
|
|
|
type GetArtistByMbzIDRow struct {
|
|
ID int32
|
|
MusicBrainzID *uuid.UUID
|
|
Image *uuid.UUID
|
|
ImageSource pgtype.Text
|
|
Name string
|
|
Aliases []string
|
|
}
|
|
|
|
func (q *Queries) GetArtistByMbzID(ctx context.Context, musicbrainzID *uuid.UUID) (GetArtistByMbzIDRow, error) {
|
|
row := q.db.QueryRow(ctx, getArtistByMbzID, musicbrainzID)
|
|
var i GetArtistByMbzIDRow
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.ImageSource,
|
|
&i.Name,
|
|
&i.Aliases,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getArtistByName = `-- name: GetArtistByName :one
|
|
WITH artist_with_aliases AS (
|
|
SELECT
|
|
a.id, a.musicbrainz_id, a.image, a.image_source, a.name,
|
|
COALESCE(array_agg(aa.alias), '{}')::text[] AS aliases
|
|
FROM artists_with_name a
|
|
LEFT JOIN artist_aliases aa ON a.id = aa.artist_id
|
|
WHERE a.id IN (
|
|
SELECT aa2.artist_id FROM artist_aliases aa2 WHERE aa2.alias = $1
|
|
)
|
|
GROUP BY a.id, a.musicbrainz_id, a.image, a.image_source, a.name
|
|
)
|
|
SELECT id, musicbrainz_id, image, image_source, name, aliases FROM artist_with_aliases
|
|
`
|
|
|
|
type GetArtistByNameRow struct {
|
|
ID int32
|
|
MusicBrainzID *uuid.UUID
|
|
Image *uuid.UUID
|
|
ImageSource pgtype.Text
|
|
Name string
|
|
Aliases []string
|
|
}
|
|
|
|
func (q *Queries) GetArtistByName(ctx context.Context, alias string) (GetArtistByNameRow, error) {
|
|
row := q.db.QueryRow(ctx, getArtistByName, alias)
|
|
var i GetArtistByNameRow
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.ImageSource,
|
|
&i.Name,
|
|
&i.Aliases,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getReleaseArtists = `-- name: GetReleaseArtists :many
|
|
SELECT
|
|
a.id, a.musicbrainz_id, a.image, a.image_source, a.name,
|
|
ar.is_primary as is_primary
|
|
FROM artists_with_name a
|
|
LEFT JOIN artist_releases ar ON a.id = ar.artist_id
|
|
WHERE ar.release_id = $1
|
|
GROUP BY a.id, a.musicbrainz_id, a.image, a.image_source, a.name, ar.is_primary
|
|
`
|
|
|
|
type GetReleaseArtistsRow struct {
|
|
ID int32
|
|
MusicBrainzID *uuid.UUID
|
|
Image *uuid.UUID
|
|
ImageSource pgtype.Text
|
|
Name string
|
|
IsPrimary pgtype.Bool
|
|
}
|
|
|
|
func (q *Queries) GetReleaseArtists(ctx context.Context, releaseID int32) ([]GetReleaseArtistsRow, error) {
|
|
rows, err := q.db.Query(ctx, getReleaseArtists, releaseID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []GetReleaseArtistsRow
|
|
for rows.Next() {
|
|
var i GetReleaseArtistsRow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.ImageSource,
|
|
&i.Name,
|
|
&i.IsPrimary,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const getTopArtistsPaginated = `-- name: GetTopArtistsPaginated :many
|
|
SELECT
|
|
a.id,
|
|
a.name,
|
|
a.musicbrainz_id,
|
|
a.image,
|
|
COUNT(*) AS listen_count
|
|
FROM listens l
|
|
JOIN tracks t ON l.track_id = t.id
|
|
JOIN artist_tracks at ON at.track_id = t.id
|
|
JOIN artists_with_name a ON a.id = at.artist_id
|
|
WHERE l.listened_at BETWEEN $1 AND $2
|
|
GROUP BY a.id, a.name, a.musicbrainz_id, a.image, a.image_source, a.name
|
|
ORDER BY listen_count DESC, a.id
|
|
LIMIT $3 OFFSET $4
|
|
`
|
|
|
|
type GetTopArtistsPaginatedParams struct {
|
|
ListenedAt time.Time
|
|
ListenedAt_2 time.Time
|
|
Limit int32
|
|
Offset int32
|
|
}
|
|
|
|
type GetTopArtistsPaginatedRow struct {
|
|
ID int32
|
|
Name string
|
|
MusicBrainzID *uuid.UUID
|
|
Image *uuid.UUID
|
|
ListenCount int64
|
|
}
|
|
|
|
func (q *Queries) GetTopArtistsPaginated(ctx context.Context, arg GetTopArtistsPaginatedParams) ([]GetTopArtistsPaginatedRow, error) {
|
|
rows, err := q.db.Query(ctx, getTopArtistsPaginated,
|
|
arg.ListenedAt,
|
|
arg.ListenedAt_2,
|
|
arg.Limit,
|
|
arg.Offset,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []GetTopArtistsPaginatedRow
|
|
for rows.Next() {
|
|
var i GetTopArtistsPaginatedRow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.Name,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.ListenCount,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const getTrackArtists = `-- name: GetTrackArtists :many
|
|
SELECT
|
|
a.id, a.musicbrainz_id, a.image, a.image_source, a.name,
|
|
at.is_primary as is_primary
|
|
FROM artists_with_name a
|
|
LEFT JOIN artist_tracks at ON a.id = at.artist_id
|
|
WHERE at.track_id = $1
|
|
GROUP BY a.id, a.musicbrainz_id, a.image, a.image_source, a.name, at.is_primary
|
|
`
|
|
|
|
type GetTrackArtistsRow struct {
|
|
ID int32
|
|
MusicBrainzID *uuid.UUID
|
|
Image *uuid.UUID
|
|
ImageSource pgtype.Text
|
|
Name string
|
|
IsPrimary pgtype.Bool
|
|
}
|
|
|
|
func (q *Queries) GetTrackArtists(ctx context.Context, trackID int32) ([]GetTrackArtistsRow, error) {
|
|
rows, err := q.db.Query(ctx, getTrackArtists, trackID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []GetTrackArtistsRow
|
|
for rows.Next() {
|
|
var i GetTrackArtistsRow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.ImageSource,
|
|
&i.Name,
|
|
&i.IsPrimary,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const insertArtist = `-- name: InsertArtist :one
|
|
INSERT INTO artists (musicbrainz_id, image, image_source)
|
|
VALUES ($1, $2, $3)
|
|
RETURNING id, musicbrainz_id, image, image_source
|
|
`
|
|
|
|
type InsertArtistParams struct {
|
|
MusicBrainzID *uuid.UUID
|
|
Image *uuid.UUID
|
|
ImageSource pgtype.Text
|
|
}
|
|
|
|
func (q *Queries) InsertArtist(ctx context.Context, arg InsertArtistParams) (Artist, error) {
|
|
row := q.db.QueryRow(ctx, insertArtist, arg.MusicBrainzID, arg.Image, arg.ImageSource)
|
|
var i Artist
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.ImageSource,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const updateArtistImage = `-- name: UpdateArtistImage :exec
|
|
UPDATE artists SET image = $2, image_source = $3
|
|
WHERE id = $1
|
|
`
|
|
|
|
type UpdateArtistImageParams struct {
|
|
ID int32
|
|
Image *uuid.UUID
|
|
ImageSource pgtype.Text
|
|
}
|
|
|
|
func (q *Queries) UpdateArtistImage(ctx context.Context, arg UpdateArtistImageParams) error {
|
|
_, err := q.db.Exec(ctx, updateArtistImage, arg.ID, arg.Image, arg.ImageSource)
|
|
return err
|
|
}
|
|
|
|
const updateArtistMbzID = `-- name: UpdateArtistMbzID :exec
|
|
UPDATE artists SET musicbrainz_id = $2
|
|
WHERE id = $1
|
|
`
|
|
|
|
type UpdateArtistMbzIDParams struct {
|
|
ID int32
|
|
MusicBrainzID *uuid.UUID
|
|
}
|
|
|
|
func (q *Queries) UpdateArtistMbzID(ctx context.Context, arg UpdateArtistMbzIDParams) error {
|
|
_, err := q.db.Exec(ctx, updateArtistMbzID, arg.ID, arg.MusicBrainzID)
|
|
return err
|
|
}
|
|
|
|
const updateArtistReleases = `-- name: UpdateArtistReleases :exec
|
|
UPDATE artist_releases
|
|
SET artist_id = $2
|
|
WHERE artist_id = $1
|
|
`
|
|
|
|
type UpdateArtistReleasesParams struct {
|
|
ArtistID int32
|
|
ArtistID_2 int32
|
|
}
|
|
|
|
func (q *Queries) UpdateArtistReleases(ctx context.Context, arg UpdateArtistReleasesParams) error {
|
|
_, err := q.db.Exec(ctx, updateArtistReleases, arg.ArtistID, arg.ArtistID_2)
|
|
return err
|
|
}
|
|
|
|
const updateArtistTracks = `-- name: UpdateArtistTracks :exec
|
|
UPDATE artist_tracks
|
|
SET artist_id = $2
|
|
WHERE artist_id = $1
|
|
`
|
|
|
|
type UpdateArtistTracksParams struct {
|
|
ArtistID int32
|
|
ArtistID_2 int32
|
|
}
|
|
|
|
func (q *Queries) UpdateArtistTracks(ctx context.Context, arg UpdateArtistTracksParams) error {
|
|
_, err := q.db.Exec(ctx, updateArtistTracks, arg.ArtistID, arg.ArtistID_2)
|
|
return err
|
|
}
|