0.2.65 - End Credits wiring / Gateway: 0.1.45 - Credits
This commit is contained in:
@@ -24,6 +24,7 @@ import (
|
||||
type Client struct {
|
||||
baseURL string
|
||||
publicURL string
|
||||
mediaURL string
|
||||
clientName string
|
||||
// gatewayClientName identifies the requests the gateway makes on its own behalf, so
|
||||
// Emby's device list separates a television from the server standing behind it. The
|
||||
@@ -72,8 +73,17 @@ type ItemsResult struct {
|
||||
|
||||
type AuthResult struct {
|
||||
User struct {
|
||||
ID string `json:"Id"`
|
||||
Name string `json:"Name"`
|
||||
ID string `json:"Id"`
|
||||
Name string `json:"Name"`
|
||||
Policy struct {
|
||||
// IsAdministrator is a pointer because "Emby says this person is not an
|
||||
// administrator" and "Emby did not answer the question" are different facts
|
||||
// that must be acted on differently: the first refuses the console, the second
|
||||
// is worth asking again rather than locking an operator out of their own
|
||||
// server. Emby returns the policy in the authentication response itself, so
|
||||
// the ordinary path costs no extra request.
|
||||
IsAdministrator *bool `json:"IsAdministrator"`
|
||||
} `json:"Policy"`
|
||||
} `json:"User"`
|
||||
AccessToken string `json:"AccessToken"`
|
||||
ServerID string `json:"ServerId"`
|
||||
@@ -83,7 +93,8 @@ type User struct {
|
||||
ID string `json:"Id"`
|
||||
Name string `json:"Name"`
|
||||
Policy struct {
|
||||
IsDisabled bool `json:"IsDisabled"`
|
||||
IsDisabled bool `json:"IsDisabled"`
|
||||
IsAdministrator bool `json:"IsAdministrator"`
|
||||
} `json:"Policy"`
|
||||
}
|
||||
|
||||
@@ -174,6 +185,18 @@ func New(baseURL, publicURL, clientName, gatewayClientName string, timeout time.
|
||||
}
|
||||
}
|
||||
|
||||
// SetMediaURL names the address server-side media reads go to, which is only ever credits
|
||||
// detection. Unset — or set to nothing — media reads use the same address as metadata.
|
||||
//
|
||||
// A setter rather than a constructor argument because it is one deployment's answer to one
|
||||
// subsystem's problem, and threading it through four test call sites that will never use it
|
||||
// would be paying for it everywhere to spend it in one place. Call it during start-up,
|
||||
// before anything is serving: nothing here is synchronised, for the same reason the client's
|
||||
// other addresses are not.
|
||||
func (c *Client) SetMediaURL(mediaURL string) {
|
||||
c.mediaURL = strings.TrimRight(strings.TrimSpace(mediaURL), "/")
|
||||
}
|
||||
|
||||
// Authenticate signs a television in. cred carries the device the record is created for
|
||||
// and that set's ClientVersion — Emby stamps it on the record, so an empty one leaves the
|
||||
// entry claiming the gateway's own build. cred.Gateway marks a sign-in the gateway is
|
||||
@@ -247,6 +270,22 @@ func (c *Client) DeleteDevice(
|
||||
return nil
|
||||
}
|
||||
|
||||
// UserByID reads one account with that account's own token. It exists for the admin gate
|
||||
// and is asked only when an authentication response carried no policy at all, which is
|
||||
// why it takes the credentials it does: the question is "who did I just authenticate",
|
||||
// and an Emby user may always read themselves.
|
||||
func (c *Client) UserByID(ctx context.Context, cred Credentials, userID string) (*User, error) {
|
||||
req, err := c.newRequest(ctx, http.MethodGet, "/Users/"+url.PathEscape(userID), nil, cred, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var user User
|
||||
if err := c.do(req, &user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user, 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) {
|
||||
@@ -593,19 +632,29 @@ func (c *Client) StreamURL(cred Credentials, itemID string) string {
|
||||
return fmt.Sprintf("%s/Videos/%s/stream?%s", c.publicURL, url.PathEscape(itemID), params.Encode())
|
||||
}
|
||||
|
||||
// InternalStreamURL is the same file, addressed the way the *gateway* reaches Emby rather
|
||||
// InternalStreamURL is the same file, addressed the way the *gateway* reads bytes rather
|
||||
// than the way a television does.
|
||||
//
|
||||
// It exists for credits detection, which is the only thing that reads media bytes on the
|
||||
// server side. Using StreamURL there would send a ranged read out to the public address and
|
||||
// back in through the reverse proxy — the two containers are on the same network, and a scan
|
||||
// has no business leaving it. Nothing here is ever handed to a client.
|
||||
// server side, and it reads them as ranged requests over the tail of a file. Using StreamURL
|
||||
// there would send every one of those out to the public address and back in through the
|
||||
// reverse proxy — and where a proxy buffers the response, the ranged read stops being a
|
||||
// ranged read and the whole economy of the scan is gone. Nothing here is ever handed to a
|
||||
// client.
|
||||
//
|
||||
// mediaURL is preferred and baseURL is the fallback, because how the gateway reaches Emby
|
||||
// for *metadata* is not evidence about the best path for megabytes: a deployment whose
|
||||
// MEMBY_EMBY_URL is a public hostname is an ordinary one, not a misconfiguration.
|
||||
func (c *Client) InternalStreamURL(cred Credentials, itemID string) string {
|
||||
host := c.mediaURL
|
||||
if host == "" {
|
||||
host = c.baseURL
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("static", "true")
|
||||
params.Set("api_key", cred.Token)
|
||||
params.Set("DeviceId", cred.DeviceID)
|
||||
return fmt.Sprintf("%s/Videos/%s/stream?%s", c.baseURL, url.PathEscape(itemID), params.Encode())
|
||||
return fmt.Sprintf("%s/Videos/%s/stream?%s", host, url.PathEscape(itemID), params.Encode())
|
||||
}
|
||||
|
||||
// DeliveryURL converts a PlaybackInfo URL into a TV-reachable, authenticated URL.
|
||||
|
||||
Reference in New Issue
Block a user