mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-01 12:06:38 +08:00
Add library favourite buttons and fix remote favourites list (#14)
* Add favourite buttons to library list and series detail pages Co-authored-by: truewhile <truewhile@users.noreply.github.com> * Fix favourites list for remote Emby mounted media Co-authored-by: truewhile <truewhile@users.noreply.github.com> * Route favourites to library series detail when appropriate Co-authored-by: truewhile <truewhile@users.noreply.github.com> * Fix favourites link to library series for remote anime paths Co-authored-by: truewhile <truewhile@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: truewhile <truewhile@users.noreply.github.com>
This commit is contained in:
@@ -300,6 +300,9 @@ func (r *EmbyRemoteService) MapRemoteItemToMedia(ctx context.Context, mount *mod
|
||||
media.SeasonNum = 0
|
||||
media.EpisodeNum = 0
|
||||
}
|
||||
if mount != nil && strings.TrimSpace(mount.RemoteViewID) != "" {
|
||||
media.DisplayLibraryID = EncodeEmbyRemoteID(mount.ID, mount.RemoteViewID)
|
||||
}
|
||||
return media
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
@@ -126,14 +127,47 @@ func (p *PlaybackService) ListFavourites(ctx context.Context, userID string) ([]
|
||||
if len(favs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
ids := make([]string, len(favs))
|
||||
for i, f := range favs {
|
||||
ids[i] = f.MediaID
|
||||
sort.Slice(favs, func(i, j int) bool {
|
||||
return favs[i].CreatedAt.After(favs[j].CreatedAt)
|
||||
})
|
||||
|
||||
localIDs := make([]string, 0, len(favs))
|
||||
for _, fav := range favs {
|
||||
if !IsEmbyRemoteID(fav.MediaID) {
|
||||
localIDs = append(localIDs, fav.MediaID)
|
||||
}
|
||||
}
|
||||
var out []model.Media
|
||||
err = p.repo.DB.Where("id IN ?", ids).
|
||||
Order("created_at desc").Find(&out).Error
|
||||
return out, err
|
||||
mediaByID := map[string]model.Media{}
|
||||
if len(localIDs) > 0 {
|
||||
var mediaRows []model.Media
|
||||
if err := p.repo.DB.WithContext(ctx).Where("id IN ?", localIDs).Find(&mediaRows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, media := range mediaRows {
|
||||
mediaByID[media.ID] = media
|
||||
}
|
||||
}
|
||||
|
||||
out := make([]model.Media, 0, len(favs))
|
||||
for _, fav := range favs {
|
||||
if media, ok := mediaByID[fav.MediaID]; ok {
|
||||
out = append(out, media)
|
||||
continue
|
||||
}
|
||||
if p.remote != nil && IsEmbyRemoteID(fav.MediaID) {
|
||||
mountID, remoteID, _ := DecodeEmbyRemoteID(fav.MediaID)
|
||||
mount, acct, _ := p.remote.ResolveMount(ctx, mountID)
|
||||
if mount == nil || acct == nil {
|
||||
continue
|
||||
}
|
||||
remoteMedia, err := p.remote.RemoteMediaDetail(ctx, mount, acct, remoteID)
|
||||
if err != nil || remoteMedia == nil {
|
||||
continue
|
||||
}
|
||||
out = append(out, *remoteMedia)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ─── Playlists ──────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func TestListFavouritesIncludesLocalAndRemoteIDs(t *testing.T) {
|
||||
db := newServiceTestDB(t, &model.Favorite{}, &model.Media{})
|
||||
repos := repository.New(db)
|
||||
userID := "user-1"
|
||||
local := model.Media{
|
||||
Base: model.Base{ID: "local-movie-1"},
|
||||
Title: "Local Movie",
|
||||
}
|
||||
if err := db.Create(&local).Error; err != nil {
|
||||
t.Fatalf("create local media: %v", err)
|
||||
}
|
||||
remoteID := EncodeEmbyRemoteID("mount-1", "remote-series-1")
|
||||
favs := []model.Favorite{
|
||||
{Base: model.Base{CreatedAt: time.Now().Add(-time.Minute)}, UserID: userID, MediaID: remoteID},
|
||||
{Base: model.Base{CreatedAt: time.Now()}, UserID: userID, MediaID: local.ID},
|
||||
}
|
||||
for i := range favs {
|
||||
if err := db.Create(&favs[i]).Error; err != nil {
|
||||
t.Fatalf("create favorite %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
svc := NewPlaybackService(zap.NewNop(), repos)
|
||||
items, err := svc.ListFavourites(context.Background(), userID)
|
||||
if err != nil {
|
||||
t.Fatalf("ListFavourites: %v", err)
|
||||
}
|
||||
if len(items) != 1 {
|
||||
t.Fatalf("expected one hydrated local favourite without remote service, got %d: %#v", len(items), items)
|
||||
}
|
||||
if items[0].ID != local.ID {
|
||||
t.Fatalf("expected local favourite first by created_at desc, got %#v", items[0])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user