From e293f68c4a29a05bb69b58ee894e1387c635148d Mon Sep 17 00:00:00 2001 From: Daniil Tsivinsky Date: Thu, 19 Feb 2026 16:53:03 +0300 Subject: [PATCH] add jackett client package instead of external library also, fixed non-tv category searches resulting in 0 results --- go.mod | 1 - go.sum | 2 -- jackett/client.go | 20 +++++++++++ jackett/search.go | 91 +++++++++++++++++++++++++++++++++++++++++++++++ main.go | 39 ++++++-------------- 5 files changed, 122 insertions(+), 31 deletions(-) create mode 100644 jackett/client.go create mode 100644 jackett/search.go diff --git a/go.mod b/go.mod index ee60cac..16314e8 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/autobrr/go-qbittorrent v1.14.0 github.com/jmoiron/sqlx v1.4.0 github.com/joho/godotenv v1.5.1 - github.com/kylesanderson/go-jackett v0.0.0-20251103073025-88ab5d10a082 github.com/mattn/go-sqlite3 v1.14.33 github.com/zeebo/bencode v1.0.0 ) diff --git a/go.sum b/go.sum index 7f6eaf5..252bc30 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,6 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/kylesanderson/go-jackett v0.0.0-20251103073025-88ab5d10a082 h1:4dvzW0EB2DDyw/Qa6ga6Ny4xDfubmbHc5JOVO0G7hFg= -github.com/kylesanderson/go-jackett v0.0.0-20251103073025-88ab5d10a082/go.mod h1:o805kiTZcYvSoF1ImxwxvU+VOmK/kvRVRLI49VHXORs= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= diff --git a/jackett/client.go b/jackett/client.go new file mode 100644 index 0000000..6be0bc2 --- /dev/null +++ b/jackett/client.go @@ -0,0 +1,20 @@ +package jackett + +type Config struct { + Host string + APIKey string +} + +type Client struct { + conf Config +} + +func NewClient(conf Config) *Client { + return &Client{ + conf: conf, + } +} + +func (c *Client) buildUrl(path string) string { + return c.conf.Host + path +} diff --git a/jackett/search.go b/jackett/search.go new file mode 100644 index 0000000..a1997d4 --- /dev/null +++ b/jackett/search.go @@ -0,0 +1,91 @@ +package jackett + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + "strconv" + "strings" +) + +type Response struct { + Results []Result `json:"results"` + Indexers []Indexer `json:"indexers"` +} + +type Result struct { + FirstSeen string `json:"FirstSeen"` + Tracker string `json:"Tracker"` + TrackerID string `json:"TrackerId"` + TrackerType string `json:"TrackerType"` + CategoryDesc string `json:"CategoryDesc"` + BlackholeLink string `json:"BlackholeLink"` + Title string `json:"Title"` + GUID string `json:"Guid"` + Link string `json:"Link"` + Details string `json:"Details"` + PublishDate string `json:"PublishDate"` + Category []int `json:"Category"` + Size int64 `json:"Size"` + Files any `json:"Files"` + Grabs int `json:"Grabs"` + Description string `json:"Description"` + RageID any `json:"RageID"` + TVDBID any `json:"TVDBId"` + Imdb any `json:"Imdb"` + TMDb any `json:"TMDb"` + DoubanID any `json:"DoubanId"` + Author string `json:"Author"` + BookTitle string `json:"BookTitle"` + Seeders int `json:"Seeders"` + Peers int `json:"Peers"` + Poster any `json:"Poster"` + InfoHash any `json:"InfoHash"` + MagnetURI any `json:"MagnetUri"` + MinimumRatio any `json:"MinimumRatio"` + MinimumSeedTime any `json:"MinimumSeedTime"` + DownloadVolumeFactor float64 `json:"DownloadVolumeFactor"` + UploadVolumeFactor float64 `json:"UploadVolumeFactor"` + Gain float64 `json:"Gain"` +} + +type Indexer struct { + ID string `json:"ID"` + Name string `json:"Name"` + Status int `json:"Status"` + Results int `json:"Results"` + Error string `json:"Error"` +} + +func (c *Client) Search(q string, categories ...int) ([]Result, error) { + req, err := http.NewRequest("GET", c.buildUrl("/api/v2.0/indexers/all/results"), nil) + if err != nil { + return nil, fmt.Errorf("failed to create request: %v", err) + } + + query := url.Values{} + query.Add("apikey", c.conf.APIKey) + query.Add("Query", q) + + categoryList := []string{} + for _, c := range categories { + categoryList = append(categoryList, strconv.Itoa(c)) + } + query.Add("Category[]", strings.Join(categoryList, ",")) + + req.URL.RawQuery = query.Encode() + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to send request: %v", err) + } + defer resp.Body.Close() + + response := new(Response) + if err := json.NewDecoder(resp.Body).Decode(response); err != nil { + return nil, fmt.Errorf("failed to decode response: %v", err) + } + + return response.Results, nil +} diff --git a/main.go b/main.go index 6a8604d..acc3da9 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "api/jackett" "api/model" "embed" _ "embed" @@ -18,7 +19,6 @@ import ( "github.com/autobrr/go-qbittorrent" "github.com/jmoiron/sqlx" "github.com/joho/godotenv" - "github.com/kylesanderson/go-jackett" _ "github.com/mattn/go-sqlite3" ) @@ -44,30 +44,13 @@ type JackettTorrent struct { } func checkForNewTorrents(jackettClient *jackett.Client, db *sqlx.DB, m *model.Model, item *model.Item) error { - results, err := jackettClient.TVSearch(jackett.TVSearchOptions{ - Query: item.Query, - }) + results, err := jackettClient.Search(item.Query, item.Category) if err != nil { return fmt.Errorf("couldn't get to jackett api: %v\n", err) } - for _, torrent := range results.Channel.Item { - size := toIntOr(torrent.Size, 0) - category := toIntOr(torrent.Category[0], 5000) - pubDate, _ := time.Parse(time.RFC1123Z, torrent.PubDate) - - seeders := 0 - peers := 0 - for _, attr := range torrent.Attr { - if attr.Name == "seeders" { - seeders = toIntOr(attr.Value, 0) - } - if attr.Name == "peers" { - peers = toIntOr(attr.Value, 0) - } - } - - guidTorrent, _ := m.GetTorrentByGuidAndItemId(torrent.Guid, item.ID) + for _, torrent := range results { + guidTorrent, _ := m.GetTorrentByGuidAndItemId(torrent.GUID, item.ID) if guidTorrent != nil { // already have this exact one, for this item. ABORT! continue @@ -76,14 +59,14 @@ func checkForNewTorrents(jackettClient *jackett.Client, db *sqlx.DB, m *model.Mo // this shit will duplicate. idk if it's ok or not, but fuck it. we ball _, err = db.NamedExec("INSERT INTO torrents (title, guid, indexer, pubdate, size, download_url, seeders, peers, category, item_id) VALUES (:title, :guid, :indexer, :pubdate, :size, :download_url, :seeders, :peers, :category, :item_id)", map[string]any{ "title": torrent.Title, - "guid": torrent.Guid, - "indexer": torrent.Jackettindexer.ID, - "pubdate": pubDate, - "size": size, + "guid": torrent.GUID, + "indexer": torrent.TrackerID, + "pubdate": torrent.PublishDate, + "size": torrent.Size, "download_url": torrent.Link, - "seeders": seeders, - "peers": peers, - "category": category, + "seeders": torrent.Seeders, + "peers": torrent.Peers, + "category": torrent.Category[0], "item_id": item.ID, }) if err != nil {