golift.io/starr@v1.0.0/shared.go (about) 1 package starr 2 3 import ( 4 "crypto/tls" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "net/url" 9 "strconv" 10 "strings" 11 "time" 12 13 "golift.io/starr/debuglog" 14 ) 15 16 /* This file contains shared structs or constants for all the *arr apps. */ 17 18 // App can be used to satisfy a context value key. 19 // It is not used in this library; provided for convenience. 20 type App string 21 22 // These constants are just here for convenience. 23 const ( 24 Emby App = "Emby" 25 Lidarr App = "Lidarr" 26 Plex App = "Plex" 27 Prowlarr App = "Prowlarr" 28 Radarr App = "Radarr" 29 Readarr App = "Readarr" 30 Sonarr App = "Sonarr" 31 Whisparr App = "Whisparr" 32 ) 33 34 // String turns an App name into a string. 35 func (a App) String() string { 36 return string(a) 37 } 38 39 // Lower turns an App name into a lowercase string. 40 func (a App) Lower() string { 41 return strings.ToLower(string(a)) 42 } 43 44 // Client returns the default client, and is used if one is not passed in. 45 func Client(timeout time.Duration, verifySSL bool) *http.Client { 46 return &http.Client{ 47 Timeout: timeout, 48 CheckRedirect: func(r *http.Request, via []*http.Request) error { 49 return http.ErrUseLastResponse 50 }, 51 Transport: &http.Transport{ 52 TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}, //nolint:gosec 53 }, 54 } 55 } 56 57 // ClientWithDebug returns an http client with a debug logger enabled. 58 func ClientWithDebug(timeout time.Duration, verifySSL bool, logConfig debuglog.Config) *http.Client { 59 client := Client(timeout, verifySSL) 60 client.Transport = debuglog.NewLoggingRoundTripper(logConfig, client.Transport) 61 62 return client 63 } 64 65 // CalendarTimeFilterFormat is the Go time format the calendar expects the filter to be in. 66 const CalendarTimeFilterFormat = "2006-01-02T03:04:05.000Z" 67 68 // StatusMessage represents the status of the item. All apps use this. 69 type StatusMessage struct { 70 Title string `json:"title"` 71 Messages []string `json:"messages"` 72 } 73 74 // BaseQuality is a base quality profile. 75 type BaseQuality struct { 76 ID int64 `json:"id"` 77 Name string `json:"name"` 78 Source string `json:"source,omitempty"` 79 Resolution int `json:"resolution,omitempty"` 80 Modifier string `json:"modifier,omitempty"` 81 } 82 83 // Quality is a download quality profile attached to a movie, book, track or series. 84 // It may contain 1 or more profiles. 85 // Sonarr nor Readarr use Name or ID in this struct. 86 type Quality struct { 87 Name string `json:"name,omitempty"` 88 ID int `json:"id,omitempty"` 89 Quality *BaseQuality `json:"quality,omitempty"` 90 Items []*Quality `json:"items,omitempty"` 91 Allowed bool `json:"allowed"` 92 Revision *QualityRevision `json:"revision,omitempty"` // Not sure which app had this.... 93 } 94 95 // QualityRevision is probably used in Sonarr. 96 type QualityRevision struct { 97 Version int64 `json:"version"` 98 Real int64 `json:"real"` 99 IsRepack bool `json:"isRepack,omitempty"` 100 } 101 102 // Ratings belong to a few types. 103 type Ratings struct { 104 Votes int64 `json:"votes"` 105 Value float64 `json:"value"` 106 Popularity float64 `json:"popularity,omitempty"` 107 Type string `json:"type,omitempty"` 108 } 109 110 // OpenRatings is a ratings type that has a source and type. 111 type OpenRatings map[string]Ratings 112 113 // IsLoaded is a generic struct used in a few places. 114 type IsLoaded struct { 115 IsLoaded bool `json:"isLoaded"` 116 } 117 118 // Link is used in a few places. 119 type Link struct { 120 URL string `json:"url"` 121 Name string `json:"name"` 122 } 123 124 // Tag may be applied to nearly anything. 125 type Tag struct { 126 ID int `json:"id,omitempty"` 127 Label string `json:"label"` 128 } 129 130 // Image is used in a few places. 131 type Image struct { 132 CoverType string `json:"coverType"` 133 URL string `json:"url,omitempty"` 134 RemoteURL string `json:"remoteUrl,omitempty"` 135 Extension string `json:"extension,omitempty"` 136 } 137 138 // Path is for unmanaged folder paths. 139 type Path struct { 140 Name string `json:"name"` 141 Path string `json:"path"` 142 } 143 144 // RemotePathMapping is the remotePathMapping endpoint. 145 type RemotePathMapping struct { 146 ID int64 `json:"id,omitempty"` 147 Host string `json:"host"` 148 RemotePath string `json:"remotePath"` 149 LocalPath string `json:"localPath"` 150 } 151 152 // Value is generic ID/Name struct applied to a few places. 153 type Value struct { 154 ID int64 `json:"id"` 155 Name string `json:"name"` 156 } 157 158 // FieldOutput is generic Name/Value struct applied to a few places. 159 type FieldOutput struct { 160 Advanced bool `json:"advanced,omitempty"` 161 Order int64 `json:"order,omitempty"` 162 HelpLink string `json:"helpLink,omitempty"` 163 HelpText string `json:"helpText,omitempty"` 164 Hidden string `json:"hidden,omitempty"` 165 Label string `json:"label,omitempty"` 166 Name string `json:"name"` 167 SelectOptionsProviderAction string `json:"selectOptionsProviderAction,omitempty"` 168 Type string `json:"type,omitempty"` 169 Privacy string `json:"privacy"` 170 Value interface{} `json:"value,omitempty"` 171 SelectOptions []*SelectOption `json:"selectOptions,omitempty"` 172 } 173 174 // FieldInput is generic Name/Value struct applied to a few places. 175 type FieldInput struct { 176 Name string `json:"name"` 177 Value interface{} `json:"value,omitempty"` 178 } 179 180 // SelectOption is part of Field. 181 type SelectOption struct { 182 DividerAfter bool `json:"dividerAfter,omitempty"` 183 Order int64 `json:"order"` 184 Value int64 `json:"value"` 185 Hint string `json:"hint"` 186 Name string `json:"name"` 187 } 188 189 // KeyValue is yet another reusable generic type. 190 type KeyValue struct { 191 Key string `json:"key"` 192 Value int `json:"value"` 193 } 194 195 // BackupFile comes from the system/backup paths in all apps. 196 type BackupFile struct { 197 Name string `json:"name"` 198 Path string `json:"path"` 199 Type string `json:"type"` 200 Time time.Time `json:"time"` 201 ID int64 `json:"id"` 202 Size int64 `json:"size"` 203 } 204 205 // QueueDeleteOpts are the extra inputs when deleting an item from the Activity Queue. 206 // Set these appropriately for your expectations. All inputs are the same in all apps. 207 // Providing this input to the QueueDelete methods is optional; nil sets the defaults shown. 208 type QueueDeleteOpts struct { 209 // Default True, use starr.False() to change it. 210 RemoveFromClient *bool 211 // Default False 212 BlockList bool 213 // Default False 214 SkipRedownload bool 215 } 216 217 // Values turns delete options into http get query parameters. 218 func (o *QueueDeleteOpts) Values() url.Values { 219 params := make(url.Values) 220 params.Set("removeFromClient", "true") 221 222 if o == nil { 223 return params 224 } 225 226 params.Set("blocklist", fmt.Sprint(o.BlockList)) 227 params.Set("skipRedownload", fmt.Sprint(o.SkipRedownload)) 228 229 if o.RemoveFromClient != nil { 230 params.Set("removeFromClient", fmt.Sprint(*o.RemoveFromClient)) 231 } 232 233 return params 234 } 235 236 // PlayTime is used in at least Sonarr, maybe other places. 237 // Holds a string duration converted from hh:mm:ss. 238 type PlayTime struct { //nolint:musttag 239 Original string 240 time.Duration 241 } 242 243 // FormatItem is part of a quality profile. 244 type FormatItem struct { 245 Format int64 `json:"format"` 246 Name string `json:"name"` 247 Score int64 `json:"score"` 248 } 249 250 // UnmarshalJSON parses a run time duration in format hh:mm:ss. 251 func (d *PlayTime) UnmarshalJSON(b []byte) error { 252 d.Original = strings.Trim(string(b), `"'`) 253 254 switch parts := strings.Split(d.Original, ":"); len(parts) { 255 case 3: //nolint:gomnd // hh:mm:ss 256 h, _ := strconv.Atoi(parts[0]) 257 m, _ := strconv.Atoi(parts[1]) 258 s, _ := strconv.Atoi(parts[2]) 259 d.Duration = (time.Hour * time.Duration(h)) + (time.Minute * time.Duration(m)) + (time.Second * time.Duration(s)) 260 case 2: //nolint:gomnd // mm:ss 261 m, _ := strconv.Atoi(parts[0]) 262 s, _ := strconv.Atoi(parts[1]) 263 d.Duration = (time.Minute * time.Duration(m)) + (time.Second * time.Duration(s)) 264 case 1: // ss 265 s, _ := strconv.Atoi(parts[0]) 266 d.Duration += (time.Second * time.Duration(s)) 267 } 268 269 return nil 270 } 271 272 func (d *PlayTime) MarshalJSON() ([]byte, error) { 273 return []byte(`"` + d.Original + `"`), nil 274 } 275 276 var _ json.Unmarshaler = (*PlayTime)(nil) 277 278 // ApplyTags is an enum used as an input for Bulk editors, and perhaps other places. 279 type ApplyTags string 280 281 // ApplyTags enum constants. Use these as inputs for "ApplyTags" member values. 282 // Schema doc'd here: https://radarr.video/docs/api/#/MovieEditor/put_api_v3_movie_editor 283 const ( 284 TagsAdd ApplyTags = "add" 285 TagsRemove ApplyTags = "remove" 286 TagsReplace ApplyTags = "replace" 287 ) 288 289 // Ptr returns a pointer to an apply tags value. Useful for a BulkEdit struct. 290 func (a ApplyTags) Ptr() *ApplyTags { 291 return &a 292 } 293 294 // TimeSpan is part of AudioTags and possibly used other places. 295 type TimeSpan struct { 296 Ticks int64 `json:"ticks"` 297 Days int64 `json:"days"` 298 Hours int64 `json:"hours"` 299 Milliseconds int64 `json:"milliseconds"` 300 Minutes int64 `json:"minutes"` 301 Seconds int64 `json:"seconds"` 302 TotalDays int64 `json:"totalDays"` 303 TotalHours int64 `json:"totalHours"` 304 TotalMilliseconds int64 `json:"totalMilliseconds"` 305 TotalMinutes int64 `json:"totalMinutes"` 306 TotalSeconds int64 `json:"totalSeconds"` 307 }