mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-03 20:47:35 +03:00
Deterministic pagination in random albums sort (#1841)
* Deterministic pagination in random albums sort * Reseed on first random page * Add unit tests * Use rand in Subsonic API * Use different seeds per user on SEEDEDRAND() SQLite3 function * Small refactor * Fix id mismatch * Add seeded random to media_file (subsonic endpoint `getRandomSongs`) * Refactor * Remove unneeded import --------- Co-authored-by: Deluan <deluan@navidrome.org>
This commit is contained in:
parent
a9feeac793
commit
98218d045e
7 changed files with 110 additions and 8 deletions
|
@ -75,7 +75,7 @@ func NewAlbumRepository(ctx context.Context, db dbx.Builder) model.AlbumReposito
|
|||
"artist": "compilation asc, COALESCE(NULLIF(sort_album_artist_name,''),order_album_artist_name) asc, COALESCE(NULLIF(sort_album_name,''),order_album_name) asc",
|
||||
"albumArtist": "compilation asc, COALESCE(NULLIF(sort_album_artist_name,''),order_album_artist_name) asc, COALESCE(NULLIF(sort_album_name,''),order_album_name) asc",
|
||||
"max_year": "coalesce(nullif(original_date,''), cast(max_year as text)), release_date, name, COALESCE(NULLIF(sort_album_name,''),order_album_name) asc",
|
||||
"random": "RANDOM()",
|
||||
"random": r.seededRandomSort(),
|
||||
"recently_added": recentlyAddedSort(),
|
||||
}
|
||||
} else {
|
||||
|
@ -84,7 +84,7 @@ func NewAlbumRepository(ctx context.Context, db dbx.Builder) model.AlbumReposito
|
|||
"artist": "compilation asc, order_album_artist_name asc, order_album_name asc",
|
||||
"albumArtist": "compilation asc, order_album_artist_name asc, order_album_name asc",
|
||||
"max_year": "coalesce(nullif(original_date,''), cast(max_year as text)), release_date, name, order_album_name asc",
|
||||
"random": "RANDOM()",
|
||||
"random": r.seededRandomSort(),
|
||||
"recently_added": recentlyAddedSort(),
|
||||
}
|
||||
}
|
||||
|
@ -180,6 +180,7 @@ func (r *albumRepository) GetAll(options ...model.QueryOptions) (model.Albums, e
|
|||
}
|
||||
|
||||
func (r *albumRepository) GetAllWithoutGenres(options ...model.QueryOptions) (model.Albums, error) {
|
||||
r.resetSeededRandom(options)
|
||||
sq := r.selectAlbum(options...)
|
||||
var dba dbAlbums
|
||||
err := r.queryAll(sq, &dba)
|
||||
|
|
|
@ -36,7 +36,7 @@ func NewMediaFileRepository(ctx context.Context, db dbx.Builder) *mediaFileRepos
|
|||
"title": "COALESCE(NULLIF(sort_title,''),title)",
|
||||
"artist": "COALESCE(NULLIF(sort_artist_name,''),order_artist_name) asc, COALESCE(NULLIF(sort_album_name,''),order_album_name) asc, release_date asc, disc_number asc, track_number asc",
|
||||
"album": "COALESCE(NULLIF(sort_album_name,''),order_album_name) asc, release_date asc, disc_number asc, track_number asc, COALESCE(NULLIF(sort_artist_name,''),order_artist_name) asc, COALESCE(NULLIF(sort_title,''),title) asc",
|
||||
"random": "RANDOM()",
|
||||
"random": r.seededRandomSort(),
|
||||
"createdAt": "media_file.created_at",
|
||||
}
|
||||
} else {
|
||||
|
@ -44,7 +44,7 @@ func NewMediaFileRepository(ctx context.Context, db dbx.Builder) *mediaFileRepos
|
|||
"title": "order_title",
|
||||
"artist": "order_artist_name asc, order_album_name asc, release_date asc, disc_number asc, track_number asc",
|
||||
"album": "order_album_name asc, release_date asc, disc_number asc, track_number asc, order_artist_name asc, title asc",
|
||||
"random": "RANDOM()",
|
||||
"random": r.seededRandomSort(),
|
||||
"createdAt": "media_file.created_at",
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ func (r *mediaFileRepository) Get(id string) (*model.MediaFile, error) {
|
|||
}
|
||||
|
||||
func (r *mediaFileRepository) GetAll(options ...model.QueryOptions) (model.MediaFiles, error) {
|
||||
r.resetSeededRandom(options)
|
||||
sq := r.selectMediaFile(options...)
|
||||
res := model.MediaFiles{}
|
||||
err := r.queryAll(sq, &res, options...)
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/navidrome/navidrome/model/request"
|
||||
"github.com/navidrome/navidrome/utils/hasher"
|
||||
"github.com/pocketbase/dbx"
|
||||
)
|
||||
|
||||
|
@ -137,6 +138,18 @@ func (r sqlRepository) applyFilters(sq SelectBuilder, options ...model.QueryOpti
|
|||
return sq
|
||||
}
|
||||
|
||||
func (r sqlRepository) seededRandomSort() string {
|
||||
u, _ := request.UserFrom(r.ctx)
|
||||
return fmt.Sprintf("SEEDEDRAND('%s', id)", r.tableName+u.ID)
|
||||
}
|
||||
|
||||
func (r sqlRepository) resetSeededRandom(options []model.QueryOptions) {
|
||||
if len(options) > 0 && options[0].Offset == 0 && options[0].Sort == "random" {
|
||||
u, _ := request.UserFrom(r.ctx)
|
||||
hasher.Reseed(r.tableName + u.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func (r sqlRepository) executeSQL(sq Sqlizer) (int64, error) {
|
||||
query, args, err := r.toSQL(sq)
|
||||
if err != nil {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue