Files
silo-server/internal/jellycompat/playback_subtitle_auth_test.go
T

141 lines
4.3 KiB
Go

package jellycompat
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
"github.com/go-chi/chi/v5"
"github.com/Silo-Server/silo-server/internal/catalog"
"github.com/Silo-Server/silo-server/internal/models"
"github.com/Silo-Server/silo-server/internal/subtitles"
)
type fakeSubtitleRepository struct {
downloaded map[int][]subtitles.DownloadedSubtitle
}
func (r fakeSubtitleRepository) InsertDownloadedSubtitle(context.Context, *subtitles.DownloadedSubtitle) error {
panic("unused")
}
func (r fakeSubtitleRepository) GetDownloadedSubtitle(context.Context, int) (*subtitles.DownloadedSubtitle, error) {
panic("unused")
}
func (r fakeSubtitleRepository) ListDownloadedSubtitles(_ context.Context, mediaFileID int) ([]subtitles.DownloadedSubtitle, error) {
return r.downloaded[mediaFileID], nil
}
func (r fakeSubtitleRepository) UpdateDownloadedSubtitle(context.Context, int, subtitles.SubtitleMetadataUpdate) (*subtitles.DownloadedSubtitle, error) {
panic("unused")
}
func (r fakeSubtitleRepository) DeleteDownloadedSubtitle(context.Context, int) (*subtitles.DownloadedSubtitle, error) {
panic("unused")
}
func (r fakeSubtitleRepository) GetDownloadedSubtitleByS3Key(context.Context, string) (*subtitles.DownloadedSubtitle, error) {
panic("unused")
}
func (r fakeSubtitleRepository) ListProviderConfigs(context.Context) ([]subtitles.ProviderConfig, error) {
panic("unused")
}
func (r fakeSubtitleRepository) GetProviderConfig(context.Context, string) (*subtitles.ProviderConfig, error) {
panic("unused")
}
func (r fakeSubtitleRepository) UpsertProviderConfig(context.Context, *subtitles.ProviderConfig) error {
panic("unused")
}
func TestHandlePlaybackInfo_AuthenticatesSubtitleDeliveryURLs(t *testing.T) {
codec := NewResourceIDCodec()
contentID := "movie-1"
routeID := codec.EncodeStringID(EncodedIDItem, contentID)
version := catalog.FileVersion{
FileID: 42,
Duration: 3600,
Container: "mkv",
Bitrate: 8000,
VideoTracks: []models.VideoTrack{
{Codec: "h264", Width: 1920, Height: 1080},
},
AudioTracks: []models.AudioTrack{
{Codec: "aac", Default: true, Title: "Main"},
},
SubtitleTracks: []catalog.VersionSubtitleTrack{
{Index: 2, Codec: "subrip", Language: "eng", Title: "English"},
{Codec: "srt", Language: "spa", Title: "Spanish", External: true},
},
}
handler := &PlaybackHandler{
content: &stubContentService{detail: &upstreamItemDetail{
ContentID: contentID,
Versions: []catalog.FileVersion{version},
}},
codec: codec,
deviceProfiles: NewDeviceProfileStore(time.Hour, nil),
playbackStore: NewPlaybackSessionStore(time.Hour, nil),
SubtitleRepo: fakeSubtitleRepository{downloaded: map[int][]subtitles.DownloadedSubtitle{
42: {
{MediaFileID: 42, Language: "fre", Format: subtitles.FormatSRT, Provider: "opensubtitles"},
},
}},
}
req := httptest.NewRequest(http.MethodPost, "/Items/"+routeID+"/PlaybackInfo", strings.NewReader(`{}`))
routeCtx := chi.NewRouteContext()
routeCtx.URLParams.Add("id", routeID)
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, routeCtx))
req = req.WithContext(context.WithValue(req.Context(), compatSessionKey, &Session{Token: "token-1"}))
rr := httptest.NewRecorder()
handler.HandlePlaybackInfo(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("status = %d, body = %s", rr.Code, rr.Body.String())
}
var resp playbackInfoResponseDTO
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
t.Fatalf("unmarshal response: %v", err)
}
if len(resp.MediaSources) != 1 {
t.Fatalf("media sources = %d, want 1", len(resp.MediaSources))
}
subtitleURLs := make([]string, 0, 3)
for _, stream := range resp.MediaSources[0].MediaStreams {
if stream.Type == "Subtitle" {
subtitleURLs = append(subtitleURLs, stream.DeliveryURL)
}
}
if len(subtitleURLs) != 3 {
t.Fatalf("subtitle URLs = %d, want 3: %#v", len(subtitleURLs), subtitleURLs)
}
for _, rawURL := range subtitleURLs {
parsed, err := url.Parse(rawURL)
if err != nil {
t.Fatalf("parse subtitle URL %q: %v", rawURL, err)
}
query := parsed.Query()
if got := query.Get("api_key"); got != "token-1" {
t.Fatalf("api_key for %q = %q, want token-1", rawURL, got)
}
if got := query.Get("PlaySessionId"); got != resp.PlaySessionID {
t.Fatalf("PlaySessionId for %q = %q, want %q", rawURL, got, resp.PlaySessionID)
}
}
}