pcgamedb/crawler/freegog.go

160 lines
4.0 KiB
Go
Raw Permalink Normal View History

2024-09-24 06:17:11 -04:00
package crawler
import (
"bytes"
"encoding/base64"
"errors"
2024-09-24 06:17:11 -04:00
"html"
"regexp"
"strings"
2024-11-20 06:09:04 -05:00
"pcgamedb/config"
"pcgamedb/constant"
"pcgamedb/db"
"pcgamedb/model"
"pcgamedb/utils"
2024-11-15 02:02:45 -05:00
2024-09-24 06:17:11 -04:00
"github.com/PuerkitoBio/goquery"
"go.uber.org/zap"
)
type FreeGOGCrawler struct {
2024-11-20 11:03:39 -05:00
logger *zap.Logger
2024-09-24 06:17:11 -04:00
}
func NewFreeGOGCrawler(logger *zap.Logger) *FreeGOGCrawler {
return &FreeGOGCrawler{
logger: logger,
}
}
func (c *FreeGOGCrawler) Name() string {
return "FreeGOG"
}
func (c *FreeGOGCrawler) Crawl(num int) ([]*model.GameItem, error) {
2024-09-24 06:17:11 -04:00
count := 0
2024-11-20 11:03:39 -05:00
session, err := utils.CCSWAFSession(config.Config.CFClearanceScraper.Url, constant.FreeGOGListURL)
if err != nil {
c.logger.Error("Failed to create session", zap.Error(err))
return nil, err
}
resp, err := utils.FetchWithWAFSession(utils.FetchConfig{
2024-09-24 06:17:11 -04:00
Url: constant.FreeGOGListURL,
2024-11-20 11:03:39 -05:00
}, session)
2024-09-24 06:17:11 -04:00
if err != nil {
c.logger.Error("Failed to fetch", zap.Error(err))
return nil, err
}
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(resp.Data))
if err != nil {
c.logger.Error("Failed to parse HTML", zap.Error(err))
return nil, err
}
var urls []string
var updateFlags []string //rawName+link
2024-09-24 06:17:11 -04:00
doc.Find(".items-outer li a").Each(func(i int, s *goquery.Selection) {
urls = append(urls, s.AttrOr("href", ""))
updateFlags = append(updateFlags, s.Text()+s.AttrOr("href", ""))
})
var res []*model.GameItem
2024-09-24 06:17:11 -04:00
for i, u := range urls {
if count == num {
break
}
if db.IsFreeGOGCrawled(updateFlags[i]) {
continue
}
c.logger.Info("Crawling", zap.String("URL", u))
2024-11-20 11:03:39 -05:00
item, err := c.CrawlByUrl(u, session)
2024-09-24 06:17:11 -04:00
if err != nil {
c.logger.Warn("Failed to crawl", zap.Error(err), zap.String("URL", u))
continue
}
item.UpdateFlag = updateFlags[i]
err = db.SaveGameItem(item)
2024-09-24 06:17:11 -04:00
if err != nil {
c.logger.Warn("Failed to save", zap.Error(err))
continue
}
res = append(res, item)
count++
if err := OrganizeGameItem(item); err != nil {
2024-09-24 06:17:11 -04:00
c.logger.Warn("Failed to organize", zap.Error(err), zap.String("URL", u))
continue
}
}
return res, nil
}
2024-11-20 11:03:39 -05:00
func (c *FreeGOGCrawler) CrawlByUrl(url string, session *utils.WAFSession) (*model.GameItem, error) {
resp, err := utils.FetchWithWAFSession(utils.FetchConfig{
2024-09-24 06:17:11 -04:00
Url: url,
2024-11-20 11:03:39 -05:00
}, session)
2024-09-24 06:17:11 -04:00
if err != nil {
return nil, err
}
item, err := db.GetGameItemByUrl(url)
2024-09-24 06:17:11 -04:00
if err != nil {
return nil, err
}
item.Url = url
rawTitleRegex := regexp.MustCompile(`(?i)<h1 class="entry-title">(.*?)</h1>`)
rawTitleRegexRes := rawTitleRegex.FindStringSubmatch(string(resp.Data))
rawName := ""
if len(rawTitleRegexRes) > 1 {
rawName = html.UnescapeString(rawTitleRegexRes[1])
item.RawName = strings.Replace(rawName, "", "-", -1)
} else {
return nil, err
}
item.Name = FreeGOGFormatter(item.RawName)
sizeRegex := regexp.MustCompile(`(?i)>Size:\s?(.*?)<`)
sizeRegexRes := sizeRegex.FindStringSubmatch(string(resp.Data))
if len(sizeRegexRes) > 1 {
item.Size = sizeRegexRes[1]
}
magnetRegex := regexp.MustCompile(`<a class="download-btn" href="https://gdl.freegogpcgames.xyz/download-gen\.php\?url=(.*?)"`)
magnetRegexRes := magnetRegex.FindStringSubmatch(string(resp.Data))
if len(magnetRegexRes) > 1 {
magnet, err := base64.StdEncoding.DecodeString(magnetRegexRes[1])
if err != nil {
return nil, err
}
item.Download = string(magnet)
} else {
return nil, errors.New("failed to find magnet link")
2024-09-24 06:17:11 -04:00
}
item.Author = "FreeGOG"
return item, nil
}
func (c *FreeGOGCrawler) CrawlAll() ([]*model.GameItem, error) {
2024-09-24 06:17:11 -04:00
return c.Crawl(-1)
}
var freeGOGRegexps = []*regexp.Regexp{
regexp.MustCompile(`(?i)\(.*\)`),
}
func FreeGOGFormatter(name string) string {
for _, re := range freeGOGRegexps {
name = re.ReplaceAllString(name, "")
}
reg1 := regexp.MustCompile(`(?i)v\d+(\.\d+)*`)
if index := reg1.FindIndex([]byte(name)); index != nil {
name = name[:index[0]]
}
if index := strings.Index(name, "+"); index != -1 {
name = name[:index]
}
reg2 := regexp.MustCompile(`(?i):\sgoty`)
name = reg2.ReplaceAllString(name, ": Game Of The Year")
return strings.TrimSpace(name)
}