init
This commit is contained in:
58
ytsclient/genre.go
Normal file
58
ytsclient/genre.go
Normal file
@ -0,0 +1,58 @@
|
||||
package ytsclient
|
||||
|
||||
type Genre string
|
||||
|
||||
const (
|
||||
// Genre Enum
|
||||
Action Genre = "Action"
|
||||
Adventure Genre = "Adventure"
|
||||
Animation Genre = "Animation"
|
||||
Biography Genre = "Biography"
|
||||
Comedy Genre = "Comedy"
|
||||
Crime Genre = "Crime"
|
||||
Documentary Genre = "Documentary"
|
||||
Drama Genre = "Drama"
|
||||
Family Genre = "Family"
|
||||
Fantasy Genre = "Fantasy"
|
||||
FilmNoir Genre = "Film Noir"
|
||||
History Genre = "History"
|
||||
Horror Genre = "Horror"
|
||||
Music Genre = "Music"
|
||||
Musical Genre = "Musical"
|
||||
Mystery Genre = "Mystery"
|
||||
Romance Genre = "Romance"
|
||||
SciFi Genre = "Sci-Fi"
|
||||
Short Genre = "Short"
|
||||
Sport Genre = "Sport"
|
||||
Superhero Genre = "Superhero"
|
||||
Thriller Genre = "Thriller"
|
||||
War Genre = "War"
|
||||
Western Genre = "Western"
|
||||
)
|
||||
|
||||
var Genres = []Genre{
|
||||
Action,
|
||||
Adventure,
|
||||
Animation,
|
||||
Biography,
|
||||
Comedy,
|
||||
Crime,
|
||||
Documentary,
|
||||
Drama,
|
||||
Family,
|
||||
Fantasy,
|
||||
FilmNoir,
|
||||
History,
|
||||
Horror,
|
||||
Music,
|
||||
Musical,
|
||||
Mystery,
|
||||
Romance,
|
||||
SciFi,
|
||||
Short,
|
||||
Sport,
|
||||
Superhero,
|
||||
Thriller,
|
||||
War,
|
||||
Western,
|
||||
}
|
91
ytsclient/movie.go
Normal file
91
ytsclient/movie.go
Normal file
@ -0,0 +1,91 @@
|
||||
package ytsclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type Movie struct {
|
||||
ID int `json:"id"`
|
||||
URL string `json:"url"`
|
||||
ImdbCode string `json:"imdb_code"`
|
||||
Title string `json:"title"`
|
||||
TitleEnglish string `json:"title_english"`
|
||||
TitleLong string `json:"title_long"`
|
||||
Slug string `json:"slug"`
|
||||
Year int `json:"year"`
|
||||
Rating float64 `json:"rating"`
|
||||
Runtime int `json:"runtime"`
|
||||
Genres []string `json:"genres"`
|
||||
DownloadCount int `json:"download_count"`
|
||||
LikeCount int `json:"like_count"`
|
||||
State string `json:"state"`
|
||||
Summary string `json:"summary"`
|
||||
Synopsis string `json:"synopsis"`
|
||||
DescriptionIntro string `json:"description_intro"`
|
||||
DescriptionFull string `json:"description_full"`
|
||||
YtTrailerCode string `json:"yt_trailer_code"`
|
||||
Language string `json:"language"`
|
||||
MpaRating string `json:"mpa_rating"`
|
||||
BackgroundImage string `json:"background_image"`
|
||||
BackgroundImageOriginal string `json:"background_image_original"`
|
||||
SmallCoverImage string `json:"small_cover_image"`
|
||||
MediumCoverImage string `json:"medium_cover_image"`
|
||||
LargeCoverImage string `json:"large_cover_image"`
|
||||
MediumScreenshotImage1 string `json:"medium_screenshot_image1"`
|
||||
MediumScreenshotImage2 string `json:"medium_screenshot_image2"`
|
||||
MediumScreenshotImage3 string `json:"medium_screenshot_image3"`
|
||||
LargeScreenshotImage1 string `json:"large_screenshot_image1"`
|
||||
LargeScreenshotImage2 string `json:"large_screenshot_image2"`
|
||||
LargeScreenshotImage3 string `json:"large_screenshot_image3"`
|
||||
Cast []Cast `json:"cast"`
|
||||
Torrents []Torrent `json:"torrents"`
|
||||
DateUploaded string `json:"date_uploaded"`
|
||||
DateUploadedUnix int `json:"date_uploaded_unix"`
|
||||
}
|
||||
|
||||
type Torrent struct {
|
||||
URL string `json:"url"`
|
||||
Hash string `json:"hash"`
|
||||
Quality string `json:"quality"`
|
||||
Seeds int `json:"seeds"`
|
||||
Peers int `json:"peers"`
|
||||
Size string `json:"size"`
|
||||
SizeBytes int `json:"size_bytes"`
|
||||
DateUploaded string `json:"date_uploaded"`
|
||||
DateUploadedUnix int `json:"date_uploaded_unix"`
|
||||
}
|
||||
|
||||
func (m *Movie) Magnet(t Torrent) (string, error) {
|
||||
if !contains(m.Torrents, t) {
|
||||
return "", errors.New("invalid torrent")
|
||||
}
|
||||
b := "magnet:?xt=urn:btih:%s&" +
|
||||
"dn=%s&" +
|
||||
"tr=udp://glotorrents.pw:6969/announce&" +
|
||||
"re=udp://tracker.opentrackr.org:1337/announce&" +
|
||||
"tr=udp://torrent.gresille.org:80/announce&" +
|
||||
"tr=udp://tracker.openbittorrent.com:80&" +
|
||||
"tr=udp://tracker.coppersurfer.tk:6969&" +
|
||||
"tr=udp://tracker.leechers-paradise.org:6969&" +
|
||||
"tr=udp://tracker.internetwarriors.net:1337"
|
||||
title := fmt.Sprintf("%s (%d) [%s]", m.Title, m.Year, t.Quality)
|
||||
return fmt.Sprintf(b, url.QueryEscape(t.Hash), url.QueryEscape(title)), nil
|
||||
}
|
||||
|
||||
type Cast struct {
|
||||
Name string `json:"name"`
|
||||
CharacterName string `json:"character_name"`
|
||||
URLSmallImage string `json:"url_small_image"`
|
||||
ImdbCode string `json:"imdb_code"`
|
||||
}
|
||||
|
||||
func contains(slice []Torrent, item Torrent) bool {
|
||||
for _, i := range slice {
|
||||
if i == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
20
ytsclient/order.go
Normal file
20
ytsclient/order.go
Normal file
@ -0,0 +1,20 @@
|
||||
package ytsclient
|
||||
|
||||
type SortBy string
|
||||
type Order string
|
||||
|
||||
const (
|
||||
// OrderBy Enum
|
||||
Title SortBy = "title"
|
||||
Year SortBy = "year"
|
||||
Rating SortBy = "rating"
|
||||
Peers SortBy = "peers"
|
||||
Seeds SortBy = "seeds"
|
||||
DownloadCount SortBy = "downloadCount"
|
||||
LikeCount SortBy = "likeCount"
|
||||
DateAdded SortBy = "dateAdded"
|
||||
|
||||
// Order Enum
|
||||
Asc Order = "asc"
|
||||
Desc Order = "desc"
|
||||
)
|
10
ytsclient/quality.go
Normal file
10
ytsclient/quality.go
Normal file
@ -0,0 +1,10 @@
|
||||
package ytsclient
|
||||
|
||||
type Quality string
|
||||
|
||||
const (
|
||||
// Quality Enum
|
||||
Quality720p Quality = "720p"
|
||||
Quality1080p Quality = "1080p"
|
||||
Quality3D Quality = "3D"
|
||||
)
|
32
ytsclient/reponses.go
Normal file
32
ytsclient/reponses.go
Normal file
@ -0,0 +1,32 @@
|
||||
package ytsclient
|
||||
|
||||
type ListResponse struct {
|
||||
Status string `json:"status"`
|
||||
StatusMessage string `json:"status_message"`
|
||||
Data struct {
|
||||
MovieCount int `json:"movie_count"`
|
||||
Limit int `json:"limit"`
|
||||
PageNumber int `json:"page_number"`
|
||||
Movies []Movie `json:"movies"`
|
||||
} `json:"data"`
|
||||
Meta struct {
|
||||
ServerTime int `json:"server_time"`
|
||||
ServerTimezone string `json:"server_timezone"`
|
||||
APIVersion int `json:"api_version"`
|
||||
ExecutionTime string `json:"execution_time"`
|
||||
} `json:"@meta"`
|
||||
}
|
||||
|
||||
type MovieResponse struct {
|
||||
Status string `json:"status"`
|
||||
StatusMessage string `json:"status_message"`
|
||||
Data struct {
|
||||
Movie Movie `json:"movie"`
|
||||
} `json:"data"`
|
||||
Meta struct {
|
||||
ServerTime int `json:"server_time"`
|
||||
ServerTimezone string `json:"server_timezone"`
|
||||
APIVersion int `json:"api_version"`
|
||||
ExecutionTime string `json:"execution_time"`
|
||||
} `json:"@meta"`
|
||||
}
|
61
ytsclient/requests.go
Normal file
61
ytsclient/requests.go
Normal file
@ -0,0 +1,61 @@
|
||||
package ytsclient
|
||||
|
||||
import (
|
||||
r "github.com/levigross/grequests"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ListParams struct {
|
||||
Limit int
|
||||
Page int
|
||||
Quality Quality
|
||||
MinimumRating int
|
||||
QueryTerm string
|
||||
Genre Genre
|
||||
SortBy SortBy
|
||||
OrderBy Order
|
||||
WithRottenTomatoesRating bool
|
||||
}
|
||||
|
||||
func (l *ListParams) format() *r.RequestOptions {
|
||||
p := map[string]string{}
|
||||
if l.Limit != 0 {
|
||||
p["limit"] = strconv.Itoa(l.Limit)
|
||||
}
|
||||
if l.Page != 0 {
|
||||
p["page"] = strconv.Itoa(l.Page)
|
||||
}
|
||||
if l.Quality != "" {
|
||||
p["quality"] = string(l.Quality)
|
||||
}
|
||||
if l.MinimumRating != 0 {
|
||||
p["minimum_rating"] = strconv.Itoa(l.MinimumRating)
|
||||
}
|
||||
if l.QueryTerm != "" {
|
||||
p["query_term"] = l.QueryTerm
|
||||
}
|
||||
if l.Genre != "" {
|
||||
p["genre"] = string(l.Genre)
|
||||
}
|
||||
if l.SortBy != "" {
|
||||
p["sort_by"] = string(l.SortBy)
|
||||
}
|
||||
if l.Genre != "" {
|
||||
p["order_by"] = string(l.Genre)
|
||||
}
|
||||
p["with_rt_ratings"] = strconv.FormatBool(l.WithRottenTomatoesRating)
|
||||
return &r.RequestOptions{Params: p}
|
||||
}
|
||||
|
||||
type MovieParams struct {
|
||||
WithImages bool
|
||||
WithCast bool
|
||||
}
|
||||
|
||||
func (m *MovieParams) format() *r.RequestOptions {
|
||||
p := map[string]string{
|
||||
"with_images": strconv.FormatBool(m.WithImages),
|
||||
"with_cast": strconv.FormatBool(m.WithCast),
|
||||
}
|
||||
return &r.RequestOptions{Params: p}
|
||||
}
|
89
ytsclient/ytsclient.go
Normal file
89
ytsclient/ytsclient.go
Normal file
@ -0,0 +1,89 @@
|
||||
package ytsclient
|
||||
|
||||
import (
|
||||
r "github.com/levigross/grequests"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
url string
|
||||
list string
|
||||
get string
|
||||
suggestions string
|
||||
}
|
||||
|
||||
const (
|
||||
list = "/list_movies.json"
|
||||
get = "/movie_details.json"
|
||||
suggestions = "/movie_suggestions.json"
|
||||
)
|
||||
|
||||
func NewClient(url string) *Client {
|
||||
if url == "" {
|
||||
url = "https://yts.am/api/v2"
|
||||
}
|
||||
return &Client{url, url + list, url + get, url + suggestions}
|
||||
}
|
||||
|
||||
func (y *Client) List(params *ListParams) ([]Movie, error) {
|
||||
if params == nil {
|
||||
params = &ListParams{}
|
||||
}
|
||||
res, err := r.Get(y.list, params.format())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resp ListResponse
|
||||
if err := res.JSON(&resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Data.Movies, nil
|
||||
}
|
||||
|
||||
func (y *Client) Search(search string, params *ListParams) ([]Movie, error) {
|
||||
if params == nil {
|
||||
params = &ListParams{}
|
||||
}
|
||||
params.QueryTerm = search
|
||||
res, err := r.Get(y.list, params.format())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resp ListResponse
|
||||
if err := res.JSON(&resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Data.Movies, nil
|
||||
}
|
||||
|
||||
func (y *Client) Get(id string, params *MovieParams) (Movie, error) {
|
||||
if params == nil {
|
||||
params = &MovieParams{}
|
||||
}
|
||||
p := params.format()
|
||||
p.Params["movie_id"] = id
|
||||
res, err := r.Get(y.get, p)
|
||||
if err != nil {
|
||||
return Movie{}, err
|
||||
}
|
||||
var resp MovieResponse
|
||||
if err := res.JSON(&resp); err != nil {
|
||||
return Movie{}, err
|
||||
}
|
||||
return resp.Data.Movie, nil
|
||||
}
|
||||
|
||||
func (y *Client) Suggestions(id int) ([]Movie, error) {
|
||||
ro := &r.RequestOptions{
|
||||
Params: map[string]string{"movie_id": strconv.Itoa(id)},
|
||||
}
|
||||
res, err := r.Get(y.suggestions, ro)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resp ListResponse
|
||||
if err := res.JSON(&resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Data.Movies, nil
|
||||
}
|
91
ytsclient/ytsclient_test.go
Normal file
91
ytsclient/ytsclient_test.go
Normal file
@ -0,0 +1,91 @@
|
||||
package ytsclient
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
southParkID = "2806"
|
||||
southParkMovie Movie
|
||||
// Removed [YTS.AG] as it may change and does not matter
|
||||
southParkMagnet = "magnet:?xt=urn:btih:04AC27DCF18C68470F35969517B477003C325301&" +
|
||||
"dn=South+Park%3A+Bigger%2C+Longer+%26+Uncut+%281999%29+%5B1080p%5D&" +
|
||||
"tr=udp%3A%2F%2Fglotorrents.pw%3A6969%2Fannounce&" +
|
||||
"tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80&" +
|
||||
"tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&" +
|
||||
"tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&" +
|
||||
"tr=udp%3A%2F%2Fp4p.arenabg.ch%3A1337&" +
|
||||
"tr=udp%3A%2F%2Ftracker.internetwarriors.net%3A1337"
|
||||
|
||||
tests = []struct {
|
||||
name string
|
||||
test func(t *testing.T)
|
||||
}{{
|
||||
name: "default url",
|
||||
test: func(t *testing.T) {
|
||||
c := NewClient("")
|
||||
assert.Equal(t, "https://yts.am/api/v2", c.url)
|
||||
},
|
||||
}, {
|
||||
name: "list",
|
||||
test: func(t *testing.T) {
|
||||
c := NewClient("")
|
||||
_, err := c.List(nil)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
}, {
|
||||
name: "search",
|
||||
test: func(t *testing.T) {
|
||||
c := NewClient("")
|
||||
l, err := c.Search("South Park", nil)
|
||||
assert.NoError(t, err)
|
||||
southParkMovie = l[0]
|
||||
assert.Equal(t, southParkID, strconv.Itoa(southParkMovie.ID))
|
||||
},
|
||||
}, {
|
||||
name: "list 50",
|
||||
test: func(t *testing.T) {
|
||||
c := NewClient("")
|
||||
p := &ListParams{Limit: 50}
|
||||
l, err := c.List(p)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 50, len(l))
|
||||
},
|
||||
}, {
|
||||
name: "get",
|
||||
test: func(t *testing.T) {
|
||||
c := NewClient("")
|
||||
m, err := c.Get(southParkID, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, m)
|
||||
assert.Equal(t, southParkMovie.Torrents, m.Torrents)
|
||||
},
|
||||
}, {
|
||||
name: "magnet",
|
||||
test: func(t *testing.T) {
|
||||
m, err := southParkMovie.Magnet(southParkMovie.Torrents[1])
|
||||
assert.NoError(t, err)
|
||||
// Don't test trackers list nor YTS extension
|
||||
e := strings.Split(southParkMagnet, "tr=")
|
||||
a := strings.Split(m, "tr=")
|
||||
assert.Equal(t, e[0], a[0])
|
||||
},
|
||||
}, {
|
||||
name: "suggestions",
|
||||
test: func(t *testing.T) {
|
||||
c := NewClient("")
|
||||
s, err := c.Suggestions(10)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, s)
|
||||
},
|
||||
}}
|
||||
)
|
||||
|
||||
func TestYTSClient(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, test.test)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user