Veiledning
1. Kom i gang
AniRena er et torrent-indeks fokusert på anime, manga, lyd og relaterte medier. Du kan bla gjennom og laste ned torrents uten en konto. En konto er nødvendig for å laste opp torrents, poste i grupper eller bruke API-en.
Navigasjonslinjen øverst gir tilgang til nettstedets hovedområder:
- Hjem — torrentliste- og søkesiden.
- Last opp — send inn en ny torrent (krever innlogging).
- Veiledning — denne siden.
- Statistikk — nettstedsomfattende statistikk (torrents, jevnaldrende, opplastinger over tid).
- Grupper — katalog over utgivelsesgrupper.
- RSS — RSS-feed med siste opplastinger, filtrerbart etter kategori.
Kontomenyen din (øverst til høyre når du er logget inn) åpner et profilpanel der du kan justere innstillinger, administrere sikkerhetsalternativer og få tilgang til API-nøkkelen din.
2. Bla gjennom og søk
Forsiden viser alle torrents sortert etter opplastingsdato. Bruk søkefeltet øverst for å filtrere resultater.
Grunnleggende søk
Skriv ord i søkefeltet og trykk Enter (eller klikk på søkeikonet). Resultater rangeres etter relevans når et søk er aktivt.
Søkeoperatorer
Følgende operatorer kan kombineres med et vanlig søk:
| Operator | Eksempel | Effekt |
|---|---|---|
user:"name" | user:"SubsPlease" | Vis bare torrents lastet opp av den brukeren. |
Å klikke på et opplasternavn i torrentlisten kjører automatisk et brukersøk for deg.
Kategorier og underkategorier
Bruk kategorivelgeren (rutenettsikonet ved siden av søkefeltet) for å begrense resultater til én kategori. Tilgjengelige kategorier:
- Anime
- Manga/Manhwa/Tegneserie
- Lyd
- Litteratur
- Live Action
- Bilder
- Programvare
- Hentai
- Annet
Hver kategori har underkategorier (f.eks. Anime til RAW, Sub/Lyd, Musikkvideo) som kan velges inne i kategoridialogen.
Sortering og filtre
Kolonneoverskriftene i torrentlisten er klikkbare for å sortere etter den kolonnen (stigende eller synkende). Tilgjengelige sorteringskolonner: dato, navn, størrelse, fullførte nedlastinger. Merk: seedere og leechere er sanntidsverdier fra Redis og kan ikke brukes til sortering.
Språkfilter
Bruk språkvelgeren (flaggikonet) for bare å vise torrents merket med et bestemt språk.
RSS-feed
RSS-feeden på /rss viser de siste opplastingene. Legg til ?category=anime (eller en annen kategori-slug) for å filtrere feeden. De fleste torrent-klienter støtter automatisk nedlasting fra RSS direkte fra denne URL-en.
3. Last ned torrents
Klikk på et torrentnavn for å åpne detaljpanelet. Derfra kan du:
- Last ned .torrent — lagrer .torrent-filen direkte. Den direkte URL-en er
/torrents/{id}.torrent - Magnetlenke — åpnes direkte i torrent-klienten din via magnet-URI-protokollen. URL-en er
/torrents/{id}/magnet
Detaljpanelet viser også torrent-beskrivelsen, fillisten, trackerlisten og seeder-/leecherantall.
Eldre nedlastingslenker
Gamle AniRena-nedlastingslenker støttes fortsatt og omdirigerer automatisk til riktig .torrent-fil ved hjelp av den eldre ID-en: /dl/{old_id}
Anbefalte BitTorrent-klienter
Enhver moderne BitTorrent-klient fungerer. Klientene nedenfor anbefales og støtter fullt ut BitTorrent v2 / hybrid-torrents:
4. Opprett en konto
Registrering
Klikk på Registrer deg i navigasjonslinjen. Velg et brukernavn, oppgi en e-postadresse og angi et passord (minimumslengde håndheves). Du må lese og godta nettstedets vilkår før kontoen din opprettes.
E-postaktivering
Etter registrering sendes en bekreftelses-e-post til adressen din. Klikk på lenken i e-posten for å aktivere kontoen din. Hvis du ikke mottok den, bruker du Aktiver kontoen din-lenken på innloggingssiden for å be om en ny kode.
Passordgjenoppretting
Hvis du glemmer passordet, klikker du på Glemt passord på innloggingssiden og skriver inn e-postadressen din. En gjenopprettingslenke sendes til deg. Lenken er engangsbruk og utløper etter kort tid.
5. Last opp torrents
Naviger til Last opp i navigasjonslinjen. Du må være logget inn med en aktiv, ikke-utestengt konto. Opplastingssiden har to faner:
Last opp-fane — send inn en eksisterende .torrent-fil
Dra og slipp eller velg en .torrent-fil. Når den er lastet, fyll ut feltene:
| Felt | Påkrevd | Beskrivelse |
|---|---|---|
| Torrent-fil | Ja | .torrent-filen som lastes opp. |
| Navn | Nei | Overstyr torrentens visningsnavn. Hvis det er tomt, brukes navnet innebygd i torrent-filen. |
| Kategori | Ja | Innholdskategori (Anime, Manga, Lyd osv.). |
| Underkategori | Nei | En mer spesifikk type innenfor kategorien (f.eks. RAW, Sub/Lyd). |
| Språk | Nei | Én eller flere språkkoder som beskriver innholdets språk. |
| Gruppe | Nei | Knytt denne utgivelsen til en gruppe du er medlem av. |
| Beskrivelse | Nei | Markdown-formatert beskrivelse vist på torrentdetaljsiden (maks. 65535 tegn). |
| Privat | Nei | Setter privatflagget i torrenten, deaktiverer DHT/PEX. Nyttig for trackere-bare torrents. |
| Kunngjørings-URL | Nei | Overstyr eller legg til primær tracker announce URL. |
| Ekstra trackere | Nei | Leses fra torrentfilen. Kan ikke endres under opplasting — bruk fanen Opprett hvis du vil tilpasse trackerlisten. |
| Kommentar | Nei | Overstyr torrent-kommentarfeltet innebygd i filen. |
Torrenten din må inneholde minst én AniRena tracker-URL i announce-listen (ethvert tier). Nettstedet sjekker dette ved opplasting og vil avvise torrenter som ikke inkluderer en AniRena tracker. Hvis du opprettet torrenten uten å legge til AniRena trackeren først, last den opp og last den deretter ned igjen fra nettstedet — den nedlastede filen vil automatisk ha de riktige trackerne.
Opprett-fane — bygg en ny torrent
Opprett-fanen lar deg generere en ny .torrent fra bunnen av ved å spesifisere filbaner, tracker-URL-er og andre torrent-parametere direkte i nettleseren. Den resulterende torrenten sendes inn med de samme metadatafeltene som ovenfor.
Moderering
Opplastinger sjekkes automatisk mot en liste over forbudte innholdsmønstre (navn, filnavn, beskrivelser). Torrents som samsvarer med et forbudt mønster vil bli avvist. Duplikate torrents (samme info-hash) avvises også.
6. Kontoen din
Klikk på brukernavnet ditt i øverste høyre hjørne for å åpne profilpanelet. Det er organisert i sammenleggbare seksjoner:
Innstillinger
Endre UI-tema, skriftstørrelse, fargevalg, grensesnittspråk og torrent-relaterte visningspreferanser. Endringer lagres automatisk.
Passord
Skriv inn det nåværende passordet ditt og det nye passordet to ganger. En bekreftelseskode sendes til den registrerte e-postadressen din og må skrives inn for å bekrefte endringen. Hvis to-faktor-autentisering er aktivert, kreves også TOTP-koden din.
To-faktor-autentisering (2FA)
Aktiver TOTP-basert to-faktor-autentisering ved hjelp av en autentiseringsapp (f.eks. Google Authenticator, Aegis, Bitwarden). Når du aktiverer 2FA:
- Skann QR-koden (eller skriv inn hemmeligheten manuelt) i autentiseringsappen din.
- Skriv inn den 6-sifrede koden som vises i appen for å bekrefte oppsettet.
- Lagre gjenopprettingskodene som vises — dette er engangskoder for å gjenvinne tilgang hvis du mister enheten.
For å deaktivere 2FA, skriv inn den nåværende TOTP-koden din og bekreft.
Aktive økter
Vis alle nåværende aktive innloggingsøkter inkludert nettleser, OS, IP-adresse og sist sett-tid. Klikk på Tilbakekall på en økt du ikke kjenner igjen. Du kan også tilbakekalle alle økter på én gang for å logge ut fra alle enheter.
API-nøkkel
Generer en personlig API-nøkkel som brukes til å laste opp torrents programmatisk via AniRena API. Klikk på Generer nøkkel for å opprette en — den fullstendige nøkkelen vises én gang umiddelbart etter generering. Oppbevar den trygt; den vises ikke i sin helhet igjen. Bruk Tilbakekall for å permanent ugyldiggjøre nøkkelen.
Slett konto
Forespørsel om sletting av konto starter en 30-dagers avkjølingsperiode. Kontoen deaktiveres umiddelbart og slettes permanent etter 30 dager. Du kan avbryte slettingen når som helst innenfor dette vinduet ved å logge inn og klikke på Avbryt sletting.
7. AniRena API
AniRena tilbyr et JSON API som lar deg laste opp torrents programmatisk ved hjelp av en personlig API-nøkkel. API-en anvender de samme reglene som nettgrensesnittet: bansjekker, fartsbegrensninger og nettstedsmodusrestriksjoner gjelder alle. Hver API-opplasting registreres i revisjonsloggen.
Autentisering
API-et bruker en to-trinns autentiseringsflyt. Bytt først din permanente API-nøkkel mot et kortvarig bearer-token, og send deretter dette tokenet i Authorization-headeren for hver API-forespørsel.
Din API-nøkkel er tilgjengelig under Din konto > API-nøkkel. Hold den hemmelig — enhver med nøkkelen kan skaffe seg bearer-tokens og laste opp på dine vegne. Hvis den kompromitteres, tilbakekall den umiddelbart og generer en ny.
Trinn 1 — Skaff et bearer-token
/api/v1/auth/tokenSend en POST-forespørsel til token-endepunktet med din API-nøkkel i Authorization-headeren. Ingen request-body er nødvendig.
Authorization: ApiKey <your-api-key>
Token-svar
{
"token": "<bearer-token>",
"token_type": "Bearer",
"expires_in": 3600
}Tokenets levetid
Bearer-tokens forblir gyldige i opptil 3600 sekunder fra de ble utstedt og kan gjenbrukes for hvert kall til de utløper. Når et token utløper, opprett et nytt via POST /api/v1/auth/token. Hver respons returnerer fortsatt det gjeldende tokenet i X-New-Token-headeren for bakoverkompatibilitet.
X-New-Token: <next-bearer-token>
Innlogging med én forespørsel (med 2FA)
/api/v1/auth/loginAutentiser med brukernavn eller e-post og passord i én forespørsel og få et bearer-token direkte. Hvis kontoen din har 2FA aktivert, ta med den gjeldende autentiseringskoden i totp_code (eller en gjenopprettingskode i recovery_code). Sett eventuelt new_api_key til true for også å opprette en helt ny permanent API-nøkkel i samme svar.
Forespørselskropp
{
"login": "username or email",
"password": "your-password",
"totp_code": "123456", // kreves hvis 2FA er aktivert (6 sifre)
"recovery_code": "", // alternativ til totp_code
"new_api_key": false // sett til true for også å opprette en ny API-nøkkel
}Token-svar
{
"ok": true,
"token": "<bearer-token>",
"token_type": "Bearer",
"expires_in": 3600,
"api_key": "<new-api-key>" // finnes bare når new_api_key var true
}Bearer-tokenet fungerer akkurat som et fra /api/v1/auth/token. Feltet api_key returneres bare når new_api_key er true — lagre det med en gang, siden det bare vises én gang og erstatter enhver tidligere nøkkel.
Eksempel — logg inn og få (valgfritt) en ny API-nøkkel
# pip install requests import requests BASE_URL = "https://www.anirena.com" # One request: authenticate (with 2FA if enabled) and get a bearer token. # Set new_api_key=True to also receive a brand-new permanent API key. resp = requests.post( f"{BASE_URL}/api/v1/auth/login", json={ "login": "your-username", # username or email "password": "your-password", "totp_code": "123456", # omit if 2FA is not enabled "new_api_key": True, # optional }, ) resp.raise_for_status() data = resp.json() token = data["token"] # use as: Authorization: Bearer <token> if "api_key" in data: print("New API key — store it now:", data["api_key"])
// Built-in fetch — requires Node.js 18+ const BASE_URL = "https://www.anirena.com"; // One request: authenticate (with 2FA if enabled) and get a bearer token. // Set new_api_key:true to also receive a brand-new permanent API key. const resp = await fetch(`${BASE_URL}/api/v1/auth/login`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ login: "your-username", // username or email password: "your-password", totp_code: "123456", // omit if 2FA is not enabled new_api_key: true, // optional }), }); const data = await resp.json(); const token = data.token; // use as: Authorization: Bearer <token> if (data.api_key) console.log("New API key — store it now:", data.api_key);
// Requires: curl extension (enabled by default in PHP 8+) <?php define("BASE_URL", "https://www.anirena.com"); // One request: authenticate (with 2FA if enabled) and get a bearer token. // Set new_api_key => true to also receive a brand-new permanent API key. $ch = curl_init(BASE_URL . "/api/v1/auth/login"); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode([ "login" => "your-username", // username or email "password" => "your-password", "totp_code" => "123456", // omit if 2FA is not enabled "new_api_key" => true, // optional ]), CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Content-Type: application/json"], ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); $token = $data["token"]; // use as: Authorization: Bearer <token> if (isset($data["api_key"])) echo "New API key — store it now: " . $data["api_key"];
// Cargo.toml: // serde_json = "1" // reqwest = { version = "0.12", features = ["blocking", "json"] } const BASE_URL: &str = "https://www.anirena.com"; fn main() { let client = reqwest::blocking::Client::new(); // One request: authenticate (with 2FA if enabled) and get a bearer token. // Set new_api_key:true to also receive a brand-new permanent API key. let data: serde_json::Value = client .post(format!("{BASE_URL}/api/v1/auth/login")) .json(&serde_json::json!({ "login": "your-username", // username or email "password": "your-password", "totp_code": "123456", // omit if 2FA is not enabled "new_api_key": true, // optional })) .send().unwrap() .json().unwrap(); let token = data["token"].as_str().unwrap(); // Authorization: Bearer <token> if let Some(key) = data["api_key"].as_str() { println!("New API key — store it now: {key}"); } }
Trinn 2 — Last opp en torrent
/api/v1/torrentsSend en enkel JSON POST-forespørsel med bearer-tokenet i Authorization-headeren.
Forespørselskropp
| Felt | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
torrent | string | Ja | Base64-kodet innhold av .torrent-filen. |
category | string | Ja | Kategori-slug: anime, manga, audio, literature, live, pictures, software, hentai, other. |
name | string | Nei | Overstyr torrentens visningsnavn. |
sub_category | string | Nei | Underkategori-slug (f.eks. raw, sub-audio). Må tilhøre den valgte kategorien. |
languages | string[] | Nei | Array av BCP 47-språkkoder (f.eks. en, ja). |
group_id | string | Nei | UUID for en gruppe du er medlem av for å knytte til denne utgivelsen. |
description | string | Nei | Markdown-formatert utgivelsesbeskrivelse (maks. 65535 tegn). |
comment | string | Nei | Overstyr det innebygde torrent-kommentarfeltet. |
is_private | boolean | Nei | Sett til true for å aktivere privatflagget i torrenten. |
comments_enabled | boolean | Nei | Tillat kommentarer på denne torrenten. Standard er true (aktivert). |
anime_id | string | Nei | UUID for en anime-oppføring som skal knyttes til denne torrenten. Hent UUID via GET /api/v1/anime/search. Returnerer 400 hvis UUID ikke samsvarer med noen kjent oppføring. |
announce | string | Nei | Overstyr eller legg til primær announce URL. |
trackers | string | Nei | Nylinje-separert liste over ytterligere tracker-URL-er. En tom linje mellom URL-er oppretter et nytt trackernivå. |
test | boolean | Nei | Sett til true for en tørrtest: forespørselen valideres fullstendig, men torrenten lagres ikke. Bruk dette for å bekrefte at nyttelasten din er riktig før innsending. |
Tørrtest-suksesssvar — 200 OK
{
"ok": true,
"test": true,
"name": "My Torrent Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null
}Tilgjengelige språkkoder
abaaafaksqamarar-001anhyasavaeayazbmbaeubebnbhbibsbrbgmyyuecachcenyzhzh-HKzh-Hanszh-SGzh-TWcucvkwcocrhrcsdadvnlnl-BEdzenen-USeoeteefofjfilfifrfr-CAffgllgkadede-ATelgnguhthahehzhihohuisioigidiaieiuikgaitjajvklknkrkskkkmkirwrnkvkgkokjkukylolalvlilnltlulbmkmgmsmlmtgvmimrmhmnnanvngnendsenonbnnocorojomospipsfaplptpt-BRpaqurormrusmsgsascgdsrsr-Latnsniisdsiskslsonrsteses-419es-MXsuswsssvtltytgtatttethbotitotstntrtktwukuruguzvevivowacyfywoxhyiyozazuEksempelforespørsel
# pip install requests import base64, pathlib, requests API_KEY = "YOUR_API_KEY" BASE_URL = "https://www.anirena.com" # Step 1: exchange API key for a short-lived bearer token auth = requests.post( f"{BASE_URL}/api/v1/auth/token", headers={"Authorization": f"ApiKey {API_KEY}"}, ) auth.raise_for_status() token = auth.json()["token"] # Step 2: upload — plain JSON with the bearer token torrent_b64 = base64.b64encode(pathlib.Path("file.torrent").read_bytes()).decode() resp = requests.post( f"{BASE_URL}/api/v1/torrents", json={ "torrent": torrent_b64, "category": "anime", "sub_category": "raw", "languages": ["ja"], "description": "# My Release\n\nRelease notes here.", "is_private": False, }, headers={"Authorization": f"Bearer {token}"}, ) resp.raise_for_status() data = resp.json() token = resp.headers.get("X-New-Token", token) # save for next request print(data["id"], data["name"]) # torrent UUID and title
// Built-in modules only — requires Node.js 18+ (for global fetch) const fs = require("fs"); const API_KEY = "YOUR_API_KEY"; const BASE_URL = "https://www.anirena.com"; // Step 1: exchange API key for a short-lived bearer token let authResp = await fetch(`${BASE_URL}/api/v1/auth/token`, { method: "POST", headers: { Authorization: `ApiKey ${API_KEY}` }, }); let { token } = await authResp.json(); // Step 2: upload — plain JSON with the bearer token const torrentB64 = fs.readFileSync("file.torrent").toString("base64"); const resp = await fetch(`${BASE_URL}/api/v1/torrents`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` }, body: JSON.stringify({ torrent: torrentB64, category: "anime", sub_category: "raw", languages: ["ja"], description: "# My Release\n\nRelease notes here.", is_private: false, }), }); const data = await resp.json(); token = resp.headers.get("x-new-token") ?? token; // save for next request console.log(data.id, data.name); // torrent UUID and title
// Requires: curl extension (enabled by default in PHP 8+) <?php define("API_KEY", "YOUR_API_KEY"); define("BASE_URL", "https://www.anirena.com"); // Step 1: exchange API key for a short-lived bearer token $ch = curl_init(BASE_URL . "/api/v1/auth/token"); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: ApiKey " . API_KEY], ]); $token = json_decode(curl_exec($ch), true)["token"]; curl_close($ch); // Step 2: upload — plain JSON with the bearer token $torrentB64 = base64_encode(file_get_contents("file.torrent")); $respHeaders = []; $ch = curl_init(BASE_URL . "/api/v1/torrents"); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode([ "torrent" => $torrentB64, "category" => "anime", "sub_category" => "raw", "languages" => ["ja"], "description" => "# My Release\n\nRelease notes here.", "is_private" => false, ]), CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADERFUNCTION => function($ch, $h) use (&$respHeaders) { $respHeaders[] = $h; return strlen($h); }, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . $token, ], ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); foreach ($respHeaders as $h) { // save new token for next request if (stripos($h, "X-New-Token:") === 0) $token = trim(substr($h, strlen("X-New-Token:"))); } echo $data["id"] . " " . $data["name"]; // torrent UUID and title
// Cargo.toml: // base64 = "0.22" // serde_json = "1" // reqwest = { version = "0.12", features = ["blocking", "json"] } use base64::{engine::general_purpose::STANDARD as B64, Engine}; const API_KEY: &str = "YOUR_API_KEY"; const BASE_URL: &str = "https://www.anirena.com"; fn main() { let client = reqwest::blocking::Client::new(); // Step 1: exchange API key for a short-lived bearer token let auth: serde_json::Value = client .post(format!("{BASE_URL}/api/v1/auth/token")) .header("Authorization", format!("ApiKey {API_KEY}")) .send().unwrap().json().unwrap(); let mut token = auth["token"].as_str().unwrap().to_string(); // Step 2: upload — plain JSON with the bearer token let torrent_b64 = B64.encode(std::fs::read("file.torrent").unwrap()); let resp = client .post(format!("{BASE_URL}/api/v1/torrents")) .header("Authorization", format!("Bearer {token}")) .json(&serde_json::json!({ "torrent": torrent_b64, "category": "anime", "sub_category": "raw", "languages": ["ja"], "description": "# My Release\n\nRelease notes here.", "is_private": false })) .send().unwrap(); if let Some(t) = resp.headers().get("x-new-token") { token = t.to_str().unwrap().to_string(); // save for next request } let data: serde_json::Value = resp.json().unwrap(); println!("{} {}", data["id"], data["name"]); // torrent UUID and title }
Vellykket respons — 200 OK
{
"ok": true,
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Torrent Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null
}Feilresponser
| HTTP-status | Betydning |
|---|---|
400 | Ugyldig forespørselskropp eller manglende påkrevd felt. |
401 | Manglende, utløpt eller allerede rotert bearer-token. Godkjenn på nytt via POST /api/v1/auth/token. |
403 | Konto utestengt, deaktivert eller IP blokkert. |
409 | Duplikat torrent — torrent med samme info-hash finnes allerede. |
422 | Torrent-filen kunne ikke analyseres eller mislyktes i validering (forbudt mønster, ugyldig struktur). |
429 | Fartsbegrensning overskredet. Prøv igjen etter at vinduet tilbakestilles. |
503 | Nettstedet er i vedlikeholds- eller skrivebeskyttet modus. |
Fartsbegrensning
API-opplastinger er underlagt en konfigurerbar fartsbegrensning separat fra nettgrensesnittet. Grensen og vinduet settes av nettstedsadministratoren. Når fartsbegrensningen overskrides, returnerer API-en 429 Too Many Requests. Grensen er per API-nøkkel.
Generere torrent-filer med torrent-builder
torrent-builder er et åpen kildekode CLI-verktøy bygget på libtorrent-rasterbar som lar deg opprette BitTorrent v1, v2 og hybrid .torrent-filer fra kommandolinjen. Det passer perfekt med AniRena upload API — generer filen lokalt og POST den deretter direkte til trackeren. cantalupo555/torrent-builder.
Bygge fra kildekode
Krever CMake >= 3.28.3 og libtorrent-rasterbar >= 2.0.11. Klon repositoriet og bygg med CMake:
# Install system dependencies sudo apt-get install build-essential cmake libtorrent-rasterbar-dev # Clone & build git clone https://github.com/cantalupo555/torrent-builder.git cd torrent-builder mkdir build && cd build cmake .. && cmake --build .
# Install dependencies via Homebrew brew install cmake libtorrent-rasterbar # Clone & build git clone https://github.com/cantalupo555/torrent-builder.git cd torrent-builder mkdir build && cd build cmake .. && cmake --build .
Viktige flagg
| Felt | Beskrivelse |
|---|---|
--path | Sti til filen eller mappen som skal pakkes (påkrevd). |
--output | Navn på utdata-.torrent-fil (påkrevd). |
--version | BitTorrent-format — 1 = v1, 2 = v2, 3 = hybrid (standard: 3). |
--tracker | Legg til en tracker announce-URL. Gjenta flagget for å legge til flere trackere. |
--comment | Integrer en metadatakommentarstreng i torrenten. |
--private | Sett privatflagget for å begrense distribusjon til kun de oppførte trackerne. |
--piece-size | Delstørrelse i KB (16-32768). La være uinnstilt for automatisk valg. |
-i | Start trinnvis interaktiv konfigurasjonsmoduset. |
Komplett arbeidsflyt: bygg -> last opp
Eksemplene nedenfor bygger en hybrid torrent med torrent-builder, godkjenner deretter med AniRena API og laster opp resultatet i ett skript.
# pip install requests import base64, subprocess, requests API_KEY = "YOUR_API_KEY" BASE_URL = "https://www.anirena.com" # Step 1: build the torrent with torrent-builder # --version 1=v1 2=v2 3=hybrid (default) subprocess.run([ "./torrent-builder/build/torrent_builder", "--path", "/data/my_release", "--output", "my_release.torrent", "--version", "3", # hybrid "--tracker", "udp://open.tracker.gg:6969/announce", "--comment", "My Release", "--creator", "--creation-date", ], check=True) # Step 2: authenticate token = requests.post( f"{BASE_URL}/api/v1/auth/token", headers={"Authorization": f"ApiKey {API_KEY}"}, ).json()["token"] # Step 3: upload torrent_b64 = base64.b64encode(open("my_release.torrent", "rb").read()).decode() resp = requests.post( f"{BASE_URL}/api/v1/torrents", json={ "torrent": torrent_b64, "category": "anime", "sub_category": "raw", "languages": ["ja"], "comments_enabled": True, }, headers={"Authorization": f"Bearer {token}"}, ) resp.raise_for_status() data = resp.json() print(data["id"], data["name"])
// Built-in modules — Node.js 18+ const fs = require("fs"); const { execFileSync } = require("child_process"); const API_KEY = "YOUR_API_KEY"; const BASE_URL = "https://www.anirena.com"; // Step 1: build the torrent (--version 1=v1, 2=v2, 3=hybrid) execFileSync("./torrent-builder/build/torrent_builder", [ "--path", "/data/my_release", "--output", "my_release.torrent", "--version", "3", "--tracker", "udp://open.tracker.gg:6969/announce", "--comment", "My Release", "--creator", "--creation-date", ]); // Step 2: authenticate let { token } = await (await fetch(`${BASE_URL}/api/v1/auth/token`, { method: "POST", headers: { Authorization: `ApiKey ${API_KEY}` }, })).json(); // Step 3: upload const torrentB64 = fs.readFileSync("my_release.torrent").toString("base64"); const resp = await fetch(`${BASE_URL}/api/v1/torrents`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` }, body: JSON.stringify({ torrent: torrentB64, category: "anime", sub_category: "raw", languages: ["ja"], comments_enabled: true, }), }); const data = await resp.json(); console.log(data.id, data.name);
// PHP 8+ with curl and proc_open <?php define("API_KEY", "YOUR_API_KEY"); define("BASE_URL", "https://www.anirena.com"); // Step 1: build the torrent (version: 1=v1, 2=v2, 3=hybrid) exec(implode(" ", array_map("escapeshellarg", [ "./torrent-builder/build/torrent_builder", "--path", "/data/my_release", "--output", "my_release.torrent", "--version", "3", "--tracker", "udp://open.tracker.gg:6969/announce", "--comment", "My Release", "--creator", "--creation-date", ]))); // Step 2: authenticate $ch = curl_init(BASE_URL . "/api/v1/auth/token"); curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: ApiKey " . API_KEY]]); $token = json_decode(curl_exec($ch), true)["token"]; curl_close($ch); // Step 3: upload $torrentB64 = base64_encode(file_get_contents("my_release.torrent")); $respHeaders = []; $ch = curl_init(BASE_URL . "/api/v1/torrents"); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode([ "torrent" => $torrentB64, "category" => "anime", "sub_category" => "raw", "languages" => ["ja"], "comments_enabled" => true, ]), CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADERFUNCTION => function($ch, $h) use (&$respHeaders) { $respHeaders[] = $h; return strlen($h); }, CURLOPT_HTTPHEADER => ["Content-Type: application/json", "Authorization: Bearer " . $token], ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); echo $data["id"] . " " . $data["name"];
// Cargo.toml: // base64 = "0.22" // serde_json = "1" // reqwest = { version = "0.12", features = ["blocking", "json"] } use base64::{engine::general_purpose::STANDARD as B64, Engine}; use std::process::Command; const API_KEY: &str = "YOUR_API_KEY"; const BASE_URL: &str = "https://www.anirena.com"; fn main() { // Step 1: build the torrent (--version 1=v1, 2=v2, 3=hybrid) Command::new("./torrent-builder/build/torrent_builder") .args([ "--path", "/data/my_release", "--output", "my_release.torrent", "--version", "3", "--tracker", "udp://open.tracker.gg:6969/announce", "--comment", "My Release", "--creator", "--creation-date", ]) .status().expect("torrent_builder failed"); let client = reqwest::blocking::Client::new(); // Step 2: authenticate let auth: serde_json::Value = client .post(format!("{BASE_URL}/api/v1/auth/token")) .header("Authorization", format!("ApiKey {API_KEY}")) .send().unwrap().json().unwrap(); let token = auth["token"].as_str().unwrap().to_string(); // Step 3: upload let torrent_b64 = B64.encode(std::fs::read("my_release.torrent").unwrap()); let resp: serde_json::Value = client .post(format!("{BASE_URL}/api/v1/torrents")) .header("Authorization", format!("Bearer {token}")) .json(&serde_json::json!({ "torrent": torrent_b64, "category": "anime", "sub_category": "raw", "languages": ["ja"], "comments_enabled": true, })) .send().unwrap().json().unwrap(); println!("{} {}", resp["id"], resp["name"]); }
Søke i torrent-metadata
/api/v1/torrents/searchSend en enkel JSON POST-forespørsel for å hente torrent-lister med de samme søke- og filtreringsalternativene som er tilgjengelige på nettstedet. Selve .torrent-filen returneres ikke — bruk den normale nedlastingsruten for det.
# pip install requests (token already obtained — see upload example) resp = requests.post( f"{BASE_URL}/api/v1/torrents/search", json={"q": "Sword Art Online", "category": "anime", "per_page": 25}, headers={"Authorization": f"Bearer {token}"}, ) resp.raise_for_status() data = resp.json() token = resp.headers.get("X-New-Token", token) # save for next request for t in data["torrents"]: print(t["title"], "-", t["magnet"])
// token already obtained — see upload example const resp = await fetch(`${BASE_URL}/api/v1/torrents/search`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` }, body: JSON.stringify({ q: "Sword Art Online", category: "anime", per_page: 25 }), }); const data = await resp.json(); token = resp.headers.get("x-new-token") ?? token; // save for next request data.torrents.forEach(t => console.log(t.title, "-", t.magnet));
// token already obtained — see upload example $respHeaders = []; $ch = curl_init(BASE_URL . "/api/v1/torrents/search"); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode([ "q" => "Sword Art Online", "category" => "anime", "per_page" => 25 ]), CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADERFUNCTION => function($ch, $h) use (&$respHeaders) { $respHeaders[] = $h; return strlen($h); }, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . $token, ], ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); foreach ($respHeaders as $h) { // save new token for next request if (stripos($h, "X-New-Token:") === 0) $token = trim(substr($h, strlen("X-New-Token:"))); } foreach ($data["torrents"] as $t) { echo $t["title"] . " - " . $t["magnet"] . "\n"; }
// client and token already obtained — see upload example let resp = client .post(format!("{BASE_URL}/api/v1/torrents/search")) .header("Authorization", format!("Bearer {token}")) .json(&serde_json::json!({"q": "Sword Art Online", "category": "anime", "per_page": 25})) .send().unwrap(); if let Some(t) = resp.headers().get("x-new-token") { token = t.to_str().unwrap().to_string(); // save for next request } let data: serde_json::Value = resp.json().unwrap(); for t in data["torrents"].as_array().unwrap() { println!("{} - {}", t["title"], t["magnet"]); }
Søkeparametere
| Felt | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
q | string | Nei | Fritekssøk. Støtter group:slug, group:"Name", user:name prefikser. |
category | string | Nei | Kategori-slug (f.eks. "anime"). |
sub_category | string | Nei | Underkategori-slug (f.eks. "raw"). |
languages | string[] | Nei | Array av BCP 47-språkkoder (f.eks. en, ja). |
sort | string | Nei | Sorteringsfelt: date (standard), size, seeders, leechers, completed, title. |
order | string | Nei | Sorteringsretning: desc (standard) eller asc. |
page | integer | Nei | Sidenummer, starter ved 1 (standard 1). |
per_page | integer | Nei | Resultater per side, 1–250 (standard 50). |
hide_adult | boolean | Nei | Ekskluder torrents i voksenkategorien. Standard true for vanlige brukere. |
show_dead | boolean | Nei | Når false (standard) ekskluderes torrenter eldre enn dead-torrent-nådeperioden uten aktive seedere. Sett til true for å inkludere dem. |
Respons
{
"total": 1234,
"page": 1,
"per_page": 50,
"total_pages": 25,
"from": 1,
"to": 50,
"torrents": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "My Release Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null,
"size_fmt": "1.4 GB",
"completed": 42,
"seeders": 10,
"leechers": 3,
"languages": ["ja", "en"],
"comment_count": 7,
"created_at": "2024-01-15 12:34",
"cat_slug": "anime",
"sub_slug": "raw",
"group_name": null,
"uploader": "username",
"magnet": "magnet:?xt=urn:btih:..."
}
]
}comment_count — Antall ikke-slettede kommentarer på denne torrenten.
Søkefartsbegrensning
Søkeforespørsler er underlagt en separat konfigurerbar fartsbegrensning (standard 60 forespørsler per 60 sekunder per API-nøkkel). Å overskride grensen returnerer 429 Too Many Requests. Personalkontoer er unntatt.
Hent torrent-detaljer
/api/v1/torrent/{id}Henter de fullstendige metadataene for én torrent — inkludert felter som søkeendepunktet utelater, som Markdown-beskrivelsen, det innebygde .torrent-kommentaret, fillisten med størrelse per fil og det fullstendige tracker-tier-oppsettet. Live seeder- og leecher-tellinger leses fra trackeren når de er tilgjengelige.
Respons
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "My Release Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null,
"size_fmt": "1.4 GB",
"completed": 42,
"seeders": 10,
"leechers": 3,
"ext_seeders": 128,
"ext_leechers": 14,
"created_at": "2024-01-15 12:34",
"torrent_created": "2024-01-15 12:30",
"created_by_client": "mktorrent 1.1",
"cat_name": "Anime",
"cat_slug": "anime",
"sub_name": "Raw",
"sub_slug": "raw",
"group_name": null,
"group_slug": null,
"uploader": "username",
"uploader_id": "...",
"description": "# My Release\n\nRelease notes here.",
"comment": "",
"is_private": false,
"magnet": "magnet:?xt=urn:btih:...",
"languages": [
{ "code": "ja", "name": "Japanese", "country_code": "jp" }
],
"tracker_tiers": [
{ "tier": 0, "urls": ["udp://tracker.example.org:6969/announce"] }
],
"files": [
{ "path": "My Release/episode-01.mkv", "size": 1503238553 }
],
"comments_enabled": true,
"comments_locked": false,
"comment_count": 7
}seeders, leechers — Live tellinger fra den interne trackeren; begge rapporterer 0 når tracker-lageret ikke har en oppføring for denne info-hashen eller er utilgjengelig.
ext_seeders, ext_leechers — Høyeste antall seedere og leechere rapportert av en enkelt ekstern tracker som er scrapet for denne torrenten. Trackere som følger samme sværm overlapper, så maksimum brukes i stedet for summen; begge rapporterer 0 når ingen tracker har scrape-data for denne info-hashen.
Feilresponser
| HTTP-status | Betydning |
|---|---|
400 | Torrent-id-en må enten være en 36-tegns UUID med bindestreker eller en 32-tegns ren hex-streng. |
401 | Manglende, utløpt eller allerede rotert bearer-token. Godkjenn på nytt via POST /api/v1/auth/token. |
404 | Torrent ikke funnet. |
429 | Fartsbegrensning overskredet. Prøv igjen etter at vinduet tilbakestilles. |
503 | Nettstedet er i vedlikeholds- eller skrivebeskyttet modus. |
Hente torrent-kommentarer
/api/v1/torrents/{id}/commentsHent paginerte kommentarer for en torrent. Antall kommentarer per side styres av COMMENT_PER_PAGE-innstillingen i serverens .env-fil (standard 20). Bare torrents med aktiverte kommentarer vil returnere resultater — alle andre returnerer 403.
Spørringsparametere
| Felt | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
page | integer | Nei | Sidenummer, startende ved 1 (standard 1). |
# pip install requests (token already obtained — see upload example) TORRENT_ID = "550e8400-e29b-41d4-a716-446655440000" resp = requests.get( f"{BASE_URL}/api/v1/torrents/{TORRENT_ID}/comments", params={"page": 1}, headers={"Authorization": f"Bearer {token}"}, ) resp.raise_for_status() data = resp.json() token = resp.headers.get("X-New-Token", token) # save for next request for c in data["comments"]: print(c["username"], "-", c["body"])
// token already obtained — see upload example const TORRENT_ID = "550e8400-e29b-41d4-a716-446655440000"; const resp = await fetch(`${BASE_URL}/api/v1/torrents/${TORRENT_ID}/comments?page=1`, { headers: { Authorization: `Bearer ${token}` }, }); const data = await resp.json(); token = resp.headers.get("x-new-token") ?? token; // save for next request data.comments.forEach(c => console.log(c.username, "-", c.body));
// token already obtained — see upload example $torrentId = "550e8400-e29b-41d4-a716-446655440000"; $respHeaders = []; $ch = curl_init(BASE_URL . "/api/v1/torrents/{$torrentId}/comments?page=1"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADERFUNCTION => function($ch, $h) use (&$respHeaders) { $respHeaders[] = $h; return strlen($h); }, CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $token], ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); foreach ($respHeaders as $h) { // save new token for next request if (stripos($h, "X-New-Token:") === 0) $token = trim(substr($h, strlen("X-New-Token:"))); } foreach ($data["comments"] as $c) { echo $c["username"] . " - " . $c["body"] . "\n"; }
// client and token already obtained — see upload example let torrent_id = "550e8400-e29b-41d4-a716-446655440000"; let resp = client .get(format!("{BASE_URL}/api/v1/torrents/{torrent_id}/comments?page=1")) .header("Authorization", format!("Bearer {token}")) .send().unwrap(); if let Some(t) = resp.headers().get("x-new-token") { token = t.to_str().unwrap().to_string(); // save for next request } let data: serde_json::Value = resp.json().unwrap(); for c in data["comments"].as_array().unwrap() { println!("{} - {}", c["username"], c["body"]); }
Respons
{
"torrent_id": "550e8400-e29b-41d4-a716-446655440000",
"page": 1,
"per_page": 20,
"total": 45,
"total_pages": 3,
"comments": [
{
"id": "...",
"user_id": "...",
"username": "uploader",
"role": "user",
"author_banned": false,
"body": "Great release!",
"created_at": "2024-01-15 12:34:00",
"edited_at": null,
"edited_by_username": null,
"deleted_at": null
}
]
}Feltet body er en tom streng når kommentarforfatteren er utestengt eller kommentaren er slettet. Flagget author_banned angir hvilken situasjon som gjelder.
Feilresponser
| HTTP-status | Betydning |
|---|---|
401 | Manglende, utløpt eller allerede rotert bearer-token. Godkjenn på nytt via POST /api/v1/auth/token. |
403 | Kommentarer er deaktivert for denne torrenten. |
404 | Torrenten ble ikke funnet. |
503 | Nettstedet er i vedlikeholds- eller skrivebeskyttet modus. |
Søker etter animeposter
/api/v1/anime/search?q=<query>Søk etter anime-oppføringer etter tittel for å hente deres UUID. UUID kan sendes som anime_id i opplastingskroppen for å knytte en torrent til en anime-oppføring ved opplasting, eller brukes med PUT /api/torrents/{id}/anime etter opplasting. Ingen autentisering kreves. Underlagt samme hastighetsbegrensning som torrent-søk (standard 60 forespørsler per 60 sekunder per IP).
# pip install requests (no authentication required)
resp = requests.get(
f"{BASE_URL}/api/v1/anime/search",
params={"q": "Sword Art Online", "page": 1, "per_page": 10},
)
resp.raise_for_status()
for item in resp.json()["results"]:
print(item["id"], "-", item["title"])// No authentication required
const resp = await fetch(
`${BASE_URL}/api/v1/anime/search?q=${encodeURIComponent("Sword Art Online")}&page=1&per_page=10`
);
const data = await resp.json();
data.results.forEach(item => console.log(item.id, "-", item.title));// No authentication required
$ch = curl_init(BASE_URL . "/api/v1/anime/search?" . http_build_query([
"q" => "Sword Art Online", "page" => 1, "per_page" => 10,
]));
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
foreach ($data["results"] as $item) {
echo $item["id"] . " - " . $item["title"] . "\n";
}// No authentication required
let data: serde_json::Value = reqwest::blocking::get(
format!("{BASE_URL}/api/v1/anime/search?q=Sword+Art+Online&page=1&per_page=10")
).unwrap().json().unwrap();
for item in data["results"].as_array().unwrap() {
println!("{} - {}", item["id"], item["title"]);
}Spørreparametere
| Felt | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
q | string | Ja | Tittelssøkestreng (obligatorisk). Matches mot tittel og synonymer. |
page | integer | Nei | Sidenummer, starter ved 1 (standard 1). |
per_page | integer | Nei | Resultater per side, 1–50 (standard 10). |
Svar
{
"total": 42,
"page": 1,
"per_page": 10,
"total_pages": 5,
"results": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "Sword Art Online",
"anime_type": "TV",
"episodes": 25,
"status": "FINISHED",
"season": "FALL",
"season_year": 2012,
"picture": "https://cdn.myanimelist.net/images/anime/...",
"thumbnail": "https://cdn.myanimelist.net/images/anime/...",
"duration_secs": 1440
}
]
}Liste og hent grupper
/api/v1/groupsReturnerer en paginert liste over offentlige grupper (aktiverte og ikke låste). Krever Bearer-token-autentisering.
/api/v1/groups/{id_or_slug}Returnerer en enkelt offentlig gruppe etter numerisk ID eller slug. Returnerer 404 hvis gruppen er deaktivert eller låst.
Spørringsparametere (kun liste)
| Felt | Type | Påkrevd | Beskrivelse |
|---|---|---|---|
q | string | Nei | Filtrer etter gruppenavn (valgfritt, delstrengmatch). |
page | integer | Nei | Sidetall (standard 1). |
per_page | integer | Nei | Resultater per side, 1–100 (standard 20). |
sort | string | Nei | Sorteringskolonne: name | slug | members | torrents | created (standard name). |
order | string | Nei | Sorteringsretning: asc eller desc (standard asc). |
Svar (liste)
{
"total": 12,
"page": 1,
"per_page": 20,
"total_pages": 1,
"groups": [
{
"id": 1,
"name": "SubsPlease",
"slug": "subsplease",
"subdomain_slug": "subsplease",
"description": "Weekly simulcast batches.",
"owner": "admin",
"member_count": 42,
"torrent_count": 1337,
"created_at": "2024-01-15 12:34"
}
]
}Svar (enkelt)
{
"id": 1,
"name": "SubsPlease",
"slug": "subsplease",
"subdomain_slug": "subsplease",
"description": "Weekly simulcast batches.",
"owner": "admin",
"member_count": 42,
"torrent_count": 1337,
"created_at": "2024-01-15 12:34"
}Feilresponser
| HTTP-status | Betydning |
|---|---|
401 | Manglende, utløpt eller allerede rotert bearer-token. Godkjenn på nytt via POST /api/v1/auth/token. |
404 | Gruppe ikke funnet eller ikke offentlig tilgjengelig. |
429 | Fartsbegrensning overskredet. Prøv igjen etter at vinduet tilbakestilles. |
503 | Nettstedet er i vedlikeholds- eller skrivebeskyttet modus. |
8. Donasjoner
Hvis du ønsker å støtte AniRena og hjelpe med å dekke kostnadene for hosting av våre servere og tjenester, er du velkommen til å sende en donasjon til en av følgende kryptovaluta-lommebøker:
bc1qy2h3ddq6ak5damvnf4r5vu3ydehhxrcq8gllwn0xCbaFe03832F95F86AF2536d52710e78C63b62Cd33ucetj2XDGHQg9PVRPMxerNi7c6kX7GJkjQNg9yjwGegLbpt61yX3RjGtB1Ef8vgVz6Hr6baQsTjVkEnhver donasjon, stor eller liten, er svært verdsatt og går direkte til å holde AniRena i gang. Takk for støtten!
9. Programvare
AniRena Player er en gratis skrivebordsapp som lar deg strømme video direkte fra torrentene som er indeksert på dette nettstedet — du trenger ikke vente på at hele nedlastingen er ferdig. Bare lim inn en magnet-lenke eller åpne en .torrent-fil, og avspillingen starter så snart det er nok data tilgjengelig.
Begge utgavene er fullstendig frittstående — alle avhengigheter er pakket inn i den kjørbare filen. Ingen installasjonsprogram, ingen kjøretid å sette opp — bare last ned og kjør.
Installasjonsprogram (.exe). Oppdaterer seg selv i appen.
Diskbilde (.dmg) for Apple Silicon-Mac (M1 og nyere). Oppdaterer seg selv i appen.
Diskbilde (.dmg) for Intel-Mac. Oppdaterer seg selv i appen.
Bærbar enkeltfil, ingen installasjon nødvendig. Det eneste Linux-formatet med oppdatering i appen.
Installasjon: sudo apt install ./<file>.deb — oppdateres via apt eller en ny nedlasting, ikke i appen.
Installasjon: sudo dnf install ./<file>.rpm — oppdateres via dnf eller en ny nedlasting, ikke i appen.
Sideload på 64-bit ARM Android-enheter (de fleste moderne telefoner / nettbrett). Oppdateres ved å laste ned en ny APK.
Eldre versjoner
Sideload på 32-bit ARM Android-enheter (eldre telefoner / nettbrett). Oppdateres ved å laste ned en ny APK.