vendor: add github.com/putdotio/go-putio for putio client

This commit is contained in:
Cenk Alti 2019-08-06 15:43:14 +03:00 committed by Nick Craig-Wood
parent 8159658e67
commit 566aa0fca7
15 changed files with 1315 additions and 0 deletions

1
go.mod
View File

@ -38,6 +38,7 @@ require (
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.8.1 github.com/pkg/errors v0.8.1
github.com/pkg/sftp v1.10.1-0.20190523025818-e98a7bef6829 github.com/pkg/sftp v1.10.1-0.20190523025818-e98a7bef6829
github.com/putdotio/go-putio v0.0.0-20190731220109-37c0795af843
github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46 github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46
github.com/sevlyar/go-daemon v0.1.5 github.com/sevlyar/go-daemon v0.1.5
github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus v1.4.2

2
go.sum
View File

@ -151,6 +151,8 @@ github.com/pkg/sftp v1.10.1-0.20190523025818-e98a7bef6829 h1:I+1BDgqX1nXLUL5Uio2
github.com/pkg/sftp v1.10.1-0.20190523025818-e98a7bef6829/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk= github.com/pkg/sftp v1.10.1-0.20190523025818-e98a7bef6829/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/putdotio/go-putio v0.0.0-20190731220109-37c0795af843 h1:Hf9Zw1N+0gQolpRwWOwisCombJ/9anLxUwFkLMQL22c=
github.com/putdotio/go-putio v0.0.0-20190731220109-37c0795af843/go.mod h1:EWtDL88jJLLWZzywr0QaPO+mGP8gFpvl8dcox8qTk3Y=
github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46 h1:w2CpS5muK+jyydnmlkqpAhzKmHmMBzBkfYUDjQNS1Dk= github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46 h1:w2CpS5muK+jyydnmlkqpAhzKmHmMBzBkfYUDjQNS1Dk=
github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46/go.mod h1:U2bmx0hDj8EyDdcxmD5t3XHDnBFnyNNc22n1R4008eM= github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46/go.mod h1:U2bmx0hDj8EyDdcxmD5t3XHDnBFnyNNc22n1R4008eM=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=

22
vendor/github.com/putdotio/go-putio/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2016 H. İbrahim Güngör
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

42
vendor/github.com/putdotio/go-putio/putio/account.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
package putio
import "context"
// AccountService is the service to gather information about user account.
type AccountService struct {
client *Client
}
// Info retrieves user account information.
func (a *AccountService) Info(ctx context.Context) (AccountInfo, error) {
req, err := a.client.NewRequest(ctx, "GET", "/v2/account/info", nil)
if err != nil {
return AccountInfo{}, nil
}
var r struct {
Info AccountInfo
}
_, err = a.client.Do(req, &r)
if err != nil {
return AccountInfo{}, err
}
return r.Info, nil
}
// Settings retrieves user preferences.
func (a *AccountService) Settings(ctx context.Context) (Settings, error) {
req, err := a.client.NewRequest(ctx, "GET", "/v2/account/settings", nil)
if err != nil {
return Settings{}, nil
}
var r struct {
Settings Settings
}
_, err = a.client.Do(req, &r)
if err != nil {
return Settings{}, err
}
return r.Settings, nil
}

180
vendor/github.com/putdotio/go-putio/putio/client.go generated vendored Normal file
View File

@ -0,0 +1,180 @@
package putio
import (
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
)
const (
defaultUserAgent = "go-putio"
defaultMediaType = "application/json"
defaultBaseURL = "https://api.put.io"
defaultUploadURL = "https://upload.put.io"
)
// Client manages communication with Put.io v2 API.
type Client struct {
// HTTP client used to communicate with Put.io API
client *http.Client
// Base URL for API requests
BaseURL *url.URL
// base url for upload requests
uploadURL *url.URL
// User agent for client
UserAgent string
// ExtraHeaders are passed to the API server on every request.
ExtraHeaders http.Header
// Services used for communicating with the API
Account *AccountService
Files *FilesService
Transfers *TransfersService
Zips *ZipsService
Friends *FriendsService
Events *EventsService
}
// NewClient returns a new Put.io API client, using the htttpClient, which must
// be a new Oauth2 enabled http.Client. If httpClient is not defined, default
// HTTP client is used.
func NewClient(httpClient *http.Client) *Client {
if httpClient == nil {
httpClient = http.DefaultClient
}
baseURL, _ := url.Parse(defaultBaseURL)
uploadURL, _ := url.Parse(defaultUploadURL)
c := &Client{
client: httpClient,
BaseURL: baseURL,
uploadURL: uploadURL,
UserAgent: defaultUserAgent,
ExtraHeaders: make(http.Header),
}
c.Account = &AccountService{client: c}
c.Files = &FilesService{client: c}
c.Transfers = &TransfersService{client: c}
c.Zips = &ZipsService{client: c}
c.Friends = &FriendsService{client: c}
c.Events = &EventsService{client: c}
return c
}
func (c *Client) ValidateToken(ctx context.Context) (userID *int64, err error) {
req, err := c.NewRequest(ctx, "GET", "/v2/oauth2/validate", nil)
if err != nil {
return
}
var r struct {
UserID *int64 `json:"user_id"`
}
_, err = c.Do(req, &r)
return r.UserID, err
}
// NewRequest creates an API request. A relative URL can be provided via
// relURL, which will be resolved to the BaseURL of the Client.
func (c *Client) NewRequest(ctx context.Context, method, relURL string, body io.Reader) (*http.Request, error) {
rel, err := url.Parse(relURL)
if err != nil {
return nil, err
}
var u *url.URL
// XXX: workaroud for upload endpoint. upload method has a different base url,
// so we've a special case for testing purposes.
if relURL == "/v2/files/upload" {
u = c.uploadURL.ResolveReference(rel)
} else {
u = c.BaseURL.ResolveReference(rel)
}
req, err := http.NewRequest(method, u.String(), body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
req.Header.Set("Accept", defaultMediaType)
req.Header.Set("User-Agent", c.UserAgent)
// merge headers with extra headers
for header, values := range c.ExtraHeaders {
for _, value := range values {
req.Header.Add(header, value)
}
}
return req, nil
}
// Do sends an API request and returns the API response. The API response is
// JSON decoded and stored in the value pointed to by v, or returned as an
// error if an API error has occurred. Response body is closed at all cases except
// v is nil. If v is nil, response body is not closed and the body can be used
// for streaming.
func (c *Client) Do(r *http.Request, v interface{}) (*http.Response, error) {
resp, err := c.client.Do(r)
if err != nil {
return nil, err
}
err = checkResponse(resp)
if err != nil {
// close the body at all times if there is an http error
resp.Body.Close()
return resp, err
}
if v == nil {
return resp, nil
}
// close the body for all cases from here
defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(v)
if err != nil {
return resp, err
}
return resp, nil
}
// checkResponse is the entrypoint to reading the API response. If the response
// status code is not in success range, it will try to return a structured
// error.
func checkResponse(r *http.Response) error {
status := r.StatusCode
switch {
case status >= 200 && status <= 399:
return nil
case status >= 400 && status <= 599:
// server returns json
default:
return fmt.Errorf("unexpected status code: %d", status)
}
errorResponse := &ErrorResponse{Response: r}
data, err := ioutil.ReadAll(r.Body)
if err != nil {
return fmt.Errorf("body read error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
}
if len(data) > 0 {
err = json.Unmarshal(data, errorResponse)
if err != nil {
return fmt.Errorf("json decod error: %s. status: %v. Details: %v:", err, status, string(data[:250]))
}
}
return errorResponse
}

11
vendor/github.com/putdotio/go-putio/putio/doc.go generated vendored Normal file
View File

@ -0,0 +1,11 @@
// Package putio is the Put.io API v2 client for Go.
//
// The go-putio package does not directly handle authentication. Instead, when
// creating a new client, pass an http.Client that can handle authentication for
// you. The easiest and recommended way to do this is using the golang.org/x/oauth2
// library, but you can always use any other library that provides an http.Client.
//
// Note that when using an authenticated Client, all calls made by the client will
// include the specified OAuth token. Therefore, authenticated clients should
// almost never be shared between different users.
package putio

25
vendor/github.com/putdotio/go-putio/putio/error.go generated vendored Normal file
View File

@ -0,0 +1,25 @@
package putio
import (
"fmt"
"net/http"
)
// ErrorResponse reports the error caused by an API request.
type ErrorResponse struct {
Response *http.Response `json:"-"`
Message string `json:"error_message"`
Type string `json:"error_type"`
}
func (e *ErrorResponse) Error() string {
return fmt.Sprintf(
"Type: %v Message: %q. Original error: %v %v: %v",
e.Type,
e.Message,
e.Response.Request.Method,
e.Response.Request.URL,
e.Response.Status,
)
}

44
vendor/github.com/putdotio/go-putio/putio/events.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
package putio
import "context"
// EventsService is the service to gather information about user's events.
type EventsService struct {
client *Client
}
// FIXME: events list returns inconsistent data structures.
// List gets list of dashboard events. It includes downloads and share events.
func (e *EventsService) List(ctx context.Context) ([]Event, error) {
req, err := e.client.NewRequest(ctx, "GET", "/v2/events/list", nil)
if err != nil {
return nil, err
}
var r struct {
Events []Event
}
_, err = e.client.Do(req, &r)
if err != nil {
return nil, err
}
return r.Events, nil
}
// Delete Clears all all dashboard events.
func (e *EventsService) Delete(ctx context.Context) error {
req, err := e.client.NewRequest(ctx, "POST", "/v2/events/delete", nil)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = e.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}

429
vendor/github.com/putdotio/go-putio/putio/files.go generated vendored Normal file
View File

@ -0,0 +1,429 @@
package putio
import (
"bytes"
"context"
"fmt"
"io"
"mime/multipart"
"net/url"
"strconv"
"strings"
)
// FilesService is a general service to gather information about user files,
// such as listing, searching, creating new ones, or just fetching a single
// file.
type FilesService struct {
client *Client
}
// Get fetches file metadata for given file ID.
func (f *FilesService) Get(ctx context.Context, id int64) (File, error) {
req, err := f.client.NewRequest(ctx, "GET", "/v2/files/"+itoa(id), nil)
if err != nil {
return File{}, err
}
var r struct {
File File `json:"file"`
}
_, err = f.client.Do(req, &r)
if err != nil {
return File{}, err
}
return r.File, nil
}
// List fetches children for given directory ID.
func (f *FilesService) List(ctx context.Context, id int64) (children []File, parent File, err error) {
req, err := f.client.NewRequest(ctx, "GET", "/v2/files/list?parent_id="+itoa(id)+"&per_page=1000", nil)
if err != nil {
return
}
var r struct {
Files []File `json:"files"`
Parent File `json:"parent"`
Cursor string `json:"cursor"`
}
_, err = f.client.Do(req, &r)
if err != nil {
return
}
children = append(children, r.Files...)
parent = r.Parent
for r.Cursor != "" {
body := strings.NewReader(`{"cursor": "` + r.Cursor + `"}`)
req, err = f.client.NewRequest(ctx, "POST", "/v2/files/list/continue", body)
if err != nil {
return
}
req.Header.Set("content-type", "application/json")
r.Files = nil
r.Cursor = ""
_, err = f.client.Do(req, &r)
if err != nil {
return
}
children = append(children, r.Files...)
}
return
}
// URL returns a URL of the file for downloading or streaming.
func (f *FilesService) URL(ctx context.Context, id int64, useTunnel bool) (string, error) {
notunnel := "notunnel=1"
if useTunnel {
notunnel = "notunnel=0"
}
req, err := f.client.NewRequest(ctx, "GET", "/v2/files/"+itoa(id)+"/url?"+notunnel, nil)
if err != nil {
return "", err
}
var r struct {
URL string `json:"url"`
}
_, err = f.client.Do(req, &r)
if err != nil {
return "", err
}
return r.URL, nil
}
// CreateFolder creates a new folder under parent.
func (f *FilesService) CreateFolder(ctx context.Context, name string, parent int64) (File, error) {
if name == "" {
return File{}, fmt.Errorf("empty folder name")
}
params := url.Values{}
params.Set("name", name)
params.Set("parent_id", itoa(parent))
req, err := f.client.NewRequest(ctx, "POST", "/v2/files/create-folder", strings.NewReader(params.Encode()))
if err != nil {
return File{}, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
var r struct {
File File `json:"file"`
}
_, err = f.client.Do(req, &r)
if err != nil {
return File{}, err
}
return r.File, nil
}
// Delete deletes given files.
func (f *FilesService) Delete(ctx context.Context, files ...int64) error {
if len(files) == 0 {
return fmt.Errorf("no file id is given")
}
var ids []string
for _, id := range files {
ids = append(ids, itoa(id))
}
params := url.Values{}
params.Set("file_ids", strings.Join(ids, ","))
req, err := f.client.NewRequest(ctx, "POST", "/v2/files/delete", strings.NewReader(params.Encode()))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = f.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}
// Rename change the name of the file to newname.
func (f *FilesService) Rename(ctx context.Context, id int64, newname string) error {
if newname == "" {
return fmt.Errorf("new filename cannot be empty")
}
params := url.Values{}
params.Set("file_id", itoa(id))
params.Set("name", newname)
req, err := f.client.NewRequest(ctx, "POST", "/v2/files/rename", strings.NewReader(params.Encode()))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = f.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}
// Move moves files to the given destination.
func (f *FilesService) Move(ctx context.Context, parent int64, files ...int64) error {
if len(files) == 0 {
return fmt.Errorf("no files given")
}
var ids []string
for _, file := range files {
ids = append(ids, itoa(file))
}
params := url.Values{}
params.Set("file_ids", strings.Join(ids, ","))
params.Set("parent_id", itoa(parent))
req, err := f.client.NewRequest(ctx, "POST", "/v2/files/move", strings.NewReader(params.Encode()))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = f.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}
// Upload reads from given io.Reader and uploads the file contents to Put.io
// servers under directory given by parent. If parent is negative, user's
// prefered folder is used.
//
// If the uploaded file is a torrent file, Put.io will interpret it as a
// transfer and Transfer field will be present to represent the status of the
// tranfer. Likewise, if the uploaded file is a regular file, Transfer field
// would be nil and the uploaded file will be represented by the File field.
//
// This method reads the file contents into the memory, so it should be used for
// <150MB files.
func (f *FilesService) Upload(ctx context.Context, r io.Reader, filename string, parent int64) (Upload, error) {
if filename == "" {
return Upload{}, fmt.Errorf("filename cannot be empty")
}
var buf bytes.Buffer
mw := multipart.NewWriter(&buf)
// negative parent means use user's prefered download folder.
if parent >= 0 {
err := mw.WriteField("parent_id", itoa(parent))
if err != nil {
return Upload{}, err
}
}
formfile, err := mw.CreateFormFile("file", filename)
if err != nil {
return Upload{}, err
}
_, err = io.Copy(formfile, r)
if err != nil {
return Upload{}, err
}
err = mw.Close()
if err != nil {
return Upload{}, err
}
req, err := f.client.NewRequest(ctx, "POST", "/v2/files/upload", &buf)
if err != nil {
return Upload{}, err
}
req.Header.Set("Content-Type", mw.FormDataContentType())
var response struct {
Upload
}
_, err = f.client.Do(req, &response)
if err != nil {
return Upload{}, err
}
return response.Upload, nil
}
// Search makes a search request with the given query. Servers return 50
// results at a time. The URL for the next 50 results are in Next field. If
// page is -1, all results are returned.
func (f *FilesService) Search(ctx context.Context, query string, page int64) (Search, error) {
if page == 0 || page < -1 {
return Search{}, fmt.Errorf("invalid page number")
}
if query == "" {
return Search{}, fmt.Errorf("no query given")
}
req, err := f.client.NewRequest(ctx, "GET", "/v2/files/search/"+query+"/page/"+itoa(page), nil)
if err != nil {
return Search{}, err
}
var r Search
_, err = f.client.Do(req, &r)
if err != nil {
return Search{}, err
}
return r, nil
}
// Shared returns list of shared files and share information.
func (f *FilesService) shared(ctx context.Context) ([]share, error) {
req, err := f.client.NewRequest(ctx, "GET", "/v2/files/shared", nil)
if err != nil {
return nil, err
}
var r struct {
Shared []share
}
_, err = f.client.Do(req, &r)
if err != nil {
return nil, err
}
return r.Shared, nil
}
// SharedWith returns list of users the given file is shared with.
func (f *FilesService) sharedWith(ctx context.Context, id int64) ([]share, error) {
// FIXME: shared-with returns different json structure than /shared/
// endpoint. so it's not an exported method until a common structure is
// decided
req, err := f.client.NewRequest(ctx, "GET", "/v2/files/"+itoa(id)+"/shared-with", nil)
if err != nil {
return nil, err
}
var r struct {
Shared []share `json:"shared-with"`
}
_, err = f.client.Do(req, &r)
if err != nil {
return nil, err
}
return r.Shared, nil
}
// Subtitles lists available subtitles for the given file for user's prefered
// subtitle language.
func (f *FilesService) Subtitles(ctx context.Context, id int64) ([]Subtitle, error) {
req, err := f.client.NewRequest(ctx, "GET", "/v2/files/"+itoa(id)+"/subtitles", nil)
if err != nil {
return nil, err
}
var r struct {
Subtitles []Subtitle
Default string
}
_, err = f.client.Do(req, &r)
if err != nil {
return nil, err
}
return r.Subtitles, nil
}
// DownloadSubtitle sends the contents of the subtitle file. If the key is empty string,
// `default` key is used. This key is used to search for a subtitle in the
// following order and returns the first match:
// - A subtitle file that has identical parent folder and name with the video.
// - Subtitle file extracted from video if the format is MKV.
// - First match from OpenSubtitles.org.
func (f *FilesService) DownloadSubtitle(ctx context.Context, id int64, key string, format string) (io.ReadCloser, error) {
if key == "" {
key = "default"
}
req, err := f.client.NewRequest(ctx, "GET", "/v2/files/"+itoa(id)+"/subtitles/"+key, nil)
if err != nil {
return nil, err
}
resp, err := f.client.Do(req, nil)
if err != nil {
return nil, err
}
return resp.Body, nil
}
// HLSPlaylist serves a HLS playlist for a video file. Use “all” as
// subtitleKey to get available subtitles for users preferred languages.
func (f *FilesService) HLSPlaylist(ctx context.Context, id int64, subtitleKey string) (io.ReadCloser, error) {
if subtitleKey == "" {
return nil, fmt.Errorf("empty subtitle key is given")
}
req, err := f.client.NewRequest(ctx, "GET", "/v2/files/"+itoa(id)+"/hls/media.m3u8?subtitle_key"+subtitleKey, nil)
if err != nil {
return nil, err
}
resp, err := f.client.Do(req, nil)
if err != nil {
return nil, err
}
return resp.Body, nil
}
// SetVideoPosition sets default video position for a video file.
func (f *FilesService) SetVideoPosition(ctx context.Context, id int64, t int) error {
if t < 0 {
return fmt.Errorf("time cannot be negative")
}
params := url.Values{}
params.Set("time", strconv.Itoa(t))
req, err := f.client.NewRequest(ctx, "POST", "/v2/files/"+itoa(id)+"/start-from", strings.NewReader(params.Encode()))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = f.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}
// DeleteVideoPosition deletes video position for a video file.
func (f *FilesService) DeleteVideoPosition(ctx context.Context, id int64) error {
req, err := f.client.NewRequest(ctx, "POST", "/v2/files/"+itoa(id)+"/start-from/delete", nil)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = f.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}
func itoa(i int64) string {
return strconv.FormatInt(i, 10)
}

124
vendor/github.com/putdotio/go-putio/putio/friends.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
package putio
import (
"context"
"fmt"
)
// FriendsService is the service to operate on user friends.
type FriendsService struct {
client *Client
}
// List lists users friends.
func (f *FriendsService) List(ctx context.Context) ([]Friend, error) {
req, err := f.client.NewRequest(ctx, "GET", "/v2/friends/list", nil)
if err != nil {
return nil, err
}
var r struct {
Friends []Friend
Total int
}
_, err = f.client.Do(req, &r)
if err != nil {
return nil, err
}
return r.Friends, nil
}
// WaitingRequests lists user's pending friend requests.
func (f *FriendsService) WaitingRequests(ctx context.Context) ([]Friend, error) {
req, err := f.client.NewRequest(ctx, "GET", "/v2/friends/waiting-requests", nil)
if err != nil {
return nil, err
}
var r struct {
Friends []Friend
}
_, err = f.client.Do(req, &r)
if err != nil {
return nil, err
}
return r.Friends, nil
}
// Request sends a friend request to the given username.
func (f *FriendsService) Request(ctx context.Context, username string) error {
if username == "" {
return fmt.Errorf("empty username")
}
req, err := f.client.NewRequest(ctx, "POST", "/v2/friends/"+username+"/request", nil)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = f.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}
// Approve approves a friend request from the given username.
func (f *FriendsService) Approve(ctx context.Context, username string) error {
if username == "" {
return fmt.Errorf("empty username")
}
req, err := f.client.NewRequest(ctx, "POST", "/v2/friends/"+username+"/approve", nil)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = f.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}
// Deny denies a friend request from the given username.
func (f *FriendsService) Deny(ctx context.Context, username string) error {
if username == "" {
return fmt.Errorf("empty username")
}
req, err := f.client.NewRequest(ctx, "POST", "/v2/friends/"+username+"/deny", nil)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = f.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}
// Unfriend removed friend from user's friend list.
func (f *FriendsService) Unfriend(ctx context.Context, username string) error {
if username == "" {
return fmt.Errorf("empty username")
}
req, err := f.client.NewRequest(ctx, "POST", "/v2/friends/"+username+"/unfriend", nil)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = f.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}

33
vendor/github.com/putdotio/go-putio/putio/time.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
package putio
import "time"
// Time is a wrapper around time.Time that can be unmarshalled from a JSON
// string formatted as "2016-04-19T15:44:42". All methods of time.Time can be
// called on Time.
type Time struct {
time.Time
}
func (t *Time) String() string {
return t.Time.String()
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (t *Time) UnmarshalJSON(data []byte) error {
// put.io API has inconsistent time layouts for different endpoints, such
// as /files and /events
var timeLayouts = []string{`"2006-01-02T15:04:05"`, `"2006-01-02 15:04:05"`}
s := string(data)
var err error
var tm time.Time
for _, layout := range timeLayouts {
tm, err = time.ParseInLocation(layout, s, time.UTC)
if err == nil {
t.Time = tm
return nil
}
}
return err
}

154
vendor/github.com/putdotio/go-putio/putio/transfers.go generated vendored Normal file
View File

@ -0,0 +1,154 @@
package putio
import (
"context"
"fmt"
"net/url"
"strings"
)
// TransfersService is the service to operate on torrent transfers, such as
// adding a torrent or magnet link, retrying a current one etc.
type TransfersService struct {
client *Client
}
// List lists all active transfers. If a transfer is completed, it will not be
// available in response.
func (t *TransfersService) List(ctx context.Context) ([]Transfer, error) {
req, err := t.client.NewRequest(ctx, "GET", "/v2/transfers/list", nil)
if err != nil {
return nil, err
}
var r struct {
Transfers []Transfer
}
_, err = t.client.Do(req, &r)
if err != nil {
return nil, err
}
return r.Transfers, nil
}
// Add creates a new transfer. A valid torrent or a magnet URL is expected.
// Parent is the folder where the new transfer is downloaded to. If a negative
// value is given, user's preferred download folder is used. CallbackURL is
// used to send a POST request after the transfer is finished downloading.
func (t *TransfersService) Add(ctx context.Context, urlStr string, parent int64, callbackURL string) (Transfer, error) {
if urlStr == "" {
return Transfer{}, fmt.Errorf("empty URL")
}
params := url.Values{}
params.Set("url", urlStr)
// negative values indicate user's preferred download folder. don't include
// it in the request
if parent >= 0 {
params.Set("save_parent_id", itoa(parent))
}
if callbackURL != "" {
params.Set("callback_url", callbackURL)
}
req, err := t.client.NewRequest(ctx, "POST", "/v2/transfers/add", strings.NewReader(params.Encode()))
if err != nil {
return Transfer{}, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
var r struct {
Transfer Transfer
}
_, err = t.client.Do(req, &r)
if err != nil {
return Transfer{}, err
}
return r.Transfer, nil
}
// Get returns the given transfer's properties.
func (t *TransfersService) Get(ctx context.Context, id int64) (Transfer, error) {
req, err := t.client.NewRequest(ctx, "GET", "/v2/transfers/"+itoa(id), nil)
if err != nil {
return Transfer{}, err
}
var r struct {
Transfer Transfer
}
_, err = t.client.Do(req, &r)
if err != nil {
return Transfer{}, err
}
return r.Transfer, nil
}
// Retry retries previously failed transfer.
func (t *TransfersService) Retry(ctx context.Context, id int64) (Transfer, error) {
params := url.Values{}
params.Set("id", itoa(id))
req, err := t.client.NewRequest(ctx, "POST", "/v2/transfers/retry", strings.NewReader(params.Encode()))
if err != nil {
return Transfer{}, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
var r struct {
Transfer Transfer
}
_, err = t.client.Do(req, &r)
if err != nil {
return Transfer{}, err
}
return r.Transfer, nil
}
// Cancel deletes given transfers.
func (t *TransfersService) Cancel(ctx context.Context, ids ...int64) error {
if len(ids) == 0 {
return fmt.Errorf("no id given")
}
var transfers []string
for _, id := range ids {
transfers = append(transfers, itoa(id))
}
params := url.Values{}
params.Set("transfer_ids", strings.Join(transfers, ","))
req, err := t.client.NewRequest(ctx, "POST", "/v2/transfers/cancel", strings.NewReader(params.Encode()))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = t.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}
// Clean removes completed transfers from the transfer list.
func (t *TransfersService) Clean(ctx context.Context) error {
req, err := t.client.NewRequest(ctx, "POST", "/v2/transfers/clean", nil)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
_, err = t.client.Do(req, &struct{}{})
if err != nil {
return err
}
return nil
}

166
vendor/github.com/putdotio/go-putio/putio/types.go generated vendored Normal file
View File

@ -0,0 +1,166 @@
package putio
import "fmt"
// File represents a Put.io file.
type File struct {
ID int64 `json:"id"`
Name string `json:"name"`
Size int64 `json:"size"`
ContentType string `json:"content_type"`
CreatedAt *Time `json:"created_at"`
UpdatedAt *Time `json:"updated_at"`
FirstAccessedAt *Time `json:"first_accessed_at"`
ParentID int64 `json:"parent_id"`
Screenshot string `json:"screenshot"`
OpensubtitlesHash string `json:"opensubtitles_hash"`
IsMP4Available bool `json:"is_mp4_available"`
Icon string `json:"icon"`
CRC32 string `json:"crc32"`
IsShared bool `json:"is_shared"`
}
func (f *File) String() string {
return fmt.Sprintf("<ID: %v Name: %q Size: %v>", f.ID, f.Name, f.Size)
}
// IsDir reports whether the file is a directory.
func (f *File) IsDir() bool {
return f.ContentType == "application/x-directory"
}
// Upload represents a Put.io upload. If the uploaded file is a torrent file,
// Transfer field will represent the status of the transfer.
type Upload struct {
File *File `json:"file"`
Transfer *Transfer `json:"transfer"`
}
// Search represents a search response.
type Search struct {
Files []File `json:"files"`
Next string `json:"next"`
}
// Transfer represents a Put.io transfer state.
type Transfer struct {
Availability int `json:"availability"`
CallbackURL string `json:"callback_url"`
CreatedAt *Time `json:"created_at"`
CreatedTorrent bool `json:"created_torrent"`
ClientIP string `json:"client_ip"`
// FIXME: API returns either string or float non-deterministically.
// CurrentRatio float32 `json:"current_ratio"`
DownloadSpeed int `json:"down_speed"`
Downloaded int64 `json:"downloaded"`
DownloadID int64 `json:"download_id"`
ErrorMessage string `json:"error_message"`
EstimatedTime int64 `json:"estimated_time"`
Extract bool `json:"extract"`
FileID int64 `json:"file_id"`
FinishedAt *Time `json:"finished_at"`
ID int64 `json:"id"`
IsPrivate bool `json:"is_private"`
MagnetURI string `json:"magneturi"`
Name string `json:"name"`
PeersConnected int `json:"peers_connected"`
PeersGettingFromUs int `json:"peers_getting_from_us"`
PeersSendingToUs int `json:"peers_sending_to_us"`
PercentDone int `json:"percent_done"`
SaveParentID int64 `json:"save_parent_id"`
SecondsSeeding int `json:"seconds_seeding"`
Size int `json:"size"`
Source string `json:"source"`
Status string `json:"status"`
StatusMessage string `json:"status_message"`
SubscriptionID int `json:"subscription_id"`
TorrentLink string `json:"torrent_link"`
TrackerMessage string `json:"tracker_message"`
Trackers string `json:"tracker"`
Type string `json:"type"`
UploadSpeed int `json:"up_speed"`
Uploaded int64 `json:"uploaded"`
}
// AccountInfo represents user's account information.
type AccountInfo struct {
AccountActive bool `json:"account_active"`
AvatarURL string `json:"avatar_url"`
DaysUntilFilesDeletion int `json:"days_until_files_deletion"`
DefaultSubtitleLanguage string `json:"default_subtitle_language"`
Disk struct {
Avail int64 `json:"avail"`
Size int64 `json:"size"`
Used int64 `json:"used"`
} `json:"disk"`
HasVoucher bool `json:"has_voucher"`
Mail string `json:"mail"`
PlanExpirationDate string `json:"plan_expiration_date"`
Settings Settings `json:"settings"`
SimultaneousDownloadLimit int `json:"simultaneous_download_limit"`
SubtitleLanguages []string `json:"subtitle_languages"`
UserID int64 `json:"user_id"`
Username string `json:"username"`
}
// Settings represents user's personal settings.
type Settings struct {
CallbackURL string `json:"callback_url"`
DefaultDownloadFolder int64 `json:"default_download_folder"`
DefaultSubtitleLanguage string `json:"default_subtitle_language"`
DownloadFolderUnset bool `json:"download_folder_unset"`
IsInvisible bool `json:"is_invisible"`
Nextepisode bool `json:"nextepisode"`
PrivateDownloadHostIP interface{} `json:"private_download_host_ip"`
PushoverToken string `json:"pushover_token"`
Routing string `json:"routing"`
Sorting string `json:"sorting"`
SSLEnabled bool `json:"ssl_enabled"`
StartFrom bool `json:"start_from"`
SubtitleLanguages []string `json:"subtitle_languages"`
}
// Friend represents Put.io user's friend.
type Friend struct {
ID int64 `json:"id"`
Name string `json:"name"`
AvatarURL string `json:"avatar_url"`
}
// Zip represents Put.io zip file.
type Zip struct {
ID int64 `json:"id"`
CreatedAt *Time `json:"created_at"`
Size int64 `json:"size"`
Status string `json:"status"`
URL string `json:"url"`
}
// Subtitle represents a subtitle.
type Subtitle struct {
Key string
Language string
Name string
Source string
}
// Event represents a Put.io event. It could be a transfer or a shared file.
type Event struct {
ID int64 `json:"id"`
FileID int64 `json:"file_id"`
Source string `json:"source"`
Type string `json:"type"`
TransferName string `json:"transfer_name"`
TransferSize int64 `json:"transfer_size"`
CreatedAt *Time `json:"created_at"`
}
type share struct {
FileID int64 `json:"file_id"`
Filename string `json:"file_name"`
// Number of friends the file is shared with
SharedWith int64 `json:"shared_with"`
}

80
vendor/github.com/putdotio/go-putio/putio/zips.go generated vendored Normal file
View File

@ -0,0 +1,80 @@
package putio
import (
"context"
"fmt"
"net/url"
"strings"
)
// ZipsService is the service manage zip streams.
type ZipsService struct {
client *Client
}
// Get gives detailed information about the given zip file id.
func (z *ZipsService) Get(ctx context.Context, id int64) (Zip, error) {
req, err := z.client.NewRequest(ctx, "GET", "/v2/zips/"+itoa(id), nil)
if err != nil {
return Zip{}, err
}
var r Zip
_, err = z.client.Do(req, &r)
if err != nil {
return Zip{}, err
}
return r, nil
}
// List lists active zip files.
func (z *ZipsService) List(ctx context.Context) ([]Zip, error) {
req, err := z.client.NewRequest(ctx, "GET", "/v2/zips/list", nil)
if err != nil {
return nil, err
}
var r struct {
Zips []Zip
}
_, err = z.client.Do(req, &r)
if err != nil {
return nil, err
}
return r.Zips, nil
}
// Create creates zip files for given file IDs. If the operation is successful,
// a zip ID will be returned to keep track of zip process.
func (z *ZipsService) Create(ctx context.Context, fileIDs ...int64) (int64, error) {
if len(fileIDs) == 0 {
return 0, fmt.Errorf("no file id given")
}
var ids []string
for _, id := range fileIDs {
ids = append(ids, itoa(id))
}
params := url.Values{}
params.Set("file_ids", strings.Join(ids, ","))
req, err := z.client.NewRequest(ctx, "POST", "/v2/zips/create", strings.NewReader(params.Encode()))
if err != nil {
return 0, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
var r struct {
ID int64 `json:"zip_id"`
}
_, err = z.client.Do(req, &r)
if err != nil {
return 0, err
}
return r.ID, nil
}

2
vendor/modules.txt vendored
View File

@ -143,6 +143,8 @@ github.com/pkg/errors
github.com/pkg/sftp github.com/pkg/sftp
# github.com/pmezard/go-difflib v1.0.0 # github.com/pmezard/go-difflib v1.0.0
github.com/pmezard/go-difflib/difflib github.com/pmezard/go-difflib/difflib
# github.com/putdotio/go-putio v0.0.0-20190731220109-37c0795af843
github.com/putdotio/go-putio/putio
# github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46 # github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46
github.com/rfjakob/eme github.com/rfjakob/eme
# github.com/russross/blackfriday v1.5.2 # github.com/russross/blackfriday v1.5.2