-
Notifications
You must be signed in to change notification settings - Fork 2
/
movie.go
316 lines (279 loc) · 9.55 KB
/
movie.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
package radarr
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strconv"
"time"
)
// Movie Radarr movie
type Movie struct {
Title string `json:"title"`
AlternativeTitles []struct {
SourceType string `json:"sourceType"`
MovieID int `json:"movieId"`
Title string `json:"title"`
SourceID int `json:"sourceId"`
Votes int `json:"votes"`
VoteCount int `json:"voteCount"`
Language struct {
ID int `json:"id"`
Name string `json:"name"`
} `json:"language"`
ID int `json:"id"`
} `json:"alternativeTitles"`
SecondaryYearSourceID int `json:"secondaryYearSourceId"`
SortTitle string `json:"sortTitle"`
SizeOnDisk int64 `json:"sizeOnDisk"`
Status string `json:"status"`
Overview string `json:"overview"`
InCinemas time.Time `json:"inCinemas"`
PhysicalRelease time.Time `json:"physicalRelease"`
Images []struct {
CoverType string `json:"coverType"`
URL string `json:"url"`
} `json:"images"`
Website string `json:"website"`
Downloaded bool `json:"downloaded"`
Year int `json:"year"`
HasFile bool `json:"hasFile"`
YouTubeTrailerID string `json:"youTubeTrailerId"`
Studio string `json:"studio"`
Path string `json:"path"`
ProfileID int `json:"profileId"`
Monitored bool `json:"monitored"`
MinimumAvailability string `json:"minimumAvailability"`
IsAvailable bool `json:"isAvailable"`
FolderName string `json:"folderName"`
Runtime int `json:"runtime"`
LastInfoSync time.Time `json:"lastInfoSync"`
CleanTitle string `json:"cleanTitle"`
ImdbID string `json:"imdbId"`
TmdbID int `json:"tmdbId"`
TitleSlug string `json:"titleSlug"`
Genres []string `json:"genres"`
Tags []int `json:"tags"`
Added time.Time `json:"added"`
Ratings struct {
Votes int `json:"votes"`
Value float64 `json:"value"`
} `json:"ratings"`
MovieFile struct {
MovieID int `json:"movieId"`
RelativePath string `json:"relativePath"`
Size int64 `json:"size"`
DateAdded time.Time `json:"dateAdded"`
SceneName string `json:"sceneName"`
Quality struct {
Quality Quality `json:"quality"`
Revision struct {
Version int `json:"version"`
Real int `json:"real"`
IsRepack bool `json:"isRepack"`
} `json:"revision"`
} `json:"quality"`
Edition string `json:"edition"`
MediaInfo struct {
ContainerFormat string `json:"containerFormat"`
VideoFormat string `json:"videoFormat"`
VideoCodecID string `json:"videoCodecID"`
VideoProfile string `json:"videoProfile"`
VideoCodecLibrary string `json:"videoCodecLibrary"`
VideoBitrate int `json:"videoBitrate"`
VideoBitDepth int `json:"videoBitDepth"`
VideoMultiViewCount int `json:"videoMultiViewCount"`
VideoColourPrimaries string `json:"videoColourPrimaries"`
VideoTransferCharacteristics string `json:"videoTransferCharacteristics"`
Width int `json:"width"`
Height int `json:"height"`
AudioFormat string `json:"audioFormat"`
AudioCodecID string `json:"audioCodecID"`
AudioCodecLibrary string `json:"audioCodecLibrary"`
AudioAdditionalFeatures string `json:"audioAdditionalFeatures"`
AudioBitrate int `json:"audioBitrate"`
RunTime string `json:"runTime"`
AudioStreamCount int `json:"audioStreamCount"`
AudioChannels int `json:"audioChannels"`
AudioChannelPositions string `json:"audioChannelPositions"`
AudioChannelPositionsText string `json:"audioChannelPositionsText"`
AudioProfile string `json:"audioProfile"`
VideoFps float64 `json:"videoFps"`
AudioLanguages string `json:"audioLanguages"`
Subtitles string `json:"subtitles"`
ScanType string `json:"scanType"`
SchemaRevision int `json:"schemaRevision"`
} `json:"mediaInfo"`
ID int `json:"id"`
} `json:"movieFile"`
QualityProfileID int `json:"qualityProfileId"`
ID int `json:"id"`
}
// Quality movie quality
type Quality struct {
ID int `json:"id"`
Name string `json:"name"`
Source string `json:"source"`
Resolution int `json:"resolution"`
Modifier string `json:"modifier"`
}
// Movies multiple Radarr movies
type Movies []*Movie
// ExcludedMovie describe an excluded movie from being downloaded
type ExcludedMovie struct {
ID int `json:"id"`
MovieTitle string `json:"movieTitle"`
MovieYear int `json:"movieYear"`
TmdbID int `json:"tmdbId"`
}
// ExcludedMovies describes a set of excluded movies
type ExcludedMovies []*ExcludedMovie
// DeleteMovieOptions optional option while deleting movie
type DeleteMovieOptions struct {
// If true the movie folder and all files will be deleted when the movie is deleted
DeleteFiles bool
// If true the movie TMDB ID will be added to the import exclusions list when the movie is deleted
AddExclusion bool
}
// MovieService contains Radarr movies operations
type MovieService struct {
s *Service
Lookup *LookupService
}
func newMovieService(s *Service) *MovieService {
return &MovieService{
s: s,
Lookup: newLookupService(s),
}
}
// UpcomingOptions describe period to search upcoming movies with
type UpcomingOptions struct {
Start *time.Time
End *time.Time
}
// Get Returns all Movies in your collection
// https://github.com/Radarr/Radarr/wiki/API:Movie#getid
func (m *MovieService) Get(movieID int) (*Movie, error) {
movieURL := fmt.Sprintf("%s/api%s/%d", m.s.url, movieURI, movieID)
resp, err := m.s.client.Get(movieURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
err = parseRadarrResponse(resp)
if err != nil {
return nil, err
}
var movie Movie
err = json.NewDecoder(resp.Body).Decode(&movie)
if err != nil {
return nil, err
}
return &movie, nil
}
// List Returns the movie with the matching ID or eerror if no matching movie is found
// https://github.com/Radarr/Radarr/wiki/API:Movie#get
func (m *MovieService) List() (Movies, error) {
moviesURL := fmt.Sprintf("%s/api%s", m.s.url, movieURI)
resp, err := m.s.client.Get(moviesURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
err = parseRadarrResponse(resp)
if err != nil {
return nil, err
}
var movies Movies
err = json.NewDecoder(resp.Body).Decode(&movies)
if err != nil {
return nil, err
}
return movies, nil
}
// Upcoming Gets upcoming movies from your Radarr library, if start/end are not supplied movies airing today and tomorrow will be returned
// Its match the physicalRelease attribute
// https://github.com/Radarr/Radarr/wiki/API:Calendar#get
func (m *MovieService) Upcoming(opts ...*UpcomingOptions) (Movies, error) {
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api%s", m.s.url, upcomingURI), nil)
if err != nil {
return nil, err
}
// If option is provided, incule them in the request
if len(opts) > 0 {
// If both dates are filled, verify order
if opts[0].Start != nil && opts[0].End != nil {
if opts[0].End.Before(*opts[0].Start) || opts[0].Start.After(*opts[0].End) {
return nil, errors.New("Incorrect dates. Please ensure date are set properly")
}
}
params := req.URL.Query()
// If start date is defined
if opts[0].Start != nil {
params.Add("start", opts[0].Start.Format(time.RFC3339))
req.URL.RawQuery = params.Encode()
}
// If end date is defined
if opts[0].End != nil {
params.Add("end", opts[0].End.Format(time.RFC3339))
req.URL.RawQuery = params.Encode()
}
}
resp, err := m.s.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
err = parseRadarrResponse(resp)
if err != nil {
return nil, err
}
var movies Movies
err = json.NewDecoder(resp.Body).Decode(&movies)
if err != nil {
return nil, err
}
return movies, nil
}
// Delete given movie
// https://github.com/Radarr/Radarr/wiki/API:Movie#deleteid
func (m *MovieService) Delete(movie *Movie, opts ...*DeleteMovieOptions) error {
req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("%s/api%s/%d", m.s.url, movieURI, movie.ID), nil)
if err != nil {
return err
}
// If option given, parse and send to request
if len(opts) > 0 {
d := opts[0]
params := req.URL.Query()
params.Add("deleteFiles", strconv.FormatBool(d.DeleteFiles))
params.Add("addExclusion", strconv.FormatBool(d.AddExclusion))
req.URL.RawQuery = params.Encode()
}
resp, err := m.s.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
err = parseRadarrResponse(resp)
return err
}
// Excluded Gets movies marked as List Exclusions
// https://github.com/Radarr/Radarr/wiki/API:List-Exclusions
func (m *MovieService) Excluded() (ExcludedMovies, error) {
resp, err := m.s.client.Get(fmt.Sprintf("%s/api%s", m.s.url, exclusionsURI))
if err != nil {
return nil, err
}
defer resp.Body.Close()
err = parseRadarrResponse(resp)
if err != nil {
return nil, err
}
var movies ExcludedMovies
err = json.NewDecoder(resp.Body).Decode(&movies)
if err != nil {
return nil, err
}
return movies, nil
}