init
This commit is contained in:
52
vendor/github.com/odwrtw/yifysubs/README.md
generated
vendored
Normal file
52
vendor/github.com/odwrtw/yifysubs/README.md
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
YIFY Subtitles client
|
||||
=========
|
||||
|
||||
[](http://godoc.org/github.com/odwrtw/yifysubs)
|
||||
[](https://goreportcard.com/report/github.com/odwrtw/yifysubs)
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/odwrtw/yifysubs"
|
||||
"github.com/kr/pretty"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create a client
|
||||
client := yifysubs.New("http://yifysubtitles.com")
|
||||
|
||||
// Search subtitles
|
||||
subtitles, err := client.Search("tt0133093")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Search subtitles by lang
|
||||
subtitles, err = client.SearchByLang("tt0133093", "French")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, subtitle := range subtitles {
|
||||
pretty.Println(subtitle)
|
||||
file, err := os.Create("/tmp/tt0133083.fr.srt")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
defer subtitle.Close()
|
||||
|
||||
if _, err := io.Copy(file, subtitle); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
192
vendor/github.com/odwrtw/yifysubs/yfi.go
generated
vendored
Normal file
192
vendor/github.com/odwrtw/yifysubs/yfi.go
generated
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
package yifysubs
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/jpillora/scraper/scraper"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// Errors
|
||||
var (
|
||||
ErrNoSubtitleFound = errors.New("yify: no subtitles found")
|
||||
)
|
||||
|
||||
// Client represent a Client used to make Search
|
||||
type Client struct {
|
||||
scraper *scraper.Endpoint
|
||||
Endpoint string
|
||||
}
|
||||
|
||||
// Subtitle represents a Subtitle
|
||||
type Subtitle struct {
|
||||
Rating int
|
||||
Lang string
|
||||
Uploader string
|
||||
URL string
|
||||
Title string
|
||||
reader io.ReadCloser
|
||||
}
|
||||
|
||||
// New return a new Searcher
|
||||
func New(endpoint string) *Client {
|
||||
e := &scraper.Endpoint{
|
||||
Name: "yifysubtitles",
|
||||
Method: "GET",
|
||||
List: "table.other-subs > tbody > tr",
|
||||
Headers: map[string]string{
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2988.133 Safari/537.36",
|
||||
},
|
||||
Result: map[string]scraper.Extractors{
|
||||
"rating": scraper.Extractors{scraper.MustExtractor("td.rating-cell"), scraper.MustExtractor("span")},
|
||||
"lang": scraper.Extractors{scraper.MustExtractor("td.flag-cell"), scraper.MustExtractor("span.sub-lang")},
|
||||
"title": scraper.Extractors{scraper.MustExtractor("td:nth-child(3)"), scraper.MustExtractor("a"), scraper.MustExtractor("/subtitle (.*)/")},
|
||||
"uploader": scraper.Extractors{scraper.MustExtractor("td.uploader-cell"), scraper.MustExtractor("a")},
|
||||
"url": scraper.Extractors{scraper.MustExtractor("td.download-cell"), scraper.MustExtractor("a"), scraper.MustExtractor("@href")},
|
||||
},
|
||||
Debug: false,
|
||||
}
|
||||
|
||||
return &Client{
|
||||
scraper: e,
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
}
|
||||
|
||||
// Search will search Subtitles
|
||||
func (c *Client) Search(imdbID string) ([]*Subtitle, error) {
|
||||
c.scraper.URL = c.Endpoint + "/movie-imdb/{{imdbId}}"
|
||||
|
||||
vars := map[string]string{
|
||||
"imdbId": imdbID,
|
||||
}
|
||||
return c.parseSubtitle(vars)
|
||||
}
|
||||
|
||||
// SearchByLang will search Subtitles with given language
|
||||
// The result will be ordered, with the highest rated subtitle first
|
||||
func (c *Client) SearchByLang(imdbID, lang string) ([]*Subtitle, error) {
|
||||
subtitles, err := c.Search(imdbID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return FilterByLang(subtitles, lang), nil
|
||||
}
|
||||
|
||||
// FilterByLang will filter the subtitles by language
|
||||
// The result will be ordered, with the highest rated subtitle first
|
||||
func FilterByLang(subtitles []*Subtitle, language string) []*Subtitle {
|
||||
filterredSubtitles := []*Subtitle{}
|
||||
for _, s := range subtitles {
|
||||
if s.Lang == language {
|
||||
filterredSubtitles = append(filterredSubtitles, s)
|
||||
}
|
||||
}
|
||||
sort.Slice(filterredSubtitles, func(i, j int) bool { return filterredSubtitles[i].Rating > filterredSubtitles[j].Rating })
|
||||
|
||||
return filterredSubtitles
|
||||
}
|
||||
|
||||
// parseSubtitle takes a map of parameters, it will do the request and return
|
||||
// the parsed Subtitles
|
||||
func (c *Client) parseSubtitle(vars map[string]string) ([]*Subtitle, error) {
|
||||
// Parse the page
|
||||
res, err := c.scraper.Execute(vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
subtitles := []*Subtitle{}
|
||||
|
||||
// Map the res to our structure
|
||||
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
WeaklyTypedInput: true,
|
||||
Result: &subtitles,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = decoder.Decode(res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(subtitles) == 0 {
|
||||
return nil, ErrNoSubtitleFound
|
||||
}
|
||||
|
||||
// Add the endpoint in front of the URLs
|
||||
for _, s := range subtitles {
|
||||
s.URL = c.Endpoint + s.URL
|
||||
}
|
||||
|
||||
return subtitles, nil
|
||||
}
|
||||
|
||||
// DownloadZipURL returns the zip file URL of the subtitle
|
||||
func (s Subtitle) DownloadZipURL() string {
|
||||
return fmt.Sprintf("%s.zip", strings.Replace(s.URL, "/subtitles/", "/subtitle/", -1))
|
||||
}
|
||||
|
||||
func getReaderFromURL(url string) (io.ReadCloser, error) {
|
||||
// Download the zip file
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
// Read all the body
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read response body with error %s", err)
|
||||
}
|
||||
|
||||
// Create a new zip Reader from a newly created bytes reader of the body
|
||||
// already read
|
||||
r, err := zip.NewReader(bytes.NewReader(body), res.ContentLength)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, f := range r.File {
|
||||
if filepath.Ext(f.Name) != ".srt" {
|
||||
continue
|
||||
}
|
||||
return f.Open()
|
||||
}
|
||||
return nil, fmt.Errorf("Empty zip subtitle")
|
||||
}
|
||||
|
||||
// Read implement the reader interface
|
||||
func (s *Subtitle) Read(p []byte) (n int, err error) {
|
||||
if s.reader == nil {
|
||||
// Download the zip and get the file reader
|
||||
r, err := getReaderFromURL(s.DownloadZipURL())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
s.reader = r
|
||||
}
|
||||
|
||||
return s.reader.Read(p)
|
||||
}
|
||||
|
||||
// Close implement the closer interface
|
||||
func (s Subtitle) Close() error {
|
||||
if s.reader != nil {
|
||||
return s.reader.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user