xdcc-cli/search/sun_xdcc.go

115 lines
2.5 KiB
Go

package search
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"strings"
)
const (
sunXdccURL = "http://sunxdcc.com/deliver.php"
sunXdccNumberOfEntries = 8
)
type SunXdccProvider struct{}
func (p *SunXdccProvider) parseResponseEntry(entry *SunXdccResponse, index int) (*XdccFileInfo, error) {
info := &XdccFileInfo{}
info.URL.Network = entry.Network[index]
info.URL.UserName = entry.Bot[index]
info.URL.Channel = entry.Channel[index]
slot, err := strconv.Atoi(entry.Packnum[index][1:])
if err != nil {
return nil, err
}
sizeString := strings.TrimLeft(strings.TrimRight(entry.Fsize[index], "]"), "[")
info.Size, _ = parseFileSize(sizeString) // ignoring error
info.Name = entry.Fname[index]
if err != nil {
return nil, err
}
info.Slot = slot
return info, nil
}
type SunXdccResponse struct {
Botrec []string
Network []string
Bot []string
Channel []string
Packnum []string
Gets []string
Fsize []string
Fname []string
}
func (p *SunXdccProvider) Search(keywords []string) ([]XdccFileInfo, error) {
keywordString := strings.Join(keywords, " ")
searchkey := strings.Join(strings.Fields(keywordString), "+")
// see https://sunxdcc.com/#api for API definition
httpResp, err := http.Get(sunXdccURL + "?sterm=" + searchkey)
if err != nil {
return nil, err
}
defer httpResp.Body.Close()
if httpResp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code error: %d %s", httpResp.StatusCode, httpResp.Status)
}
resp, err := p.parseResponse(httpResp)
if err != nil {
return nil, err
}
if !p.validateResult(resp) {
return nil, fmt.Errorf("parse Error, not all fields have the same size")
}
return p.parseResults(resp)
}
func (p *SunXdccProvider) parseResults(resp *SunXdccResponse) ([]XdccFileInfo, error) {
fileInfos := make([]XdccFileInfo, 0)
for i := 0; i < len(resp.Botrec); i++ {
info, err := p.parseResponseEntry(resp, i)
if err == nil {
fileInfos = append(fileInfos, *info)
}
}
return fileInfos, nil
}
func (*SunXdccProvider) validateResult(entry *SunXdccResponse) bool {
sizes := [8]int{
len(entry.Botrec),
len(entry.Network),
len(entry.Bot),
len(entry.Channel),
len(entry.Packnum),
len(entry.Gets),
len(entry.Fsize),
len(entry.Fname),
}
length := sizes[0]
for _, l := range sizes {
if length != l {
return false
}
}
return true
}
func (*SunXdccProvider) parseResponse(res *http.Response) (*SunXdccResponse, error) {
entry := &SunXdccResponse{}
decoder := json.NewDecoder(res.Body)
err := decoder.Decode(entry)
return entry, err
}