mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-01 07:21:17 +00:00
fix(subsonic): expose cover cache-buster on bookmarked songs
GetBookmarks selected media_file.* without the album cover-stamp projection, so bookmarked songs kept emitting the pre-edit coverArt id after a cover upload/delete. With this fourth copy of the projection appearing, extract it into a shared coverArtUpdatedAtCol helper used by all media_file read paths (list, playlist tracks, single playlist track, bookmarks).
This commit is contained in:
parent
a5d3d615d8
commit
d509d8b2f8
@ -90,3 +90,9 @@ func mapSortOrder(tableName, order string) string {
|
||||
repl := fmt.Sprintf("(coalesce(nullif(%[1]s.sort_$1,''),%[1]s.order_$1) collate nocase)", tableName)
|
||||
return sortOrderRegex.ReplaceAllString(order, repl)
|
||||
}
|
||||
|
||||
// coverArtUpdatedAtCol projects the album's manual-cover timestamp onto rows of the given
|
||||
// table/alias as a scalar subquery — a join would clash with media_file's column names.
|
||||
func coverArtUpdatedAtCol(alias string) string {
|
||||
return "(select cover_art_updated_at from album where album.id = " + alias + ".album_id) as cover_art_updated_at"
|
||||
}
|
||||
|
||||
@ -184,10 +184,8 @@ func (r *mediaFileRepository) UpdateProbeData(id string, data string) error {
|
||||
}
|
||||
|
||||
func (r *mediaFileRepository) selectMediaFile(options ...model.QueryOptions) SelectBuilder {
|
||||
// Scalar subquery (not a join): album shares column names with media_file, and a join
|
||||
// would make unqualified filter/sort references ambiguous.
|
||||
sql := r.newSelect(options...).Columns("media_file.*", "library.path as library_path", "library.name as library_name",
|
||||
"(select cover_art_updated_at from album where album.id = media_file.album_id) as cover_art_updated_at").
|
||||
coverArtUpdatedAtCol("media_file")).
|
||||
LeftJoin("library on media_file.library_id = library.id")
|
||||
sql = r.withAnnotation(sql, "media_file.id")
|
||||
sql = r.withBookmark(sql, "media_file.id")
|
||||
|
||||
@ -314,7 +314,7 @@ func (r *playlistRepository) tracksQuery(query SelectBuilder, id string) SelectB
|
||||
"playlist_tracks.*",
|
||||
"library.path as library_path",
|
||||
"library.name as library_name",
|
||||
"(select cover_art_updated_at from album where album.id = f.album_id) as cover_art_updated_at",
|
||||
coverArtUpdatedAtCol("f"),
|
||||
).
|
||||
LeftJoin("annotation on (" +
|
||||
"annotation.item_id = media_file_id" +
|
||||
|
||||
@ -108,7 +108,7 @@ func (r *playlistTrackRepository) Read(id string) (any, error) {
|
||||
"rated_at",
|
||||
"f.*",
|
||||
"playlist_tracks.*",
|
||||
"(select cover_art_updated_at from album where album.id = f.album_id) as cover_art_updated_at",
|
||||
coverArtUpdatedAtCol("f"),
|
||||
).
|
||||
Join("media_file f on f.id = media_file_id").
|
||||
Where(And{Eq{"playlist_id": r.playlistId}, Eq{"playlist_tracks.id": id}})
|
||||
|
||||
@ -100,7 +100,9 @@ func (r sqlRepository) GetBookmarks() (model.Bookmarks, error) {
|
||||
user, _ := request.UserFrom(r.ctx)
|
||||
|
||||
idField := r.tableName + ".id"
|
||||
sq := r.newSelect().Columns(r.tableName + ".*")
|
||||
// Only media files are bookmarkable (see dbMediaFiles scan below), so the cover
|
||||
// stamp projection is safe to add here
|
||||
sq := r.newSelect().Columns(r.tableName+".*", coverArtUpdatedAtCol(r.tableName))
|
||||
sq = r.withAnnotation(sq, idField)
|
||||
sq = r.withBookmark(sq, idField).Where(NotEq{bookmarkTable + ".item_id": nil})
|
||||
var mfs dbMediaFiles // TODO Decouple from media_file
|
||||
|
||||
@ -3,6 +3,7 @@ package persistence
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/navidrome/navidrome/model/request"
|
||||
@ -70,5 +71,24 @@ var _ = Describe("sqlBookmarks", func() {
|
||||
Expect(mr.DeleteBookmark(songComeTogether.ID)).To(Succeed())
|
||||
Expect(mr.GetBookmarks()).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("exposes the album's cover timestamp on bookmarked songs", func() {
|
||||
albumRepo := NewAlbumRepository(request.WithUser(GinkgoT().Context(), model.User{ID: "userid"}), GetDBXBuilder()).(*albumRepository)
|
||||
Expect(mr.AddBookmark(songAntenna.ID, "cover test", 1)).To(Succeed())
|
||||
DeferCleanup(func() {
|
||||
_ = mr.DeleteBookmark(songAntenna.ID)
|
||||
// Restore both columns so fixture-equality tests stay untouched
|
||||
_, _ = albumRepo.executeSQL(squirrel.Update("album").
|
||||
Set("uploaded_image", "").Set("cover_art_updated_at", nil).
|
||||
Where(squirrel.Eq{"id": songAntenna.AlbumID}))
|
||||
})
|
||||
|
||||
Expect(albumRepo.UpdateImage(songAntenna.AlbumID, "cover-bm.jpg")).To(Succeed())
|
||||
|
||||
bms, err := mr.GetBookmarks()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bms).To(HaveLen(1))
|
||||
Expect(bms[0].Item.CoverArtUpdatedAt).ToNot(BeNil())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user