Guide
1. Kom i gang
AniRena er et torrent-indeks med fokus på anime, manga, lyd og relaterede medier. Du kan gennemse og downloade torrents uden en konto. En konto er påkrævet for at uploade torrents, poste i grupper eller bruge API'en.
Navigationslinjen øverst giver adgang til sidens hovedområder:
- Hjem — torrentliste- og søgesiden.
- Upload — indsend en ny torrent (kræver login).
- Guide — denne side.
- Statistik — site-dækkende statistik (torrents, peers, uploads over tid).
- Grupper — udgivelsesgruppekatalog.
- RSS — RSS-feed med seneste uploads, filtrerbart efter kategori.
Din kontomenu (øverste højre hjørne, når du er logget ind) åbner et profilpanel, hvor du kan justere indstillinger, administrere sikkerhedsindstillinger og få adgang til din API-nøgle.
2. Gennemsøg og søg
Forsiden viser alle torrents sorteret efter uploaddato. Brug søgefeltet øverst til at filtrere resultater.
Grundlæggende søgning
Skriv ord i søgefeltet og tryk Enter (eller klik på søgeikonet). Resultater rangeres efter relevans, når en søgeforespørgsel er aktiv.
Søgeoperatorer
Følgende operatorer kan kombineres med en normal søgeforespørgsel:
| Operator | Eksempel | Effekt |
|---|---|---|
user:"name" | user:"SubsPlease" | Vis kun torrents uploadet af den bruger. |
Klik på et uploadernavn i torrentlisten kører automatisk en brugersøgning for dig.
Kategorier og underkategorier
Brug kategorivælgeren (gitterikonet ved siden af søgefeltet) til at begrænse resultater til én kategori. Tilgængelige kategorier:
- Anime
- Manga/Manhwa/Tegneserie
- Lyd
- Litteratur
- Live Action
- Billeder
- Software
- Hentai
- Andet
Hver kategori har underkategorier (f.eks. Anime til RAW, Sub/Audio, Musikvideo) der kan vælges inde i kategoridialogen.
Sortering og filtre
Kolonneoverskrifterne på torrentlisten er klikbare for at sortere efter den kolonne (stigende eller faldende). Tilgængelige sorteringskolonner: dato, navn, størrelse, fuldførte downloads. Bemærk: seedere og leechere er live-tal hentet fra Redis og kan ikke bruges til sortering.
Sprogfilter
Brug sprogvælgeren (flagikon) til kun at vise torrents mærket med et specifikt sprog.
RSS-feed
RSS-feedet på /rss giver de seneste uploads. Tilføj ?category=anime (eller enhver anden kategori-slug) for at filtrere feedet. De fleste torrentklienter understøtter RSS auto-download direkte fra denne URL.
3. Download torrents
Klik på et torrentnavn for at åbne detaljepanelet. Derfra kan du:
- Download .torrent — gemmer .torrent-filen direkte. Den direkte URL er
/torrents/{id}.torrent - Magnetlink — åbner direkte i din torrentklient via magnet-URI-protokollen. URL'en er
/torrents/{id}/magnet
Detaljepanelet viser også torrentbeskrivelsen, fillisten, trackerlisten og seeder-/leecherantal.
Ældre downloadlinks
Gamle AniRena-downloadlinks understøttes stadig og omdirigerer automatisk til den korrekte .torrent-fil ved hjælp af det ældre ID: /dl/{old_id}
Anbefalede BitTorrent-klienter
Enhver moderne BitTorrent-klient fungerer. Klienterne nedenfor anbefales og understøtter fuldt ud BitTorrent v2 / hybridtorrents:
4. Opret en konto
Registrering
Klik på Opret konto i navigationslinjen. Vælg et brugernavn, angiv en e-mailadresse og angiv en adgangskode (minimumslængde håndhæves). Du skal læse og acceptere webstedets vilkår, inden din konto oprettes.
E-mailaktivering
Efter tilmelding sendes en bekræftelsesmail til din adresse. Klik på linket i e-mailen for at aktivere din konto. Hvis du ikke modtog den, skal du bruge linket Aktivér din konto på loginsiden for at anmode om en ny kode.
Adgangskodegendannelse
Hvis du glemmer din adgangskode, skal du klikke på Glemt adgangskode på loginsiden og indtaste din e-mailadresse. Et gendannelseslink sendes til dig. Linket er engangsbrug og udløber efter kort tid.
5. Upload torrents
Gå til Upload i navigationslinjen. Du skal være logget ind med en aktiv, ikke-udelukket konto. Uploadsiden har to faner:
Upload-fane — indsend en eksisterende .torrent-fil
Træk og slip eller vælg en .torrent-fil. Når den er indlæst, skal du udfylde felterne:
| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| Torrent-fil | Ja | Den .torrent-fil der uploades. |
| Navn | Nej | Tilsidesæt torrentens visningsnavn. Hvis det efterlades tomt, bruges det navn, der er indlejret i torrent-filen. |
| Kategori | Ja | Indholdskategori (Anime, Manga, Lyd osv.). |
| Underkategori | Nej | En mere specifik type inden for kategorien (f.eks. RAW, Sub/Audio). |
| Sprog | Nej | Én eller flere sprogtags der beskriver indholdssproget. |
| Gruppe | Nej | Tilknyt denne udgivelse til en gruppe, du er medlem af. |
| Beskrivelse | Nej | Markdown-formateret beskrivelse vist på torrentdetaljersiden (maks. 65535 tegn). |
| Privat | Nej | Sætter privatflagget i torrenten, deaktiverer DHT/PEX. Nyttigt til trackere-only torrents. |
| Announce-URL | Nej | Tilsidesæt eller tilføj den primære tracker announce URL. |
| Ekstra trackere | Nej | Læses fra torrentfilen. Kan ikke ændres under upload — brug fanen Opret, hvis du vil tilpasse trackerlisten. |
| Kommentar | Nej | Tilsidesæt torrentkommentarfeltet indlejret i filen. |
Din torrent skal indeholde mindst én AniRena tracker-URL på dens announce-liste (ethvert tier). Siden kontrollerer dette ved upload og afviser torrents, der ikke inkluderer en AniRena tracker. Hvis du oprettede torrenten uden at tilføje AniRena trackeren først, skal du uploade den og derefter downloade den igen fra siden — den downloadede fil vil automatisk have de korrekte trackere.
Opret-fane — byg en ny torrent
Opret-fanen lader dig generere en ny .torrent fra bunden ved at angive filstier, tracker-URL'er og andre torrentparametre direkte i browseren. Den resulterende torrent indsendes med de samme metadatafelter som ovenfor.
Moderering
Uploads kontrolleres automatisk mod en liste over forbudte indholdsmønstre (navne, filnavne, beskrivelser). Torrents der matcher et forbudt mønster vil blive afvist. Duplikate torrents (samme info-hash) afvises også.
6. Din konto
Klik på dit brugernavn i det øverste højre hjørne for at åbne profilpanelet. Det er organiseret i sammenfoldelige sektioner:
Indstillinger
Skift UI-tema, skriftstørrelse, farveskema, grænsefladessprog og torrent-relaterede visningspræferencer. Ændringer gemmes automatisk.
Adgangskode
Indtast din nuværende adgangskode og den nye adgangskode to gange. En bekræftelseskode sendes til din registrerede e-mailadresse og skal indtastes for at bekræfte ændringen. Hvis to-faktor-godkendelse er aktiveret, kræves din TOTP-kode også.
To-faktor-godkendelse (2FA)
Aktivér TOTP-baseret to-faktor-godkendelse ved hjælp af enhver godkendelsesapp (f.eks. Google Authenticator, Aegis, Bitwarden). Når du aktiverer 2FA:
- Scan QR-koden (eller indtast hemmeligheden manuelt) i din godkendelsesapp.
- Indtast den 6-cifrede kode vist i din app for at bekræfte opsætningen.
- Gem de viste gendannelseskoder — disse er engangskoder til at genvinde adgangen, hvis du mister din enhed.
For at deaktivere 2FA skal du indtaste din nuværende TOTP-kode og bekræfte.
Aktive sessioner
Vis alle aktuelle aktive loginsessioner, herunder browser, OS, IP-adresse og sidst-set-tidspunkt. Klik på Tilbagekald på enhver session, du ikke genkender. Du kan også tilbagekalde alle sessioner på én gang for at logge ud fra alle enheder.
API-nøgle
Generer en personlig API-nøgle brugt til at uploade torrents programmatisk via AniRena API. Klik på Generer nøgle for at oprette én — den fulde nøgle vises én gang umiddelbart efter generering. Opbevar den sikkert; den vises ikke i fuld længde igen. Brug Tilbagekald til permanent at ugyldiggøre nøglen.
Slet konto
Anmodning om kontosletning starter en 30-dages afkølingsperiode. Din konto deaktiveres øjeblikkeligt og slettes permanent efter 30 dage. Du kan annullere sletningen til enhver tid inden for dette vindue ved at logge ind og klikke på Annuller sletning.
7. AniRena API
AniRena tilbyder en JSON API, der lader dig uploade torrents programmatisk ved hjælp af en personlig API-nøgle. API'en anvender de samme regler som webgrænsefladen: forbudscheck, hastighedsgrænser og site-modebegrænsninger gælder alle. Hver API-upload registreres i revisionsloggen.
Godkendelse
API'et bruger et to-trins autentificeringsflow. Byt først din permanente API-nøgle ud med et kortvarigt bearer token, og videregiv derefter dette token i Authorization-headeren for hver API-anmodning.
Din API-nøgle er tilgængelig under Din konto > API-nøgle. Hold den hemmelig — enhver med nøglen kan få bearer tokens og uploade på dine vegne. Hvis den kompromitteres, tilbagekaldes den straks og genereres en ny.
Trin 1 — Få et bearer token
/api/v1/auth/tokenSend en POST-anmodning til token-endpointet med din API-nøgle 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
}Tokens levetid
Bearer-tokens forbliver gyldige i op til 3600 sekunder fra udstedelsestidspunktet og kan genbruges til hvert kald, indtil de udløber. Når en token udløber, opret en ny via POST /api/v1/auth/token. Hver respons gentager stadig den aktuelle token i X-New-Token-headeren af hensyn til bagudkompatibilitet.
X-New-Token: <next-bearer-token>
Login med én forespørgsel (med 2FA)
/api/v1/auth/loginGodkend med dit brugernavn eller din e-mail og din adgangskode i én forespørgsel og få et bearer-token direkte. Hvis din konto har 2FA aktiveret, skal du angive din aktuelle autentificeringskode i totp_code (eller en gendannelseskode i recovery_code). Sæt eventuelt new_api_key til true for også at oprette en helt ny permanent API-nøgle i samme svar.
Anmodningskrop
{
"login": "username or email",
"password": "your-password",
"totp_code": "123456", // kræves, hvis 2FA er aktiveret (6 cifre)
"recovery_code": "", // alternativ til totp_code
"new_api_key": false // sæt til true for også at oprette en ny API-nøgle
}Token-svar
{
"ok": true,
"token": "<bearer-token>",
"token_type": "Bearer",
"expires_in": 3600,
"api_key": "<new-api-key>" // vises kun, når new_api_key var true
}Bearer-tokenet fungerer præcis som et fra /api/v1/auth/token. Feltet api_key returneres kun, når new_api_key er true — gem det med det samme, da det kun vises én gang og erstatter enhver tidligere nøgle.
Eksempel — log ind og få (valgfrit) en ny API-nøgle
# 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}"); } }
Trin 2 — Upload en torrent
/api/v1/torrentsSend en simpel JSON POST-anmodning med bearer token i Authorization-headeren.
Anmodningskrop
| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
torrent | string | Ja | Base64-kodet indhold af .torrent-filen. |
category | string | Ja | Kategori-slug: anime, manga, audio, literature, live, pictures, software, hentai, other. |
name | string | Nej | Tilsidesæt torrentens visningsnavn. |
sub_category | string | Nej | Underkategori-slug (f.eks. raw, sub-audio). Skal tilhøre den valgte kategori. |
languages | string[] | Nej | Array af BCP 47-sprogkoder (f.eks. en, ja). |
group_id | string | Nej | UUID for en gruppe, du er medlem af, for at tilknytte denne udgivelse. |
description | string | Nej | Markdown-formateret udgivelsesbeskrivelse (maks. 65535 tegn). |
comment | string | Nej | Tilsidesæt det indlejrede torrentkommentarfelt. |
is_private | boolean | Nej | Sæt til true for at aktivere privatflagget i torrenten. |
comments_enabled | boolean | Nej | Tillad kommentarer til denne torrent. Standardværdi er true (aktiveret). |
anime_id | string | Nej | UUID for en anime-post, der skal tilknyttes denne torrent. Hent UUID via GET /api/v1/anime/search. Returnerer 400, hvis UUID ikke matcher nogen kendt post. |
announce | string | Nej | Tilsidesæt eller tilføj den primære announce URL. |
trackers | string | Nej | Nylinjesepareret liste over yderligere tracker-URL'er. En tom linje mellem URL'er opretter et nyt trackerniveau. |
test | boolean | Nej | Sæt til true for at udføre en tørtest: anmodningen valideres fuldt ud, men torrenten gemmes ikke. Brug dette til at bekræfte, at din payload er korrekt, før du indsender for alvor. |
Tørtest-succes svar — 200 OK
{
"ok": true,
"test": true,
"name": "My Torrent Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null
}Tilgængelige sprogkoder
abaaafaksqamarar-001anhyasavaeayazbmbaeubebnbhbibsbrbgmyyuecachcenyzhzh-HKzh-Hanszh-SGzh-TWcucvkwcocrhrcsdadvnlnl-BEdzenen-USeoeteefofjfilfifrfr-CAffgllgkadede-ATelgnguhthahehzhihohuisioigidiaieiuikgaitjajvklknkrkskkkmkirwrnkvkgkokjkukylolalvlilnltlulbmkmgmsmlmtgvmimrmhmnnanvngnendsenonbnnocorojomospipsfaplptpt-BRpaqurormrusmsgsascgdsrsr-Latnsniisdsiskslsonrsteses-419es-MXsuswsssvtltytgtatttethbotitotstntrtktwukuruguzvevivowacyfywoxhyiyozazuEksempelanmodning
# 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 }
Succesrespons — 200 OK
{
"ok": true,
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Torrent Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null
}Fejlresponser
| HTTP-status | Betydning |
|---|---|
400 | Ugyldig anmodningskrop eller manglende påkrævet felt. |
401 | Manglende, udløbet eller allerede roteret bearer token. Godkend igen via POST /api/v1/auth/token. |
403 | Konto udelukket, deaktiveret eller IP blokeret. |
409 | Duplikat torrent — torrent med samme info-hash eksisterer allerede. |
422 | Torrent-fil kunne ikke parses eller fejlede validering (forbudt mønster, ugyldig struktur). |
429 | Hastighedsgrænse overskredet. Prøv igen, når vinduet nulstilles. |
503 | Siden er i vedligeholdelses- eller skrivebeskyttet tilstand. |
Hastighedsbegrænsning
API-uploads er underlagt en konfigurerbar hastighedsgrænse adskilt fra webgrænsefladen. Grænsen og vinduet er angivet af siteadministratoren. Når hastighedsgrænsen overskrides, returnerer API'en 429 Too Many Requests. Grænsen er per API-nøgle.
Generering af torrent-filer med torrent-builder
torrent-builder er et open source CLI-værktøj bygget oven på libtorrent-rasterbar, der lader dig oprette BitTorrent v1, v2 og hybrid .torrent-filer fra kommandolinjen. Det passer perfekt til AniRena upload API — generer filen lokalt og POST den derefter direkte til trackeren. cantalupo555/torrent-builder.
Byg fra kildekode
Kræver CMake >= 3.28.3 og libtorrent-rasterbar >= 2.0.11. Klon repositoriet og byg 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 .
Vigtige flag
| Felt | Beskrivelse |
|---|---|
--path | Sti til filen eller mappen der skal pakkes (påkrævet). |
--output | Output .torrent-filnavn (påkrævet). |
--version | BitTorrent-format — 1 = v1, 2 = v2, 3 = hybrid (standard: 3). |
--tracker | Tilføj en tracker announce URL. Gentag flaget for at tilføje flere trackere. |
--comment | Indlejr en metadata-kommentarstreng i torrenten. |
--private | Sæt det private flag for at begrænse distribution til kun de angivne trackere. |
--piece-size | Delstørrelse i KB (16-32768). Lad være uindstillet for automatisk valg. |
-i | Start trinvis interaktiv konfigurationstilstand. |
Komplet arbejdsgang: byg -> upload
Eksemplerne nedenfor bygger en hybrid torrent med torrent-builder, godkender derefter med AniRena API og uploader resultatet i ét script.
# 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øgning i torrent-metadata
/api/v1/torrents/searchSend en simpel JSON POST-anmodning for at hente torrent-oversigter med de samme søge- og filtreringsmuligheder, der er tilgængelige på webstedet. Selve .torrent-filen returneres ikke — brug den normale downloadrute til 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øgeparametre
| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
q | string | Nej | Fritekstsøgning. Understøtter group:slug, group:"Name", user:name præfikser. |
category | string | Nej | Kategori-slug (f.eks. "anime"). |
sub_category | string | Nej | Underkategori-slug (f.eks. "raw"). |
languages | string[] | Nej | Array af BCP 47-sprogkoder (f.eks. en, ja). |
sort | string | Nej | Sorteringsfelt: date (standard), size, seeders, leechers, completed, title. |
order | string | Nej | Sorteringsretning: desc (standard) eller asc. |
page | integer | Nej | Sidenummer, startende ved 1 (standard 1). |
per_page | integer | Nej | Resultater per side, 1–250 (standard 50). |
hide_adult | boolean | Nej | Udeluk torrents i voksenkategorien. Standard true for almindelige brugere. |
show_dead | boolean | Nej | Når false (standard) udelukkes torrents, der er ældre end den dead-torrent-frist og ikke har nogen aktive seedere. Sæt til true for at 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 — Antal ikke-slettede kommentarer til denne torrent.
Søgehastighedsbegrænsning
Søgeanmodninger er underlagt en separat konfigurerbar hastighedsgrænse (standard 60 anmodninger per 60 sekunder per API-nøgle). Overskridelse af grænsen returnerer 429 Too Many Requests. Personalekontier er fritaget.
Hent torrent-detaljer
/api/v1/torrent/{id}Hent de fulde metadata for en enkelt torrent — inklusive felter som søge-endpointet udelader, såsom markdown-beskrivelsen, den indlejrede .torrent-kommentar, fil-listen med størrelse pr. fil og den fulde tracker-tier-opsætning. Live seeder- og leecher-tællinger læses fra trackeren, når de er tilgængelige.
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 tællinger fra den interne tracker; begge rapporteres som 0, når tracker-lageret ikke har en post for dette info hash eller er utilgængeligt.
ext_seeders, ext_leechers — Højeste antal seedere og leechere rapporteret af en enkelt ekstern tracker scrapet for denne torrent. Trackere, der følger den samme sværm, overlapper, så maksimum bruges i stedet for summen; begge rapporterer 0, når ingen tracker har scrape-data for dette info hash.
Fejlresponser
| HTTP-status | Betydning |
|---|---|
400 | Torrent-id'et skal være enten et 36-tegns UUID med bindestreger eller en 32-tegns ren hex-streng. |
401 | Manglende, udløbet eller allerede roteret bearer token. Godkend igen via POST /api/v1/auth/token. |
404 | Torrent ikke fundet. |
429 | Hastighedsgrænse overskredet. Prøv igen, når vinduet nulstilles. |
503 | Siden er i vedligeholdelses- eller skrivebeskyttet tilstand. |
Hentning af torrent-kommentarer
/api/v1/torrents/{id}/commentsHent paginerede kommentarer til en torrent. Antallet af kommentarer per side styres af COMMENT_PER_PAGE-indstillingen i serverens .env-fil (standard 20). Kun torrents med aktiverede kommentarer vil returnere resultater — alle andre returnerer 403.
Forespørgselsparametre
| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
page | integer | Nej | 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 udelukket, eller kommentaren er slettet. Flaget author_banned angiver, hvilken sag der gælder.
Fejlresponser
| HTTP-status | Betydning |
|---|---|
401 | Manglende, udløbet eller allerede roteret bearer token. Godkend igen via POST /api/v1/auth/token. |
403 | Kommentarer er deaktiveret for denne torrent. |
404 | Torrent ikke fundet. |
503 | Siden er i vedligeholdelses- eller skrivebeskyttet tilstand. |
Søger i animeposter
/api/v1/anime/search?q=<query>Søg efter anime-poster via titel for at hente deres UUID. UUID kan angives som anime_id i upload-body'en for at knytte en torrent til en anime-post ved upload, eller bruges med PUT /api/torrents/{id}/anime efter upload. Ingen godkendelse er påkrævet. Underlagt samme hastighedsbegrænsning som torrent-søgning (standard 60 anmodninger 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"]);
}Forespørgselsparametre
| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
q | string | Ja | Titelsøgestreng (påkrævet). Matches mod titel og synonymer. |
page | integer | Nej | Sidenummer, startende ved 1 (standard 1). |
per_page | integer | Nej | 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
}
]
}Vis og hent grupper
/api/v1/groupsReturnerer en pagineret liste over offentlige grupper (aktiverede og ikke låste). Kræver Bearer-tokengodkendelse.
/api/v1/groups/{id_or_slug}Returnerer en enkelt offentlig gruppe efter numerisk ID eller slug. Returnerer 404, hvis gruppen er deaktiveret eller låst.
Forespørgselsparametre (kun liste)
| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
q | string | Nej | Filtrer efter gruppenavn (valgfrit, delstrengsmatch). |
page | integer | Nej | Sidenummer (standard 1). |
per_page | integer | Nej | Resultater pr. side, 1–100 (standard 20). |
sort | string | Nej | Sorteringskolonne: name | slug | members | torrents | created (standard name). |
order | string | Nej | 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"
}Fejlresponser
| HTTP-status | Betydning |
|---|---|
401 | Manglende, udløbet eller allerede roteret bearer token. Godkend igen via POST /api/v1/auth/token. |
404 | Gruppe ikke fundet eller ikke offentligt tilgængelig. |
429 | Hastighedsgrænse overskredet. Prøv igen, når vinduet nulstilles. |
503 | Siden er i vedligeholdelses- eller skrivebeskyttet tilstand. |
8. Donationer
Hvis du ønsker at støtte AniRena og hjælpe med at dække omkostningerne til vores servere og tjenester, er du velkommen til at sende en donation til en af følgende kryptovaluta-punge:
bc1qy2h3ddq6ak5damvnf4r5vu3ydehhxrcq8gllwn0xCbaFe03832F95F86AF2536d52710e78C63b62Cd33ucetj2XDGHQg9PVRPMxerNi7c6kX7GJkjQNg9yjwGegLbpt61yX3RjGtB1Ef8vgVz6Hr6baQsTjVkEnhver donation, stor eller lille, er meget værdsat og går direkte til at holde AniRena kørende. Tak for din støtte!
9. Software
AniRena Player er en gratis skrivebordsapp, der lader dig streame video direkte fra torrents indekseret på dette site — du behøver ikke vente på, at hele downloaden er færdig. Indsæt blot et magnet-link eller åbn en .torrent-fil, og afspilningen starter, så snart der er nok data tilgængelig.
Begge builds er fuldt selvstændige — alle afhængigheder er pakket ind i den eksekverbare fil. Ingen installer, intet runtime — bare download og kør.
Installer (.exe). Opdaterer sig selv i appen.
Diskbillede (.dmg) til Apple Silicon-Mac (M1 og nyere). Opdaterer sig selv i appen.
Diskbillede (.dmg) til Intel-Mac. Opdaterer sig selv i appen.
Bærbar enkeltfil, ingen installation nødvendig. Det eneste Linux-format med opdatering i appen.
Installation: sudo apt install ./<file>.deb — opdateres via apt eller en ny download, ikke i appen.
Installation: sudo dnf install ./<file>.rpm — opdateres via dnf eller en ny download, ikke i appen.
Sideload på 64-bit ARM Android-enheder (de fleste moderne telefoner / tablets). Opdateres ved at downloade en ny APK.
Ældre versioner
Sideload på 32-bit ARM Android-enheder (ældre telefoner / tablets). Opdateres ved at downloade en ny APK.