xdcc-cli/xdcc.go

127 lines
2.5 KiB
Go

package main
import (
"errors"
"log"
"net/http"
"strconv"
"strings"
"sync"
"github.com/PuerkitoBio/goquery"
)
type XdccFileInfo struct {
Network string
Channel string
BotName string
Name string
Slot int
}
type XdccProvider interface {
Search(fileName string) ([]XdccFileInfo, error)
}
type XdccProviderRegistry struct {
providerList []XdccProvider
}
const MaxProviders = 100
func NewProviderRegistry() *XdccProviderRegistry {
return &XdccProviderRegistry{
providerList: make([]XdccProvider, 0, MaxProviders),
}
}
func (registry *XdccProviderRegistry) AddProvider(provider XdccProvider) {
registry.providerList = append(registry.providerList, provider)
}
const MaxResults = 1024
func (registry *XdccProviderRegistry) Search(fileName string) ([]XdccFileInfo, error) {
allResults := make([]XdccFileInfo, 0, MaxResults)
wg := sync.WaitGroup{}
wg.Add(len(registry.providerList))
for _, p := range registry.providerList {
go func(p XdccProvider) {
res, err := p.Search(fileName)
if err != nil {
return
}
allResults = append(allResults, res...)
wg.Done()
}(p)
}
wg.Wait()
return allResults, nil
}
type XdccEuProvider struct{}
const XdccEuURL = "https://www.xdcc.eu/search.php"
func (p *XdccEuProvider) parseFields(fields []string) (*XdccFileInfo, error) {
if len(fields) != 7 {
return nil, errors.New("unespected number of search entry fields")
}
fInfo := &XdccFileInfo{}
fInfo.Network = fields[0]
fInfo.Channel = fields[1]
fInfo.BotName = fields[2]
slot, err := strconv.Atoi(fields[3][1:])
fInfo.Name = fields[6]
if err != nil {
return nil, err
}
fInfo.Slot = slot
return fInfo, nil
}
func (p *XdccEuProvider) Search(fileName string) ([]XdccFileInfo, error) {
searchkey := strings.Join(strings.Fields(fileName), "+")
res, err := http.Get(XdccEuURL + "?searchkey=" + searchkey)
if err != nil {
log.Fatal(err)
return nil, err
}
defer res.Body.Close()
if res.StatusCode != 200 {
log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
return nil, err
}
// Load the HTML document
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
log.Fatal(err)
return nil, err
}
fileInfos := make([]XdccFileInfo, 0)
doc.Find("tr").Each(func(i int, s *goquery.Selection) {
fields := make([]string, 0)
s.Find("td").Each(func(j int, si *goquery.Selection) {
fields = append(fields, strings.TrimSpace(si.Text()))
})
info, err := p.parseFields(fields)
if err == nil {
fileInfos = append(fileInfos, *info)
}
})
return fileInfos, nil
}