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>
493 lines
12 KiB
Go
493 lines
12 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.30.0
|
|
// source: release.sql
|
|
|
|
package repository
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const associateArtistToRelease = `-- name: AssociateArtistToRelease :exec
|
|
INSERT INTO artist_releases (artist_id, release_id, is_primary)
|
|
VALUES ($1, $2, $3)
|
|
ON CONFLICT DO NOTHING
|
|
`
|
|
|
|
type AssociateArtistToReleaseParams struct {
|
|
ArtistID int32
|
|
ReleaseID int32
|
|
IsPrimary bool
|
|
}
|
|
|
|
func (q *Queries) AssociateArtistToRelease(ctx context.Context, arg AssociateArtistToReleaseParams) error {
|
|
_, err := q.db.Exec(ctx, associateArtistToRelease, arg.ArtistID, arg.ReleaseID, arg.IsPrimary)
|
|
return err
|
|
}
|
|
|
|
const countReleasesFromArtist = `-- name: CountReleasesFromArtist :one
|
|
SELECT COUNT(*)
|
|
FROM releases r
|
|
JOIN artist_releases ar ON r.id = ar.release_id
|
|
WHERE ar.artist_id = $1
|
|
`
|
|
|
|
func (q *Queries) CountReleasesFromArtist(ctx context.Context, artistID int32) (int64, error) {
|
|
row := q.db.QueryRow(ctx, countReleasesFromArtist, artistID)
|
|
var count int64
|
|
err := row.Scan(&count)
|
|
return count, err
|
|
}
|
|
|
|
const countTopReleases = `-- name: CountTopReleases :one
|
|
SELECT COUNT(DISTINCT r.id) AS total_count
|
|
FROM listens l
|
|
JOIN tracks t ON l.track_id = t.id
|
|
JOIN releases r ON t.release_id = r.id
|
|
WHERE l.listened_at BETWEEN $1 AND $2
|
|
`
|
|
|
|
type CountTopReleasesParams struct {
|
|
ListenedAt time.Time
|
|
ListenedAt_2 time.Time
|
|
}
|
|
|
|
func (q *Queries) CountTopReleases(ctx context.Context, arg CountTopReleasesParams) (int64, error) {
|
|
row := q.db.QueryRow(ctx, countTopReleases, arg.ListenedAt, arg.ListenedAt_2)
|
|
var total_count int64
|
|
err := row.Scan(&total_count)
|
|
return total_count, err
|
|
}
|
|
|
|
const deleteRelease = `-- name: DeleteRelease :exec
|
|
DELETE FROM releases WHERE id = $1
|
|
`
|
|
|
|
func (q *Queries) DeleteRelease(ctx context.Context, id int32) error {
|
|
_, err := q.db.Exec(ctx, deleteRelease, id)
|
|
return err
|
|
}
|
|
|
|
const deleteReleasesFromArtist = `-- name: DeleteReleasesFromArtist :exec
|
|
DELETE FROM releases r
|
|
USING artist_releases ar
|
|
WHERE ar.release_id = r.id
|
|
AND ar.artist_id = $1
|
|
`
|
|
|
|
func (q *Queries) DeleteReleasesFromArtist(ctx context.Context, artistID int32) error {
|
|
_, err := q.db.Exec(ctx, deleteReleasesFromArtist, artistID)
|
|
return err
|
|
}
|
|
|
|
const getRelease = `-- name: GetRelease :one
|
|
SELECT
|
|
id, musicbrainz_id, image, various_artists, image_source, title,
|
|
get_artists_for_release(id) AS artists
|
|
FROM releases_with_title
|
|
WHERE id = $1 LIMIT 1
|
|
`
|
|
|
|
type GetReleaseRow struct {
|
|
ID int32
|
|
MusicBrainzID *uuid.UUID
|
|
Image *uuid.UUID
|
|
VariousArtists bool
|
|
ImageSource pgtype.Text
|
|
Title string
|
|
Artists []byte
|
|
}
|
|
|
|
func (q *Queries) GetRelease(ctx context.Context, id int32) (GetReleaseRow, error) {
|
|
row := q.db.QueryRow(ctx, getRelease, id)
|
|
var i GetReleaseRow
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.VariousArtists,
|
|
&i.ImageSource,
|
|
&i.Title,
|
|
&i.Artists,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getReleaseByArtistAndTitle = `-- name: GetReleaseByArtistAndTitle :one
|
|
SELECT r.id, r.musicbrainz_id, r.image, r.various_artists, r.image_source, r.title
|
|
FROM releases_with_title r
|
|
JOIN artist_releases ar ON r.id = ar.release_id
|
|
WHERE r.title = $1 AND ar.artist_id = $2
|
|
LIMIT 1
|
|
`
|
|
|
|
type GetReleaseByArtistAndTitleParams struct {
|
|
Title string
|
|
ArtistID int32
|
|
}
|
|
|
|
func (q *Queries) GetReleaseByArtistAndTitle(ctx context.Context, arg GetReleaseByArtistAndTitleParams) (ReleasesWithTitle, error) {
|
|
row := q.db.QueryRow(ctx, getReleaseByArtistAndTitle, arg.Title, arg.ArtistID)
|
|
var i ReleasesWithTitle
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.VariousArtists,
|
|
&i.ImageSource,
|
|
&i.Title,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getReleaseByArtistAndTitles = `-- name: GetReleaseByArtistAndTitles :one
|
|
SELECT r.id, r.musicbrainz_id, r.image, r.various_artists, r.image_source, r.title
|
|
FROM releases_with_title r
|
|
JOIN artist_releases ar ON r.id = ar.release_id
|
|
WHERE r.title = ANY ($1::TEXT[]) AND ar.artist_id = $2
|
|
LIMIT 1
|
|
`
|
|
|
|
type GetReleaseByArtistAndTitlesParams struct {
|
|
Column1 []string
|
|
ArtistID int32
|
|
}
|
|
|
|
func (q *Queries) GetReleaseByArtistAndTitles(ctx context.Context, arg GetReleaseByArtistAndTitlesParams) (ReleasesWithTitle, error) {
|
|
row := q.db.QueryRow(ctx, getReleaseByArtistAndTitles, arg.Column1, arg.ArtistID)
|
|
var i ReleasesWithTitle
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.VariousArtists,
|
|
&i.ImageSource,
|
|
&i.Title,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getReleaseByImageID = `-- name: GetReleaseByImageID :one
|
|
SELECT id, musicbrainz_id, image, various_artists, image_source FROM releases
|
|
WHERE image = $1 LIMIT 1
|
|
`
|
|
|
|
func (q *Queries) GetReleaseByImageID(ctx context.Context, image *uuid.UUID) (Release, error) {
|
|
row := q.db.QueryRow(ctx, getReleaseByImageID, image)
|
|
var i Release
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.VariousArtists,
|
|
&i.ImageSource,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getReleaseByMbzID = `-- name: GetReleaseByMbzID :one
|
|
SELECT id, musicbrainz_id, image, various_artists, image_source, title FROM releases_with_title
|
|
WHERE musicbrainz_id = $1 LIMIT 1
|
|
`
|
|
|
|
func (q *Queries) GetReleaseByMbzID(ctx context.Context, musicbrainzID *uuid.UUID) (ReleasesWithTitle, error) {
|
|
row := q.db.QueryRow(ctx, getReleaseByMbzID, musicbrainzID)
|
|
var i ReleasesWithTitle
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.VariousArtists,
|
|
&i.ImageSource,
|
|
&i.Title,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getReleasesWithoutImages = `-- name: GetReleasesWithoutImages :many
|
|
SELECT
|
|
r.id, r.musicbrainz_id, r.image, r.various_artists, r.image_source, r.title,
|
|
get_artists_for_release(r.id) AS artists
|
|
FROM releases_with_title r
|
|
WHERE r.image IS NULL
|
|
AND r.id > $2
|
|
ORDER BY r.id ASC
|
|
LIMIT $1
|
|
`
|
|
|
|
type GetReleasesWithoutImagesParams struct {
|
|
Limit int32
|
|
ID int32
|
|
}
|
|
|
|
type GetReleasesWithoutImagesRow struct {
|
|
ID int32
|
|
MusicBrainzID *uuid.UUID
|
|
Image *uuid.UUID
|
|
VariousArtists bool
|
|
ImageSource pgtype.Text
|
|
Title string
|
|
Artists []byte
|
|
}
|
|
|
|
func (q *Queries) GetReleasesWithoutImages(ctx context.Context, arg GetReleasesWithoutImagesParams) ([]GetReleasesWithoutImagesRow, error) {
|
|
rows, err := q.db.Query(ctx, getReleasesWithoutImages, arg.Limit, arg.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []GetReleasesWithoutImagesRow
|
|
for rows.Next() {
|
|
var i GetReleasesWithoutImagesRow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.VariousArtists,
|
|
&i.ImageSource,
|
|
&i.Title,
|
|
&i.Artists,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const getTopReleasesFromArtist = `-- name: GetTopReleasesFromArtist :many
|
|
SELECT
|
|
r.id, r.musicbrainz_id, r.image, r.various_artists, r.image_source, r.title,
|
|
COUNT(*) AS listen_count,
|
|
get_artists_for_release(r.id) AS artists
|
|
FROM listens l
|
|
JOIN tracks t ON l.track_id = t.id
|
|
JOIN releases_with_title r ON t.release_id = r.id
|
|
JOIN artist_releases ar ON r.id = ar.release_id
|
|
WHERE ar.artist_id = $5
|
|
AND l.listened_at BETWEEN $1 AND $2
|
|
GROUP BY r.id, r.title, r.musicbrainz_id, r.various_artists, r.image, r.image_source
|
|
ORDER BY listen_count DESC, r.id
|
|
LIMIT $3 OFFSET $4
|
|
`
|
|
|
|
type GetTopReleasesFromArtistParams struct {
|
|
ListenedAt time.Time
|
|
ListenedAt_2 time.Time
|
|
Limit int32
|
|
Offset int32
|
|
ArtistID int32
|
|
}
|
|
|
|
type GetTopReleasesFromArtistRow struct {
|
|
ID int32
|
|
MusicBrainzID *uuid.UUID
|
|
Image *uuid.UUID
|
|
VariousArtists bool
|
|
ImageSource pgtype.Text
|
|
Title string
|
|
ListenCount int64
|
|
Artists []byte
|
|
}
|
|
|
|
func (q *Queries) GetTopReleasesFromArtist(ctx context.Context, arg GetTopReleasesFromArtistParams) ([]GetTopReleasesFromArtistRow, error) {
|
|
rows, err := q.db.Query(ctx, getTopReleasesFromArtist,
|
|
arg.ListenedAt,
|
|
arg.ListenedAt_2,
|
|
arg.Limit,
|
|
arg.Offset,
|
|
arg.ArtistID,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []GetTopReleasesFromArtistRow
|
|
for rows.Next() {
|
|
var i GetTopReleasesFromArtistRow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.VariousArtists,
|
|
&i.ImageSource,
|
|
&i.Title,
|
|
&i.ListenCount,
|
|
&i.Artists,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const getTopReleasesPaginated = `-- name: GetTopReleasesPaginated :many
|
|
SELECT
|
|
r.id, r.musicbrainz_id, r.image, r.various_artists, r.image_source, r.title,
|
|
COUNT(*) AS listen_count,
|
|
get_artists_for_release(r.id) AS artists
|
|
FROM listens l
|
|
JOIN tracks t ON l.track_id = t.id
|
|
JOIN releases_with_title r ON t.release_id = r.id
|
|
WHERE l.listened_at BETWEEN $1 AND $2
|
|
GROUP BY r.id, r.title, r.musicbrainz_id, r.various_artists, r.image, r.image_source
|
|
ORDER BY listen_count DESC, r.id
|
|
LIMIT $3 OFFSET $4
|
|
`
|
|
|
|
type GetTopReleasesPaginatedParams struct {
|
|
ListenedAt time.Time
|
|
ListenedAt_2 time.Time
|
|
Limit int32
|
|
Offset int32
|
|
}
|
|
|
|
type GetTopReleasesPaginatedRow struct {
|
|
ID int32
|
|
MusicBrainzID *uuid.UUID
|
|
Image *uuid.UUID
|
|
VariousArtists bool
|
|
ImageSource pgtype.Text
|
|
Title string
|
|
ListenCount int64
|
|
Artists []byte
|
|
}
|
|
|
|
func (q *Queries) GetTopReleasesPaginated(ctx context.Context, arg GetTopReleasesPaginatedParams) ([]GetTopReleasesPaginatedRow, error) {
|
|
rows, err := q.db.Query(ctx, getTopReleasesPaginated,
|
|
arg.ListenedAt,
|
|
arg.ListenedAt_2,
|
|
arg.Limit,
|
|
arg.Offset,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []GetTopReleasesPaginatedRow
|
|
for rows.Next() {
|
|
var i GetTopReleasesPaginatedRow
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.VariousArtists,
|
|
&i.ImageSource,
|
|
&i.Title,
|
|
&i.ListenCount,
|
|
&i.Artists,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const insertRelease = `-- name: InsertRelease :one
|
|
INSERT INTO releases (musicbrainz_id, various_artists, image, image_source)
|
|
VALUES ($1, $2, $3, $4)
|
|
RETURNING id, musicbrainz_id, image, various_artists, image_source
|
|
`
|
|
|
|
type InsertReleaseParams struct {
|
|
MusicBrainzID *uuid.UUID
|
|
VariousArtists bool
|
|
Image *uuid.UUID
|
|
ImageSource pgtype.Text
|
|
}
|
|
|
|
func (q *Queries) InsertRelease(ctx context.Context, arg InsertReleaseParams) (Release, error) {
|
|
row := q.db.QueryRow(ctx, insertRelease,
|
|
arg.MusicBrainzID,
|
|
arg.VariousArtists,
|
|
arg.Image,
|
|
arg.ImageSource,
|
|
)
|
|
var i Release
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.MusicBrainzID,
|
|
&i.Image,
|
|
&i.VariousArtists,
|
|
&i.ImageSource,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const updateReleaseImage = `-- name: UpdateReleaseImage :exec
|
|
UPDATE releases SET image = $2, image_source = $3
|
|
WHERE id = $1
|
|
`
|
|
|
|
type UpdateReleaseImageParams struct {
|
|
ID int32
|
|
Image *uuid.UUID
|
|
ImageSource pgtype.Text
|
|
}
|
|
|
|
func (q *Queries) UpdateReleaseImage(ctx context.Context, arg UpdateReleaseImageParams) error {
|
|
_, err := q.db.Exec(ctx, updateReleaseImage, arg.ID, arg.Image, arg.ImageSource)
|
|
return err
|
|
}
|
|
|
|
const updateReleaseMbzID = `-- name: UpdateReleaseMbzID :exec
|
|
UPDATE releases SET musicbrainz_id = $2
|
|
WHERE id = $1
|
|
`
|
|
|
|
type UpdateReleaseMbzIDParams struct {
|
|
ID int32
|
|
MusicBrainzID *uuid.UUID
|
|
}
|
|
|
|
func (q *Queries) UpdateReleaseMbzID(ctx context.Context, arg UpdateReleaseMbzIDParams) error {
|
|
_, err := q.db.Exec(ctx, updateReleaseMbzID, arg.ID, arg.MusicBrainzID)
|
|
return err
|
|
}
|
|
|
|
const updateReleasePrimaryArtist = `-- name: UpdateReleasePrimaryArtist :exec
|
|
UPDATE artist_releases SET is_primary = $3
|
|
WHERE artist_id = $1 AND release_id = $2
|
|
`
|
|
|
|
type UpdateReleasePrimaryArtistParams struct {
|
|
ArtistID int32
|
|
ReleaseID int32
|
|
IsPrimary bool
|
|
}
|
|
|
|
func (q *Queries) UpdateReleasePrimaryArtist(ctx context.Context, arg UpdateReleasePrimaryArtistParams) error {
|
|
_, err := q.db.Exec(ctx, updateReleasePrimaryArtist, arg.ArtistID, arg.ReleaseID, arg.IsPrimary)
|
|
return err
|
|
}
|
|
|
|
const updateReleaseVariousArtists = `-- name: UpdateReleaseVariousArtists :exec
|
|
UPDATE releases SET various_artists = $2
|
|
WHERE id = $1
|
|
`
|
|
|
|
type UpdateReleaseVariousArtistsParams struct {
|
|
ID int32
|
|
VariousArtists bool
|
|
}
|
|
|
|
func (q *Queries) UpdateReleaseVariousArtists(ctx context.Context, arg UpdateReleaseVariousArtistsParams) error {
|
|
_, err := q.db.Exec(ctx, updateReleaseVariousArtists, arg.ID, arg.VariousArtists)
|
|
return err
|
|
}
|