179 lines
4.6 KiB
Go
179 lines
4.6 KiB
Go
package core
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/url"
|
|
"path"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gocolly/colly/v2"
|
|
|
|
"github.com/javtube/metatube-sdk-go/common/parser"
|
|
"github.com/javtube/metatube-sdk-go/model"
|
|
"github.com/javtube/metatube-sdk-go/provider/internal/scraper"
|
|
)
|
|
|
|
type Core struct {
|
|
*scraper.Scraper
|
|
|
|
// URLs
|
|
BaseURL string
|
|
MovieURL string
|
|
|
|
// Values
|
|
DefaultPriority int
|
|
DefaultName string
|
|
DefaultMaker string
|
|
}
|
|
|
|
func (core *Core) Init() *Core {
|
|
core.Scraper = scraper.NewDefaultScraper(
|
|
core.DefaultName,
|
|
core.BaseURL,
|
|
core.DefaultPriority,
|
|
scraper.WithDetectCharset())
|
|
return core
|
|
}
|
|
|
|
func (core *Core) GetMovieInfoByID(id string) (info *model.MovieInfo, err error) {
|
|
return core.GetMovieInfoByURL(fmt.Sprintf(core.MovieURL, id))
|
|
}
|
|
|
|
func (core *Core) ParseIDFromURL(rawURL string) (string, error) {
|
|
homepage, err := url.Parse(rawURL)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return path.Base(path.Dir(homepage.Path)), nil
|
|
}
|
|
|
|
func (core *Core) GetMovieInfoByURL(rawURL string) (info *model.MovieInfo, err error) {
|
|
id, err := core.ParseIDFromURL(rawURL)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
info = &model.MovieInfo{
|
|
ID: id,
|
|
Number: strings.ToLower(fmt.Sprintf("%s-%s", core.DefaultName, id)),
|
|
Provider: core.Name(),
|
|
Homepage: rawURL,
|
|
Maker: core.DefaultMaker,
|
|
Actors: []string{},
|
|
PreviewImages: []string{},
|
|
Genres: []string{},
|
|
}
|
|
|
|
c := core.ClonedCollector()
|
|
|
|
// JSON
|
|
c.OnXML(`//script[@type="application/ld+json"]`, func(e *colly.XMLElement) {
|
|
data := struct {
|
|
Name string `json:"name"`
|
|
Image string `json:"image"`
|
|
Actor struct {
|
|
Name string `json:"name"`
|
|
Image string `json:"image"`
|
|
} `json:"actor"`
|
|
Description string `json:"description"`
|
|
Duration string `json:"duration"`
|
|
DateCreated string `json:"dateCreated"`
|
|
ReleasedEvent struct {
|
|
StartDate string `json:"startDate"`
|
|
Location struct {
|
|
Name string `json:"name"`
|
|
} `json:"location"`
|
|
} `json:"releasedEvent"`
|
|
Video struct {
|
|
Thumbnail string `json:"thumbnail"`
|
|
Duration string `json:"duration"`
|
|
Actor string `json:"actor"`
|
|
Provider string `json:"provider"`
|
|
} `json:"video"`
|
|
AggregateRating struct {
|
|
RatingValue string `json:"ratingValue"`
|
|
} `json:"aggregateRating"`
|
|
}{}
|
|
if json.Unmarshal([]byte(strings.ReplaceAll(e.Text, "\n", "")), &data) == nil {
|
|
info.Title = data.Name
|
|
info.Summary = data.Description
|
|
if data.Image != "" {
|
|
info.CoverURL = e.Request.AbsoluteURL(data.Image)
|
|
info.ThumbURL = info.CoverURL /* use cover as thumb */
|
|
}
|
|
info.ReleaseDate = parser.ParseDate(data.ReleasedEvent.StartDate)
|
|
info.Runtime = parser.ParseRuntime(data.Video.Duration)
|
|
info.Score = parser.ParseScore(data.AggregateRating.RatingValue)
|
|
if data.Video.Provider != "" {
|
|
info.Maker = data.Video.Provider
|
|
}
|
|
if data.Video.Actor != "" {
|
|
info.Actors = []string{data.Video.Actor}
|
|
}
|
|
}
|
|
})
|
|
|
|
// Title
|
|
c.OnXML(`//*[@id="moviePlay"]//div[@class="moviePlay_title"]/h1/span`, func(e *colly.XMLElement) {
|
|
if title := strings.TrimSpace(e.Text); title != "" {
|
|
info.Title = title
|
|
}
|
|
})
|
|
|
|
// Fields
|
|
c.OnXML(`//*[@id="movieInfo"]//section/dl`, func(e *colly.XMLElement) {
|
|
for i, dt := range e.ChildTexts(`.//dt`) {
|
|
dd := fmt.Sprintf(`.//dd[%d]`, i+1)
|
|
switch dt {
|
|
case "年齢":
|
|
case "身長":
|
|
case "3サイズ":
|
|
case "タイプ":
|
|
case "動画":
|
|
if info.Runtime == 0 {
|
|
info.Runtime = parser.ParseRuntime(e.ChildText(dd))
|
|
}
|
|
case "公開日":
|
|
if time.Time(info.ReleaseDate).IsZero() {
|
|
info.ReleaseDate = parser.ParseDate(e.ChildText(dd))
|
|
}
|
|
case "プレイ内容":
|
|
// info.Genres = strings.Fields(e.ChildText(dd))
|
|
for _, genre := range strings.Split(e.ChildText(dd), "\u00a0") {
|
|
if genre := strings.TrimSpace(genre); genre != "" {
|
|
info.Genres = append(info.Genres, genre)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
// Thumb+Cover+Preview Video
|
|
c.OnXML(`//*[@id="movieContent"]`, func(e *colly.XMLElement) {
|
|
if poster := e.Attr("poster"); poster != "" {
|
|
info.CoverURL = e.Request.AbsoluteURL(poster)
|
|
info.ThumbURL = info.CoverURL /* use cover as thumb */
|
|
}
|
|
if src := e.ChildAttr(`./source`, "src"); src != "" {
|
|
info.PreviewVideoURL = e.Request.AbsoluteURL(src)
|
|
}
|
|
})
|
|
|
|
// Preview Images
|
|
c.OnXML(`//*[@id="movieGallery"]//script[@type="text/javascript"]`, func(e *colly.XMLElement) {
|
|
if ss := regexp.MustCompile(`href="(.+?)"`).FindAllStringSubmatch(e.Text, -1); len(ss) > 0 {
|
|
for _, ss := range ss {
|
|
if !strings.Contains(ss[1], "member") {
|
|
info.PreviewImages = append(info.PreviewImages, ss[1])
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
err = c.Visit(info.Homepage)
|
|
return
|
|
}
|