diff --git a/config.go b/config.go index 492cbd8..9ceaa06 100644 --- a/config.go +++ b/config.go @@ -94,7 +94,7 @@ var defaultConfig = Config{ Image: []string{"Qwant", "Bing", "DeviantArt"}, // For Files search - Files: []string{"TorrentGalaxy", "ThePirateBay"}, + Files: []string{"TorrentGalaxy", "ThePirateBay", "Nyaa"}, // For Video (piped instances) Video: []string{ diff --git a/files-nyaa.go b/files-nyaa.go new file mode 100644 index 0000000..db9f04a --- /dev/null +++ b/files-nyaa.go @@ -0,0 +1,107 @@ +package main + +import ( + "fmt" + "net/http" + "net/url" + "strings" + + "github.com/PuerkitoBio/goquery" +) + +const NYAA_DOMAIN = "nyaa.si" + +type Nyaa struct{} + +func NewNyaa() *Nyaa { + return &Nyaa{} +} + +func (n *Nyaa) Name() string { + return "nyaa" +} + +func (n *Nyaa) getCategoryCode(cat string) string { + switch cat { + case "all": + return "" + case "anime": + return "&c=1_0" + case "music": + return "&c=2_0" + case "game": + return "&c=6_2" + case "software": + return "&c=6_1" + default: + return "ignore" + } +} + +func (n *Nyaa) Search(query string, category string) ([]TorrentResult, error) { + categoryCode := n.getCategoryCode(category) + if categoryCode == "ignore" { + return []TorrentResult{}, nil + } + + searchURL := fmt.Sprintf("https://%s/?f=0&q=%s%s", NYAA_DOMAIN, url.QueryEscape(query), categoryCode) + + userAgent, err := GetUserAgent("files-nyaa") + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", searchURL, nil) + if err != nil { + return nil, err + } + req.Header.Set("User-Agent", userAgent) + + resp, err := DoMetaProxyRequest(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode) + } + + doc, err := goquery.NewDocumentFromReader(resp.Body) + if err != nil { + return nil, err + } + + var results []TorrentResult + doc.Find(".default, .success, .danger").Each(func(i int, s *goquery.Selection) { + tds := s.Find("td") + if tds.Length() < 7 { + return + } + + title := tds.Eq(1).Find("a").Last().Text() + magnet, _ := tds.Eq(2).Find("a").Last().Attr("href") + sizeStr := strings.TrimSpace(tds.Eq(3).Text()) + byteSize := parseSize(sizeStr) + + seeders := parseInt(tds.Eq(5).Text()) + leechers := parseInt(tds.Eq(6).Text()) + + results = append(results, TorrentResult{ + URL: "https://" + NYAA_DOMAIN, + Title: title, + Magnet: applyTrackers(magnet), + Size: formatSize(byteSize), + Seeders: seeders, + Leechers: leechers, + Views: 0, + }) + }) + + // Reverse the results slice, so It's from newest to oldest, but the orders is still kinda random + for i, j := 0, len(results)-1; i < j; i, j = i+1, j-1 { + results[i], results[j] = results[j], results[i] + } + + return results, nil +} diff --git a/files.go b/files.go index 6ae3b1a..1c71940 100755 --- a/files.go +++ b/files.go @@ -32,7 +32,7 @@ func initFileEngines() { torrentGalaxy = nil thePirateBay = nil - // nyaa = nil + nyaa = nil // rutor = nil for _, engineName := range config.MetaSearch.Files { @@ -41,8 +41,8 @@ func initFileEngines() { torrentGalaxy = NewTorrentGalaxy() case "ThePirateBay": thePirateBay = NewThePirateBay() - // case "Nyaa": - // nyaa = NewNyaa() + case "Nyaa": + nyaa = NewNyaa() // case "Rutor": // rutor = NewRutor() } @@ -174,33 +174,34 @@ func parseSize(sizeStr string) int64 { return 0 } - // Use regex to extract numeric value and unit separately - re := regexp.MustCompile(`(?i)([\d.]+)\s*([KMGT]?B)`) + re := regexp.MustCompile(`(?i)([\d.]+)\s*(K?M?G?T?i?B)`) matches := re.FindStringSubmatch(sizeStr) if len(matches) < 3 { printWarn("Error parsing size: invalid format %s", sizeStr) return 0 } - sizeStr = matches[1] + numStr := matches[1] unit := strings.ToUpper(matches[2]) var multiplier int64 = 1 switch unit { - case "KB": + case "B": + multiplier = 1 + case "KB", "KIB": multiplier = 1024 - case "MB": + case "MB", "MIB": multiplier = 1024 * 1024 - case "GB": + case "GB", "GIB": multiplier = 1024 * 1024 * 1024 - case "TB": + case "TB", "TIB": multiplier = 1024 * 1024 * 1024 * 1024 default: printWarn("Unknown unit: %s", unit) return 0 } - size, err := strconv.ParseFloat(sizeStr, 64) + size, err := strconv.ParseFloat(numStr, 64) if err != nil { printWarn("Error parsing size: %v", err) return 0 @@ -226,16 +227,16 @@ func applyTrackers(magnetLink string) string { } func formatSize(size int64) string { - if size >= 1024*1024*1024*1024 { - return fmt.Sprintf("%.2f TB", float64(size)/(1024*1024*1024*1024)) - } else if size >= 1024*1024*1024 { - return fmt.Sprintf("%.2f GB", float64(size)/(1024*1024*1024)) - } else if size >= 1024*1024 { - return fmt.Sprintf("%.2f MB", float64(size)/(1024*1024)) - } else if size >= 1024 { - return fmt.Sprintf("%.2f KB", float64(size)/1024) + const unit = 1024 + if size < unit { + return fmt.Sprintf("%d B", size) } - return fmt.Sprintf("%d B", size) + div, exp := unit, 0 + for n := size / unit; n >= unit; n /= unit { + div *= unit + exp++ + } + return fmt.Sprintf("%.1f %siB", float64(size)/float64(div), []string{"K", "M", "G", "T", "P", "E"}[exp]) } func sanitizeFileName(name string) string { @@ -245,12 +246,3 @@ func sanitizeFileName(name string) string { sanitized = regexp.MustCompile(`[^a-zA-Z0-9\-\(\)]`).ReplaceAllString(sanitized, "") return sanitized } - -func contains(slice []string, item string) bool { - for _, v := range slice { - if v == item { - return true - } - } - return false -}