Publish current app and server

This commit is contained in:
ponzischeme89
2026-08-02 22:10:19 +12:00
parent a265636139
commit 1ed180c739
203 changed files with 23933 additions and 2788 deletions
+74 -41
View File
@@ -33,6 +33,15 @@ type Credentials struct {
DeviceName string
}
type Device struct {
ID string `json:"Id"`
ReportedDeviceID string `json:"ReportedDeviceId"`
}
type DevicesResult struct {
Items []Device `json:"Items"`
}
type ItemsResult struct {
Items []json.RawMessage `json:"Items"`
TotalRecordCount int `json:"TotalRecordCount"`
@@ -57,10 +66,15 @@ type User struct {
// Summary is the minimal view of an item the gateway needs for its own logic.
type Summary struct {
ID string `json:"Id"`
Name string `json:"Name"`
Type string `json:"Type"`
UserData struct {
ID string `json:"Id"`
Name string `json:"Name"`
Type string `json:"Type"`
Overview string `json:"Overview"`
SeriesName string `json:"SeriesName"`
RunTimeTicks int64 `json:"RunTimeTicks"`
ParentIndexNumber int `json:"ParentIndexNumber"`
IndexNumber int `json:"IndexNumber"`
UserData struct {
PlaybackPositionTicks int64 `json:"PlaybackPositionTicks"`
} `json:"UserData"`
}
@@ -71,10 +85,13 @@ type PlaybackInfo struct {
}
type MediaSourceInfo struct {
ID string `json:"Id"`
MediaStreams []MediaStream `json:"MediaStreams"`
DirectStreamURL string `json:"DirectStreamUrl"`
TranscodingURL string `json:"TranscodingUrl"`
ID string `json:"Id"`
MediaStreams []MediaStream `json:"MediaStreams"`
SupportsDirectPlay bool `json:"SupportsDirectPlay"`
SupportsDirectStream bool `json:"SupportsDirectStream"`
SupportsTranscoding bool `json:"SupportsTranscoding"`
DirectStreamURL string `json:"DirectStreamUrl"`
TranscodingURL string `json:"TranscodingUrl"`
}
type MediaStream struct {
@@ -152,6 +169,38 @@ func (c *Client) Logout(ctx context.Context, cred Credentials) error {
return c.do(req, nil)
}
// DeleteDevice removes the persistent Emby device record whose client-supplied ID
// matches reportedDeviceID. Logging out only revokes the access token; Emby deliberately
// keeps the device in its dashboard until the record itself is deleted.
func (c *Client) DeleteDevice(
ctx context.Context,
cred Credentials,
reportedDeviceID string,
) error {
req, err := c.newRequest(ctx, http.MethodGet, "/Devices", nil, cred, nil)
if err != nil {
return err
}
var devices DevicesResult
if err := c.do(req, &devices); err != nil {
return err
}
for _, device := range devices.Items {
if device.ReportedDeviceID != reportedDeviceID || device.ID == "" {
continue
}
params := url.Values{"Id": {device.ID}}
req, err := c.newRequest(ctx, http.MethodDelete, "/Devices", params, cred, nil)
if err != nil {
return err
}
if err := c.do(req, nil); err != nil {
return err
}
}
return nil
}
// Users returns the household accounts visible to an administrative/service token.
// It is used only by the background For You builder, never on a television request.
func (c *Client) Users(ctx context.Context, cred Credentials) ([]User, error) {
@@ -225,6 +274,8 @@ func (c *Client) PlaybackInfo(
startTicks int64,
subtitleStreamIndex *int,
currentPlaySessionID string,
forceTranscode bool,
capabilities PlaybackCapabilities,
) (*PlaybackInfo, error) {
params := url.Values{
"UserId": {cred.UserID},
@@ -232,39 +283,10 @@ func (c *Client) PlaybackInfo(
}
body, err := json.Marshal(map[string]any{
"Id": itemID, "UserId": cred.UserID, "IsPlayback": true,
"StartTimeTicks": startTicks,
"DeviceProfile": map[string]any{
"Name": "Memby Android TV", "SupportedMediaTypes": "Video",
"DirectPlayProfiles": []map[string]string{
{
"Container": "mkv,mp4,m4v,mov,webm,ts,mpegts,avi",
"VideoCodec": "h264,hevc,vp8,vp9,av1,mpeg2video,mpeg4",
"AudioCodec": "aac,ac3,eac3,mp3,opus,vorbis,flac,pcm",
"Type": "Video",
},
},
"TranscodingProfiles": []map[string]string{
{
"Container": "ts", "VideoCodec": "h264", "AudioCodec": "aac",
"Protocol": "hls", "Type": "Video", "Context": "Streaming",
},
},
"SubtitleProfiles": []map[string]string{
{"Format": "srt", "Method": "External"},
{"Format": "subrip", "Method": "External"},
{"Format": "ass", "Method": "External"},
{"Format": "ssa", "Method": "External"},
{"Format": "vtt", "Method": "External"},
{"Format": "webvtt", "Method": "External"},
{"Format": "mov_text", "Method": "External"},
{"Format": "tx3g", "Method": "External"},
{"Format": "pgs", "Method": "Encode"},
{"Format": "pgssub", "Method": "Encode"},
{"Format": "sup", "Method": "Encode"},
{"Format": "vobsub", "Method": "Encode"},
{"Format": "dvdsub", "Method": "Encode"},
},
},
"StartTimeTicks": startTicks, "EnableDirectPlay": !forceTranscode,
"EnableDirectStream": !forceTranscode, "EnableTranscoding": true,
"AllowVideoStreamCopy": true, "AllowAudioStreamCopy": true,
"DeviceProfile": androidTVDeviceProfile(capabilities),
})
var requestBody map[string]any
if err == nil {
@@ -276,6 +298,10 @@ func (c *Client) PlaybackInfo(
if currentPlaySessionID != "" {
requestBody["CurrentPlaySessionId"] = currentPlaySessionID
}
if forceTranscode {
profile := requestBody["DeviceProfile"].(map[string]any)
profile["DirectPlayProfiles"] = []map[string]string{}
}
if err == nil {
body, err = json.Marshal(requestBody)
}
@@ -301,6 +327,13 @@ func (c *Client) PlaybackInfo(
return &out, nil
}
func directPlayVideoCodecs(supportsHEVC bool) string {
if supportsHEVC {
return "h264,hevc"
}
return "h264"
}
func (c *Client) ResumeItems(ctx context.Context, cred Credentials, params url.Values) (*ItemsResult, error) {
return c.items(ctx, cred, "/Users/"+url.PathEscape(cred.UserID)+"/Items/Resume", params)
}