golift.io/starr@v1.0.0/readarr/bookfile.go (about) 1 package readarr 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "net/url" 9 "path" 10 "time" 11 12 "golift.io/starr" 13 ) 14 15 const bpBookFile = APIver + "/bookfile" 16 17 // BookFile represents the data from the bookfile endpoint. 18 type BookFile struct { 19 AuthorID int64 `json:"authorId"` 20 BookID int64 `json:"bookId"` 21 Path string `json:"path"` 22 Size int `json:"size,omitempty"` 23 DateAdded time.Time `json:"dateAdded,omitempty"` 24 Quality *starr.Quality `json:"quality"` 25 QualityWeight int `json:"qualityWeight,omitempty"` 26 QualityCutoffNotMet bool `json:"qualityCutoffNotMet"` 27 ID int64 `json:"id"` 28 AudioTags *AudioTags `json:"audioTags,omitempty"` 29 } 30 31 /* I've never seen audio tags in the wild. */ 32 33 // AudioTags are part of a bookfile. 34 type AudioTags struct { 35 Title string `json:"title"` 36 CleanTitle string `json:"cleanTitle"` 37 Authors []string `json:"authors"` 38 AuthorTitle string `json:"authorTitle"` 39 BookTitle string `json:"bookTitle"` 40 SeriesTitle string `json:"seriesTitle"` 41 SeriesIndex string `json:"seriesIndex"` 42 ISBN string `json:"isbn"` 43 ASIN string `json:"asin"` 44 GoodreadsID string `json:"goodreadsId"` 45 AuthorMBID string `json:"authorMBId"` 46 BookMBID string `json:"bookMBId"` 47 ReleaseMBID string `json:"releaseMBId"` 48 RecordingMBID string `json:"recordingMBId"` 49 TrackMBID string `json:"trackMBId"` 50 DiscNumber int `json:"discNumber"` 51 DiscCount int `json:"discCount"` 52 Country *AudioCountry `json:"country"` 53 Year int `json:"year"` 54 Publisher string `json:"publisher"` 55 Label string `json:"label"` 56 Source string `json:"source"` 57 CatalogNumber string `json:"catalogNumber"` 58 Disambiguation string `json:"disambiguation"` 59 Duration *starr.TimeSpan `json:"duration"` 60 Quality *starr.Quality `json:"quality"` 61 MediaInfo *AudioMediaInfo `json:"mediaInfo"` 62 TrackNumbers []int `json:"trackNumbers"` 63 Language string `json:"language"` 64 ReleaseGroup string `json:"releaseGroup"` 65 ReleaseHash string `json:"releaseHash"` 66 } 67 68 // AudioMediaInfo is part of AudioTags. 69 type AudioMediaInfo struct { 70 AudioFormat string `json:"audioFormat"` 71 AudioBitrate int `json:"audioBitrate"` 72 AudioChannels int `json:"audioChannels"` 73 AudioBits int `json:"audioBits"` 74 AudioSampleRate int `json:"audioSampleRate"` 75 } 76 77 // AudioCountry is part of AudioTags. 78 type AudioCountry struct { 79 TwoLetterCode string `json:"twoLetterCode"` 80 Name string `json:"name"` 81 } 82 83 // GetBookFilesForAuthor returns the book files for an author. 84 func (r *Readarr) GetBookFilesForAuthor(authorID int64) ([]*BookFile, error) { 85 return r.GetBookFilesForAuthorContext(context.Background(), authorID) 86 } 87 88 // GetBookFilesForAuthorContext returns the book files for an author. 89 func (r *Readarr) GetBookFilesForAuthorContext(ctx context.Context, authorID int64) ([]*BookFile, error) { 90 var output []*BookFile 91 92 req := starr.Request{URI: bpBookFile, Query: make(url.Values)} 93 req.Query.Add("authorId", fmt.Sprint(authorID)) 94 95 if err := r.GetInto(ctx, req, &output); err != nil { 96 return nil, fmt.Errorf("api.Get(%s): %w", &req, err) 97 } 98 99 return output, nil 100 } 101 102 // GetBookFilesForBook returns the book files for a book or books. 103 func (r *Readarr) GetBookFilesForBook(bookID ...int64) ([]*BookFile, error) { 104 return r.GetBookFilesForBookContext(context.Background(), bookID...) 105 } 106 107 // GetBookFilesForBookContext returns the book files for a book or books. 108 func (r *Readarr) GetBookFilesForBookContext(ctx context.Context, bookID ...int64) ([]*BookFile, error) { 109 var output []*BookFile 110 111 req := starr.Request{URI: bpBookFile, Query: make(url.Values)} 112 113 for _, id := range bookID { 114 req.Query.Add("bookId", fmt.Sprint(id)) 115 } 116 117 if err := r.GetInto(ctx, req, &output); err != nil { 118 return nil, fmt.Errorf("api.Get(%s): %w", &req, err) 119 } 120 121 return output, nil 122 } 123 124 // GetBookFiles returns the requested book files by ID. 125 func (r *Readarr) GetBookFiles(bookFileIDs []int64) ([]*BookFile, error) { 126 return r.GetBookFilesContext(context.Background(), bookFileIDs) 127 } 128 129 // GetBookFilesContext returns the requested book files by their IDs. 130 func (r *Readarr) GetBookFilesContext(ctx context.Context, bookFileIDs []int64) ([]*BookFile, error) { 131 var output []*BookFile 132 133 if len(bookFileIDs) == 0 { 134 return output, nil 135 } 136 137 req := starr.Request{URI: bpBookFile, Query: make(url.Values)} 138 139 for _, fileID := range bookFileIDs { 140 req.Query.Add("bookFileIds", fmt.Sprint(fileID)) 141 } 142 143 if err := r.GetInto(ctx, req, &output); err != nil { 144 return nil, fmt.Errorf("api.Get(%s): %w", &req, err) 145 } 146 147 return output, nil 148 } 149 150 // UpdateBookFile updates a book file. 151 func (r *Readarr) UpdateBookFile(bookFile *BookFile) (*BookFile, error) { 152 return r.UpdateBookFileContext(context.Background(), bookFile) 153 } 154 155 // UpdateBookFileContext updates a book file. 156 func (r *Readarr) UpdateBookFileContext(ctx context.Context, bookFile *BookFile) (*BookFile, error) { 157 var output BookFile 158 159 var body bytes.Buffer 160 if err := json.NewEncoder(&body).Encode(bookFile); err != nil { 161 return nil, fmt.Errorf("json.Marshal(%s): %w", bpBookFile, err) 162 } 163 164 req := starr.Request{URI: path.Join(bpBookFile, fmt.Sprint(bookFile.ID)), Body: &body} 165 if err := r.PutInto(ctx, req, &output); err != nil { 166 return nil, fmt.Errorf("api.Put(%s): %w", &req, err) 167 } 168 169 return &output, nil 170 } 171 172 // DeleteBookFile deletes a book file. 173 func (r *Readarr) DeleteBookFile(bookFileID int64) error { 174 return r.DeleteBookFileContext(context.Background(), bookFileID) 175 } 176 177 // DeleteBookFileContext deletes a book file. 178 func (r *Readarr) DeleteBookFileContext(ctx context.Context, bookFileID int64) error { 179 req := starr.Request{URI: path.Join(bpBookFile, fmt.Sprint(bookFileID))} 180 if err := r.DeleteAny(ctx, req); err != nil { 181 return fmt.Errorf("api.Delete(%s): %w", &req, err) 182 } 183 184 return nil 185 } 186 187 // DeleteBookFiles bulk deletes book files by their IDs. 188 func (r *Readarr) DeleteBookFiles(bookFileIDs []int64) error { 189 return r.DeleteBookFilesContext(context.Background(), bookFileIDs) 190 } 191 192 // DeleteBookFilesContext bulk deletes book files by their IDs. 193 func (r *Readarr) DeleteBookFilesContext(ctx context.Context, bookFileIDs []int64) error { 194 postData := struct { 195 T []int64 `json:"bookFileIds"` 196 }{bookFileIDs} 197 198 var body bytes.Buffer 199 if err := json.NewEncoder(&body).Encode(&postData); err != nil { 200 return fmt.Errorf("json.Marshal(%s): %w", bpBookFile, err) 201 } 202 203 req := starr.Request{URI: path.Join(bpBookFile, "bulk"), Body: &body} 204 if err := r.DeleteAny(ctx, req); err != nil { 205 return fmt.Errorf("api.Delete(%s): %w", &req, err) 206 } 207 208 return nil 209 }