#!/usr/bin/env nix-shell #!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.natsort ps.requests ])" """ usage: sane-bt-search searches Jackett for torrent files matching the title. returns select results and magnet links """ from dataclasses import dataclass from datetime import datetime import natsort import requests import sys import time SERVICE = "https://jackett.uninsane.org" ENDPOINTS = dict( results="api/v2.0/indexers/all/results" ) @dataclass(eq=True, order=True) class Torrent: seeders: int pub_date: datetime size: int tracker: str title: str magnet: str def __str__(self) -> str: return f"{self.seeders}[S]\t{self.pub_date}\t{self.mib}M\t{self.tracker}\t{self.title}\t{self.magnet}" @property def mib(self) -> int: return int(round(self.size / 1024 / 1024)) @staticmethod def from_dict(d: dict) -> 'Torrent': seeders = d.get("Seeders") pub_date = d.get("PublishDate") size = d.get("Size") tracker = d.get("Tracker") title = d.get("Title") magnet = d.get("MagnetUri") if seeders is not None and pub_date is not None and title is not None and magnet is not None: pub_date = datetime.fromisoformat(pub_date).astimezone() return Torrent(seeders, pub_date, size, tracker, title, magnet) class Client: def __init__(self): self.apikey = open("/run/secrets/jackett_apikey").read() def api_call(self, method: str, params: dict) -> dict: endpoint = ENDPOINTS[method] url = f"{SERVICE}/{endpoint}" params = params.copy() params.update(apikey=self.apikey, _=str(int(time.time()))) print(url) print(params) resp = requests.get(url, params=params) print(resp) return resp.json() def query(self, q: str) -> list: torrents = [] api_res = self.api_call("results", dict(Query=q)) for r in api_res["Results"]: t = Torrent.from_dict(r) if t is not None: torrents.append(t) return sorted(torrents, reverse=True) q = " ".join(sys.argv[1:]) client = Client() res = client.query(q) print(f"found {len(res)} result(s)") for r in res[:5]: print(r)