Compare commits

...

2 Commits

Author SHA1 Message Date
speakeasy-github[bot]
2cfb7aefac chore: update dependencies 2024-02-23 14:47:13 +00:00
speakeasybot
41ce744f6d ci: regenerated with OpenAPI Doc 0.0.3, Speakeasy CLI 1.193.0 2024-02-23 14:46:43 +00:00
52 changed files with 3002 additions and 963 deletions

View File

@@ -1,29 +1,29 @@
lockVersion: 2.0.0 lockVersion: 2.0.0
id: dfa99515-01c0-42eb-9be5-ee212fd03eb3 id: dfa99515-01c0-42eb-9be5-ee212fd03eb3
management: management:
docChecksum: 099fc5bbb987ae7e391f7f07b4212860 docChecksum: 278d186496d83d5830ba4870f8cad39d
docVersion: 0.0.3 docVersion: 0.0.3
speakeasyVersion: internal speakeasyVersion: internal
generationVersion: 2.249.1 generationVersion: 2.269.0
releaseVersion: 0.3.0 releaseVersion: 0.4.0
configChecksum: ae48b3df080bde21a30ed099e1ffc0d8 configChecksum: 319de8bf53c668d84b706d9496459b7c
repoURL: https://github.com/LukeHagar/plexgo.git repoURL: https://github.com/LukeHagar/plexgo.git
repoSubDirectory: . repoSubDirectory: .
installationURL: https://github.com/LukeHagar/plexgo installationURL: https://github.com/LukeHagar/plexgo
published: true published: true
features: features:
go: go:
constsAndDefaults: 0.1.2 constsAndDefaults: 0.1.3
core: 3.3.2 core: 3.4.1
flattening: 2.81.1 flattening: 2.81.1
globalSecurity: 2.82.6 globalSecurity: 2.82.6
globalServerURLs: 2.82.1 globalServerURLs: 2.82.1
methodServerURLs: 2.82.1 methodServerURLs: 2.82.1
nameOverrides: 2.81.1 nameOverrides: 2.81.1
unions: 2.85.2
generatedFiles: generatedFiles:
- server.go - server.go
- media.go - media.go
- video.go
- activities.go - activities.go
- butler.go - butler.go
- hubs.go - hubs.go
@@ -33,12 +33,11 @@ generatedFiles:
- plex.go - plex.go
- playlists.go - playlists.go
- security.go - security.go
- statistics.go
- sessions.go - sessions.go
- updater.go - updater.go
- video.go
- plexapi.go - plexapi.go
- go.mod - go.mod
- go.sum
- models/sdkerrors/sdkerror.go - models/sdkerrors/sdkerror.go
- types/bigint.go - types/bigint.go
- types/date.go - types/date.go
@@ -66,6 +65,8 @@ generatedFiles:
- /models/operations/markplayed.go - /models/operations/markplayed.go
- /models/operations/markunplayed.go - /models/operations/markunplayed.go
- /models/operations/updateplayprogress.go - /models/operations/updateplayprogress.go
- /models/operations/gettimeline.go
- /models/operations/startuniversaltranscode.go
- /models/operations/getserveractivities.go - /models/operations/getserveractivities.go
- /models/operations/cancelserveractivities.go - /models/operations/cancelserveractivities.go
- /models/operations/getbutlertasks.go - /models/operations/getbutlertasks.go
@@ -105,6 +106,7 @@ generatedFiles:
- /models/operations/uploadplaylist.go - /models/operations/uploadplaylist.go
- /models/operations/gettransienttoken.go - /models/operations/gettransienttoken.go
- /models/operations/getsourceconnectioninformation.go - /models/operations/getsourceconnectioninformation.go
- /models/operations/getstatistics.go
- /models/operations/getsessions.go - /models/operations/getsessions.go
- /models/operations/getsessionhistory.go - /models/operations/getsessionhistory.go
- /models/operations/gettranscodesessions.go - /models/operations/gettranscodesessions.go
@@ -112,8 +114,6 @@ generatedFiles:
- /models/operations/getupdatestatus.go - /models/operations/getupdatestatus.go
- /models/operations/checkforupdates.go - /models/operations/checkforupdates.go
- /models/operations/applyupdates.go - /models/operations/applyupdates.go
- /models/operations/startuniversaltranscode.go
- /models/operations/gettimeline.go
- /models/sdkerrors/getservercapabilities.go - /models/sdkerrors/getservercapabilities.go
- /models/sdkerrors/getserverpreferences.go - /models/sdkerrors/getserverpreferences.go
- /models/sdkerrors/getavailableclients.go - /models/sdkerrors/getavailableclients.go
@@ -125,6 +125,8 @@ generatedFiles:
- /models/sdkerrors/markplayed.go - /models/sdkerrors/markplayed.go
- /models/sdkerrors/markunplayed.go - /models/sdkerrors/markunplayed.go
- /models/sdkerrors/updateplayprogress.go - /models/sdkerrors/updateplayprogress.go
- /models/sdkerrors/gettimeline.go
- /models/sdkerrors/startuniversaltranscode.go
- /models/sdkerrors/getserveractivities.go - /models/sdkerrors/getserveractivities.go
- /models/sdkerrors/cancelserveractivities.go - /models/sdkerrors/cancelserveractivities.go
- /models/sdkerrors/getbutlertasks.go - /models/sdkerrors/getbutlertasks.go
@@ -162,6 +164,7 @@ generatedFiles:
- /models/sdkerrors/uploadplaylist.go - /models/sdkerrors/uploadplaylist.go
- /models/sdkerrors/gettransienttoken.go - /models/sdkerrors/gettransienttoken.go
- /models/sdkerrors/getsourceconnectioninformation.go - /models/sdkerrors/getsourceconnectioninformation.go
- /models/sdkerrors/getstatistics.go
- /models/sdkerrors/getsessions.go - /models/sdkerrors/getsessions.go
- /models/sdkerrors/getsessionhistory.go - /models/sdkerrors/getsessionhistory.go
- /models/sdkerrors/gettranscodesessions.go - /models/sdkerrors/gettranscodesessions.go
@@ -169,15 +172,11 @@ generatedFiles:
- /models/sdkerrors/getupdatestatus.go - /models/sdkerrors/getupdatestatus.go
- /models/sdkerrors/checkforupdates.go - /models/sdkerrors/checkforupdates.go
- /models/sdkerrors/applyupdates.go - /models/sdkerrors/applyupdates.go
- /models/sdkerrors/startuniversaltranscode.go
- /models/sdkerrors/gettimeline.go
- /models/components/security.go - /models/components/security.go
- docs/models/operations/directory.md - docs/models/operations/directory.md
- docs/models/operations/mediacontainer.md - docs/models/operations/mediacontainer.md
- docs/models/operations/getservercapabilitiesresponsebody.md - docs/models/operations/getservercapabilitiesresponsebody.md
- docs/models/operations/getservercapabilitiesresponse.md - docs/models/operations/getservercapabilitiesresponse.md
- docs/models/operations/two.md
- docs/models/operations/one.md
- docs/models/operations/setting.md - docs/models/operations/setting.md
- docs/models/operations/getserverpreferencesmediacontainer.md - docs/models/operations/getserverpreferencesmediacontainer.md
- docs/models/operations/getserverpreferencesresponsebody.md - docs/models/operations/getserverpreferencesresponsebody.md
@@ -210,6 +209,11 @@ generatedFiles:
- docs/models/operations/markunplayedresponse.md - docs/models/operations/markunplayedresponse.md
- docs/models/operations/updateplayprogressrequest.md - docs/models/operations/updateplayprogressrequest.md
- docs/models/operations/updateplayprogressresponse.md - docs/models/operations/updateplayprogressresponse.md
- docs/models/operations/state.md
- docs/models/operations/gettimelinerequest.md
- docs/models/operations/gettimelineresponse.md
- docs/models/operations/startuniversaltranscoderequest.md
- docs/models/operations/startuniversaltranscoderesponse.md
- docs/models/operations/context.md - docs/models/operations/context.md
- docs/models/operations/activity.md - docs/models/operations/activity.md
- docs/models/operations/getserveractivitiesmediacontainer.md - docs/models/operations/getserveractivitiesmediacontainer.md
@@ -413,6 +417,13 @@ generatedFiles:
- docs/models/operations/gettransienttokenresponse.md - docs/models/operations/gettransienttokenresponse.md
- docs/models/operations/getsourceconnectioninformationrequest.md - docs/models/operations/getsourceconnectioninformationrequest.md
- docs/models/operations/getsourceconnectioninformationresponse.md - docs/models/operations/getsourceconnectioninformationresponse.md
- docs/models/operations/getstatisticsrequest.md
- docs/models/operations/getstatisticsdevice.md
- docs/models/operations/account.md
- docs/models/operations/statisticsmedia.md
- docs/models/operations/getstatisticsmediacontainer.md
- docs/models/operations/getstatisticsresponsebody.md
- docs/models/operations/getstatisticsresponse.md
- docs/models/operations/getsessionsstream.md - docs/models/operations/getsessionsstream.md
- docs/models/operations/getsessionspart.md - docs/models/operations/getsessionspart.md
- docs/models/operations/getsessionsmedia.md - docs/models/operations/getsessionsmedia.md
@@ -444,11 +455,6 @@ generatedFiles:
- docs/models/operations/skip.md - docs/models/operations/skip.md
- docs/models/operations/applyupdatesrequest.md - docs/models/operations/applyupdatesrequest.md
- docs/models/operations/applyupdatesresponse.md - docs/models/operations/applyupdatesresponse.md
- docs/models/operations/startuniversaltranscoderequest.md
- docs/models/operations/startuniversaltranscoderesponse.md
- docs/models/operations/state.md
- docs/models/operations/gettimelinerequest.md
- docs/models/operations/gettimelineresponse.md
- docs/models/sdkerrors/errors.md - docs/models/sdkerrors/errors.md
- docs/models/sdkerrors/getservercapabilitiesresponsebody.md - docs/models/sdkerrors/getservercapabilitiesresponsebody.md
- docs/models/sdkerrors/getserverpreferenceserrors.md - docs/models/sdkerrors/getserverpreferenceserrors.md
@@ -471,6 +477,10 @@ generatedFiles:
- docs/models/sdkerrors/markunplayedresponsebody.md - docs/models/sdkerrors/markunplayedresponsebody.md
- docs/models/sdkerrors/updateplayprogresserrors.md - docs/models/sdkerrors/updateplayprogresserrors.md
- docs/models/sdkerrors/updateplayprogressresponsebody.md - docs/models/sdkerrors/updateplayprogressresponsebody.md
- docs/models/sdkerrors/gettimelineerrors.md
- docs/models/sdkerrors/gettimelineresponsebody.md
- docs/models/sdkerrors/startuniversaltranscodeerrors.md
- docs/models/sdkerrors/startuniversaltranscoderesponsebody.md
- docs/models/sdkerrors/getserveractivitieserrors.md - docs/models/sdkerrors/getserveractivitieserrors.md
- docs/models/sdkerrors/getserveractivitiesresponsebody.md - docs/models/sdkerrors/getserveractivitiesresponsebody.md
- docs/models/sdkerrors/cancelserveractivitieserrors.md - docs/models/sdkerrors/cancelserveractivitieserrors.md
@@ -545,6 +555,8 @@ generatedFiles:
- docs/models/sdkerrors/gettransienttokenresponsebody.md - docs/models/sdkerrors/gettransienttokenresponsebody.md
- docs/models/sdkerrors/getsourceconnectioninformationerrors.md - docs/models/sdkerrors/getsourceconnectioninformationerrors.md
- docs/models/sdkerrors/getsourceconnectioninformationresponsebody.md - docs/models/sdkerrors/getsourceconnectioninformationresponsebody.md
- docs/models/sdkerrors/getstatisticserrors.md
- docs/models/sdkerrors/getstatisticsresponsebody.md
- docs/models/sdkerrors/getsessionserrors.md - docs/models/sdkerrors/getsessionserrors.md
- docs/models/sdkerrors/getsessionsresponsebody.md - docs/models/sdkerrors/getsessionsresponsebody.md
- docs/models/sdkerrors/getsessionhistoryerrors.md - docs/models/sdkerrors/getsessionhistoryerrors.md
@@ -559,14 +571,11 @@ generatedFiles:
- docs/models/sdkerrors/checkforupdatesresponsebody.md - docs/models/sdkerrors/checkforupdatesresponsebody.md
- docs/models/sdkerrors/applyupdateserrors.md - docs/models/sdkerrors/applyupdateserrors.md
- docs/models/sdkerrors/applyupdatesresponsebody.md - docs/models/sdkerrors/applyupdatesresponsebody.md
- docs/models/sdkerrors/startuniversaltranscodeerrors.md
- docs/models/sdkerrors/startuniversaltranscoderesponsebody.md
- docs/models/sdkerrors/gettimelineerrors.md
- docs/models/sdkerrors/gettimelineresponsebody.md
- docs/models/components/security.md - docs/models/components/security.md
- docs/sdks/plexapi/README.md - docs/sdks/plexapi/README.md
- docs/sdks/server/README.md - docs/sdks/server/README.md
- docs/sdks/media/README.md - docs/sdks/media/README.md
- docs/sdks/video/README.md
- docs/sdks/activities/README.md - docs/sdks/activities/README.md
- docs/sdks/butler/README.md - docs/sdks/butler/README.md
- docs/sdks/hubs/README.md - docs/sdks/hubs/README.md
@@ -577,9 +586,10 @@ generatedFiles:
- docs/sdks/plex/README.md - docs/sdks/plex/README.md
- docs/sdks/playlists/README.md - docs/sdks/playlists/README.md
- docs/sdks/security/README.md - docs/sdks/security/README.md
- docs/sdks/statistics/README.md
- docs/sdks/sessions/README.md - docs/sdks/sessions/README.md
- docs/sdks/updater/README.md - docs/sdks/updater/README.md
- docs/sdks/video/README.md
- USAGE.md - USAGE.md
- models/operations/options.go - models/operations/options.go
- .gitattributes - .gitattributes
- internal/hooks/hooks.go

View File

@@ -69,6 +69,11 @@ func main() {
* [MarkUnplayed](docs/sdks/media/README.md#markunplayed) - Mark Media Unplayed * [MarkUnplayed](docs/sdks/media/README.md#markunplayed) - Mark Media Unplayed
* [UpdatePlayProgress](docs/sdks/media/README.md#updateplayprogress) - Update Media Play Progress * [UpdatePlayProgress](docs/sdks/media/README.md#updateplayprogress) - Update Media Play Progress
### [Video](docs/sdks/video/README.md)
* [GetTimeline](docs/sdks/video/README.md#gettimeline) - Get the timeline for a media item
* [StartUniversalTranscode](docs/sdks/video/README.md#startuniversaltranscode) - Start Universal Transcode
### [Activities](docs/sdks/activities/README.md) ### [Activities](docs/sdks/activities/README.md)
* [GetServerActivities](docs/sdks/activities/README.md#getserveractivities) - Get Server Activities * [GetServerActivities](docs/sdks/activities/README.md#getserveractivities) - Get Server Activities
@@ -135,6 +140,10 @@ func main() {
* [GetTransientToken](docs/sdks/security/README.md#gettransienttoken) - Get a Transient Token. * [GetTransientToken](docs/sdks/security/README.md#gettransienttoken) - Get a Transient Token.
* [GetSourceConnectionInformation](docs/sdks/security/README.md#getsourceconnectioninformation) - Get Source Connection Information * [GetSourceConnectionInformation](docs/sdks/security/README.md#getsourceconnectioninformation) - Get Source Connection Information
### [Statistics](docs/sdks/statistics/README.md)
* [GetStatistics](docs/sdks/statistics/README.md#getstatistics) - Get Media Statistics
### [Sessions](docs/sdks/sessions/README.md) ### [Sessions](docs/sdks/sessions/README.md)
* [GetSessions](docs/sdks/sessions/README.md#getsessions) - Get Active Sessions * [GetSessions](docs/sdks/sessions/README.md#getsessions) - Get Active Sessions
@@ -147,11 +156,6 @@ func main() {
* [GetUpdateStatus](docs/sdks/updater/README.md#getupdatestatus) - Querying status of updates * [GetUpdateStatus](docs/sdks/updater/README.md#getupdatestatus) - Querying status of updates
* [CheckForUpdates](docs/sdks/updater/README.md#checkforupdates) - Checking for updates * [CheckForUpdates](docs/sdks/updater/README.md#checkforupdates) - Checking for updates
* [ApplyUpdates](docs/sdks/updater/README.md#applyupdates) - Apply Updates * [ApplyUpdates](docs/sdks/updater/README.md#applyupdates) - Apply Updates
### [Video](docs/sdks/video/README.md)
* [StartUniversalTranscode](docs/sdks/video/README.md#startuniversaltranscode) - Start Universal Transcode
* [GetTimeline](docs/sdks/video/README.md#gettimeline) - Get the timeline for a media item
<!-- End Available Resources and Operations [operations] --> <!-- End Available Resources and Operations [operations] -->
<!-- Start Error Handling [errors] --> <!-- Start Error Handling [errors] -->
@@ -303,9 +307,9 @@ func main() {
plexgo.WithSecurity("<YOUR_API_KEY_HERE>"), plexgo.WithSecurity("<YOUR_API_KEY_HERE>"),
) )
var xPlexClientIdentifier string = "string" var xPlexClientIdentifier string = "<value>"
var strong *bool = false var strong *bool = plexgo.Bool(false)
ctx := context.Background() ctx := context.Background()
res, err := s.Plex.GetPin(ctx, operations.WithServerURL("https://plex.tv/api/v2"), xPlexClientIdentifier, strong) res, err := s.Plex.GetPin(ctx, operations.WithServerURL("https://plex.tv/api/v2"), xPlexClientIdentifier, strong)

View File

@@ -119,3 +119,13 @@ Based on:
- [go v0.3.0] . - [go v0.3.0] .
### Releases ### Releases
- [Go v0.3.0] https://github.com/LukeHagar/plexgo/releases/tag/v0.3.0 - . - [Go v0.3.0] https://github.com/LukeHagar/plexgo/releases/tag/v0.3.0 - .
## 2024-02-23 14:46:30
### Changes
Based on:
- OpenAPI Doc 0.0.3
- Speakeasy CLI 1.193.0 (2.269.0) https://github.com/speakeasy-api/speakeasy
### Generated
- [go v0.4.0] .
### Releases
- [Go v0.4.0] https://github.com/LukeHagar/plexgo/releases/tag/v0.4.0 - .

View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Activities are awesome. They provide a way to monitor and control asynchronous operations on the server. In order to receive real-time updates for activities, a client would normally subscribe via either EventSource or Websocket endpoints. // Activities are awesome. They provide a way to monitor and control asynchronous operations on the server. In order to receive real-time updates for activities, a client would normally subscribe via either EventSource or Websocket endpoints.
@@ -34,26 +35,49 @@ func newActivities(sdkConfig sdkConfiguration) *Activities {
// GetServerActivities - Get Server Activities // GetServerActivities - Get Server Activities
// Get Server Activities // Get Server Activities
func (s *Activities) GetServerActivities(ctx context.Context) (*operations.GetServerActivitiesResponse, error) { func (s *Activities) GetServerActivities(ctx context.Context) (*operations.GetServerActivitiesResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getServerActivities"}
url := strings.TrimSuffix(baseURL, "/") + "/activities"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/activities")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetServerActivitiesResponse{ res := &operations.GetServerActivitiesResponse{
@@ -68,6 +92,7 @@ func (s *Activities) GetServerActivities(ctx context.Context) (*operations.GetSe
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -108,33 +133,53 @@ func (s *Activities) GetServerActivities(ctx context.Context) (*operations.GetSe
// CancelServerActivities - Cancel Server Activities // CancelServerActivities - Cancel Server Activities
// Cancel Server Activities // Cancel Server Activities
func (s *Activities) CancelServerActivities(ctx context.Context, activityUUID string) (*operations.CancelServerActivitiesResponse, error) { func (s *Activities) CancelServerActivities(ctx context.Context, activityUUID string) (*operations.CancelServerActivitiesResponse, error) {
hookCtx := hooks.HookContext{OperationID: "cancelServerActivities"}
request := operations.CancelServerActivitiesRequest{ request := operations.CancelServerActivitiesRequest{
ActivityUUID: activityUUID, ActivityUUID: activityUUID,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/activities/{activityUUID}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/activities/{activityUUID}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "DELETE", url, nil) req, err := http.NewRequestWithContext(ctx, "DELETE", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.CancelServerActivitiesResponse{ res := &operations.CancelServerActivitiesResponse{
@@ -149,6 +194,7 @@ func (s *Activities) CancelServerActivities(ctx context.Context, activityUUID st
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:

193
butler.go
View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Butler is the task manager of the Plex Media Server Ecosystem. // Butler is the task manager of the Plex Media Server Ecosystem.
@@ -28,26 +29,49 @@ func newButler(sdkConfig sdkConfiguration) *Butler {
// GetButlerTasks - Get Butler tasks // GetButlerTasks - Get Butler tasks
// Returns a list of butler tasks // Returns a list of butler tasks
func (s *Butler) GetButlerTasks(ctx context.Context) (*operations.GetButlerTasksResponse, error) { func (s *Butler) GetButlerTasks(ctx context.Context) (*operations.GetButlerTasksResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getButlerTasks"}
url := strings.TrimSuffix(baseURL, "/") + "/butler"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/butler")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetButlerTasksResponse{ res := &operations.GetButlerTasksResponse{
@@ -62,6 +86,7 @@ func (s *Butler) GetButlerTasks(ctx context.Context) (*operations.GetButlerTasks
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -106,26 +131,49 @@ func (s *Butler) GetButlerTasks(ctx context.Context) (*operations.GetButlerTasks
// 3. If a task is configured to run at a random time during the configured window and we are within that window, the task will be scheduled at a random time within the window. // 3. If a task is configured to run at a random time during the configured window and we are within that window, the task will be scheduled at a random time within the window.
// 4. If we are outside the configured window, the task will start immediately. // 4. If we are outside the configured window, the task will start immediately.
func (s *Butler) StartAllTasks(ctx context.Context) (*operations.StartAllTasksResponse, error) { func (s *Butler) StartAllTasks(ctx context.Context) (*operations.StartAllTasksResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "startAllTasks"}
url := strings.TrimSuffix(baseURL, "/") + "/butler"
req, err := http.NewRequestWithContext(ctx, "POST", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/butler")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.StartAllTasksResponse{ res := &operations.StartAllTasksResponse{
@@ -140,6 +188,7 @@ func (s *Butler) StartAllTasks(ctx context.Context) (*operations.StartAllTasksRe
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -169,26 +218,49 @@ func (s *Butler) StartAllTasks(ctx context.Context) (*operations.StartAllTasksRe
// StopAllTasks - Stop all Butler tasks // StopAllTasks - Stop all Butler tasks
// This endpoint will stop all currently running tasks and remove any scheduled tasks from the queue. // This endpoint will stop all currently running tasks and remove any scheduled tasks from the queue.
func (s *Butler) StopAllTasks(ctx context.Context) (*operations.StopAllTasksResponse, error) { func (s *Butler) StopAllTasks(ctx context.Context) (*operations.StopAllTasksResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "stopAllTasks"}
url := strings.TrimSuffix(baseURL, "/") + "/butler"
req, err := http.NewRequestWithContext(ctx, "DELETE", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/butler")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "DELETE", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.StopAllTasksResponse{ res := &operations.StopAllTasksResponse{
@@ -203,6 +275,7 @@ func (s *Butler) StopAllTasks(ctx context.Context) (*operations.StopAllTasksResp
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -236,33 +309,53 @@ func (s *Butler) StopAllTasks(ctx context.Context) (*operations.StopAllTasksResp
// 3. If a task is configured to run at a random time during the configured window and we are within that window, the task will be scheduled at a random time within the window. // 3. If a task is configured to run at a random time during the configured window and we are within that window, the task will be scheduled at a random time within the window.
// 4. If we are outside the configured window, the task will start immediately. // 4. If we are outside the configured window, the task will start immediately.
func (s *Butler) StartTask(ctx context.Context, taskName operations.TaskName) (*operations.StartTaskResponse, error) { func (s *Butler) StartTask(ctx context.Context, taskName operations.TaskName) (*operations.StartTaskResponse, error) {
hookCtx := hooks.HookContext{OperationID: "startTask"}
request := operations.StartTaskRequest{ request := operations.StartTaskRequest{
TaskName: taskName, TaskName: taskName,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/butler/{taskName}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/butler/{taskName}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "POST", url, nil) req, err := http.NewRequestWithContext(ctx, "POST", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.StartTaskResponse{ res := &operations.StartTaskResponse{
@@ -277,6 +370,7 @@ func (s *Butler) StartTask(ctx context.Context, taskName operations.TaskName) (*
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
fallthrough fallthrough
@@ -308,33 +402,53 @@ func (s *Butler) StartTask(ctx context.Context, taskName operations.TaskName) (*
// StopTask - Stop a single Butler task // StopTask - Stop a single Butler task
// This endpoint will stop a currently running task by name, or remove it from the list of scheduled tasks if it exists. See the section above for a list of task names for this endpoint. // This endpoint will stop a currently running task by name, or remove it from the list of scheduled tasks if it exists. See the section above for a list of task names for this endpoint.
func (s *Butler) StopTask(ctx context.Context, taskName operations.PathParamTaskName) (*operations.StopTaskResponse, error) { func (s *Butler) StopTask(ctx context.Context, taskName operations.PathParamTaskName) (*operations.StopTaskResponse, error) {
hookCtx := hooks.HookContext{OperationID: "stopTask"}
request := operations.StopTaskRequest{ request := operations.StopTaskRequest{
TaskName: taskName, TaskName: taskName,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/butler/{taskName}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/butler/{taskName}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "DELETE", url, nil) req, err := http.NewRequestWithContext(ctx, "DELETE", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "404", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.StopTaskResponse{ res := &operations.StopTaskResponse{
@@ -349,6 +463,7 @@ func (s *Butler) StopTask(ctx context.Context, taskName operations.PathParamTask
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:

View File

@@ -0,0 +1,15 @@
# Account
## Fields
| Field | Type | Required | Description | Example |
| ---------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------- |
| `ID` | **int* | :heavy_minus_sign: | N/A | 238960586 |
| `Key` | **string* | :heavy_minus_sign: | N/A | /accounts/238960586 |
| `Name` | **string* | :heavy_minus_sign: | N/A | Diane |
| `DefaultAudioLanguage` | **string* | :heavy_minus_sign: | N/A | en |
| `AutoSelectAudio` | **bool* | :heavy_minus_sign: | N/A | true |
| `DefaultSubtitleLanguage` | **string* | :heavy_minus_sign: | N/A | en |
| `SubtitleMode` | **int* | :heavy_minus_sign: | N/A | 1 |
| `Thumb` | **string* | :heavy_minus_sign: | N/A | https://plex.tv/users/50d83634246da1de/avatar?c=1707110967 |

View File

@@ -4,6 +4,6 @@
## Fields ## Fields
| Field | Type | Required | Description | Example | | Field | Type | Required | Description | Example |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Size` | **int* | :heavy_minus_sign: | N/A | 161 | | `Size` | **int* | :heavy_minus_sign: | N/A | 161 |
| `Setting` | [][operations.Setting](../../models/operations/setting.md) | :heavy_minus_sign: | N/A | [{"advanced":false,"default":"","group":"general","hidden":false,"id":"FriendlyName","label":"Friendly name","summary":"This name will be used to identify this media server to other computers on your network. If you leave it blank, your computer's name will be used instead.","type":"text","value":"Hera"},{"advanced":false,"default":3600,"enumValues":"900:every 15 minutes\|1800:every 30 minutes\|3600:hourly\|7200:every 2 hours\|21600:every 6 hours\|43200:every 12 hours\|86400:daily","group":"library","hidden":false,"id":"ScheduledLibraryUpdateInterval","label":"Library scan interval","summary":"","type":"int","value":3600}] | | `Setting` | [][operations.Setting](../../models/operations/setting.md) | :heavy_minus_sign: | N/A | [{"advanced":false,"default":false,"enumValues":"1:admin only\|2:everyone","group":"","hidden":true,"id":"EnableDatabaseTrace","label":"","summary":"","type":"bool","value":false}] |

View File

@@ -0,0 +1,12 @@
# GetStatisticsDevice
## Fields
| Field | Type | Required | Description | Example |
| -------------------------------- | -------------------------------- | -------------------------------- | -------------------------------- | -------------------------------- |
| `ID` | **int* | :heavy_minus_sign: | N/A | 208 |
| `Name` | **string* | :heavy_minus_sign: | N/A | Roku Express |
| `Platform` | **string* | :heavy_minus_sign: | N/A | Roku |
| `ClientIdentifier` | **string* | :heavy_minus_sign: | N/A | 793095d235660625108ef785cc7646e9 |
| `CreatedAt` | **int* | :heavy_minus_sign: | N/A | 1706470556 |

View File

@@ -1,17 +1,11 @@
# Two # GetStatisticsMediaContainer
## Fields ## Fields
| Field | Type | Required | Description | Example | | Field | Type | Required | Description | Example |
| ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ID` | **string* | :heavy_minus_sign: | N/A | ScheduledLibraryUpdateInterval | | `Size` | **int* | :heavy_minus_sign: | N/A | 5497 |
| `Label` | **string* | :heavy_minus_sign: | N/A | Library scan interval | | `Device` | [][operations.GetStatisticsDevice](../../models/operations/getstatisticsdevice.md) | :heavy_minus_sign: | N/A | [{"clientIdentifier":"793095d235660625108ef785cc7646e9","createdAt":1706470556,"id":208,"name":"Roku Express","platform":"Roku"}] |
| `Summary` | **string* | :heavy_minus_sign: | N/A | | | `Account` | [][operations.Account](../../models/operations/account.md) | :heavy_minus_sign: | N/A | [{"autoSelectAudio":true,"defaultAudioLanguage":"en","defaultSubtitleLanguage":"en","id":238960586,"key":"/accounts/238960586","name":"Diane","subtitleMode":1,"thumb":"https://plex.tv/users/50d83634246da1de/avatar?c=1707110967"}] |
| `Type` | **string* | :heavy_minus_sign: | N/A | int | | `StatisticsMedia` | [][operations.StatisticsMedia](../../models/operations/statisticsmedia.md) | :heavy_minus_sign: | N/A | [{"accountID":1,"at":1707141600,"count":1,"deviceID":13,"duration":1555,"metadataType":4,"timespan":4}] |
| `Default` | **int* | :heavy_minus_sign: | N/A | 3600 |
| `Value` | **int* | :heavy_minus_sign: | N/A | 3600 |
| `Hidden` | **bool* | :heavy_minus_sign: | N/A | false |
| `Advanced` | **bool* | :heavy_minus_sign: | N/A | false |
| `Group` | **string* | :heavy_minus_sign: | N/A | library |
| `EnumValues` | **string* | :heavy_minus_sign: | N/A | 900:every 15 minutes\|1800:every 30 minutes\|3600:hourly\|7200:every 2 hours\|21600:every 6 hours\|43200:every 12 hours\|86400:daily |

View File

@@ -0,0 +1,8 @@
# GetStatisticsRequest
## Fields
| Field | Type | Required | Description |
| ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `Timespan` | **int64* | :heavy_minus_sign: | The timespan to retrieve statistics for<br/>the exact meaning of this parameter is not known<br/> |

View File

@@ -0,0 +1,11 @@
# GetStatisticsResponse
## Fields
| Field | Type | Required | Description |
| --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `ContentType` | *string* | :heavy_check_mark: | HTTP response content type for this operation |
| `StatusCode` | *int* | :heavy_check_mark: | HTTP response status code for this operation |
| `RawResponse` | [*http.Response](https://pkg.go.dev/net/http#Response) | :heavy_check_mark: | Raw HTTP response; suitable for custom response parsing |
| `Object` | [*operations.GetStatisticsResponseBody](../../models/operations/getstatisticsresponsebody.md) | :heavy_minus_sign: | Media Statistics |

View File

@@ -0,0 +1,10 @@
# GetStatisticsResponseBody
Media Statistics
## Fields
| Field | Type | Required | Description |
| ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `MediaContainer` | [*operations.GetStatisticsMediaContainer](../../models/operations/getstatisticsmediacontainer.md) | :heavy_minus_sign: | N/A |

View File

@@ -1,16 +0,0 @@
# One
## Fields
| Field | Type | Required | Description | Example |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ID` | **string* | :heavy_minus_sign: | N/A | FriendlyName |
| `Label` | **string* | :heavy_minus_sign: | N/A | Friendly name |
| `Summary` | **string* | :heavy_minus_sign: | N/A | This name will be used to identify this media server to other computers on your network. If you leave it blank, your computer's name will be used instead. |
| `Type` | **string* | :heavy_minus_sign: | N/A | text |
| `Default` | **string* | :heavy_minus_sign: | N/A | |
| `Value` | **string* | :heavy_minus_sign: | N/A | Hera |
| `Hidden` | **bool* | :heavy_minus_sign: | N/A | false |
| `Advanced` | **bool* | :heavy_minus_sign: | N/A | false |
| `Group` | **string* | :heavy_minus_sign: | N/A | general |

View File

@@ -1,17 +1,17 @@
# Setting # Setting
## Supported Types ## Fields
### One
```go
setting := operations.CreateSettingOne(operations.One{/* values here */})
```
### Two
```go
setting := operations.CreateSettingTwo(operations.Two{/* values here */})
```
| Field | Type | Required | Description | Example |
| ----------------------- | ----------------------- | ----------------------- | ----------------------- | ----------------------- |
| `ID` | **string* | :heavy_minus_sign: | N/A | EnableDatabaseTrace |
| `Label` | **string* | :heavy_minus_sign: | N/A | |
| `Summary` | **string* | :heavy_minus_sign: | N/A | |
| `Type` | **string* | :heavy_minus_sign: | N/A | bool |
| `Default` | **bool* | :heavy_minus_sign: | N/A | false |
| `Value` | **bool* | :heavy_minus_sign: | N/A | false |
| `Hidden` | **bool* | :heavy_minus_sign: | N/A | true |
| `Advanced` | **bool* | :heavy_minus_sign: | N/A | false |
| `Group` | **string* | :heavy_minus_sign: | N/A | |
| `EnumValues` | **string* | :heavy_minus_sign: | N/A | 1:admin only\|2:everyone |

View File

@@ -0,0 +1,14 @@
# StatisticsMedia
## Fields
| Field | Type | Required | Description | Example |
| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ |
| `AccountID` | **int* | :heavy_minus_sign: | N/A | 1 |
| `DeviceID` | **int* | :heavy_minus_sign: | N/A | 13 |
| `Timespan` | **int* | :heavy_minus_sign: | N/A | 4 |
| `At` | **int* | :heavy_minus_sign: | N/A | 1707141600 |
| `MetadataType` | **int* | :heavy_minus_sign: | N/A | 4 |
| `Count` | **int* | :heavy_minus_sign: | N/A | 1 |
| `Duration` | **int* | :heavy_minus_sign: | N/A | 1555 |

View File

@@ -0,0 +1,10 @@
# GetStatisticsErrors
## Fields
| Field | Type | Required | Description | Example |
| ------------------------------- | ------------------------------- | ------------------------------- | ------------------------------- | ------------------------------- |
| `Code` | **float64* | :heavy_minus_sign: | N/A | 1001 |
| `Message` | **string* | :heavy_minus_sign: | N/A | User could not be authenticated |
| `Status` | **float64* | :heavy_minus_sign: | N/A | 401 |

View File

@@ -0,0 +1,11 @@
# GetStatisticsResponseBody
Unauthorized - Returned if the X-Plex-Token is missing from the header or query.
## Fields
| Field | Type | Required | Description |
| -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `Errors` | [][sdkerrors.GetStatisticsErrors](../../models/sdkerrors/getstatisticserrors.md) | :heavy_minus_sign: | N/A |
| `RawResponse` | [*http.Response](https://pkg.go.dev/net/http#Response) | :heavy_minus_sign: | Raw HTTP response; suitable for custom response parsing |

View File

@@ -88,7 +88,7 @@ func main() {
) )
var activityUUID string = "string" var activityUUID string = "<value>"
ctx := context.Background() ctx := context.Background()
res, err := s.Activities.CancelServerActivities(ctx, activityUUID) res, err := s.Activities.CancelServerActivities(ctx, activityUUID)

View File

@@ -34,9 +34,9 @@ func main() {
) )
var count *float64 = 1262.49 var count *float64 = plexgo.Float64(1262.49)
var onlyTransient *operations.OnlyTransient = operations.OnlyTransientOne var onlyTransient *operations.OnlyTransient = operations.OnlyTransientOne.ToPointer()
ctx := context.Background() ctx := context.Background()
res, err := s.Hubs.GetGlobalHubs(ctx, count, onlyTransient) res, err := s.Hubs.GetGlobalHubs(ctx, count, onlyTransient)
@@ -93,9 +93,9 @@ func main() {
var sectionID float64 = 6728.76 var sectionID float64 = 6728.76
var count *float64 = 9010.22 var count *float64 = plexgo.Float64(9010.22)
var onlyTransient *operations.QueryParamOnlyTransient = operations.QueryParamOnlyTransientZero var onlyTransient *operations.QueryParamOnlyTransient = operations.QueryParamOnlyTransientZero.ToPointer()
ctx := context.Background() ctx := context.Background()
res, err := s.Hubs.GetLibraryHubs(ctx, sectionID, count, onlyTransient) res, err := s.Hubs.GetLibraryHubs(ctx, sectionID, count, onlyTransient)

View File

@@ -45,7 +45,7 @@ func main() {
var url_ string = "file://C:\Image.png&type=13" var url_ string = "file://C:\Image.png&type=13"
var type_ *float64 = 4462.17 var type_ *float64 = plexgo.Float64(4462.17)
ctx := context.Background() ctx := context.Background()
res, err := s.Library.GetFileHash(ctx, url_, type_) res, err := s.Library.GetFileHash(ctx, url_, type_)
@@ -243,7 +243,7 @@ func main() {
var sectionID float64 = 1000 var sectionID float64 = 1000
var includeDetails *operations.IncludeDetails = operations.IncludeDetailsZero var includeDetails *operations.IncludeDetails = operations.IncludeDetailsZero.ToPointer()
ctx := context.Background() ctx := context.Background()
res, err := s.Library.GetLibrary(ctx, sectionID, includeDetails) res, err := s.Library.GetLibrary(ctx, sectionID, includeDetails)

View File

@@ -142,11 +142,11 @@ func main() {
) )
var key string = "string" var key string = "<value>"
var time float64 = 6900.91 var time float64 = 6900.91
var state string = "string" var state string = "<value>"
ctx := context.Background() ctx := context.Background()
res, err := s.Media.UpdatePlayProgress(ctx, key, time, state) res, err := s.Media.UpdatePlayProgress(ctx, key, time, state)

View File

@@ -48,7 +48,7 @@ func main() {
ctx := context.Background() ctx := context.Background()
res, err := s.Playlists.CreatePlaylist(ctx, operations.CreatePlaylistRequest{ res, err := s.Playlists.CreatePlaylist(ctx, operations.CreatePlaylistRequest{
Title: "string", Title: "<value>",
Type: operations.QueryParamTypePhoto, Type: operations.QueryParamTypePhoto,
Smart: operations.SmartOne, Smart: operations.SmartOne,
URI: "https://inborn-brochure.biz", URI: "https://inborn-brochure.biz",
@@ -102,9 +102,9 @@ func main() {
) )
var playlistType *operations.PlaylistType = operations.PlaylistTypeAudio var playlistType *operations.PlaylistType = operations.PlaylistTypeAudio.ToPointer()
var smart *operations.QueryParamSmart = operations.QueryParamSmartZero var smart *operations.QueryParamSmart = operations.QueryParamSmartZero.ToPointer()
ctx := context.Background() ctx := context.Background()
res, err := s.Playlists.GetPlaylists(ctx, playlistType, smart) res, err := s.Playlists.GetPlaylists(ctx, playlistType, smart)
@@ -269,9 +269,9 @@ func main() {
var playlistID float64 = 3915 var playlistID float64 = 3915
var title *string = "string" var title *string = plexgo.String("<value>")
var summary *string = "string" var summary *string = plexgo.String("<value>")
ctx := context.Background() ctx := context.Background()
res, err := s.Playlists.UpdatePlaylist(ctx, playlistID, title, summary) res, err := s.Playlists.UpdatePlaylist(ctx, playlistID, title, summary)
@@ -444,7 +444,7 @@ func main() {
var uri string = "server://12345/com.plexapp.plugins.library/library/metadata/1" var uri string = "server://12345/com.plexapp.plugins.library/library/metadata/1"
var playQueueID *float64 = 123 var playQueueID *float64 = plexgo.Float64(123)
ctx := context.Background() ctx := context.Background()
res, err := s.Playlists.AddPlaylistContents(ctx, playlistID, uri, playQueueID) res, err := s.Playlists.AddPlaylistContents(ctx, playlistID, uri, playQueueID)

View File

@@ -33,9 +33,9 @@ func main() {
) )
var xPlexClientIdentifier string = "string" var xPlexClientIdentifier string = "<value>"
var strong *bool = false var strong *bool = plexgo.Bool(false)
ctx := context.Background() ctx := context.Background()
res, err := s.Plex.GetPin(ctx, xPlexClientIdentifier, strong) res, err := s.Plex.GetPin(ctx, xPlexClientIdentifier, strong)
@@ -90,9 +90,9 @@ func main() {
) )
var pinID string = "string" var pinID string = "<value>"
var xPlexClientIdentifier string = "string" var xPlexClientIdentifier string = "<value>"
ctx := context.Background() ctx := context.Background()
res, err := s.Plex.GetToken(ctx, pinID, xPlexClientIdentifier) res, err := s.Plex.GetToken(ctx, pinID, xPlexClientIdentifier)

View File

@@ -49,9 +49,9 @@ func main() {
var query string = "dylan" var query string = "dylan"
var sectionID *float64 = 1516.53 var sectionID *float64 = plexgo.Float64(1516.53)
var limit *float64 = 5 var limit *float64 = plexgo.Float64(5)
ctx := context.Background() ctx := context.Background()
res, err := s.Search.PerformSearch(ctx, query, sectionID, limit) res, err := s.Search.PerformSearch(ctx, query, sectionID, limit)
@@ -112,9 +112,9 @@ func main() {
var query string = "dead+poop" var query string = "dead+poop"
var sectionID *float64 = 4094.8 var sectionID *float64 = plexgo.Float64(4094.8)
var limit *float64 = 5 var limit *float64 = plexgo.Float64(5)
ctx := context.Background() ctx := context.Background()
res, err := s.Search.PerformVoiceSearch(ctx, query, sectionID, limit) res, err := s.Search.PerformVoiceSearch(ctx, query, sectionID, limit)

View File

@@ -0,0 +1,63 @@
# Statistics
(*Statistics*)
## Overview
API Calls that perform operations with Plex Media Server Statistics
### Available Operations
* [GetStatistics](#getstatistics) - Get Media Statistics
## GetStatistics
This will return the media statistics for the server
### Example Usage
```go
package main
import(
"github.com/LukeHagar/plexgo/models/components"
"github.com/LukeHagar/plexgo"
"context"
"log"
)
func main() {
s := plexgo.New(
plexgo.WithSecurity("<YOUR_API_KEY_HERE>"),
)
var timespan *int64 = plexgo.Int64(411769)
ctx := context.Background()
res, err := s.Statistics.GetStatistics(ctx, timespan)
if err != nil {
log.Fatal(err)
}
if res.Object != nil {
// handle response
}
}
```
### Parameters
| Parameter | Type | Required | Description |
| ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `ctx` | [context.Context](https://pkg.go.dev/context#Context) | :heavy_check_mark: | The context to use for the request. |
| `timespan` | **int64* | :heavy_minus_sign: | The timespan to retrieve statistics for<br/>the exact meaning of this parameter is not known<br/> |
### Response
**[*operations.GetStatisticsResponse](../../models/operations/getstatisticsresponse.md), error**
| Error Object | Status Code | Content Type |
| ----------------------------------- | ----------------------------------- | ----------------------------------- |
| sdkerrors.GetStatisticsResponseBody | 401 | application/json |
| sdkerrors.SDKError | 4xx-5xx | */* |

View File

@@ -85,7 +85,7 @@ func main() {
) )
var download *operations.Download = operations.DownloadOne var download *operations.Download = operations.DownloadOne.ToPointer()
ctx := context.Background() ctx := context.Background()
res, err := s.Updater.CheckForUpdates(ctx, download) res, err := s.Updater.CheckForUpdates(ctx, download)
@@ -140,9 +140,9 @@ func main() {
) )
var tonight *operations.Tonight = operations.TonightOne var tonight *operations.Tonight = operations.TonightOne.ToPointer()
var skip *operations.Skip = operations.SkipZero var skip *operations.Skip = operations.SkipZero.ToPointer()
ctx := context.Background() ctx := context.Background()
res, err := s.Updater.ApplyUpdates(ctx, tonight, skip) res, err := s.Updater.ApplyUpdates(ctx, tonight, skip)

View File

@@ -8,65 +8,8 @@ API Calls that perform operations with Plex Media Server Videos
### Available Operations ### Available Operations
* [StartUniversalTranscode](#startuniversaltranscode) - Start Universal Transcode
* [GetTimeline](#gettimeline) - Get the timeline for a media item * [GetTimeline](#gettimeline) - Get the timeline for a media item
* [StartUniversalTranscode](#startuniversaltranscode) - Start Universal Transcode
## StartUniversalTranscode
Begin a Universal Transcode Session
### Example Usage
```go
package main
import(
"github.com/LukeHagar/plexgo/models/components"
"github.com/LukeHagar/plexgo"
"context"
"github.com/LukeHagar/plexgo/models/operations"
"log"
"net/http"
)
func main() {
s := plexgo.New(
plexgo.WithSecurity("<YOUR_API_KEY_HERE>"),
)
ctx := context.Background()
res, err := s.Video.StartUniversalTranscode(ctx, operations.StartUniversalTranscodeRequest{
HasMDE: 8924.99,
Path: "/etc/mail",
MediaIndex: 9962.95,
PartIndex: 1232.82,
Protocol: "string",
})
if err != nil {
log.Fatal(err)
}
if res.StatusCode == http.StatusOK {
// handle response
}
}
```
### Parameters
| Parameter | Type | Required | Description |
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
| `ctx` | [context.Context](https://pkg.go.dev/context#Context) | :heavy_check_mark: | The context to use for the request. |
| `request` | [operations.StartUniversalTranscodeRequest](../../models/operations/startuniversaltranscoderequest.md) | :heavy_check_mark: | The request object to use for the request. |
### Response
**[*operations.StartUniversalTranscodeResponse](../../models/operations/startuniversaltranscoderesponse.md), error**
| Error Object | Status Code | Content Type |
| --------------------------------------------- | --------------------------------------------- | --------------------------------------------- |
| sdkerrors.StartUniversalTranscodeResponseBody | 401 | application/json |
| sdkerrors.SDKError | 4xx-5xx | */* |
## GetTimeline ## GetTimeline
@@ -99,7 +42,7 @@ func main() {
HasMDE: 7574.33, HasMDE: 7574.33,
Time: 3327.51, Time: 3327.51,
Duration: 7585.39, Duration: 7585.39,
Context: "string", Context: "<value>",
PlayQueueItemID: 1406.21, PlayQueueItemID: 1406.21,
PlayBackTime: 2699.34, PlayBackTime: 2699.34,
Row: 3536.42, Row: 3536.42,
@@ -129,3 +72,60 @@ func main() {
| --------------------------------- | --------------------------------- | --------------------------------- | | --------------------------------- | --------------------------------- | --------------------------------- |
| sdkerrors.GetTimelineResponseBody | 401 | application/json | | sdkerrors.GetTimelineResponseBody | 401 | application/json |
| sdkerrors.SDKError | 4xx-5xx | */* | | sdkerrors.SDKError | 4xx-5xx | */* |
## StartUniversalTranscode
Begin a Universal Transcode Session
### Example Usage
```go
package main
import(
"github.com/LukeHagar/plexgo/models/components"
"github.com/LukeHagar/plexgo"
"context"
"github.com/LukeHagar/plexgo/models/operations"
"log"
"net/http"
)
func main() {
s := plexgo.New(
plexgo.WithSecurity("<YOUR_API_KEY_HERE>"),
)
ctx := context.Background()
res, err := s.Video.StartUniversalTranscode(ctx, operations.StartUniversalTranscodeRequest{
HasMDE: 8924.99,
Path: "/etc/mail",
MediaIndex: 9962.95,
PartIndex: 1232.82,
Protocol: "<value>",
})
if err != nil {
log.Fatal(err)
}
if res.StatusCode == http.StatusOK {
// handle response
}
}
```
### Parameters
| Parameter | Type | Required | Description |
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
| `ctx` | [context.Context](https://pkg.go.dev/context#Context) | :heavy_check_mark: | The context to use for the request. |
| `request` | [operations.StartUniversalTranscodeRequest](../../models/operations/startuniversaltranscoderequest.md) | :heavy_check_mark: | The request object to use for the request. |
### Response
**[*operations.StartUniversalTranscodeResponse](../../models/operations/startuniversaltranscoderesponse.md), error**
| Error Object | Status Code | Content Type |
| --------------------------------------------- | --------------------------------------------- | --------------------------------------------- |
| sdkerrors.StartUniversalTranscodeResponseBody | 401 | application/json |
| sdkerrors.SDKError | 4xx-5xx | */* |

View File

@@ -8,8 +8,10 @@ generation:
fixes: fixes:
nameResolutionDec2023: false nameResolutionDec2023: false
parameterOrderingFeb2024: false parameterOrderingFeb2024: false
requestResponseComponentNamesFeb2024: false
go: go:
version: 0.3.0 version: 0.4.0
additionalDependencies: {}
clientServerStatusCodesAsErrors: true clientServerStatusCodesAsErrors: true
flattenGlobalSecurity: true flattenGlobalSecurity: true
imports: imports:

2
go.mod
View File

@@ -5,6 +5,4 @@ go 1.20
require ( require (
github.com/cenkalti/backoff/v4 v4.2.0 github.com/cenkalti/backoff/v4 v4.2.0
github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05
github.com/mitchellh/mapstructure v1.5.0
github.com/spyzhov/ajson v0.8.0
) )

4
go.sum
View File

@@ -2,7 +2,3 @@ github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+M
github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 h1:S92OBrGuLLZsyM5ybUzgc/mPjIYk2AZqufieooe98uw= github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 h1:S92OBrGuLLZsyM5ybUzgc/mPjIYk2AZqufieooe98uw=
github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ= github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/spyzhov/ajson v0.8.0 h1:sFXyMbi4Y/BKjrsfkUZHSjA2JM1184enheSjjoT/zCc=
github.com/spyzhov/ajson v0.8.0/go.mod h1:63V+CGM6f1Bu/p4nLIN8885ojBdt88TbLoSFzyqMuVA=

76
hubs.go
View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Hubs are a structured two-dimensional container for media, generally represented by multiple horizontal rows. // Hubs are a structured two-dimensional container for media, generally represented by multiple horizontal rows.
@@ -28,35 +29,58 @@ func newHubs(sdkConfig sdkConfiguration) *Hubs {
// GetGlobalHubs - Get Global Hubs // GetGlobalHubs - Get Global Hubs
// Get Global Hubs filtered by the parameters provided. // Get Global Hubs filtered by the parameters provided.
func (s *Hubs) GetGlobalHubs(ctx context.Context, count *float64, onlyTransient *operations.OnlyTransient) (*operations.GetGlobalHubsResponse, error) { func (s *Hubs) GetGlobalHubs(ctx context.Context, count *float64, onlyTransient *operations.OnlyTransient) (*operations.GetGlobalHubsResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getGlobalHubs"}
request := operations.GetGlobalHubsRequest{ request := operations.GetGlobalHubsRequest{
Count: count, Count: count,
OnlyTransient: onlyTransient, OnlyTransient: onlyTransient,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/hubs" opURL, err := url.JoinPath(baseURL, "/hubs")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetGlobalHubsResponse{ res := &operations.GetGlobalHubsResponse{
@@ -71,6 +95,7 @@ func (s *Hubs) GetGlobalHubs(ctx context.Context, count *float64, onlyTransient
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -111,6 +136,8 @@ func (s *Hubs) GetGlobalHubs(ctx context.Context, count *float64, onlyTransient
// GetLibraryHubs - Get library specific hubs // GetLibraryHubs - Get library specific hubs
// This endpoint will return a list of library specific hubs // This endpoint will return a list of library specific hubs
func (s *Hubs) GetLibraryHubs(ctx context.Context, sectionID float64, count *float64, onlyTransient *operations.QueryParamOnlyTransient) (*operations.GetLibraryHubsResponse, error) { func (s *Hubs) GetLibraryHubs(ctx context.Context, sectionID float64, count *float64, onlyTransient *operations.QueryParamOnlyTransient) (*operations.GetLibraryHubsResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getLibraryHubs"}
request := operations.GetLibraryHubsRequest{ request := operations.GetLibraryHubsRequest{
SectionID: sectionID, SectionID: sectionID,
Count: count, Count: count,
@@ -118,32 +145,50 @@ func (s *Hubs) GetLibraryHubs(ctx context.Context, sectionID float64, count *flo
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/hubs/sections/{sectionId}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/hubs/sections/{sectionId}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetLibraryHubsResponse{ res := &operations.GetLibraryHubsResponse{
@@ -158,6 +203,7 @@ func (s *Hubs) GetLibraryHubs(ctx context.Context, sectionID float64, count *flo
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {

140
internal/hooks/hooks.go Normal file
View File

@@ -0,0 +1,140 @@
// Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT.
package hooks
import (
"errors"
"net/http"
)
type FailEarly struct {
Cause error
}
var _ error = (*FailEarly)(nil)
func (f *FailEarly) Error() string {
return f.Cause.Error()
}
// HTTPClient provides an interface for supplying the SDK with a custom HTTP client
type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}
type HookContext struct {
OperationID string
}
type BeforeRequestContext struct {
HookContext
}
type AfterSuccessContext struct {
HookContext
}
type AfterErrorContext struct {
HookContext
}
// clientInitHook is called when the SDK is initializing the HTTP client. The hook can return a new HTTP client to be used by the SDK.
type clientInitHook interface {
ClientInit(client HTTPClient) HTTPClient
}
// beforeRequestHook is called before the SDK sends a request. The hook can modify the request before it is sent or return an error to stop the request from being sent.
type beforeRequestHook interface {
BeforeRequest(hookCtx BeforeRequestContext, req *http.Request) (*http.Request, error)
}
// afterSuccessHook is called after the SDK receives a response. The hook can modify the response before it is handled or return an error to stop the response from being handled.
type afterSuccessHook interface {
AfterSuccess(hookCtx AfterSuccessContext, res *http.Response) (*http.Response, error)
}
// afterErrorHook is called after the SDK encounters an error, or a non-successful response. The hook can modify the response if available otherwise modify the error.
// All afterErrorHook hooks are called and returning an error won't stop the other hooks from being called. But if you want to stop the other hooks from being called, you can return a FailEarly error wrapping your error.
type afterErrorHook interface {
AfterError(hookCtx AfterErrorContext, res *http.Response, err error) (*http.Response, error)
}
type Hooks struct {
clientInitHooks []clientInitHook
beforeRequestHook []beforeRequestHook
afterSuccessHook []afterSuccessHook
afterErrorHook []afterErrorHook
}
func New() *Hooks {
h := &Hooks{
clientInitHooks: []clientInitHook{},
beforeRequestHook: []beforeRequestHook{},
afterSuccessHook: []afterSuccessHook{},
afterErrorHook: []afterErrorHook{},
}
initHooks(h)
return h
}
// registerClientInitHook registers a hook to be used by the SDK for the client initialization event.
func (h *Hooks) registerClientInitHook(hook clientInitHook) {
h.clientInitHooks = append(h.clientInitHooks, hook)
}
// registerBeforeRequestHook registers a hook to be used by the SDK for the before request event.
func (h *Hooks) registerBeforeRequestHook(hook beforeRequestHook) {
h.beforeRequestHook = append(h.beforeRequestHook, hook)
}
// registerAfterSuccessHook registers a hook to be used by the SDK for the after success event.
func (h *Hooks) registerAfterSuccessHook(hook afterSuccessHook) {
h.afterSuccessHook = append(h.afterSuccessHook, hook)
}
// registerAfterErrorHook registers a hook to be used by the SDK for the after error event.
func (h *Hooks) registerAfterErrorHook(hook afterErrorHook) {
h.afterErrorHook = append(h.afterErrorHook, hook)
}
func (h *Hooks) ClientInit(client HTTPClient) HTTPClient {
for _, hook := range h.clientInitHooks {
client = hook.ClientInit(client)
}
return client
}
func (h *Hooks) BeforeRequest(hookCtx BeforeRequestContext, req *http.Request) (*http.Request, error) {
for _, hook := range h.beforeRequestHook {
var err error
req, err = hook.BeforeRequest(hookCtx, req)
if err != nil {
return req, err
}
}
return req, nil
}
func (h *Hooks) AfterSuccess(hookCtx AfterSuccessContext, res *http.Response) (*http.Response, error) {
for _, hook := range h.afterSuccessHook {
var err error
res, err = hook.AfterSuccess(hookCtx, res)
if err != nil {
return res, err
}
}
return res, nil
}
func (h *Hooks) AfterError(hookCtx AfterErrorContext, res *http.Response, err error) (*http.Response, error) {
for _, hook := range h.afterErrorHook {
res, err = hook.AfterError(hookCtx, res, err)
var fe *FailEarly
if errors.As(err, &fe) {
return nil, fe.Cause
}
}
return res, err
}

View File

@@ -0,0 +1,13 @@
package hooks
/*
* This file is only ever generated once on the first generation and then is free to be modified.
* Any hooks you wish to add should be registered in the InitHooks function. Feel free to define them
* in this file or in separate files in the hooks package.
*/
func initHooks(h *Hooks) {
// Add hooks by calling h.register{ClientInit/BeforeRequest/AfterRequest/AfterError}Hook
// with an instance of a hook that implements that specific Hook interface
// Hooks are registered per SDK instance, and are valid for the lifetime of the SDK instance
}

View File

@@ -358,7 +358,7 @@ func handleDefaultConstValue(tagValue string, val interface{}, tag reflect.Struc
return []byte(fmt.Sprintf(`"%s"`, tagValue)) return []byte(fmt.Sprintf(`"%s"`, tagValue))
default: default:
if typ.Kind() == reflect.String { if typ.Kind() == reflect.String {
return []byte(fmt.Sprintf(`"%s"`, tagValue)) return []byte(fmt.Sprintf("%q", tagValue))
} }
} }

View File

@@ -26,6 +26,19 @@ var (
) )
func SerializeRequestBody(ctx context.Context, request interface{}, nullable, optional bool, requestFieldName, serializationMethod, tag string) (io.Reader, string, error) { func SerializeRequestBody(ctx context.Context, request interface{}, nullable, optional bool, requestFieldName, serializationMethod, tag string) (io.Reader, string, error) {
bodyReader, contentType, err := serializeRequestBody(ctx, request, nullable, optional, requestFieldName, serializationMethod, tag)
if err != nil {
return nil, "", fmt.Errorf("error serializing request body: %w", err)
}
if bodyReader == nil && !optional {
return nil, "", fmt.Errorf("request body is required")
}
return bodyReader, contentType, nil
}
func serializeRequestBody(ctx context.Context, request interface{}, nullable, optional bool, requestFieldName, serializationMethod, tag string) (io.Reader, string, error) {
requestStructType := reflect.TypeOf(request) requestStructType := reflect.TypeOf(request)
requestValType := reflect.ValueOf(request) requestValType := reflect.ValueOf(request)

View File

@@ -8,6 +8,7 @@ import (
"math/big" "math/big"
"reflect" "reflect"
"regexp" "regexp"
"strconv"
"strings" "strings"
"time" "time"
@@ -63,6 +64,29 @@ func Contains(slice []string, item string) bool {
return false return false
} }
func MatchStatusCodes(expectedCodes []string, statusCode int) bool {
for _, codeStr := range expectedCodes {
code, err := strconv.Atoi(codeStr)
if err == nil {
if code == statusCode {
return true
}
continue
}
codeRange, err := strconv.Atoi(string(codeStr[0]))
if err != nil {
continue
}
if statusCode >= (codeRange*100) && statusCode < ((codeRange+1)*100) {
return true
}
}
return false
}
func parseStructTag(tagKey string, field reflect.StructField) map[string]string { func parseStructTag(tagKey string, field reflect.StructField) map[string]string {
tag := field.Tag.Get(tagKey) tag := field.Tag.Get(tagKey)
if tag == "" { if tag == "" {

View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Library - API Calls interacting with Plex Media Server Libraries // Library - API Calls interacting with Plex Media Server Libraries
@@ -28,35 +29,58 @@ func newLibrary(sdkConfig sdkConfiguration) *Library {
// GetFileHash - Get Hash Value // GetFileHash - Get Hash Value
// This resource returns hash values for local files // This resource returns hash values for local files
func (s *Library) GetFileHash(ctx context.Context, url_ string, type_ *float64) (*operations.GetFileHashResponse, error) { func (s *Library) GetFileHash(ctx context.Context, url_ string, type_ *float64) (*operations.GetFileHashResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getFileHash"}
request := operations.GetFileHashRequest{ request := operations.GetFileHashRequest{
URL: url_, URL: url_,
Type: type_, Type: type_,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/library/hashes" opURL, err := url.JoinPath(baseURL, "/library/hashes")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetFileHashResponse{ res := &operations.GetFileHashResponse{
@@ -71,6 +95,7 @@ func (s *Library) GetFileHash(ctx context.Context, url_ string, type_ *float64)
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -100,26 +125,49 @@ func (s *Library) GetFileHash(ctx context.Context, url_ string, type_ *float64)
// GetRecentlyAdded - Get Recently Added // GetRecentlyAdded - Get Recently Added
// This endpoint will return the recently added content. // This endpoint will return the recently added content.
func (s *Library) GetRecentlyAdded(ctx context.Context) (*operations.GetRecentlyAddedResponse, error) { func (s *Library) GetRecentlyAdded(ctx context.Context) (*operations.GetRecentlyAddedResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getRecentlyAdded"}
url := strings.TrimSuffix(baseURL, "/") + "/library/recentlyAdded"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/library/recentlyAdded")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetRecentlyAddedResponse{ res := &operations.GetRecentlyAddedResponse{
@@ -134,6 +182,7 @@ func (s *Library) GetRecentlyAdded(ctx context.Context) (*operations.GetRecently
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -179,26 +228,49 @@ func (s *Library) GetRecentlyAdded(ctx context.Context) (*operations.GetRecently
// Libraries have features beyond just being a collection of media; for starters, they include information about supported types, filters and sorts. // Libraries have features beyond just being a collection of media; for starters, they include information about supported types, filters and sorts.
// This allows a client to provide a rich interface around the media (e.g. allow sorting movies by release year). // This allows a client to provide a rich interface around the media (e.g. allow sorting movies by release year).
func (s *Library) GetLibraries(ctx context.Context) (*operations.GetLibrariesResponse, error) { func (s *Library) GetLibraries(ctx context.Context) (*operations.GetLibrariesResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getLibraries"}
url := strings.TrimSuffix(baseURL, "/") + "/library/sections"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/library/sections")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetLibrariesResponse{ res := &operations.GetLibrariesResponse{
@@ -213,6 +285,7 @@ func (s *Library) GetLibraries(ctx context.Context) (*operations.GetLibrariesRes
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -291,38 +364,58 @@ func (s *Library) GetLibraries(ctx context.Context) (*operations.GetLibrariesRes
// //
// > **Note**: Filters and sorts are optional; without them, no filtering controls are rendered. // > **Note**: Filters and sorts are optional; without them, no filtering controls are rendered.
func (s *Library) GetLibrary(ctx context.Context, sectionID float64, includeDetails *operations.IncludeDetails) (*operations.GetLibraryResponse, error) { func (s *Library) GetLibrary(ctx context.Context, sectionID float64, includeDetails *operations.IncludeDetails) (*operations.GetLibraryResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getLibrary"}
request := operations.GetLibraryRequest{ request := operations.GetLibraryRequest{
SectionID: sectionID, SectionID: sectionID,
IncludeDetails: includeDetails, IncludeDetails: includeDetails,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/library/sections/{sectionId}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/library/sections/{sectionId}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetLibraryResponse{ res := &operations.GetLibraryResponse{
@@ -337,6 +430,7 @@ func (s *Library) GetLibrary(ctx context.Context, sectionID float64, includeDeta
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -377,33 +471,53 @@ func (s *Library) GetLibrary(ctx context.Context, sectionID float64, includeDeta
// DeleteLibrary - Delete Library Section // DeleteLibrary - Delete Library Section
// Delate a library using a specific section // Delate a library using a specific section
func (s *Library) DeleteLibrary(ctx context.Context, sectionID float64) (*operations.DeleteLibraryResponse, error) { func (s *Library) DeleteLibrary(ctx context.Context, sectionID float64) (*operations.DeleteLibraryResponse, error) {
hookCtx := hooks.HookContext{OperationID: "deleteLibrary"}
request := operations.DeleteLibraryRequest{ request := operations.DeleteLibraryRequest{
SectionID: sectionID, SectionID: sectionID,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/library/sections/{sectionId}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/library/sections/{sectionId}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "DELETE", url, nil) req, err := http.NewRequestWithContext(ctx, "DELETE", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.DeleteLibraryResponse{ res := &operations.DeleteLibraryResponse{
@@ -418,6 +532,7 @@ func (s *Library) DeleteLibrary(ctx context.Context, sectionID float64) (*operat
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -466,34 +581,54 @@ func (s *Library) DeleteLibrary(ctx context.Context, sectionID float64) (*operat
// - `firstCharacter`: Items categorized by the first letter. // - `firstCharacter`: Items categorized by the first letter.
// - `folder`: Items categorized by folder. // - `folder`: Items categorized by folder.
func (s *Library) GetLibraryItems(ctx context.Context, sectionID int64, tag operations.Tag) (*operations.GetLibraryItemsResponse, error) { func (s *Library) GetLibraryItems(ctx context.Context, sectionID int64, tag operations.Tag) (*operations.GetLibraryItemsResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getLibraryItems"}
request := operations.GetLibraryItemsRequest{ request := operations.GetLibraryItemsRequest{
SectionID: sectionID, SectionID: sectionID,
Tag: tag, Tag: tag,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/library/sections/{sectionId}/{tag}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/library/sections/{sectionId}/{tag}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetLibraryItemsResponse{ res := &operations.GetLibraryItemsResponse{
@@ -508,6 +643,7 @@ func (s *Library) GetLibraryItems(ctx context.Context, sectionID int64, tag oper
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -533,33 +669,53 @@ func (s *Library) GetLibraryItems(ctx context.Context, sectionID int64, tag oper
// RefreshLibrary - Refresh Library // RefreshLibrary - Refresh Library
// This endpoint Refreshes the library. // This endpoint Refreshes the library.
func (s *Library) RefreshLibrary(ctx context.Context, sectionID float64) (*operations.RefreshLibraryResponse, error) { func (s *Library) RefreshLibrary(ctx context.Context, sectionID float64) (*operations.RefreshLibraryResponse, error) {
hookCtx := hooks.HookContext{OperationID: "refreshLibrary"}
request := operations.RefreshLibraryRequest{ request := operations.RefreshLibraryRequest{
SectionID: sectionID, SectionID: sectionID,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/library/sections/{sectionId}/refresh", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/library/sections/{sectionId}/refresh", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.RefreshLibraryResponse{ res := &operations.RefreshLibraryResponse{
@@ -574,6 +730,7 @@ func (s *Library) RefreshLibrary(ctx context.Context, sectionID float64) (*opera
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -620,38 +777,58 @@ func (s *Library) RefreshLibrary(ctx context.Context, sectionID float64) (*opera
// //
// > **Note**: Filters and sorts are optional; without them, no filtering controls are rendered. // > **Note**: Filters and sorts are optional; without them, no filtering controls are rendered.
func (s *Library) SearchLibrary(ctx context.Context, sectionID int64, type_ operations.Type) (*operations.SearchLibraryResponse, error) { func (s *Library) SearchLibrary(ctx context.Context, sectionID int64, type_ operations.Type) (*operations.SearchLibraryResponse, error) {
hookCtx := hooks.HookContext{OperationID: "searchLibrary"}
request := operations.SearchLibraryRequest{ request := operations.SearchLibraryRequest{
SectionID: sectionID, SectionID: sectionID,
Type: type_, Type: type_,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/library/sections/{sectionId}/search", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/library/sections/{sectionId}/search", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.SearchLibraryResponse{ res := &operations.SearchLibraryResponse{
@@ -666,6 +843,7 @@ func (s *Library) SearchLibrary(ctx context.Context, sectionID int64, type_ oper
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -691,33 +869,53 @@ func (s *Library) SearchLibrary(ctx context.Context, sectionID int64, type_ oper
// GetMetadata - Get Items Metadata // GetMetadata - Get Items Metadata
// This endpoint will return the metadata of a library item specified with the ratingKey. // This endpoint will return the metadata of a library item specified with the ratingKey.
func (s *Library) GetMetadata(ctx context.Context, ratingKey float64) (*operations.GetMetadataResponse, error) { func (s *Library) GetMetadata(ctx context.Context, ratingKey float64) (*operations.GetMetadataResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getMetadata"}
request := operations.GetMetadataRequest{ request := operations.GetMetadataRequest{
RatingKey: ratingKey, RatingKey: ratingKey,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/library/metadata/{ratingKey}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/library/metadata/{ratingKey}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetMetadataResponse{ res := &operations.GetMetadataResponse{
@@ -732,6 +930,7 @@ func (s *Library) GetMetadata(ctx context.Context, ratingKey float64) (*operatio
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -772,33 +971,53 @@ func (s *Library) GetMetadata(ctx context.Context, ratingKey float64) (*operatio
// GetMetadataChildren - Get Items Children // GetMetadataChildren - Get Items Children
// This endpoint will return the children of of a library item specified with the ratingKey. // This endpoint will return the children of of a library item specified with the ratingKey.
func (s *Library) GetMetadataChildren(ctx context.Context, ratingKey float64) (*operations.GetMetadataChildrenResponse, error) { func (s *Library) GetMetadataChildren(ctx context.Context, ratingKey float64) (*operations.GetMetadataChildrenResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getMetadataChildren"}
request := operations.GetMetadataChildrenRequest{ request := operations.GetMetadataChildrenRequest{
RatingKey: ratingKey, RatingKey: ratingKey,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/library/metadata/{ratingKey}/children", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/library/metadata/{ratingKey}/children", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetMetadataChildrenResponse{ res := &operations.GetMetadataChildrenResponse{
@@ -813,6 +1032,7 @@ func (s *Library) GetMetadataChildren(ctx context.Context, ratingKey float64) (*
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -853,26 +1073,49 @@ func (s *Library) GetMetadataChildren(ctx context.Context, ratingKey float64) (*
// GetOnDeck - Get On Deck // GetOnDeck - Get On Deck
// This endpoint will return the on deck content. // This endpoint will return the on deck content.
func (s *Library) GetOnDeck(ctx context.Context) (*operations.GetOnDeckResponse, error) { func (s *Library) GetOnDeck(ctx context.Context) (*operations.GetOnDeckResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getOnDeck"}
url := strings.TrimSuffix(baseURL, "/") + "/library/onDeck"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/library/onDeck")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetOnDeckResponse{ res := &operations.GetOnDeckResponse{
@@ -887,6 +1130,7 @@ func (s *Library) GetOnDeck(ctx context.Context) (*operations.GetOnDeckResponse,
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {

125
log.go
View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Log - Submit logs to the Log Handler for Plex Media Server // Log - Submit logs to the Log Handler for Plex Media Server
@@ -28,6 +29,8 @@ func newLog(sdkConfig sdkConfiguration) *Log {
// LogLine - Logging a single line message. // LogLine - Logging a single line message.
// This endpoint will write a single-line log message, including a level and source to the main Plex Media Server log. // This endpoint will write a single-line log message, including a level and source to the main Plex Media Server log.
func (s *Log) LogLine(ctx context.Context, level operations.Level, message string, source string) (*operations.LogLineResponse, error) { func (s *Log) LogLine(ctx context.Context, level operations.Level, message string, source string) (*operations.LogLineResponse, error) {
hookCtx := hooks.HookContext{OperationID: "logLine"}
request := operations.LogLineRequest{ request := operations.LogLineRequest{
Level: level, Level: level,
Message: message, Message: message,
@@ -35,29 +38,50 @@ func (s *Log) LogLine(ctx context.Context, level operations.Level, message strin
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/log" opURL, err := url.JoinPath(baseURL, "/log")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.LogLineResponse{ res := &operations.LogLineResponse{
@@ -72,6 +96,7 @@ func (s *Log) LogLine(ctx context.Context, level operations.Level, message strin
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -121,36 +146,55 @@ func (s *Log) LogLine(ctx context.Context, level operations.Level, message strin
// //
// Ensure each parameter is properly URL-encoded to avoid interpretation issues. // Ensure each parameter is properly URL-encoded to avoid interpretation issues.
func (s *Log) LogMultiLine(ctx context.Context, request string) (*operations.LogMultiLineResponse, error) { func (s *Log) LogMultiLine(ctx context.Context, request string) (*operations.LogMultiLineResponse, error) {
hookCtx := hooks.HookContext{OperationID: "logMultiLine"}
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/log" opURL, err := url.JoinPath(baseURL, "/log")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
bodyReader, reqContentType, err := utils.SerializeRequestBody(ctx, request, false, false, "Request", "string", `request:"mediaType=text/plain"`) bodyReader, reqContentType, err := utils.SerializeRequestBody(ctx, request, false, false, "Request", "string", `request:"mediaType=text/plain"`)
if err != nil { if err != nil {
return nil, fmt.Errorf("error serializing request body: %w", err) return nil, err
}
if bodyReader == nil {
return nil, fmt.Errorf("request body is required")
} }
req, err := http.NewRequestWithContext(ctx, "POST", url, bodyReader) req, err := http.NewRequestWithContext(ctx, "POST", opURL, bodyReader)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req.Header.Set("Content-Type", reqContentType) req.Header.Set("Content-Type", reqContentType)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.LogMultiLineResponse{ res := &operations.LogMultiLineResponse{
@@ -165,6 +209,7 @@ func (s *Log) LogMultiLine(ctx context.Context, request string) (*operations.Log
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -194,26 +239,49 @@ func (s *Log) LogMultiLine(ctx context.Context, request string) (*operations.Log
// EnablePaperTrail - Enabling Papertrail // EnablePaperTrail - Enabling Papertrail
// This endpoint will enable all Plex Media Serverlogs to be sent to the Papertrail networked logging site for a period of time. // This endpoint will enable all Plex Media Serverlogs to be sent to the Papertrail networked logging site for a period of time.
func (s *Log) EnablePaperTrail(ctx context.Context) (*operations.EnablePaperTrailResponse, error) { func (s *Log) EnablePaperTrail(ctx context.Context) (*operations.EnablePaperTrailResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "enablePaperTrail"}
url := strings.TrimSuffix(baseURL, "/") + "/log/networked"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/log/networked")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "403", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.EnablePaperTrailResponse{ res := &operations.EnablePaperTrailResponse{
@@ -228,6 +296,7 @@ func (s *Log) EnablePaperTrail(ctx context.Context) (*operations.EnablePaperTrai
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:

117
media.go
View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Media - API Calls interacting with Plex Media Server Media // Media - API Calls interacting with Plex Media Server Media
@@ -28,34 +29,57 @@ func newMedia(sdkConfig sdkConfiguration) *Media {
// MarkPlayed - Mark Media Played // MarkPlayed - Mark Media Played
// This will mark the provided media key as Played. // This will mark the provided media key as Played.
func (s *Media) MarkPlayed(ctx context.Context, key float64) (*operations.MarkPlayedResponse, error) { func (s *Media) MarkPlayed(ctx context.Context, key float64) (*operations.MarkPlayedResponse, error) {
hookCtx := hooks.HookContext{OperationID: "markPlayed"}
request := operations.MarkPlayedRequest{ request := operations.MarkPlayedRequest{
Key: key, Key: key,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/:/scrobble" opURL, err := url.JoinPath(baseURL, "/:/scrobble")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.MarkPlayedResponse{ res := &operations.MarkPlayedResponse{
@@ -70,6 +94,7 @@ func (s *Media) MarkPlayed(ctx context.Context, key float64) (*operations.MarkPl
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -99,34 +124,57 @@ func (s *Media) MarkPlayed(ctx context.Context, key float64) (*operations.MarkPl
// MarkUnplayed - Mark Media Unplayed // MarkUnplayed - Mark Media Unplayed
// This will mark the provided media key as Unplayed. // This will mark the provided media key as Unplayed.
func (s *Media) MarkUnplayed(ctx context.Context, key float64) (*operations.MarkUnplayedResponse, error) { func (s *Media) MarkUnplayed(ctx context.Context, key float64) (*operations.MarkUnplayedResponse, error) {
hookCtx := hooks.HookContext{OperationID: "markUnplayed"}
request := operations.MarkUnplayedRequest{ request := operations.MarkUnplayedRequest{
Key: key, Key: key,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/:/unscrobble" opURL, err := url.JoinPath(baseURL, "/:/unscrobble")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.MarkUnplayedResponse{ res := &operations.MarkUnplayedResponse{
@@ -141,6 +189,7 @@ func (s *Media) MarkUnplayed(ctx context.Context, key float64) (*operations.Mark
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -170,6 +219,8 @@ func (s *Media) MarkUnplayed(ctx context.Context, key float64) (*operations.Mark
// UpdatePlayProgress - Update Media Play Progress // UpdatePlayProgress - Update Media Play Progress
// This API command can be used to update the play progress of a media item. // This API command can be used to update the play progress of a media item.
func (s *Media) UpdatePlayProgress(ctx context.Context, key string, time float64, state string) (*operations.UpdatePlayProgressResponse, error) { func (s *Media) UpdatePlayProgress(ctx context.Context, key string, time float64, state string) (*operations.UpdatePlayProgressResponse, error) {
hookCtx := hooks.HookContext{OperationID: "updatePlayProgress"}
request := operations.UpdatePlayProgressRequest{ request := operations.UpdatePlayProgressRequest{
Key: key, Key: key,
Time: time, Time: time,
@@ -177,29 +228,50 @@ func (s *Media) UpdatePlayProgress(ctx context.Context, key string, time float64
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/:/progress" opURL, err := url.JoinPath(baseURL, "/:/progress")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", url, nil) req, err := http.NewRequestWithContext(ctx, "POST", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.UpdatePlayProgressResponse{ res := &operations.UpdatePlayProgressResponse{
@@ -214,6 +286,7 @@ func (s *Media) UpdatePlayProgress(ctx context.Context, key string, time float64
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:

View File

@@ -3,232 +3,92 @@
package operations package operations
import ( import (
"errors"
"github.com/LukeHagar/plexgo/internal/utils"
"net/http" "net/http"
) )
type Two struct { type Setting struct {
ID *string `json:"id,omitempty"` ID *string `json:"id,omitempty"`
Label *string `json:"label,omitempty"` Label *string `json:"label,omitempty"`
Summary *string `json:"summary,omitempty"` Summary *string `json:"summary,omitempty"`
Type *string `json:"type,omitempty"` Type *string `json:"type,omitempty"`
Default *int `json:"default,omitempty"` Default *bool `json:"default,omitempty"`
Value *int `json:"value,omitempty"` Value *bool `json:"value,omitempty"`
Hidden *bool `json:"hidden,omitempty"` Hidden *bool `json:"hidden,omitempty"`
Advanced *bool `json:"advanced,omitempty"` Advanced *bool `json:"advanced,omitempty"`
Group *string `json:"group,omitempty"` Group *string `json:"group,omitempty"`
EnumValues *string `json:"enumValues,omitempty"` EnumValues *string `json:"enumValues,omitempty"`
} }
func (o *Two) GetID() *string { func (o *Setting) GetID() *string {
if o == nil { if o == nil {
return nil return nil
} }
return o.ID return o.ID
} }
func (o *Two) GetLabel() *string { func (o *Setting) GetLabel() *string {
if o == nil { if o == nil {
return nil return nil
} }
return o.Label return o.Label
} }
func (o *Two) GetSummary() *string { func (o *Setting) GetSummary() *string {
if o == nil { if o == nil {
return nil return nil
} }
return o.Summary return o.Summary
} }
func (o *Two) GetType() *string { func (o *Setting) GetType() *string {
if o == nil { if o == nil {
return nil return nil
} }
return o.Type return o.Type
} }
func (o *Two) GetDefault() *int { func (o *Setting) GetDefault() *bool {
if o == nil { if o == nil {
return nil return nil
} }
return o.Default return o.Default
} }
func (o *Two) GetValue() *int { func (o *Setting) GetValue() *bool {
if o == nil { if o == nil {
return nil return nil
} }
return o.Value return o.Value
} }
func (o *Two) GetHidden() *bool { func (o *Setting) GetHidden() *bool {
if o == nil { if o == nil {
return nil return nil
} }
return o.Hidden return o.Hidden
} }
func (o *Two) GetAdvanced() *bool { func (o *Setting) GetAdvanced() *bool {
if o == nil { if o == nil {
return nil return nil
} }
return o.Advanced return o.Advanced
} }
func (o *Two) GetGroup() *string { func (o *Setting) GetGroup() *string {
if o == nil { if o == nil {
return nil return nil
} }
return o.Group return o.Group
} }
func (o *Two) GetEnumValues() *string { func (o *Setting) GetEnumValues() *string {
if o == nil { if o == nil {
return nil return nil
} }
return o.EnumValues return o.EnumValues
} }
type One struct {
ID *string `json:"id,omitempty"`
Label *string `json:"label,omitempty"`
Summary *string `json:"summary,omitempty"`
Type *string `json:"type,omitempty"`
Default *string `json:"default,omitempty"`
Value *string `json:"value,omitempty"`
Hidden *bool `json:"hidden,omitempty"`
Advanced *bool `json:"advanced,omitempty"`
Group *string `json:"group,omitempty"`
}
func (o *One) GetID() *string {
if o == nil {
return nil
}
return o.ID
}
func (o *One) GetLabel() *string {
if o == nil {
return nil
}
return o.Label
}
func (o *One) GetSummary() *string {
if o == nil {
return nil
}
return o.Summary
}
func (o *One) GetType() *string {
if o == nil {
return nil
}
return o.Type
}
func (o *One) GetDefault() *string {
if o == nil {
return nil
}
return o.Default
}
func (o *One) GetValue() *string {
if o == nil {
return nil
}
return o.Value
}
func (o *One) GetHidden() *bool {
if o == nil {
return nil
}
return o.Hidden
}
func (o *One) GetAdvanced() *bool {
if o == nil {
return nil
}
return o.Advanced
}
func (o *One) GetGroup() *string {
if o == nil {
return nil
}
return o.Group
}
type SettingType string
const (
SettingTypeOne SettingType = "1"
SettingTypeTwo SettingType = "2"
)
type Setting struct {
One *One
Two *Two
Type SettingType
}
func CreateSettingOne(one One) Setting {
typ := SettingTypeOne
return Setting{
One: &one,
Type: typ,
}
}
func CreateSettingTwo(two Two) Setting {
typ := SettingTypeTwo
return Setting{
Two: &two,
Type: typ,
}
}
func (u *Setting) UnmarshalJSON(data []byte) error {
one := One{}
if err := utils.UnmarshalJSON(data, &one, "", true, true); err == nil {
u.One = &one
u.Type = SettingTypeOne
return nil
}
two := Two{}
if err := utils.UnmarshalJSON(data, &two, "", true, true); err == nil {
u.Two = &two
u.Type = SettingTypeTwo
return nil
}
return errors.New("could not unmarshal into supported union types")
}
func (u Setting) MarshalJSON() ([]byte, error) {
if u.One != nil {
return utils.MarshalJSON(u.One, "", true)
}
if u.Two != nil {
return utils.MarshalJSON(u.Two, "", true)
}
return nil, errors.New("could not marshal union type: all fields are null")
}
type GetServerPreferencesMediaContainer struct { type GetServerPreferencesMediaContainer struct {
Size *int `json:"size,omitempty"` Size *int `json:"size,omitempty"`
Setting []Setting `json:"Setting,omitempty"` Setting []Setting `json:"Setting,omitempty"`

View File

@@ -0,0 +1,276 @@
// Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT.
package operations
import (
"net/http"
)
type GetStatisticsRequest struct {
// The timespan to retrieve statistics for
// the exact meaning of this parameter is not known
//
Timespan *int64 `queryParam:"style=form,explode=true,name=Timespan"`
}
func (o *GetStatisticsRequest) GetTimespan() *int64 {
if o == nil {
return nil
}
return o.Timespan
}
type GetStatisticsDevice struct {
ID *int `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
Platform *string `json:"platform,omitempty"`
ClientIdentifier *string `json:"clientIdentifier,omitempty"`
CreatedAt *int `json:"createdAt,omitempty"`
}
func (o *GetStatisticsDevice) GetID() *int {
if o == nil {
return nil
}
return o.ID
}
func (o *GetStatisticsDevice) GetName() *string {
if o == nil {
return nil
}
return o.Name
}
func (o *GetStatisticsDevice) GetPlatform() *string {
if o == nil {
return nil
}
return o.Platform
}
func (o *GetStatisticsDevice) GetClientIdentifier() *string {
if o == nil {
return nil
}
return o.ClientIdentifier
}
func (o *GetStatisticsDevice) GetCreatedAt() *int {
if o == nil {
return nil
}
return o.CreatedAt
}
type Account struct {
ID *int `json:"id,omitempty"`
Key *string `json:"key,omitempty"`
Name *string `json:"name,omitempty"`
DefaultAudioLanguage *string `json:"defaultAudioLanguage,omitempty"`
AutoSelectAudio *bool `json:"autoSelectAudio,omitempty"`
DefaultSubtitleLanguage *string `json:"defaultSubtitleLanguage,omitempty"`
SubtitleMode *int `json:"subtitleMode,omitempty"`
Thumb *string `json:"thumb,omitempty"`
}
func (o *Account) GetID() *int {
if o == nil {
return nil
}
return o.ID
}
func (o *Account) GetKey() *string {
if o == nil {
return nil
}
return o.Key
}
func (o *Account) GetName() *string {
if o == nil {
return nil
}
return o.Name
}
func (o *Account) GetDefaultAudioLanguage() *string {
if o == nil {
return nil
}
return o.DefaultAudioLanguage
}
func (o *Account) GetAutoSelectAudio() *bool {
if o == nil {
return nil
}
return o.AutoSelectAudio
}
func (o *Account) GetDefaultSubtitleLanguage() *string {
if o == nil {
return nil
}
return o.DefaultSubtitleLanguage
}
func (o *Account) GetSubtitleMode() *int {
if o == nil {
return nil
}
return o.SubtitleMode
}
func (o *Account) GetThumb() *string {
if o == nil {
return nil
}
return o.Thumb
}
type StatisticsMedia struct {
AccountID *int `json:"accountID,omitempty"`
DeviceID *int `json:"deviceID,omitempty"`
Timespan *int `json:"timespan,omitempty"`
At *int `json:"at,omitempty"`
MetadataType *int `json:"metadataType,omitempty"`
Count *int `json:"count,omitempty"`
Duration *int `json:"duration,omitempty"`
}
func (o *StatisticsMedia) GetAccountID() *int {
if o == nil {
return nil
}
return o.AccountID
}
func (o *StatisticsMedia) GetDeviceID() *int {
if o == nil {
return nil
}
return o.DeviceID
}
func (o *StatisticsMedia) GetTimespan() *int {
if o == nil {
return nil
}
return o.Timespan
}
func (o *StatisticsMedia) GetAt() *int {
if o == nil {
return nil
}
return o.At
}
func (o *StatisticsMedia) GetMetadataType() *int {
if o == nil {
return nil
}
return o.MetadataType
}
func (o *StatisticsMedia) GetCount() *int {
if o == nil {
return nil
}
return o.Count
}
func (o *StatisticsMedia) GetDuration() *int {
if o == nil {
return nil
}
return o.Duration
}
type GetStatisticsMediaContainer struct {
Size *int `json:"size,omitempty"`
Device []GetStatisticsDevice `json:"Device,omitempty"`
Account []Account `json:"Account,omitempty"`
StatisticsMedia []StatisticsMedia `json:"StatisticsMedia,omitempty"`
}
func (o *GetStatisticsMediaContainer) GetSize() *int {
if o == nil {
return nil
}
return o.Size
}
func (o *GetStatisticsMediaContainer) GetDevice() []GetStatisticsDevice {
if o == nil {
return nil
}
return o.Device
}
func (o *GetStatisticsMediaContainer) GetAccount() []Account {
if o == nil {
return nil
}
return o.Account
}
func (o *GetStatisticsMediaContainer) GetStatisticsMedia() []StatisticsMedia {
if o == nil {
return nil
}
return o.StatisticsMedia
}
// GetStatisticsResponseBody - Media Statistics
type GetStatisticsResponseBody struct {
MediaContainer *GetStatisticsMediaContainer `json:"MediaContainer,omitempty"`
}
func (o *GetStatisticsResponseBody) GetMediaContainer() *GetStatisticsMediaContainer {
if o == nil {
return nil
}
return o.MediaContainer
}
type GetStatisticsResponse struct {
// HTTP response content type for this operation
ContentType string
// HTTP response status code for this operation
StatusCode int
// Raw HTTP response; suitable for custom response parsing
RawResponse *http.Response
// Media Statistics
Object *GetStatisticsResponseBody
}
func (o *GetStatisticsResponse) GetContentType() string {
if o == nil {
return ""
}
return o.ContentType
}
func (o *GetStatisticsResponse) GetStatusCode() int {
if o == nil {
return 0
}
return o.StatusCode
}
func (o *GetStatisticsResponse) GetRawResponse() *http.Response {
if o == nil {
return nil
}
return o.RawResponse
}
func (o *GetStatisticsResponse) GetObject() *GetStatisticsResponseBody {
if o == nil {
return nil
}
return o.Object
}

View File

@@ -0,0 +1,49 @@
// Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT.
package sdkerrors
import (
"encoding/json"
"net/http"
)
type GetStatisticsErrors struct {
Code *float64 `json:"code,omitempty"`
Message *string `json:"message,omitempty"`
Status *float64 `json:"status,omitempty"`
}
func (o *GetStatisticsErrors) GetCode() *float64 {
if o == nil {
return nil
}
return o.Code
}
func (o *GetStatisticsErrors) GetMessage() *string {
if o == nil {
return nil
}
return o.Message
}
func (o *GetStatisticsErrors) GetStatus() *float64 {
if o == nil {
return nil
}
return o.Status
}
// GetStatisticsResponseBody - Unauthorized - Returned if the X-Plex-Token is missing from the header or query.
type GetStatisticsResponseBody struct {
Errors []GetStatisticsErrors `json:"errors,omitempty"`
// Raw HTTP response; suitable for custom response parsing
RawResponse *http.Response `json:"-"`
}
var _ error = &GetStatisticsResponseBody{}
func (e *GetStatisticsResponseBody) Error() string {
data, _ := json.Marshal(e)
return string(data)
}

View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Playlists are ordered collections of media. They can be dumb (just a list of media) or smart (based on a media query, such as "all albums from 2017"). // Playlists are ordered collections of media. They can be dumb (just a list of media) or smart (based on a media query, such as "all albums from 2017").
@@ -33,30 +34,53 @@ func newPlaylists(sdkConfig sdkConfiguration) *Playlists {
// - `uri` - The content URI for what we're playing (e.g. `server://1234/com.plexapp.plugins.library/library/metadata/1`). // - `uri` - The content URI for what we're playing (e.g. `server://1234/com.plexapp.plugins.library/library/metadata/1`).
// - `playQueueID` - To create a playlist from an existing play queue. // - `playQueueID` - To create a playlist from an existing play queue.
func (s *Playlists) CreatePlaylist(ctx context.Context, request operations.CreatePlaylistRequest) (*operations.CreatePlaylistResponse, error) { func (s *Playlists) CreatePlaylist(ctx context.Context, request operations.CreatePlaylistRequest) (*operations.CreatePlaylistResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "createPlaylist"}
url := strings.TrimSuffix(baseURL, "/") + "/playlists"
req, err := http.NewRequestWithContext(ctx, "POST", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/playlists")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.CreatePlaylistResponse{ res := &operations.CreatePlaylistResponse{
@@ -71,6 +95,7 @@ func (s *Playlists) CreatePlaylist(ctx context.Context, request operations.Creat
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -111,35 +136,58 @@ func (s *Playlists) CreatePlaylist(ctx context.Context, request operations.Creat
// GetPlaylists - Get All Playlists // GetPlaylists - Get All Playlists
// Get All Playlists given the specified filters. // Get All Playlists given the specified filters.
func (s *Playlists) GetPlaylists(ctx context.Context, playlistType *operations.PlaylistType, smart *operations.QueryParamSmart) (*operations.GetPlaylistsResponse, error) { func (s *Playlists) GetPlaylists(ctx context.Context, playlistType *operations.PlaylistType, smart *operations.QueryParamSmart) (*operations.GetPlaylistsResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getPlaylists"}
request := operations.GetPlaylistsRequest{ request := operations.GetPlaylistsRequest{
PlaylistType: playlistType, PlaylistType: playlistType,
Smart: smart, Smart: smart,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/playlists" opURL, err := url.JoinPath(baseURL, "/playlists")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetPlaylistsResponse{ res := &operations.GetPlaylistsResponse{
@@ -154,6 +202,7 @@ func (s *Playlists) GetPlaylists(ctx context.Context, playlistType *operations.P
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -195,33 +244,53 @@ func (s *Playlists) GetPlaylists(ctx context.Context, playlistType *operations.P
// Gets detailed metadata for a playlist. A playlist for many purposes (rating, editing metadata, tagging), can be treated like a regular metadata item: // Gets detailed metadata for a playlist. A playlist for many purposes (rating, editing metadata, tagging), can be treated like a regular metadata item:
// Smart playlist details contain the `content` attribute. This is the content URI for the generator. This can then be parsed by a client to provide smart playlist editing. // Smart playlist details contain the `content` attribute. This is the content URI for the generator. This can then be parsed by a client to provide smart playlist editing.
func (s *Playlists) GetPlaylist(ctx context.Context, playlistID float64) (*operations.GetPlaylistResponse, error) { func (s *Playlists) GetPlaylist(ctx context.Context, playlistID float64) (*operations.GetPlaylistResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getPlaylist"}
request := operations.GetPlaylistRequest{ request := operations.GetPlaylistRequest{
PlaylistID: playlistID, PlaylistID: playlistID,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetPlaylistResponse{ res := &operations.GetPlaylistResponse{
@@ -236,6 +305,7 @@ func (s *Playlists) GetPlaylist(ctx context.Context, playlistID float64) (*opera
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -276,33 +346,53 @@ func (s *Playlists) GetPlaylist(ctx context.Context, playlistID float64) (*opera
// DeletePlaylist - Deletes a Playlist // DeletePlaylist - Deletes a Playlist
// This endpoint will delete a playlist // This endpoint will delete a playlist
func (s *Playlists) DeletePlaylist(ctx context.Context, playlistID float64) (*operations.DeletePlaylistResponse, error) { func (s *Playlists) DeletePlaylist(ctx context.Context, playlistID float64) (*operations.DeletePlaylistResponse, error) {
hookCtx := hooks.HookContext{OperationID: "deletePlaylist"}
request := operations.DeletePlaylistRequest{ request := operations.DeletePlaylistRequest{
PlaylistID: playlistID, PlaylistID: playlistID,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "DELETE", url, nil) req, err := http.NewRequestWithContext(ctx, "DELETE", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.DeletePlaylistResponse{ res := &operations.DeletePlaylistResponse{
@@ -317,6 +407,7 @@ func (s *Playlists) DeletePlaylist(ctx context.Context, playlistID float64) (*op
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -346,6 +437,8 @@ func (s *Playlists) DeletePlaylist(ctx context.Context, playlistID float64) (*op
// UpdatePlaylist - Update a Playlist // UpdatePlaylist - Update a Playlist
// From PMS version 1.9.1 clients can also edit playlist metadata using this endpoint as they would via `PUT /library/metadata/{playlistID}` // From PMS version 1.9.1 clients can also edit playlist metadata using this endpoint as they would via `PUT /library/metadata/{playlistID}`
func (s *Playlists) UpdatePlaylist(ctx context.Context, playlistID float64, title *string, summary *string) (*operations.UpdatePlaylistResponse, error) { func (s *Playlists) UpdatePlaylist(ctx context.Context, playlistID float64, title *string, summary *string) (*operations.UpdatePlaylistResponse, error) {
hookCtx := hooks.HookContext{OperationID: "updatePlaylist"}
request := operations.UpdatePlaylistRequest{ request := operations.UpdatePlaylistRequest{
PlaylistID: playlistID, PlaylistID: playlistID,
Title: title, Title: title,
@@ -353,32 +446,50 @@ func (s *Playlists) UpdatePlaylist(ctx context.Context, playlistID float64, titl
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "PUT", url, nil) req, err := http.NewRequestWithContext(ctx, "PUT", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.UpdatePlaylistResponse{ res := &operations.UpdatePlaylistResponse{
@@ -393,6 +504,7 @@ func (s *Playlists) UpdatePlaylist(ctx context.Context, playlistID float64, titl
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -425,38 +537,58 @@ func (s *Playlists) UpdatePlaylist(ctx context.Context, playlistID float64, titl
// For example, you could use this to display a list of recently added albums vis a smart playlist. // For example, you could use this to display a list of recently added albums vis a smart playlist.
// Note that for dumb playlists, items have a `playlistItemID` attribute which is used for deleting or moving items. // Note that for dumb playlists, items have a `playlistItemID` attribute which is used for deleting or moving items.
func (s *Playlists) GetPlaylistContents(ctx context.Context, playlistID float64, type_ float64) (*operations.GetPlaylistContentsResponse, error) { func (s *Playlists) GetPlaylistContents(ctx context.Context, playlistID float64, type_ float64) (*operations.GetPlaylistContentsResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getPlaylistContents"}
request := operations.GetPlaylistContentsRequest{ request := operations.GetPlaylistContentsRequest{
PlaylistID: playlistID, PlaylistID: playlistID,
Type: type_, Type: type_,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}/items", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}/items", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetPlaylistContentsResponse{ res := &operations.GetPlaylistContentsResponse{
@@ -471,6 +603,7 @@ func (s *Playlists) GetPlaylistContents(ctx context.Context, playlistID float64,
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -511,33 +644,53 @@ func (s *Playlists) GetPlaylistContents(ctx context.Context, playlistID float64,
// ClearPlaylistContents - Delete Playlist Contents // ClearPlaylistContents - Delete Playlist Contents
// Clears a playlist, only works with dumb playlists. Returns the playlist. // Clears a playlist, only works with dumb playlists. Returns the playlist.
func (s *Playlists) ClearPlaylistContents(ctx context.Context, playlistID float64) (*operations.ClearPlaylistContentsResponse, error) { func (s *Playlists) ClearPlaylistContents(ctx context.Context, playlistID float64) (*operations.ClearPlaylistContentsResponse, error) {
hookCtx := hooks.HookContext{OperationID: "clearPlaylistContents"}
request := operations.ClearPlaylistContentsRequest{ request := operations.ClearPlaylistContentsRequest{
PlaylistID: playlistID, PlaylistID: playlistID,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}/items", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}/items", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "DELETE", url, nil) req, err := http.NewRequestWithContext(ctx, "DELETE", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.ClearPlaylistContentsResponse{ res := &operations.ClearPlaylistContentsResponse{
@@ -552,6 +705,7 @@ func (s *Playlists) ClearPlaylistContents(ctx context.Context, playlistID float6
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -582,6 +736,8 @@ func (s *Playlists) ClearPlaylistContents(ctx context.Context, playlistID float6
// Adds a generator to a playlist, same parameters as the POST to create. With a dumb playlist, this adds the specified items to the playlist. // Adds a generator to a playlist, same parameters as the POST to create. With a dumb playlist, this adds the specified items to the playlist.
// With a smart playlist, passing a new `uri` parameter replaces the rules for the playlist. Returns the playlist. // With a smart playlist, passing a new `uri` parameter replaces the rules for the playlist. Returns the playlist.
func (s *Playlists) AddPlaylistContents(ctx context.Context, playlistID float64, uri string, playQueueID *float64) (*operations.AddPlaylistContentsResponse, error) { func (s *Playlists) AddPlaylistContents(ctx context.Context, playlistID float64, uri string, playQueueID *float64) (*operations.AddPlaylistContentsResponse, error) {
hookCtx := hooks.HookContext{OperationID: "addPlaylistContents"}
request := operations.AddPlaylistContentsRequest{ request := operations.AddPlaylistContentsRequest{
PlaylistID: playlistID, PlaylistID: playlistID,
URI: uri, URI: uri,
@@ -589,32 +745,50 @@ func (s *Playlists) AddPlaylistContents(ctx context.Context, playlistID float64,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}/items", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/playlists/{playlistID}/items", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "PUT", url, nil) req, err := http.NewRequestWithContext(ctx, "PUT", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.AddPlaylistContentsResponse{ res := &operations.AddPlaylistContentsResponse{
@@ -629,6 +803,7 @@ func (s *Playlists) AddPlaylistContents(ctx context.Context, playlistID float64,
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -669,35 +844,58 @@ func (s *Playlists) AddPlaylistContents(ctx context.Context, playlistID float64,
// UploadPlaylist - Upload Playlist // UploadPlaylist - Upload Playlist
// Imports m3u playlists by passing a path on the server to scan for m3u-formatted playlist files, or a path to a single playlist file. // Imports m3u playlists by passing a path on the server to scan for m3u-formatted playlist files, or a path to a single playlist file.
func (s *Playlists) UploadPlaylist(ctx context.Context, path string, force operations.Force) (*operations.UploadPlaylistResponse, error) { func (s *Playlists) UploadPlaylist(ctx context.Context, path string, force operations.Force) (*operations.UploadPlaylistResponse, error) {
hookCtx := hooks.HookContext{OperationID: "uploadPlaylist"}
request := operations.UploadPlaylistRequest{ request := operations.UploadPlaylistRequest{
Path: path, Path: path,
Force: force, Force: force,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/playlists/upload" opURL, err := url.JoinPath(baseURL, "/playlists/upload")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", url, nil) req, err := http.NewRequestWithContext(ctx, "POST", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.UploadPlaylistResponse{ res := &operations.UploadPlaylistResponse{
@@ -712,6 +910,7 @@ func (s *Playlists) UploadPlaylist(ctx context.Context, path string, force opera
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:

76
plex.go
View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Plex - API Calls that perform operations directly against https://Plex.tv // Plex - API Calls that perform operations directly against https://Plex.tv
@@ -28,6 +29,8 @@ func newPlex(sdkConfig sdkConfiguration) *Plex {
// GetPin - Get a Pin // GetPin - Get a Pin
// Retrieve a Pin from Plex.tv for authentication flows // Retrieve a Pin from Plex.tv for authentication flows
func (s *Plex) GetPin(ctx context.Context, xPlexClientIdentifier string, strong *bool, opts ...operations.Option) (*operations.GetPinResponse, error) { func (s *Plex) GetPin(ctx context.Context, xPlexClientIdentifier string, strong *bool, opts ...operations.Option) (*operations.GetPinResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getPin"}
request := operations.GetPinRequest{ request := operations.GetPinRequest{
XPlexClientIdentifier: xPlexClientIdentifier, XPlexClientIdentifier: xPlexClientIdentifier,
Strong: strong, Strong: strong,
@@ -48,14 +51,17 @@ func (s *Plex) GetPin(ctx context.Context, xPlexClientIdentifier string, strong
baseURL = *o.ServerURL baseURL = *o.ServerURL
} }
url := strings.TrimSuffix(baseURL, "/") + "/pins" opURL, err := url.JoinPath(baseURL, "/pins")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", url, nil) req, err := http.NewRequestWithContext(ctx, "POST", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
utils.PopulateHeaders(ctx, req, request) utils.PopulateHeaders(ctx, req, request)
@@ -63,16 +69,34 @@ func (s *Plex) GetPin(ctx context.Context, xPlexClientIdentifier string, strong
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetPinResponse{ res := &operations.GetPinResponse{
@@ -87,6 +111,7 @@ func (s *Plex) GetPin(ctx context.Context, xPlexClientIdentifier string, strong
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -125,6 +150,8 @@ func (s *Plex) GetPin(ctx context.Context, xPlexClientIdentifier string, strong
// GetToken - Get Access Token // GetToken - Get Access Token
// Retrieve an Access Token from Plex.tv after the Pin has already been authenticated // Retrieve an Access Token from Plex.tv after the Pin has already been authenticated
func (s *Plex) GetToken(ctx context.Context, pinID string, xPlexClientIdentifier string, opts ...operations.Option) (*operations.GetTokenResponse, error) { func (s *Plex) GetToken(ctx context.Context, pinID string, xPlexClientIdentifier string, opts ...operations.Option) (*operations.GetTokenResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getToken"}
request := operations.GetTokenRequest{ request := operations.GetTokenRequest{
PinID: pinID, PinID: pinID,
XPlexClientIdentifier: xPlexClientIdentifier, XPlexClientIdentifier: xPlexClientIdentifier,
@@ -145,30 +172,48 @@ func (s *Plex) GetToken(ctx context.Context, pinID string, xPlexClientIdentifier
baseURL = *o.ServerURL baseURL = *o.ServerURL
} }
url, err := utils.GenerateURL(ctx, baseURL, "/pins/{pinID}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/pins/{pinID}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
utils.PopulateHeaders(ctx, req, request) utils.PopulateHeaders(ctx, req, request)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetTokenResponse{ res := &operations.GetTokenResponse{
@@ -183,6 +228,7 @@ func (s *Plex) GetToken(ctx context.Context, pinID string, xPlexClientIdentifier
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:

View File

@@ -6,6 +6,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/components" "github.com/LukeHagar/plexgo/models/components"
"net/http" "net/http"
@@ -54,6 +55,7 @@ type sdkConfiguration struct {
GenVersion string GenVersion string
UserAgent string UserAgent string
RetryConfig *utils.RetryConfig RetryConfig *utils.RetryConfig
Hooks *hooks.Hooks
} }
func (c *sdkConfiguration) GetServerDetails() (string, map[string]string) { func (c *sdkConfiguration) GetServerDetails() (string, map[string]string) {
@@ -73,6 +75,9 @@ type PlexAPI struct {
// API Calls interacting with Plex Media Server Media // API Calls interacting with Plex Media Server Media
// //
Media *Media Media *Media
// API Calls that perform operations with Plex Media Server Videos
//
Video *Video
// Activities are awesome. They provide a way to monitor and control asynchronous operations on the server. In order to receive real-time updates for activities, a client would normally subscribe via either EventSource or Websocket endpoints. // Activities are awesome. They provide a way to monitor and control asynchronous operations on the server. In order to receive real-time updates for activities, a client would normally subscribe via either EventSource or Websocket endpoints.
// Activities are associated with HTTP replies via a special `X-Plex-Activity` header which contains the UUID of the activity. // Activities are associated with HTTP replies via a special `X-Plex-Activity` header which contains the UUID of the activity.
// Activities are optional cancellable. If cancellable, they may be cancelled via the `DELETE` endpoint. Other details: // Activities are optional cancellable. If cancellable, they may be cancelled via the `DELETE` endpoint. Other details:
@@ -109,6 +114,9 @@ type PlexAPI struct {
// API Calls against Security for Plex Media Server // API Calls against Security for Plex Media Server
// //
Security *Security Security *Security
// API Calls that perform operations with Plex Media Server Statistics
//
Statistics *Statistics
// API Calls that perform search operations with Plex Media Server Sessions // API Calls that perform search operations with Plex Media Server Sessions
// //
Sessions *Sessions Sessions *Sessions
@@ -116,9 +124,6 @@ type PlexAPI struct {
// Updates to the status can be observed via the Event API. // Updates to the status can be observed via the Event API.
// //
Updater *Updater Updater *Updater
// API Calls that perform operations with Plex Media Server Videos
//
Video *Video
sdkConfiguration sdkConfiguration sdkConfiguration sdkConfiguration
} }
@@ -263,9 +268,9 @@ func New(opts ...SDKOption) *PlexAPI {
sdkConfiguration: sdkConfiguration{ sdkConfiguration: sdkConfiguration{
Language: "go", Language: "go",
OpenAPIDocVersion: "0.0.3", OpenAPIDocVersion: "0.0.3",
SDKVersion: "0.3.0", SDKVersion: "0.4.0",
GenVersion: "2.249.1", GenVersion: "2.269.0",
UserAgent: "speakeasy-sdk/go 0.3.0 2.249.1 0.0.3 github.com/LukeHagar/plexgo", UserAgent: "speakeasy-sdk/go 0.4.0 2.269.0 0.0.3 github.com/LukeHagar/plexgo",
ServerDefaults: []map[string]string{ ServerDefaults: []map[string]string{
{ {
"protocol": "http", "protocol": "http",
@@ -273,12 +278,15 @@ func New(opts ...SDKOption) *PlexAPI {
"port": "32400", "port": "32400",
}, },
}, },
Hooks: hooks.New(),
}, },
} }
for _, opt := range opts { for _, opt := range opts {
opt(sdk) opt(sdk)
} }
sdk.sdkConfiguration.DefaultClient = sdk.sdkConfiguration.Hooks.ClientInit(sdk.sdkConfiguration.DefaultClient)
// Use WithClient to override the default client if you would like to customize the timeout // Use WithClient to override the default client if you would like to customize the timeout
if sdk.sdkConfiguration.DefaultClient == nil { if sdk.sdkConfiguration.DefaultClient == nil {
sdk.sdkConfiguration.DefaultClient = &http.Client{Timeout: 60 * time.Second} sdk.sdkConfiguration.DefaultClient = &http.Client{Timeout: 60 * time.Second}
@@ -295,6 +303,8 @@ func New(opts ...SDKOption) *PlexAPI {
sdk.Media = newMedia(sdk.sdkConfiguration) sdk.Media = newMedia(sdk.sdkConfiguration)
sdk.Video = newVideo(sdk.sdkConfiguration)
sdk.Activities = newActivities(sdk.sdkConfiguration) sdk.Activities = newActivities(sdk.sdkConfiguration)
sdk.Butler = newButler(sdk.sdkConfiguration) sdk.Butler = newButler(sdk.sdkConfiguration)
@@ -313,11 +323,11 @@ func New(opts ...SDKOption) *PlexAPI {
sdk.Security = newSecurity(sdk.sdkConfiguration) sdk.Security = newSecurity(sdk.sdkConfiguration)
sdk.Statistics = newStatistics(sdk.sdkConfiguration)
sdk.Sessions = newSessions(sdk.sdkConfiguration) sdk.Sessions = newSessions(sdk.sdkConfiguration)
sdk.Updater = newUpdater(sdk.sdkConfiguration) sdk.Updater = newUpdater(sdk.sdkConfiguration)
sdk.Video = newVideo(sdk.sdkConfiguration)
return sdk return sdk
} }

117
search.go
View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Search - API Calls that perform search operations with Plex Media Server // Search - API Calls that perform search operations with Plex Media Server
@@ -40,6 +41,8 @@ func newSearch(sdkConfig sdkConfiguration) *Search {
// //
// This request is intended to be very fast, and called as the user types. // This request is intended to be very fast, and called as the user types.
func (s *Search) PerformSearch(ctx context.Context, query string, sectionID *float64, limit *float64) (*operations.PerformSearchResponse, error) { func (s *Search) PerformSearch(ctx context.Context, query string, sectionID *float64, limit *float64) (*operations.PerformSearchResponse, error) {
hookCtx := hooks.HookContext{OperationID: "performSearch"}
request := operations.PerformSearchRequest{ request := operations.PerformSearchRequest{
Query: query, Query: query,
SectionID: sectionID, SectionID: sectionID,
@@ -47,29 +50,50 @@ func (s *Search) PerformSearch(ctx context.Context, query string, sectionID *flo
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/hubs/search" opURL, err := url.JoinPath(baseURL, "/hubs/search")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.PerformSearchResponse{ res := &operations.PerformSearchResponse{
@@ -84,6 +108,7 @@ func (s *Search) PerformSearch(ctx context.Context, query string, sectionID *flo
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -116,6 +141,8 @@ func (s *Search) PerformSearch(ctx context.Context, query string, sectionID *flo
// Whenever possible, clients should limit the search to the appropriate type. // Whenever possible, clients should limit the search to the appropriate type.
// Results, as well as their containing per-type hubs, contain a `distance` attribute which can be used to judge result quality. // Results, as well as their containing per-type hubs, contain a `distance` attribute which can be used to judge result quality.
func (s *Search) PerformVoiceSearch(ctx context.Context, query string, sectionID *float64, limit *float64) (*operations.PerformVoiceSearchResponse, error) { func (s *Search) PerformVoiceSearch(ctx context.Context, query string, sectionID *float64, limit *float64) (*operations.PerformVoiceSearchResponse, error) {
hookCtx := hooks.HookContext{OperationID: "performVoiceSearch"}
request := operations.PerformVoiceSearchRequest{ request := operations.PerformVoiceSearchRequest{
Query: query, Query: query,
SectionID: sectionID, SectionID: sectionID,
@@ -123,29 +150,50 @@ func (s *Search) PerformVoiceSearch(ctx context.Context, query string, sectionID
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/hubs/search/voice" opURL, err := url.JoinPath(baseURL, "/hubs/search/voice")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.PerformVoiceSearchResponse{ res := &operations.PerformVoiceSearchResponse{
@@ -160,6 +208,7 @@ func (s *Search) PerformVoiceSearch(ctx context.Context, query string, sectionID
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -189,34 +238,57 @@ func (s *Search) PerformVoiceSearch(ctx context.Context, query string, sectionID
// GetSearchResults - Get Search Results // GetSearchResults - Get Search Results
// This will search the database for the string provided. // This will search the database for the string provided.
func (s *Search) GetSearchResults(ctx context.Context, query string) (*operations.GetSearchResultsResponse, error) { func (s *Search) GetSearchResults(ctx context.Context, query string) (*operations.GetSearchResultsResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getSearchResults"}
request := operations.GetSearchResultsRequest{ request := operations.GetSearchResultsRequest{
Query: query, Query: query,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/search" opURL, err := url.JoinPath(baseURL, "/search")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetSearchResultsResponse{ res := &operations.GetSearchResultsResponse{
@@ -231,6 +303,7 @@ func (s *Search) GetSearchResults(ctx context.Context, query string) (*operation
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {

View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Security - API Calls against Security for Plex Media Server // Security - API Calls against Security for Plex Media Server
@@ -28,35 +29,58 @@ func newSecurity(sdkConfig sdkConfiguration) *Security {
// GetTransientToken - Get a Transient Token. // GetTransientToken - Get a Transient Token.
// This endpoint provides the caller with a temporary token with the same access level as the caller's token. These tokens are valid for up to 48 hours and are destroyed if the server instance is restarted. // This endpoint provides the caller with a temporary token with the same access level as the caller's token. These tokens are valid for up to 48 hours and are destroyed if the server instance is restarted.
func (s *Security) GetTransientToken(ctx context.Context, type_ operations.GetTransientTokenQueryParamType, scope operations.Scope) (*operations.GetTransientTokenResponse, error) { func (s *Security) GetTransientToken(ctx context.Context, type_ operations.GetTransientTokenQueryParamType, scope operations.Scope) (*operations.GetTransientTokenResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getTransientToken"}
request := operations.GetTransientTokenRequest{ request := operations.GetTransientTokenRequest{
Type: type_, Type: type_,
Scope: scope, Scope: scope,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/security/token" opURL, err := url.JoinPath(baseURL, "/security/token")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetTransientTokenResponse{ res := &operations.GetTransientTokenResponse{
@@ -71,6 +95,7 @@ func (s *Security) GetTransientToken(ctx context.Context, type_ operations.GetTr
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -101,34 +126,57 @@ func (s *Security) GetTransientToken(ctx context.Context, type_ operations.GetTr
// If a caller requires connection details and a transient token for a source that is known to the server, for example a cloud media provider or shared PMS, then this endpoint can be called. This endpoint is only accessible with either an admin token or a valid transient token generated from an admin token. // If a caller requires connection details and a transient token for a source that is known to the server, for example a cloud media provider or shared PMS, then this endpoint can be called. This endpoint is only accessible with either an admin token or a valid transient token generated from an admin token.
// Note: requires Plex Media Server >= 1.15.4. // Note: requires Plex Media Server >= 1.15.4.
func (s *Security) GetSourceConnectionInformation(ctx context.Context, source string) (*operations.GetSourceConnectionInformationResponse, error) { func (s *Security) GetSourceConnectionInformation(ctx context.Context, source string) (*operations.GetSourceConnectionInformationResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getSourceConnectionInformation"}
request := operations.GetSourceConnectionInformationRequest{ request := operations.GetSourceConnectionInformationRequest{
Source: source, Source: source,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/security/resources" opURL, err := url.JoinPath(baseURL, "/security/resources")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetSourceConnectionInformationResponse{ res := &operations.GetSourceConnectionInformationResponse{
@@ -143,6 +191,7 @@ func (s *Security) GetSourceConnectionInformation(ctx context.Context, source st
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:

323
server.go
View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Server - Operations against the Plex Media Server System. // Server - Operations against the Plex Media Server System.
@@ -28,26 +29,49 @@ func newServer(sdkConfig sdkConfiguration) *Server {
// GetServerCapabilities - Server Capabilities // GetServerCapabilities - Server Capabilities
// Server Capabilities // Server Capabilities
func (s *Server) GetServerCapabilities(ctx context.Context) (*operations.GetServerCapabilitiesResponse, error) { func (s *Server) GetServerCapabilities(ctx context.Context) (*operations.GetServerCapabilitiesResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getServerCapabilities"}
url := strings.TrimSuffix(baseURL, "/") + "/"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetServerCapabilitiesResponse{ res := &operations.GetServerCapabilitiesResponse{
@@ -62,6 +86,7 @@ func (s *Server) GetServerCapabilities(ctx context.Context) (*operations.GetServ
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -102,26 +127,49 @@ func (s *Server) GetServerCapabilities(ctx context.Context) (*operations.GetServ
// GetServerPreferences - Get Server Preferences // GetServerPreferences - Get Server Preferences
// Get Server Preferences // Get Server Preferences
func (s *Server) GetServerPreferences(ctx context.Context) (*operations.GetServerPreferencesResponse, error) { func (s *Server) GetServerPreferences(ctx context.Context) (*operations.GetServerPreferencesResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getServerPreferences"}
url := strings.TrimSuffix(baseURL, "/") + "/:/prefs"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/:/prefs")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetServerPreferencesResponse{ res := &operations.GetServerPreferencesResponse{
@@ -136,6 +184,7 @@ func (s *Server) GetServerPreferences(ctx context.Context) (*operations.GetServe
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -176,26 +225,49 @@ func (s *Server) GetServerPreferences(ctx context.Context) (*operations.GetServe
// GetAvailableClients - Get Available Clients // GetAvailableClients - Get Available Clients
// Get Available Clients // Get Available Clients
func (s *Server) GetAvailableClients(ctx context.Context) (*operations.GetAvailableClientsResponse, error) { func (s *Server) GetAvailableClients(ctx context.Context) (*operations.GetAvailableClientsResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getAvailableClients"}
url := strings.TrimSuffix(baseURL, "/") + "/clients"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/clients")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetAvailableClientsResponse{ res := &operations.GetAvailableClientsResponse{
@@ -210,6 +282,7 @@ func (s *Server) GetAvailableClients(ctx context.Context) (*operations.GetAvaila
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -250,26 +323,49 @@ func (s *Server) GetAvailableClients(ctx context.Context) (*operations.GetAvaila
// GetDevices - Get Devices // GetDevices - Get Devices
// Get Devices // Get Devices
func (s *Server) GetDevices(ctx context.Context) (*operations.GetDevicesResponse, error) { func (s *Server) GetDevices(ctx context.Context) (*operations.GetDevicesResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getDevices"}
url := strings.TrimSuffix(baseURL, "/") + "/devices"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/devices")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetDevicesResponse{ res := &operations.GetDevicesResponse{
@@ -284,6 +380,7 @@ func (s *Server) GetDevices(ctx context.Context) (*operations.GetDevicesResponse
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -324,26 +421,49 @@ func (s *Server) GetDevices(ctx context.Context) (*operations.GetDevicesResponse
// GetServerIdentity - Get Server Identity // GetServerIdentity - Get Server Identity
// Get Server Identity // Get Server Identity
func (s *Server) GetServerIdentity(ctx context.Context) (*operations.GetServerIdentityResponse, error) { func (s *Server) GetServerIdentity(ctx context.Context) (*operations.GetServerIdentityResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getServerIdentity"}
url := strings.TrimSuffix(baseURL, "/") + "/identity"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/identity")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetServerIdentityResponse{ res := &operations.GetServerIdentityResponse{
@@ -358,6 +478,7 @@ func (s *Server) GetServerIdentity(ctx context.Context) (*operations.GetServerId
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -398,26 +519,49 @@ func (s *Server) GetServerIdentity(ctx context.Context) (*operations.GetServerId
// GetMyPlexAccount - Get MyPlex Account // GetMyPlexAccount - Get MyPlex Account
// Returns MyPlex Account Information // Returns MyPlex Account Information
func (s *Server) GetMyPlexAccount(ctx context.Context) (*operations.GetMyPlexAccountResponse, error) { func (s *Server) GetMyPlexAccount(ctx context.Context) (*operations.GetMyPlexAccountResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getMyPlexAccount"}
url := strings.TrimSuffix(baseURL, "/") + "/myplex/account"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/myplex/account")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetMyPlexAccountResponse{ res := &operations.GetMyPlexAccountResponse{
@@ -432,6 +576,7 @@ func (s *Server) GetMyPlexAccount(ctx context.Context) (*operations.GetMyPlexAcc
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -472,30 +617,53 @@ func (s *Server) GetMyPlexAccount(ctx context.Context) (*operations.GetMyPlexAcc
// GetResizedPhoto - Get a Resized Photo // GetResizedPhoto - Get a Resized Photo
// Plex's Photo transcoder is used throughout the service to serve images at specified sizes. // Plex's Photo transcoder is used throughout the service to serve images at specified sizes.
func (s *Server) GetResizedPhoto(ctx context.Context, request operations.GetResizedPhotoRequest) (*operations.GetResizedPhotoResponse, error) { func (s *Server) GetResizedPhoto(ctx context.Context, request operations.GetResizedPhotoRequest) (*operations.GetResizedPhotoResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getResizedPhoto"}
url := strings.TrimSuffix(baseURL, "/") + "/photo/:/transcode"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/photo/:/transcode")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetResizedPhotoResponse{ res := &operations.GetResizedPhotoResponse{
@@ -510,6 +678,7 @@ func (s *Server) GetResizedPhoto(ctx context.Context, request operations.GetResi
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -539,26 +708,49 @@ func (s *Server) GetResizedPhoto(ctx context.Context, request operations.GetResi
// GetServerList - Get Server List // GetServerList - Get Server List
// Get Server List // Get Server List
func (s *Server) GetServerList(ctx context.Context) (*operations.GetServerListResponse, error) { func (s *Server) GetServerList(ctx context.Context) (*operations.GetServerListResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getServerList"}
url := strings.TrimSuffix(baseURL, "/") + "/servers"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/servers")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetServerListResponse{ res := &operations.GetServerListResponse{
@@ -573,6 +765,7 @@ func (s *Server) GetServerList(ctx context.Context) (*operations.GetServerListRe
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {

View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Sessions - API Calls that perform search operations with Plex Media Server Sessions // Sessions - API Calls that perform search operations with Plex Media Server Sessions
@@ -28,26 +29,49 @@ func newSessions(sdkConfig sdkConfiguration) *Sessions {
// GetSessions - Get Active Sessions // GetSessions - Get Active Sessions
// This will retrieve the "Now Playing" Information of the PMS. // This will retrieve the "Now Playing" Information of the PMS.
func (s *Sessions) GetSessions(ctx context.Context) (*operations.GetSessionsResponse, error) { func (s *Sessions) GetSessions(ctx context.Context) (*operations.GetSessionsResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getSessions"}
url := strings.TrimSuffix(baseURL, "/") + "/status/sessions"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/status/sessions")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetSessionsResponse{ res := &operations.GetSessionsResponse{
@@ -62,6 +86,7 @@ func (s *Sessions) GetSessions(ctx context.Context) (*operations.GetSessionsResp
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -102,26 +127,49 @@ func (s *Sessions) GetSessions(ctx context.Context) (*operations.GetSessionsResp
// GetSessionHistory - Get Session History // GetSessionHistory - Get Session History
// This will Retrieve a listing of all history views. // This will Retrieve a listing of all history views.
func (s *Sessions) GetSessionHistory(ctx context.Context) (*operations.GetSessionHistoryResponse, error) { func (s *Sessions) GetSessionHistory(ctx context.Context) (*operations.GetSessionHistoryResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getSessionHistory"}
url := strings.TrimSuffix(baseURL, "/") + "/status/sessions/history/all"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/status/sessions/history/all")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetSessionHistoryResponse{ res := &operations.GetSessionHistoryResponse{
@@ -136,6 +184,7 @@ func (s *Sessions) GetSessionHistory(ctx context.Context) (*operations.GetSessio
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -176,26 +225,49 @@ func (s *Sessions) GetSessionHistory(ctx context.Context) (*operations.GetSessio
// GetTranscodeSessions - Get Transcode Sessions // GetTranscodeSessions - Get Transcode Sessions
// Get Transcode Sessions // Get Transcode Sessions
func (s *Sessions) GetTranscodeSessions(ctx context.Context) (*operations.GetTranscodeSessionsResponse, error) { func (s *Sessions) GetTranscodeSessions(ctx context.Context) (*operations.GetTranscodeSessionsResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getTranscodeSessions"}
url := strings.TrimSuffix(baseURL, "/") + "/transcode/sessions"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/transcode/sessions")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetTranscodeSessionsResponse{ res := &operations.GetTranscodeSessionsResponse{
@@ -210,6 +282,7 @@ func (s *Sessions) GetTranscodeSessions(ctx context.Context) (*operations.GetTra
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -250,33 +323,53 @@ func (s *Sessions) GetTranscodeSessions(ctx context.Context) (*operations.GetTra
// StopTranscodeSession - Stop a Transcode Session // StopTranscodeSession - Stop a Transcode Session
// Stop a Transcode Session // Stop a Transcode Session
func (s *Sessions) StopTranscodeSession(ctx context.Context, sessionKey string) (*operations.StopTranscodeSessionResponse, error) { func (s *Sessions) StopTranscodeSession(ctx context.Context, sessionKey string) (*operations.StopTranscodeSessionResponse, error) {
hookCtx := hooks.HookContext{OperationID: "stopTranscodeSession"}
request := operations.StopTranscodeSessionRequest{ request := operations.StopTranscodeSessionRequest{
SessionKey: sessionKey, SessionKey: sessionKey,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url, err := utils.GenerateURL(ctx, baseURL, "/transcode/sessions/{sessionKey}", request, nil) opURL, err := utils.GenerateURL(ctx, baseURL, "/transcode/sessions/{sessionKey}", request, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err) return nil, fmt.Errorf("error generating URL: %w", err)
} }
req, err := http.NewRequestWithContext(ctx, "DELETE", url, nil) req, err := http.NewRequestWithContext(ctx, "DELETE", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.StopTranscodeSessionResponse{ res := &operations.StopTranscodeSessionResponse{
@@ -291,6 +384,7 @@ func (s *Sessions) StopTranscodeSession(ctx context.Context, sessionKey string)
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 204: case httpRes.StatusCode == 204:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:

133
statistics.go Normal file
View File

@@ -0,0 +1,133 @@
// Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT.
package plexgo
import (
"bytes"
"context"
"fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors"
"io"
"net/http"
"net/url"
)
// Statistics - API Calls that perform operations with Plex Media Server Statistics
type Statistics struct {
sdkConfiguration sdkConfiguration
}
func newStatistics(sdkConfig sdkConfiguration) *Statistics {
return &Statistics{
sdkConfiguration: sdkConfig,
}
}
// GetStatistics - Get Media Statistics
// This will return the media statistics for the server
func (s *Statistics) GetStatistics(ctx context.Context, timespan *int64) (*operations.GetStatisticsResponse, error) {
hookCtx := hooks.HookContext{OperationID: "getStatistics"}
request := operations.GetStatisticsRequest{
Timespan: timespan,
}
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/statistics/media")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err)
}
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil {
err = fmt.Errorf("error sending request: %w", err)
} else {
err = fmt.Errorf("error sending request: no response")
}
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetStatisticsResponse{
StatusCode: httpRes.StatusCode,
ContentType: contentType,
RawResponse: httpRes,
}
rawBody, err := io.ReadAll(httpRes.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch {
case httpRes.StatusCode == 200:
switch {
case utils.MatchContentType(contentType, `application/json`):
var out operations.GetStatisticsResponseBody
if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil {
return nil, err
}
res.Object = &out
default:
return nil, sdkerrors.NewSDKError(fmt.Sprintf("unknown content-type received: %s", contentType), httpRes.StatusCode, string(rawBody), httpRes)
}
case httpRes.StatusCode == 400:
fallthrough
case httpRes.StatusCode >= 400 && httpRes.StatusCode < 500:
fallthrough
case httpRes.StatusCode >= 500 && httpRes.StatusCode < 600:
return nil, sdkerrors.NewSDKError("API error occurred", httpRes.StatusCode, string(rawBody), httpRes)
case httpRes.StatusCode == 401:
switch {
case utils.MatchContentType(contentType, `application/json`):
var out sdkerrors.GetStatisticsResponseBody
if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil {
return nil, err
}
out.RawResponse = httpRes
return nil, &out
default:
return nil, sdkerrors.NewSDKError(fmt.Sprintf("unknown content-type received: %s", contentType), httpRes.StatusCode, string(rawBody), httpRes)
}
}
return res, nil
}

View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Updater - This describes the API for searching and applying updates to the Plex Media Server. // Updater - This describes the API for searching and applying updates to the Plex Media Server.
@@ -29,26 +30,49 @@ func newUpdater(sdkConfig sdkConfiguration) *Updater {
// GetUpdateStatus - Querying status of updates // GetUpdateStatus - Querying status of updates
// Querying status of updates // Querying status of updates
func (s *Updater) GetUpdateStatus(ctx context.Context) (*operations.GetUpdateStatusResponse, error) { func (s *Updater) GetUpdateStatus(ctx context.Context) (*operations.GetUpdateStatusResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getUpdateStatus"}
url := strings.TrimSuffix(baseURL, "/") + "/updater/status"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/updater/status")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetUpdateStatusResponse{ res := &operations.GetUpdateStatusResponse{
@@ -63,6 +87,7 @@ func (s *Updater) GetUpdateStatus(ctx context.Context) (*operations.GetUpdateSta
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
switch { switch {
@@ -103,34 +128,57 @@ func (s *Updater) GetUpdateStatus(ctx context.Context) (*operations.GetUpdateSta
// CheckForUpdates - Checking for updates // CheckForUpdates - Checking for updates
// Checking for updates // Checking for updates
func (s *Updater) CheckForUpdates(ctx context.Context, download *operations.Download) (*operations.CheckForUpdatesResponse, error) { func (s *Updater) CheckForUpdates(ctx context.Context, download *operations.Download) (*operations.CheckForUpdatesResponse, error) {
hookCtx := hooks.HookContext{OperationID: "checkForUpdates"}
request := operations.CheckForUpdatesRequest{ request := operations.CheckForUpdatesRequest{
Download: download, Download: download,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/updater/check" opURL, err := url.JoinPath(baseURL, "/updater/check")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "PUT", url, nil) req, err := http.NewRequestWithContext(ctx, "PUT", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.CheckForUpdatesResponse{ res := &operations.CheckForUpdatesResponse{
@@ -145,6 +193,7 @@ func (s *Updater) CheckForUpdates(ctx context.Context, download *operations.Down
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -174,35 +223,58 @@ func (s *Updater) CheckForUpdates(ctx context.Context, download *operations.Down
// ApplyUpdates - Apply Updates // ApplyUpdates - Apply Updates
// Note that these two parameters are effectively mutually exclusive. The `tonight` parameter takes precedence and `skip` will be ignored if `tonight` is also passed // Note that these two parameters are effectively mutually exclusive. The `tonight` parameter takes precedence and `skip` will be ignored if `tonight` is also passed
func (s *Updater) ApplyUpdates(ctx context.Context, tonight *operations.Tonight, skip *operations.Skip) (*operations.ApplyUpdatesResponse, error) { func (s *Updater) ApplyUpdates(ctx context.Context, tonight *operations.Tonight, skip *operations.Skip) (*operations.ApplyUpdatesResponse, error) {
hookCtx := hooks.HookContext{OperationID: "applyUpdates"}
request := operations.ApplyUpdatesRequest{ request := operations.ApplyUpdatesRequest{
Tonight: tonight, Tonight: tonight,
Skip: skip, Skip: skip,
} }
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/updater/apply" opURL, err := url.JoinPath(baseURL, "/updater/apply")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "PUT", url, nil) req, err := http.NewRequestWithContext(ctx, "PUT", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "500", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.ApplyUpdatesResponse{ res := &operations.ApplyUpdatesResponse{
@@ -217,6 +289,7 @@ func (s *Updater) ApplyUpdates(ctx context.Context, tonight *operations.Tonight,
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:

201
video.go
View File

@@ -6,12 +6,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/LukeHagar/plexgo/internal/hooks"
"github.com/LukeHagar/plexgo/internal/utils" "github.com/LukeHagar/plexgo/internal/utils"
"github.com/LukeHagar/plexgo/models/operations" "github.com/LukeHagar/plexgo/models/operations"
"github.com/LukeHagar/plexgo/models/sdkerrors" "github.com/LukeHagar/plexgo/models/sdkerrors"
"io" "io"
"net/http" "net/http"
"strings" "net/url"
) )
// Video - API Calls that perform operations with Plex Media Server Videos // Video - API Calls that perform operations with Plex Media Server Videos
@@ -25,100 +26,56 @@ func newVideo(sdkConfig sdkConfiguration) *Video {
} }
} }
// StartUniversalTranscode - Start Universal Transcode
// Begin a Universal Transcode Session
func (s *Video) StartUniversalTranscode(ctx context.Context, request operations.StartUniversalTranscodeRequest) (*operations.StartUniversalTranscodeResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
url := strings.TrimSuffix(baseURL, "/") + "/video/:/transcode/universal/start.mpd"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err)
}
client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("error sending request: %w", err)
}
if httpRes == nil {
return nil, fmt.Errorf("error sending request: no response")
}
contentType := httpRes.Header.Get("Content-Type")
res := &operations.StartUniversalTranscodeResponse{
StatusCode: httpRes.StatusCode,
ContentType: contentType,
RawResponse: httpRes,
}
rawBody, err := io.ReadAll(httpRes.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch {
case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400:
fallthrough
case httpRes.StatusCode >= 400 && httpRes.StatusCode < 500:
fallthrough
case httpRes.StatusCode >= 500 && httpRes.StatusCode < 600:
return nil, sdkerrors.NewSDKError("API error occurred", httpRes.StatusCode, string(rawBody), httpRes)
case httpRes.StatusCode == 401:
switch {
case utils.MatchContentType(contentType, `application/json`):
var out sdkerrors.StartUniversalTranscodeResponseBody
if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil {
return nil, err
}
out.RawResponse = httpRes
return nil, &out
default:
return nil, sdkerrors.NewSDKError(fmt.Sprintf("unknown content-type received: %s", contentType), httpRes.StatusCode, string(rawBody), httpRes)
}
}
return res, nil
}
// GetTimeline - Get the timeline for a media item // GetTimeline - Get the timeline for a media item
// Get the timeline for a media item // Get the timeline for a media item
func (s *Video) GetTimeline(ctx context.Context, request operations.GetTimelineRequest) (*operations.GetTimelineResponse, error) { func (s *Video) GetTimeline(ctx context.Context, request operations.GetTimelineRequest) (*operations.GetTimelineResponse, error) {
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) hookCtx := hooks.HookContext{OperationID: "getTimeline"}
url := strings.TrimSuffix(baseURL, "/") + "/:/timeline"
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/:/timeline")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating request: %w", err) return nil, fmt.Errorf("error creating request: %w", err)
} }
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
req.Header.Set("user-agent", s.sdkConfiguration.UserAgent) req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil { if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err) return nil, fmt.Errorf("error populating query params: %w", err)
} }
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req) httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error sending request: %w", err) err = fmt.Errorf("error sending request: %w", err)
} } else {
if httpRes == nil { err = fmt.Errorf("error sending request: no response")
return nil, fmt.Errorf("error sending request: no response")
} }
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type") contentType := httpRes.Header.Get("Content-Type")
res := &operations.GetTimelineResponse{ res := &operations.GetTimelineResponse{
@@ -133,6 +90,7 @@ func (s *Video) GetTimeline(ctx context.Context, request operations.GetTimelineR
} }
httpRes.Body.Close() httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody)) httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch { switch {
case httpRes.StatusCode == 200: case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400: case httpRes.StatusCode == 400:
@@ -158,3 +116,94 @@ func (s *Video) GetTimeline(ctx context.Context, request operations.GetTimelineR
return res, nil return res, nil
} }
// StartUniversalTranscode - Start Universal Transcode
// Begin a Universal Transcode Session
func (s *Video) StartUniversalTranscode(ctx context.Context, request operations.StartUniversalTranscodeRequest) (*operations.StartUniversalTranscodeResponse, error) {
hookCtx := hooks.HookContext{OperationID: "startUniversalTranscode"}
baseURL := utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails())
opURL, err := url.JoinPath(baseURL, "/video/:/transcode/universal/start.mpd")
if err != nil {
return nil, fmt.Errorf("error generating URL: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "GET", opURL, nil)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent)
if err := utils.PopulateQueryParams(ctx, req, request, nil); err != nil {
return nil, fmt.Errorf("error populating query params: %w", err)
}
req, err = s.sdkConfiguration.Hooks.BeforeRequest(hooks.BeforeRequestContext{hookCtx}, req)
if err != nil {
return nil, err
}
client := s.sdkConfiguration.SecurityClient
httpRes, err := client.Do(req)
if err != nil || httpRes == nil {
if err != nil {
err = fmt.Errorf("error sending request: %w", err)
} else {
err = fmt.Errorf("error sending request: no response")
}
_, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, nil, err)
return nil, err
} else if utils.MatchStatusCodes([]string{"400", "401", "4XX", "5XX"}, httpRes.StatusCode) {
httpRes, err = s.sdkConfiguration.Hooks.AfterError(hooks.AfterErrorContext{hookCtx}, httpRes, nil)
if err != nil {
return nil, err
}
} else {
httpRes, err = s.sdkConfiguration.Hooks.AfterSuccess(hooks.AfterSuccessContext{hookCtx}, httpRes)
if err != nil {
return nil, err
}
}
contentType := httpRes.Header.Get("Content-Type")
res := &operations.StartUniversalTranscodeResponse{
StatusCode: httpRes.StatusCode,
ContentType: contentType,
RawResponse: httpRes,
}
rawBody, err := io.ReadAll(httpRes.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
httpRes.Body.Close()
httpRes.Body = io.NopCloser(bytes.NewBuffer(rawBody))
switch {
case httpRes.StatusCode == 200:
case httpRes.StatusCode == 400:
fallthrough
case httpRes.StatusCode >= 400 && httpRes.StatusCode < 500:
fallthrough
case httpRes.StatusCode >= 500 && httpRes.StatusCode < 600:
return nil, sdkerrors.NewSDKError("API error occurred", httpRes.StatusCode, string(rawBody), httpRes)
case httpRes.StatusCode == 401:
switch {
case utils.MatchContentType(contentType, `application/json`):
var out sdkerrors.StartUniversalTranscodeResponseBody
if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil {
return nil, err
}
out.RawResponse = httpRes
return nil, &out
default:
return nil, sdkerrors.NewSDKError(fmt.Sprintf("unknown content-type received: %s", contentType), httpRes.StatusCode, string(rawBody), httpRes)
}
}
return res, nil
}