github.com/artpar/rclone@v1.67.3/backend/pikpak/api/types.go (about) 1 // Package api has type definitions for pikpak 2 // 3 // Manually obtained from the API responses using Browse Dev. Tool and https://mholt.github.io/json-to-go/ 4 package api 5 6 import ( 7 "fmt" 8 "reflect" 9 "strconv" 10 "time" 11 ) 12 13 const ( 14 // "2022-09-17T14:31:06.056+08:00" 15 timeFormat = `"` + time.RFC3339 + `"` 16 ) 17 18 // Time represents date and time information for the pikpak API, by using RFC3339 19 type Time time.Time 20 21 // MarshalJSON turns a Time into JSON (in UTC) 22 func (t *Time) MarshalJSON() (out []byte, err error) { 23 timeString := (*time.Time)(t).Format(timeFormat) 24 return []byte(timeString), nil 25 } 26 27 // UnmarshalJSON turns JSON into a Time 28 func (t *Time) UnmarshalJSON(data []byte) error { 29 if string(data) == "null" || string(data) == `""` { 30 return nil 31 } 32 newT, err := time.Parse(timeFormat, string(data)) 33 if err != nil { 34 return err 35 } 36 *t = Time(newT) 37 return nil 38 } 39 40 // Types of things in Item 41 const ( 42 KindOfFolder = "drive#folder" 43 KindOfFile = "drive#file" 44 KindOfFileList = "drive#fileList" 45 KindOfResumable = "drive#resumable" 46 KindOfForm = "drive#form" 47 ThumbnailSizeS = "SIZE_SMALL" 48 ThumbnailSizeM = "SIZE_MEDIUM" 49 ThumbnailSizeL = "SIZE_LARGE" 50 PhaseTypeComplete = "PHASE_TYPE_COMPLETE" 51 PhaseTypeRunning = "PHASE_TYPE_RUNNING" 52 PhaseTypeError = "PHASE_TYPE_ERROR" 53 PhaseTypePending = "PHASE_TYPE_PENDING" 54 UploadTypeForm = "UPLOAD_TYPE_FORM" 55 UploadTypeResumable = "UPLOAD_TYPE_RESUMABLE" 56 ListLimit = 100 57 ) 58 59 // ------------------------------------------------------------ 60 61 // Error details api error from pikpak 62 type Error struct { 63 Reason string `json:"error"` // short description of the reason, e.g. "file_name_empty" "invalid_request" 64 Code int `json:"error_code"` 65 URL string `json:"error_url,omitempty"` 66 Message string `json:"error_description,omitempty"` 67 // can have either of `error_details` or `details`` 68 ErrorDetails []*ErrorDetails `json:"error_details,omitempty"` 69 Details []*ErrorDetails `json:"details,omitempty"` 70 } 71 72 // ErrorDetails contains further details of api error 73 type ErrorDetails struct { 74 Type string `json:"@type,omitempty"` 75 Reason string `json:"reason,omitempty"` 76 Domain string `json:"domain,omitempty"` 77 Metadata struct{} `json:"metadata,omitempty"` // TODO: undiscovered yet 78 Locale string `json:"locale,omitempty"` // e.g. "en" 79 Message string `json:"message,omitempty"` 80 StackEntries []interface{} `json:"stack_entries,omitempty"` // TODO: undiscovered yet 81 Detail string `json:"detail,omitempty"` 82 } 83 84 // Error returns a string for the error and satisfies the error interface 85 func (e *Error) Error() string { 86 out := fmt.Sprintf("Error %q (%d)", e.Reason, e.Code) 87 if e.Message != "" { 88 out += ": " + e.Message 89 } 90 return out 91 } 92 93 // Check Error satisfies the error interface 94 var _ error = (*Error)(nil) 95 96 // ------------------------------------------------------------ 97 98 // Filters contains parameters for filters when listing. 99 // 100 // possible operators 101 // * in: a list of comma-separated string 102 // * eq: "true" or "false" 103 // * gt or lt: time format string, e.g. "2023-01-28T10:56:49.757+08:00" 104 type Filters struct { 105 Phase map[string]string `json:"phase,omitempty"` // "in" or "eq" 106 Trashed map[string]bool `json:"trashed,omitempty"` // "eq" 107 Kind map[string]string `json:"kind,omitempty"` // "eq" 108 Starred map[string]bool `json:"starred,omitempty"` // "eq" 109 ModifiedTime map[string]string `json:"modified_time,omitempty"` // "gt" or "lt" 110 } 111 112 // Set sets filter values using field name, operator and corresponding value 113 func (f *Filters) Set(field, operator, value string) { 114 if value == "" { 115 // UNSET for empty values 116 return 117 } 118 r := reflect.ValueOf(f) 119 fd := reflect.Indirect(r).FieldByName(field) 120 if v, err := strconv.ParseBool(value); err == nil { 121 fd.Set(reflect.ValueOf(map[string]bool{operator: v})) 122 } else { 123 fd.Set(reflect.ValueOf(map[string]string{operator: value})) 124 } 125 } 126 127 // ------------------------------------------------------------ 128 // Common Elements 129 130 // Link contains a download URL for opening files 131 type Link struct { 132 URL string `json:"url"` 133 Token string `json:"token"` 134 Expire Time `json:"expire"` 135 Type string `json:"type,omitempty"` 136 } 137 138 // Valid reports whether l is non-nil, has an URL, and is not expired. 139 func (l *Link) Valid() bool { 140 return l != nil && l.URL != "" && time.Now().Add(10*time.Second).Before(time.Time(l.Expire)) 141 } 142 143 // URL is a basic form of URL 144 type URL struct { 145 Kind string `json:"kind,omitempty"` // e.g. "upload#url" 146 URL string `json:"url,omitempty"` 147 } 148 149 // ------------------------------------------------------------ 150 // Base Elements 151 152 // FileList contains a list of File elements 153 type FileList struct { 154 Kind string `json:"kind,omitempty"` // drive#fileList 155 Files []*File `json:"files,omitempty"` 156 NextPageToken string `json:"next_page_token"` 157 Version string `json:"version,omitempty"` 158 VersionOutdated bool `json:"version_outdated,omitempty"` 159 } 160 161 // File is a basic element representing a single file object 162 // 163 // There are two types of download links, 164 // 1) one from File.WebContentLink or File.Links.ApplicationOctetStream.URL and 165 // 2) the other from File.Medias[].Link.URL. 166 // Empirically, 2) is less restrictive to multiple concurrent range-requests 167 // for a single file, i.e. supports for higher `--multi-thread-streams=N`. 168 // However, it is not generally applicable as it is only for meadia. 169 type File struct { 170 Apps []*FileApp `json:"apps,omitempty"` 171 Audit *FileAudit `json:"audit,omitempty"` 172 Collection string `json:"collection,omitempty"` // TODO 173 CreatedTime Time `json:"created_time,omitempty"` 174 DeleteTime Time `json:"delete_time,omitempty"` 175 FileCategory string `json:"file_category,omitempty"` 176 FileExtension string `json:"file_extension,omitempty"` 177 FolderType string `json:"folder_type,omitempty"` 178 Hash string `json:"hash,omitempty"` // sha1 but NOT a valid file hash. looks like a torrent hash 179 IconLink string `json:"icon_link,omitempty"` 180 ID string `json:"id,omitempty"` 181 Kind string `json:"kind,omitempty"` // "drive#file" 182 Links *FileLinks `json:"links,omitempty"` 183 Md5Checksum string `json:"md5_checksum,omitempty"` 184 Medias []*Media `json:"medias,omitempty"` 185 MimeType string `json:"mime_type,omitempty"` 186 ModifiedTime Time `json:"modified_time,omitempty"` // updated when renamed or moved 187 Name string `json:"name,omitempty"` 188 OriginalFileIndex int `json:"original_file_index,omitempty"` // TODO 189 OriginalURL string `json:"original_url,omitempty"` 190 Params *FileParams `json:"params,omitempty"` 191 ParentID string `json:"parent_id,omitempty"` 192 Phase string `json:"phase,omitempty"` 193 Revision int `json:"revision,omitempty,string"` 194 Size int64 `json:"size,omitempty,string"` 195 SortName string `json:"sort_name,omitempty"` 196 Space string `json:"space,omitempty"` 197 SpellName []interface{} `json:"spell_name,omitempty"` // TODO maybe list of something? 198 Starred bool `json:"starred,omitempty"` 199 ThumbnailLink string `json:"thumbnail_link,omitempty"` 200 Trashed bool `json:"trashed,omitempty"` 201 UserID string `json:"user_id,omitempty"` 202 UserModifiedTime Time `json:"user_modified_time,omitempty"` 203 WebContentLink string `json:"web_content_link,omitempty"` 204 Writable bool `json:"writable,omitempty"` 205 } 206 207 // FileLinks includes links to file at backend 208 type FileLinks struct { 209 ApplicationOctetStream *Link `json:"application/octet-stream,omitempty"` 210 } 211 212 // FileAudit contains audit information for the file 213 type FileAudit struct { 214 Status string `json:"status,omitempty"` // "STATUS_OK" 215 Message string `json:"message,omitempty"` 216 Title string `json:"title,omitempty"` 217 } 218 219 // Media contains info about supported version of media, e.g. original, transcoded, etc 220 type Media struct { 221 MediaID string `json:"media_id,omitempty"` 222 MediaName string `json:"media_name,omitempty"` 223 Video struct { 224 Height int `json:"height,omitempty"` 225 Width int `json:"width,omitempty"` 226 Duration int64 `json:"duration,omitempty"` 227 BitRate int `json:"bit_rate,omitempty"` 228 FrameRate int `json:"frame_rate,omitempty"` 229 VideoCodec string `json:"video_codec,omitempty"` // "h264", "hevc" 230 AudioCodec string `json:"audio_codec,omitempty"` // "pcm_bluray", "aac" 231 VideoType string `json:"video_type,omitempty"` // "mpegts" 232 HdrType string `json:"hdr_type,omitempty"` 233 } `json:"video,omitempty"` 234 Link *Link `json:"link,omitempty"` 235 NeedMoreQuota bool `json:"need_more_quota,omitempty"` 236 VipTypes []interface{} `json:"vip_types,omitempty"` // TODO maybe list of something? 237 RedirectLink string `json:"redirect_link,omitempty"` 238 IconLink string `json:"icon_link,omitempty"` 239 IsDefault bool `json:"is_default,omitempty"` 240 Priority int `json:"priority,omitempty"` 241 IsOrigin bool `json:"is_origin,omitempty"` 242 ResolutionName string `json:"resolution_name,omitempty"` 243 IsVisible bool `json:"is_visible,omitempty"` 244 Category string `json:"category,omitempty"` 245 } 246 247 // FileParams includes parameters for instant open 248 type FileParams struct { 249 Duration int64 `json:"duration,omitempty,string"` // in seconds 250 Height int `json:"height,omitempty,string"` 251 Platform string `json:"platform,omitempty"` // "Upload" 252 PlatformIcon string `json:"platform_icon,omitempty"` 253 URL string `json:"url,omitempty"` 254 Width int `json:"width,omitempty,string"` 255 } 256 257 // FileApp includes parameters for instant open 258 type FileApp struct { 259 ID string `json:"id,omitempty"` // "decompress" for rar files 260 Name string `json:"name,omitempty"` // decompress" for rar files 261 Access []interface{} `json:"access,omitempty"` 262 Link string `json:"link,omitempty"` // "https://mypikpak.com/drive/decompression/{File.Id}?gcid={File.Hash}\u0026wv-style=topbar%3Ahide" 263 RedirectLink string `json:"redirect_link,omitempty"` 264 VipTypes []interface{} `json:"vip_types,omitempty"` 265 NeedMoreQuota bool `json:"need_more_quota,omitempty"` 266 IconLink string `json:"icon_link,omitempty"` 267 IsDefault bool `json:"is_default,omitempty"` 268 Params struct{} `json:"params,omitempty"` // TODO 269 CategoryIDs []interface{} `json:"category_ids,omitempty"` 270 AdSceneType int `json:"ad_scene_type,omitempty"` 271 Space string `json:"space,omitempty"` 272 Links struct{} `json:"links,omitempty"` // TODO 273 } 274 275 // ------------------------------------------------------------ 276 277 // TaskList contains a list of Task elements 278 type TaskList struct { 279 Tasks []*Task `json:"tasks,omitempty"` // "drive#task" 280 NextPageToken string `json:"next_page_token"` 281 ExpiresIn int `json:"expires_in,omitempty"` 282 } 283 284 // Task is a basic element representing a single task such as offline download and upload 285 type Task struct { 286 Kind string `json:"kind,omitempty"` // "drive#task" 287 ID string `json:"id,omitempty"` // task id? 288 Name string `json:"name,omitempty"` // torrent name? 289 Type string `json:"type,omitempty"` // "offline" 290 UserID string `json:"user_id,omitempty"` 291 Statuses []interface{} `json:"statuses,omitempty"` // TODO 292 StatusSize int `json:"status_size,omitempty"` // TODO 293 Params *TaskParams `json:"params,omitempty"` // TODO 294 FileID string `json:"file_id,omitempty"` 295 FileName string `json:"file_name,omitempty"` 296 FileSize string `json:"file_size,omitempty"` 297 Message string `json:"message,omitempty"` // e.g. "Saving" 298 CreatedTime Time `json:"created_time,omitempty"` 299 UpdatedTime Time `json:"updated_time,omitempty"` 300 ThirdTaskID string `json:"third_task_id,omitempty"` // TODO 301 Phase string `json:"phase,omitempty"` // e.g. "PHASE_TYPE_RUNNING" 302 Progress int `json:"progress,omitempty"` 303 IconLink string `json:"icon_link,omitempty"` 304 Callback string `json:"callback,omitempty"` 305 ReferenceResource interface{} `json:"reference_resource,omitempty"` // TODO 306 Space string `json:"space,omitempty"` 307 } 308 309 // TaskParams includes parameters informing status of Task 310 type TaskParams struct { 311 Age string `json:"age,omitempty"` 312 PredictSpeed string `json:"predict_speed,omitempty"` 313 PredictType string `json:"predict_type,omitempty"` 314 URL string `json:"url,omitempty"` 315 } 316 317 // Form contains parameters for upload by multipart/form-data 318 type Form struct { 319 Headers struct{} `json:"headers"` 320 Kind string `json:"kind"` // "drive#form" 321 Method string `json:"method"` // "POST" 322 MultiParts struct { 323 OSSAccessKeyID string `json:"OSSAccessKeyId"` 324 Signature string `json:"Signature"` 325 Callback string `json:"callback"` 326 Key string `json:"key"` 327 Policy string `json:"policy"` 328 XUserData string `json:"x:user_data"` 329 } `json:"multi_parts"` 330 URL string `json:"url"` 331 } 332 333 // Resumable contains parameters for upload by resumable 334 type Resumable struct { 335 Kind string `json:"kind,omitempty"` // "drive#resumable" 336 Provider string `json:"provider,omitempty"` // e.g. "PROVIDER_ALIYUN" 337 Params *ResumableParams `json:"params,omitempty"` 338 } 339 340 // ResumableParams specifies resumable paramegers 341 type ResumableParams struct { 342 AccessKeyID string `json:"access_key_id,omitempty"` 343 AccessKeySecret string `json:"access_key_secret,omitempty"` 344 Bucket string `json:"bucket,omitempty"` 345 Endpoint string `json:"endpoint,omitempty"` 346 Expiration Time `json:"expiration,omitempty"` 347 Key string `json:"key,omitempty"` 348 SecurityToken string `json:"security_token,omitempty"` 349 } 350 351 // FileInArchive is a basic element in archive 352 type FileInArchive struct { 353 Index int `json:"index,omitempty"` 354 Filename string `json:"filename,omitempty"` 355 Filesize string `json:"filesize,omitempty"` 356 MimeType string `json:"mime_type,omitempty"` 357 Gcid string `json:"gcid,omitempty"` 358 Kind string `json:"kind,omitempty"` 359 IconLink string `json:"icon_link,omitempty"` 360 Path string `json:"path,omitempty"` 361 } 362 363 // ------------------------------------------------------------ 364 365 // NewFile is a response to RequestNewFile 366 type NewFile struct { 367 File *File `json:"file,omitempty"` 368 Form *Form `json:"form,omitempty"` 369 Resumable *Resumable `json:"resumable,omitempty"` 370 Task *Task `json:"task,omitempty"` // null in this case 371 UploadType string `json:"upload_type,omitempty"` // "UPLOAD_TYPE_FORM" or "UPLOAD_TYPE_RESUMABLE" 372 } 373 374 // NewTask is a response to RequestNewTask 375 type NewTask struct { 376 UploadType string `json:"upload_type,omitempty"` // "UPLOAD_TYPE_URL" 377 File *File `json:"file,omitempty"` // null in this case 378 Task *Task `json:"task,omitempty"` 379 URL *URL `json:"url,omitempty"` // {"kind": "upload#url"} 380 } 381 382 // About informs drive status 383 type About struct { 384 Kind string `json:"kind,omitempty"` // "drive#about" 385 Quota *Quota `json:"quota,omitempty"` 386 ExpiresAt string `json:"expires_at,omitempty"` 387 Quotas struct{} `json:"quotas,omitempty"` // maybe []*Quota? 388 } 389 390 // Quota informs drive quota 391 type Quota struct { 392 Kind string `json:"kind,omitempty"` // "drive#quota" 393 Limit int64 `json:"limit,omitempty,string"` // limit in bytes 394 Usage int64 `json:"usage,omitempty,string"` // bytes in use 395 UsageInTrash int64 `json:"usage_in_trash,omitempty,string"` // bytes in trash but this seems not working 396 PlayTimesLimit string `json:"play_times_limit,omitempty"` // maybe in seconds 397 PlayTimesUsage string `json:"play_times_usage,omitempty"` // maybe in seconds 398 } 399 400 // Share is a response to RequestShare 401 // 402 // used in PublicLink() 403 type Share struct { 404 ShareID string `json:"share_id,omitempty"` 405 ShareURL string `json:"share_url,omitempty"` 406 PassCode string `json:"pass_code,omitempty"` 407 ShareText string `json:"share_text,omitempty"` 408 } 409 410 // User contains user account information 411 // 412 // GET https://user.mypikpak.com/v1/user/me 413 type User struct { 414 Sub string `json:"sub,omitempty"` // userid for internal use 415 Name string `json:"name,omitempty"` // Username 416 Picture string `json:"picture,omitempty"` // URL to Avatar image 417 Email string `json:"email,omitempty"` // redacted email address 418 Providers *[]UserProvider `json:"providers,omitempty"` // OAuth provider 419 PhoneNumber string `json:"phone_number,omitempty"` 420 Password string `json:"password,omitempty"` // "SET" if configured 421 Status string `json:"status,omitempty"` // "ACTIVE" 422 CreatedAt Time `json:"created_at,omitempty"` 423 PasswordUpdatedAt Time `json:"password_updated_at,omitempty"` 424 } 425 426 // UserProvider details third-party authentication 427 type UserProvider struct { 428 ID string `json:"id,omitempty"` // e.g. "google.com" 429 ProviderUserID string `json:"provider_user_id,omitempty"` 430 Name string `json:"name,omitempty"` // username 431 } 432 433 // VIP includes subscription details about premium account 434 // 435 // GET https://api-drive.mypikpak.com/drive/v1/privilege/vip 436 type VIP struct { 437 Result string `json:"result,omitempty"` // "ACCEPTED" 438 Message string `json:"message,omitempty"` 439 RedirectURI string `json:"redirect_uri,omitempty"` 440 Data struct { 441 Expire Time `json:"expire,omitempty"` 442 Status string `json:"status,omitempty"` // "invalid" or "ok" 443 Type string `json:"type,omitempty"` // "novip" or "platinum" 444 UserID string `json:"user_id,omitempty"` // same as User.Sub 445 } `json:"data,omitempty"` 446 } 447 448 // DecompressResult is a response to RequestDecompress 449 type DecompressResult struct { 450 Status string `json:"status,omitempty"` // "OK" 451 StatusText string `json:"status_text,omitempty"` 452 TaskID string `json:"task_id,omitempty"` // same as File.Id 453 FilesNum int `json:"files_num,omitempty"` // number of files in archive 454 RedirectLink string `json:"redirect_link,omitempty"` 455 } 456 457 // ------------------------------------------------------------ 458 459 // RequestShare is to request for file share 460 type RequestShare struct { 461 FileIDs []string `json:"file_ids,omitempty"` 462 ShareTo string `json:"share_to,omitempty"` // "publiclink", 463 ExpirationDays int `json:"expiration_days,omitempty"` // -1 = 'forever' 464 PassCodeOption string `json:"pass_code_option,omitempty"` // "NOT_REQUIRED" 465 } 466 467 // RequestBatch is to request for batch actions 468 type RequestBatch struct { 469 IDs []string `json:"ids,omitempty"` 470 To map[string]string `json:"to,omitempty"` 471 } 472 473 // RequestNewFile is to request for creating a new `drive#folder` or `drive#file` 474 type RequestNewFile struct { 475 // always required 476 Kind string `json:"kind"` // "drive#folder" or "drive#file" 477 Name string `json:"name"` 478 ParentID string `json:"parent_id"` 479 FolderType string `json:"folder_type"` 480 // only when uploading a new file 481 Hash string `json:"hash,omitempty"` // sha1sum 482 Resumable map[string]string `json:"resumable,omitempty"` // {"provider": "PROVIDER_ALIYUN"} 483 Size int64 `json:"size,omitempty"` 484 UploadType string `json:"upload_type,omitempty"` // "UPLOAD_TYPE_FORM" or "UPLOAD_TYPE_RESUMABLE" 485 } 486 487 // RequestNewTask is to request for creating a new task like offline downloads 488 // 489 // Name and ParentID can be left empty. 490 type RequestNewTask struct { 491 Kind string `json:"kind,omitempty"` // "drive#file" 492 Name string `json:"name,omitempty"` 493 ParentID string `json:"parent_id,omitempty"` 494 UploadType string `json:"upload_type,omitempty"` // "UPLOAD_TYPE_URL" 495 URL *URL `json:"url,omitempty"` // {"url": downloadUrl} 496 FolderType string `json:"folder_type,omitempty"` // "" if parent_id else "DOWNLOAD" 497 } 498 499 // RequestDecompress is to request for decompress of archive files 500 type RequestDecompress struct { 501 Gcid string `json:"gcid,omitempty"` // same as File.Hash 502 Password string `json:"password,omitempty"` // "" 503 FileID string `json:"file_id,omitempty"` 504 Files []*FileInArchive `json:"files,omitempty"` // can request selected files to be decompressed 505 DefaultParent bool `json:"default_parent,omitempty"` 506 } 507 508 // ------------------------------------------------------------ 509 510 // NOT implemented YET 511 512 // RequestArchiveFileList is to request for a list of files in archive 513 // 514 // POST https://api-drive.mypikpak.com/decompress/v1/list 515 type RequestArchiveFileList struct { 516 Gcid string `json:"gcid,omitempty"` // same as api.File.Hash 517 Path string `json:"path,omitempty"` // "" by default 518 Password string `json:"password,omitempty"` // "" by default 519 FileID string `json:"file_id,omitempty"` 520 } 521 522 // ArchiveFileList is a response to RequestArchiveFileList 523 type ArchiveFileList struct { 524 Status string `json:"status,omitempty"` // "OK" 525 StatusText string `json:"status_text,omitempty"` // "" 526 TaskID string `json:"task_id,omitempty"` // "" 527 CurrentPath string `json:"current_path,omitempty"` // "" 528 Title string `json:"title,omitempty"` 529 FileSize int64 `json:"file_size,omitempty"` 530 Gcid string `json:"gcid,omitempty"` // same as File.Hash 531 Files []*FileInArchive `json:"files,omitempty"` 532 }