Build and publish / Test and build (darwin) (push) Failing after 1m42s
Build and publish / Test and build (linux) (push) Failing after 1m53s
Build and publish / Test and build (windows) (push) Failing after 2m50s
Build and publish / Build and publish Docker image (push) Skipped
Go rewrite of the Python Emby.MCP server with tool parity (20 tools), plus a streamable-HTTP transport with per-request Emby authentication (Basic / Bearer token passthrough), a multi-arch Docker build, and a Gitea CI workflow.
124 lines
3.8 KiB
Go
124 lines
3.8 KiB
Go
package emby
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestGetPlayerSessions(t *testing.T) {
|
|
c, srv := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
|
|
if got := r.URL.Query().Get("ControllableByUserId"); got != "u1" {
|
|
t.Errorf("ControllableByUserId = %q", got)
|
|
}
|
|
json.NewEncoder(w).Encode([]map[string]any{
|
|
{
|
|
"Client": "Emby Web", "Id": "s1", "DeviceId": "d1",
|
|
"DeviceName": "Chrome", "RemoteEndPoint": "127.0.0.1",
|
|
"PlayableMediaTypes": []string{"Audio", "Video"},
|
|
"NowPlayingItem": map[string]any{
|
|
"Name": "Track", "Id": "i1", "Artists": []string{"A"},
|
|
"Album": "Alb", "RunTimeTicks": 36610000000,
|
|
},
|
|
"PlayState": map[string]any{"PositionTicks": 610000000, "IsPaused": true},
|
|
},
|
|
{"Client": "Idle", "Id": "s2", "PlayableMediaTypes": []string{}},
|
|
})
|
|
})
|
|
defer srv.Close()
|
|
ss, err := c.GetPlayerSessions(context.Background(), "u1", "audio")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(ss) != 1 {
|
|
t.Fatalf("sessions = %+v", ss)
|
|
}
|
|
s := ss[0]
|
|
if !s.LocalToMediaServer {
|
|
t.Error("expected local_to_media_server true for 127.0.0.1")
|
|
}
|
|
if s.NowPlayingTitle != "Track" || s.NowPlayingTotalTime != "01:01:01" {
|
|
t.Errorf("now_playing = %+v", s)
|
|
}
|
|
if s.NowPlayingPositionMilliseconds == nil || *s.NowPlayingPositionMilliseconds != 61000 {
|
|
t.Errorf("position = %v", s.NowPlayingPositionMilliseconds)
|
|
}
|
|
if s.NowPlayingIsPaused == nil || !*s.NowPlayingIsPaused {
|
|
t.Error("expected is_paused")
|
|
}
|
|
}
|
|
|
|
func TestGetPlayerSessionsMediaTypeFilter(t *testing.T) {
|
|
c, srv := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewEncoder(w).Encode([]map[string]any{
|
|
{"Client": "A", "Id": "s1", "PlayableMediaTypes": []string{"Video"}},
|
|
{"Client": "B", "Id": "s2", "PlayableMediaTypes": []string{"Audio"}},
|
|
})
|
|
})
|
|
defer srv.Close()
|
|
ss, _ := c.GetPlayerSessions(context.Background(), "", "Audio")
|
|
if len(ss) != 1 || ss[0].SessionID != "s2" {
|
|
t.Fatalf("sessions = %+v", ss)
|
|
}
|
|
}
|
|
|
|
func TestSendPlayerCommandPlayNow(t *testing.T) {
|
|
var path, q string
|
|
var body map[string]any
|
|
c, srv := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
|
|
path, q = r.URL.Path, r.URL.RawQuery
|
|
json.NewDecoder(r.Body).Decode(&body)
|
|
w.WriteHeader(200)
|
|
})
|
|
defer srv.Close()
|
|
err := c.SendPlayerCommand(context.Background(), "s1", "PlayNow", "i1,i2", "u1", 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if path != "/Sessions/s1/Playing" {
|
|
t.Errorf("path = %s", path)
|
|
}
|
|
if !strings.Contains(q, "Ids=i1%2Ci2") || !strings.Contains(q, "PlayCommand=PlayNow") {
|
|
t.Errorf("query = %s", q)
|
|
}
|
|
}
|
|
|
|
func TestSendPlayerCommandRewindBecomesSeekRelative(t *testing.T) {
|
|
var path string
|
|
var body map[string]any
|
|
c, srv := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
|
|
path = r.URL.Path
|
|
json.NewDecoder(r.Body).Decode(&body)
|
|
w.WriteHeader(200)
|
|
})
|
|
defer srv.Close()
|
|
if err := c.SendPlayerCommand(context.Background(), "s1", "Rewind", "", "u1", 0); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if path != "/Sessions/s1/Playing/SeekRelative" {
|
|
t.Errorf("path = %s", path)
|
|
}
|
|
if body["Command"] != "SeekRelative" || body["SeekPositionTicks"] != float64(-30000*10000) {
|
|
t.Errorf("body = %v", body)
|
|
}
|
|
if body["ControllingUserId"] != "u1" {
|
|
t.Errorf("body = %v", body)
|
|
}
|
|
}
|
|
|
|
func TestSendPlayerCommandValidation(t *testing.T) {
|
|
c, srv := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {})
|
|
defer srv.Close()
|
|
if err := c.SendPlayerCommand(context.Background(), "s1", "PlayNow", "", "u1", 0); err == nil {
|
|
t.Error("expected item_ids error")
|
|
}
|
|
if err := c.SendPlayerCommand(context.Background(), "s1", "Bogus", "", "u1", 0); err == nil {
|
|
t.Error("expected unsupported command error")
|
|
}
|
|
if err := c.SendPlayerCommand(context.Background(), "s1", "Pause", "", "", 0); err == nil {
|
|
t.Error("expected user_id error")
|
|
}
|
|
}
|