352 lines
8.7 KiB
Go
352 lines
8.7 KiB
Go
package realdebrid
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
)
|
|
|
|
func UnrestrictCheck(accessToken, link string) (*UnrestrictResponse, error) {
|
|
data := url.Values{}
|
|
data.Set("link", link)
|
|
|
|
req, err := http.NewRequest("POST", "https://api.real-debrid.com/rest/1.0/unrestrict/check", bytes.NewBufferString(data.Encode()))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("HTTP error: %s", resp.Status)
|
|
}
|
|
|
|
var response UnrestrictResponse
|
|
err = json.Unmarshal(body, &response)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &response, nil
|
|
}
|
|
|
|
func UnrestrictLink(accessToken, link string) (*UnrestrictResponse, error) {
|
|
data := url.Values{}
|
|
data.Set("link", link)
|
|
|
|
req, err := http.NewRequest("POST", "https://api.real-debrid.com/rest/1.0/unrestrict/link", bytes.NewBufferString(data.Encode()))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("HTTP error: %s", resp.Status)
|
|
}
|
|
|
|
var response UnrestrictResponse
|
|
err = json.Unmarshal(body, &response)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !canFetchFirstByte(response.Download) {
|
|
return nil, fmt.Errorf("can't fetch first byte")
|
|
}
|
|
return &response, nil
|
|
}
|
|
|
|
// GetTorrents returns all torrents, paginated
|
|
// if customLimit is 0, the default limit of 2500 is used
|
|
func GetTorrents(accessToken string, customLimit int) ([]Torrent, int, error) {
|
|
baseURL := "https://api.real-debrid.com/rest/1.0/torrents"
|
|
var allTorrents []Torrent
|
|
page := 1
|
|
limit := customLimit
|
|
if limit == 0 {
|
|
limit = 2500
|
|
}
|
|
totalCount := 0
|
|
|
|
for {
|
|
params := url.Values{}
|
|
params.Set("page", fmt.Sprintf("%d", page))
|
|
params.Set("limit", fmt.Sprintf("%d", limit))
|
|
|
|
reqURL := baseURL + "?" + params.Encode()
|
|
|
|
req, err := http.NewRequest("GET", reqURL, nil)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, 0, fmt.Errorf("HTTP error: %s", resp.Status)
|
|
}
|
|
|
|
var torrents []Torrent
|
|
decoder := json.NewDecoder(resp.Body)
|
|
err = decoder.Decode(&torrents)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
allTorrents = append(allTorrents, torrents...)
|
|
|
|
totalCountHeader := resp.Header.Get("x-total-count")
|
|
totalCount, err = strconv.Atoi(totalCountHeader)
|
|
if err != nil {
|
|
break
|
|
}
|
|
|
|
if len(allTorrents) >= totalCount || (customLimit != 0 && customLimit <= len(allTorrents) && customLimit <= totalCount) {
|
|
break
|
|
}
|
|
|
|
page++
|
|
}
|
|
|
|
return allTorrents, totalCount, nil
|
|
}
|
|
|
|
func GetTorrentInfo(accessToken, id string) (*Torrent, error) {
|
|
url := "https://api.real-debrid.com/rest/1.0/torrents/info/" + id
|
|
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("HTTP error: %s", resp.Status)
|
|
}
|
|
|
|
var response Torrent
|
|
err = json.Unmarshal(body, &response)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &response, nil
|
|
}
|
|
|
|
// SelectTorrentFiles selects files of a torrent to start it.
|
|
func SelectTorrentFiles(accessToken string, id string, files string) error {
|
|
// Prepare request data
|
|
data := url.Values{}
|
|
data.Set("files", files)
|
|
|
|
// Construct request URL
|
|
reqURL := fmt.Sprintf("https://api.real-debrid.com/rest/1.0/torrents/selectFiles/%s", id)
|
|
req, err := http.NewRequest("POST", reqURL, bytes.NewBufferString(data.Encode()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set request headers
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
// Send the request
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// Handle response status codes
|
|
switch resp.StatusCode {
|
|
case http.StatusOK, http.StatusNoContent:
|
|
return nil // Success
|
|
case http.StatusAccepted:
|
|
return errors.New("action already done")
|
|
case http.StatusBadRequest:
|
|
return errors.New("bad request")
|
|
case http.StatusUnauthorized:
|
|
return errors.New("bad token (expired or invalid)")
|
|
case http.StatusForbidden:
|
|
return errors.New("permission denied (account locked or not premium)")
|
|
case http.StatusNotFound:
|
|
return errors.New("wrong parameter (invalid file id(s)) or unknown resource (invalid id)")
|
|
default:
|
|
return fmt.Errorf("unexpected HTTP error: %s", resp.Status)
|
|
}
|
|
}
|
|
|
|
// DeleteTorrent deletes a torrent from the torrents list.
|
|
func DeleteTorrent(accessToken string, id string) error {
|
|
// Construct request URL
|
|
reqURL := fmt.Sprintf("https://api.real-debrid.com/rest/1.0/torrents/delete/%s", id)
|
|
req, err := http.NewRequest("DELETE", reqURL, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set request headers
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
|
|
// Send the request
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// Handle response status codes
|
|
switch resp.StatusCode {
|
|
case http.StatusNoContent:
|
|
return nil // Success
|
|
case http.StatusUnauthorized:
|
|
return errors.New("bad token (expired or invalid)")
|
|
case http.StatusForbidden:
|
|
return errors.New("permission denied (account locked)")
|
|
case http.StatusNotFound:
|
|
return errors.New("unknown resource")
|
|
default:
|
|
return fmt.Errorf("unexpected HTTP error: %s", resp.Status)
|
|
}
|
|
}
|
|
|
|
// AddMagnet adds a magnet link to download.
|
|
func AddMagnet(accessToken, magnet, host string) (*MagnetResponse, error) {
|
|
// Prepare request data
|
|
data := url.Values{}
|
|
data.Set("magnet", magnet)
|
|
data.Set("host", host)
|
|
|
|
// Construct request URL
|
|
reqURL := "https://api.real-debrid.com/rest/1.0/torrents/addMagnet"
|
|
req, err := http.NewRequest("POST", reqURL, bytes.NewBufferString(data.Encode()))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set request headers
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
// Send the request
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// Handle response status codes
|
|
switch resp.StatusCode {
|
|
case http.StatusCreated:
|
|
var response MagnetResponse
|
|
err := json.NewDecoder(resp.Body).Decode(&response)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &response, nil
|
|
case http.StatusBadRequest:
|
|
return nil, errors.New("bad request")
|
|
case http.StatusUnauthorized:
|
|
return nil, errors.New("bad token (expired or invalid)")
|
|
case http.StatusForbidden:
|
|
return nil, errors.New("permission denied (account locked or not premium)")
|
|
case http.StatusServiceUnavailable:
|
|
return nil, errors.New("service unavailable")
|
|
default:
|
|
return nil, fmt.Errorf("unexpected HTTP error: %s", resp.Status)
|
|
}
|
|
}
|
|
|
|
// GetActiveTorrentCount gets the number of currently active torrents and the current maximum limit.
|
|
func GetActiveTorrentCount(accessToken string) (*ActiveTorrentCountResponse, error) {
|
|
// Construct request URL
|
|
reqURL := "https://api.real-debrid.com/rest/1.0/torrents/activeCount"
|
|
req, err := http.NewRequest("GET", reqURL, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set request headers
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
|
|
// Send the request
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// Handle response status codes
|
|
switch resp.StatusCode {
|
|
case http.StatusOK:
|
|
var response ActiveTorrentCountResponse
|
|
err := json.NewDecoder(resp.Body).Decode(&response)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &response, nil
|
|
case http.StatusUnauthorized:
|
|
return nil, errors.New("bad token (expired or invalid)")
|
|
case http.StatusForbidden:
|
|
return nil, errors.New("permission denied (account locked)")
|
|
default:
|
|
return nil, fmt.Errorf("unexpected HTTP error: %s", resp.Status)
|
|
}
|
|
}
|