Gabay
1. Pagsisimula
Ang AniRena ay isang torrent index na nakatuon sa anime, manga, audio, at kaugnay na media. Maaari kang mag-browse at mag-download ng mga torrent nang walang account. Kailangan ng account para mag-upload ng mga torrent, mag-post sa mga grupo, o gumamit ng API.
Ang navigation bar sa itaas ay nagbibigay ng access sa mga pangunahing lugar ng site:
- Tahanan — ang pahina ng listahan at paghahanap ng torrent.
- Mag-upload — magsumite ng bagong torrent (kailangan ng login).
- Gabay — ang pahinang ito.
- Istatistika — istatistika sa buong site.
- Mga Grupo — direktoryo ng mga grupo ng release.
- RSS — RSS feed ng mga kamakailang upload.
Ang iyong menu ng account (kanang sulok sa itaas kapag naka-login) ay nagbubukas ng panel ng profile.
2. Pag-browse at Paghahanap
Ang home page ay naglilista ng lahat ng torrent na inayos ayon sa petsa ng upload. Gamitin ang search bar sa itaas para i-filter ang mga resulta.
Pangunahing paghahanap
Mag-type ng anumang salita sa search bar at pindutin ang Enter (o i-click ang icon ng paghahanap).
Mga operator ng paghahanap
Ang mga sumusunod na operator ay maaaring pagsamahin sa regular na query:
| Operator | Halimbawa | Epekto |
|---|---|---|
user:"name" | user:"SubsPlease" | Ipakita lamang ang mga torrent na na-upload ng user na iyon. |
Ang pag-click sa pangalan ng nag-upload sa listahan ng torrent ay awtomatikong nagpapatakbo ng paghahanap ng user para sa iyo.
Mga kategorya at sub-kategorya
Gamitin ang category selector para limitahan ang mga resulta sa isang kategorya.
- Anime
- Manga/Manhwa/Comic
- Audio
- Literatura
- Live Action
- Mga Larawan
- Software
- Hentai
- Iba pa
Ang bawat kategorya ay may mga sub-kategorya.
Pag-sort at mga filter
Ang mga header ng column sa listahan ng torrent ay maaaring i-click para mag-sort. Tandaan: ang seeders at leechers ay mga live na bilang mula sa Redis at hindi magagamit para sa pag-sort.
Filter ng wika
Gamitin ang language selector para ipakita lamang ang mga torrent na may tukoy na wika.
RSS feed
Ang RSS feed sa /rss ay nagbibigay ng mga pinakabagong upload.
3. Pag-download ng Mga Torrent
I-click ang anumang pangalan ng torrent para buksan ang panel ng detalye. Mula doon maaari kang:
- Mag-download ng .torrent — nagse-save ng .torrent file nang direkta. Ang direktang URL ay
/torrents/{id}.torrent - Magnet link — nagbubukas nang direkta sa iyong torrent client sa pamamagitan ng magnet URI protocol. Ang URL ay
/torrents/{id}/magnet
Ipinapakita rin ng panel ng detalye ang paglalarawan, listahan ng file, listahan ng tracker, at bilang ng seeder/leecher.
Mga legacy na download link
Ang mga lumang AniRena download link ay sinusuportahan pa rin at awtomatikong nire-redirect. /dl/{old_id}
Inirekomendang mga BitTorrent client
Anumang modernong BitTorrent client ay gumagana. Ang mga client sa ibaba ay inirerekomenda at ganap na sumusuporta sa BitTorrent v2 / hybrid na mga torrent:
4. Paglikha ng Account
Pagpaparehistro
I-click ang Sign Up sa navigation bar. Pumili ng username, magbigay ng email address, at magtakda ng password.
Pag-activate ng email
Pagkatapos mag-sign up, isang verification email ang ipapadala sa iyong address. I-click ang link sa email para i-activate ang iyong account.
Pagbawi ng password
Kung nakalimutan mo ang iyong password, i-click ang Forgot password sa pahina ng pag-sign-in at ilagay ang iyong email address.
5. Pag-upload ng Mga Torrent
Pumunta sa Upload sa navigation bar. Kailangan mong naka-login na may aktibo, hindi naka-ban na account.
Tab ng upload — magsumite ng kasalukuyang .torrent file
Mag-drag-and-drop o pumili ng .torrent file.
| Field | Kinakailangan | Paglalarawan |
|---|---|---|
| Torrent file | Oo | Ang .torrent file na ia-upload. |
| Pangalan | Hindi | I-override ang display name ng torrent. |
| Kategorya | Oo | Ang kategorya ng nilalaman (Anime, Manga, Audio, atbp.). |
| Sub-kategorya | Hindi | Mas tukoy na uri sa loob ng kategorya. |
| Mga Wika | Hindi | Isa o higit pang language tag. |
| Grupo | Hindi | Iugnay ang release na ito sa isang grupo na miyembro ka. |
| Paglalarawan | Hindi | Paglalarawan sa format na Markdown (max 65535 character). |
| Pribado | Hindi | Itatakda ang private flag sa torrent, hindi papaganahin ang DHT/PEX. |
| Announce URL | Hindi | I-override o magdagdag ng pangunahing tracker announce URL. |
| Karagdagang mga tracker | Hindi | Binabasa mula sa torrent file. Hindi mababago sa panahon ng pag-upload — gamitin ang tab na Create kung gusto mong i-customize ang tracker list. |
| Komento | Hindi | I-override ang field ng komento na naka-embed sa file. |
Ang iyong torrent ay dapat maglaman ng kahit isang AniRena tracker URL sa announce list nito (anumang tier). Sinusuri ito ng site sa pag-upload at tatanggihan ang mga torrent na hindi naglalaman ng AniRena tracker. Kung ginawa mo ang torrent nang hindi muna idinidagdag ang AniRena tracker, i-upload ito at i-download muli mula sa site — ang na-download na file ay awtomatikong magtataglay ng tamang mga tracker.
Tab ng paglikha — bumuo ng bagong torrent
Ang tab ng Lumikha ay nagbibigay-daan sa iyo na gumawa ng bagong .torrent mula sa simula.
Moderasyon
Awtomatikong sinusuri ang mga upload laban sa listahan ng mga ipinagbabawal na pattern. Tinatanggihan din ang mga duplicate na torrent.
6. Ang Iyong Account
I-click ang iyong username sa kanang sulok sa itaas para buksan ang panel ng profile.
Mga Setting
Baguhin ang UI theme, laki ng font, kulay na scheme, wika ng interface, at mga kagustuhan sa pagpapakita na may kaugnayan sa torrent.
Password
Ilagay ang iyong kasalukuyang password at ang bagong password nang dalawang beses.
Two-Factor Authentication (2FA)
I-enable ang TOTP-based na two-factor authentication gamit ang anumang authenticator app.
- I-scan ang QR code (o ilagay ang secret nang manu-mano) sa iyong authenticator app.
- Ilagay ang 6-digit na code na ipinapakita sa iyong app para kumpirmahin ang setup.
- I-save ang mga recovery code na ipinapakita — ito ay mga one-time code para mabawi ang access.
Para i-disable ang 2FA, ilagay ang iyong kasalukuyang TOTP code at kumpirmahin.
Mga Aktibong Session
Tingnan ang lahat ng kasalukuyang aktibong login session kasama ang browser, OS, IP address, at huling nakita.
API Key
Gumawa ng personal na API key para sa pag-upload ng mga torrent sa pamamagitan ng programa.
Burahin ang Account
Ang paghiling ng pagbubura ng account ay nagsisimula ng 30-araw na grace period.
7. AniRena API
Nagbibigay ang AniRena ng JSON API na nagbibigay-daan sa iyo na mag-upload ng mga torrent sa pamamagitan ng programa gamit ang personal na API key.
Authentication
Gumagamit ang API ng dalawang-hakbang na authentication flow. Una, palitan ang iyong permanenteng API key ng isang panandaliang bearer token, pagkatapos ay ipasa ang token na iyon sa Authorization header ng bawat API request.
Ang iyong API key ay makukuha sa Iyong Account > API Key. Panatilihing lihim — sinumang may key ay maaaring makakuha ng mga bearer token at mag-upload sa iyong ngalan. Kung nakompromiso, bawiin kaagad at gumawa ng bago.
Hakbang 1 — Kumuha ng bearer token
/api/v1/auth/tokenMagpadala ng POST request sa token endpoint na may iyong API key sa Authorization header. Hindi kailangan ng request body.
Authorization: ApiKey <your-api-key>
Tugon ng token
{
"token": "<bearer-token>",
"token_type": "Bearer",
"expires_in": 3600
}Tagal ng buhay ng token
Mananatiling balido ang Bearer tokens hanggang 3600 segundo mula sa pagkakaisyu at maaaring magamit muli sa bawat tawag hanggang mag-expire ang mga ito. Kapag nag-expire ang isang token, gumawa ng bago sa pamamagitan ng POST /api/v1/auth/token. Bawat tugon ay nagba-balik pa rin ng kasalukuyang token sa header na X-New-Token para sa backward compatibility.
X-New-Token: <next-bearer-token>
Pag-login sa iisang request (may 2FA)
/api/v1/auth/loginMag-authenticate gamit ang iyong username o email at password sa iisang request at direktang makatanggap ng bearer token. Kung naka-enable ang 2FA sa iyong account, isama ang kasalukuyang authenticator code sa totp_code (o isang recovery code sa recovery_code). Opsyonal na itakda ang new_api_key sa true upang lumikha rin ng bagong permanenteng API key sa parehong tugon.
Request body
{
"login": "username or email",
"password": "your-password",
"totp_code": "123456", // kinakailangan kung naka-enable ang 2FA (6 na digit)
"recovery_code": "", // alternatibo sa totp_code
"new_api_key": false // itakda sa true upang lumikha rin ng bagong API key
}Tugon ng token
{
"ok": true,
"token": "<bearer-token>",
"token_type": "Bearer",
"expires_in": 3600,
"api_key": "<new-api-key>" // naroroon lamang kapag true ang new_api_key
}Gumagana ang bearer token nang eksaktong katulad ng nakukuha mula sa /api/v1/auth/token. Ibinabalik lamang ang field na api_key kapag true ang new_api_key — i-save ito agad, dahil ipinapakita ito nang isang beses lamang at pinapalitan ang anumang dating key.
Halimbawa — mag-login at (opsyonal) kumuha ng bagong API key
# 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}"); } }
Hakbang 2 — Mag-upload ng torrent
/api/v1/torrentsMagpadala ng simpleng JSON POST request na may bearer token sa Authorization header.
Request body
| Field | Uri | Kinakailangan | Paglalarawan |
|---|---|---|---|
torrent | string | Oo | Base64-encoded na nilalaman ng .torrent file. |
category | string | Oo | Category slug: anime, manga, audio, literature, live, pictures, software, hentai, other. |
name | string | Hindi | I-override ang display name ng torrent. |
sub_category | string | Hindi | Sub-category slug (hal. raw, sub-audio). |
languages | string[] | Hindi | Array ng BCP 47 language code (hal. en, ja). |
group_id | string | Hindi | UUID ng grupo na miyembro ka. |
description | string | Hindi | Paglalarawan sa format na Markdown (max 65535 character). |
comment | string | Hindi | I-override ang embedded na field ng komento ng torrent. |
is_private | boolean | Hindi | Itakda sa true para paganahin ang private flag. |
comments_enabled | boolean | Hindi | Payagan ang mga komento sa torrent na ito. Ang default ay true (pinagana). |
anime_id | string | Hindi | UUID ng isang anime entry para i-link sa torrent na ito. Makuha ang UUID sa pamamagitan ng GET /api/v1/anime/search. Nagbabalik ng 400 kung ang UUID ay hindi tumutugma sa anumang kilalang entry. |
announce | string | Hindi | I-override o magdagdag ng pangunahing announce URL. |
trackers | string | Hindi | Listahan ng karagdagang tracker URL na pinaghiwalay ng bagong linya. |
test | boolean | Hindi | I-set sa true para sa dry run: ang kahilingan ay ganap na bine-validate ngunit hindi nai-save ang torrent. Gamitin ito para maberipika ang iyong payload bago ang aktwal na pagsusumite. |
Dry-run success response — 200 OK
{
"ok": true,
"test": true,
"name": "My Torrent Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null
}Mga available na language code
abaaafaksqamarar-001anhyasavaeayazbmbaeubebnbhbibsbrbgmyyuecachcenyzhzh-HKzh-Hanszh-SGzh-TWcucvkwcocrhrcsdadvnlnl-BEdzenen-USeoeteefofjfilfifrfr-CAffgllgkadede-ATelgnguhthahehzhihohuisioigidiaieiuikgaitjajvklknkrkskkkmkirwrnkvkgkokjkukylolalvlilnltlulbmkmgmsmlmtgvmimrmhmnnanvngnendsenonbnnocorojomospipsfaplptpt-BRpaqurormrusmsgsascgdsrsr-Latnsniisdsiskslsonrsteses-419es-MXsuswsssvtltytgtatttethbotitotstntrtktwukuruguzvevivowacyfywoxhyiyozazuHalimbawa ng kahilingan
# 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 }
Matagumpay na tugon — 200 OK
{
"ok": true,
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Torrent Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null
}Mga tugon sa error
| HTTP status | Kahulugan |
|---|---|
400 | Di-wastong request body o nawawalang kinakailangang field. |
401 | Nawawala, nag-expire, o napalitan na bearer token. Mag-authenticate muli sa pamamagitan ng POST /api/v1/auth/token. |
403 | Account na naka-ban, hindi pinagana, o naka-block ang IP. |
409 | Duplicate na torrent — may parehong info hash na. |
422 | Hindi ma-parse ang torrent file o nabigo ang validation. |
429 | Nalampasan ang rate limit. Subukan muli pagkatapos mag-reset ang window. |
503 | Ang site ay nasa maintenance o read-only mode. |
Rate limiting
Ang mga API upload ay napapailalim sa nako-configure na rate limit na hiwalay mula sa web interface.
Paglikha ng mga torrent file gamit ang torrent-builder
Ang torrent-builder ay isang open-source na CLI tool na itinayo sa ibabaw ng libtorrent-rasterbar na nagpapahintulot sa iyo na lumikha ng mga .torrent file na BitTorrent v1, v2, at hybrid mula sa command line. Perpekto itong kasama ng AniRena upload API — lumikha ng file nang lokal, pagkatapos ay i-POST ito nang direkta sa tracker. cantalupo555/torrent-builder.
Pagbuo mula sa source code
Nangangailangan ng CMake >= 3.28.3 at libtorrent-rasterbar >= 2.0.11. I-clone ang repository at buuin gamit ang 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 .
Mga pangunahing flag
| Field | Paglalarawan |
|---|---|
--path | Landas sa file o direktoryo na ipapadala (kinakailangan). |
--output | Pangalan ng output .torrent file (kinakailangan). |
--version | Format ng BitTorrent — 1 = v1, 2 = v2, 3 = hybrid (default: 3). |
--tracker | Magdagdag ng tracker announce URL. Ulitin ang flag para magdagdag ng maraming tracker. |
--comment | Mag-embed ng metadata comment string sa torrent. |
--private | Itakda ang private flag upang limitahan ang distribusyon sa mga nakalistan na tracker lamang. |
--piece-size | Laki ng piraso sa KB (16-32768). Iwanang hindi nakatakda para sa awtomatikong pagpili. |
-i | Ilunsad ang hakbang-hakbang na interactive na mode ng pagsasaayos. |
Kumpletong workflow: build -> upload
Ang mga halimbawa sa ibaba ay nagtatayo ng hybrid torrent gamit ang torrent-builder, pagkatapos ay nagpapatunay sa AniRena API at ina-upload ang resulta sa isang 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"]); }
Paghahanap ng metadata ng torrent
/api/v1/torrents/searchMagpadala ng simpleng JSON POST request para makuha ang mga torrent listing na may parehong mga opsyon sa paghahanap at pag-filter na makukuha sa website. Ang .torrent file mismo ay hindi ibinabalik — gamitin ang normal na download route para doon.
# 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"]); }
Mga parameter ng paghahanap
| Field | Uri | Kinakailangan | Paglalarawan |
|---|---|---|---|
q | string | Hindi | Free-text na paghahanap. Sumusuporta sa mga prefix na group:slug, group:"Name", user:name. |
category | string | Hindi | Category slug (hal. "anime"). |
sub_category | string | Hindi | Sub-category slug (hal. "raw"). |
languages | string[] | Hindi | Array ng BCP 47 language code (hal. en, ja). |
sort | string | Hindi | Sort field: petsa (default), laki, seeders, leechers, natapos, pamagat. |
order | string | Hindi | Sort direction: desc (default) o asc. |
page | integer | Hindi | Numero ng pahina, nagsisimula sa 1. |
per_page | integer | Hindi | Mga resulta bawat pahina, 1–250. |
hide_adult | boolean | Hindi | Ibukod ang mga torrent ng kategoryang pang-adulto. |
show_dead | boolean | Hindi | Kapag false (default), ang mga torrent na mas matanda kaysa sa grace period para sa patay na torrent at walang aktibong seeder ay hindi isinasama. Itakda sa true upang isama ang mga ito. |
Tugon
{
"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 — Bilang ng hindi tinanggal na mga komento sa torrent na ito.
Rate limiting ng paghahanap
Ang mga kahilingan sa paghahanap ay napapailalim sa hiwalay na nako-configure na rate limit (default na 60 kahilingan bawat 60 segundo bawat API key).
Kunin ang mga detalye ng torrent
/api/v1/torrent/{id}Kunin ang kumpletong metadata para sa isang torrent — kasama ang mga field na hindi ibinabalik ng search endpoint, tulad ng markdown na paglalarawan, ang naka-embed na .torrent comment, ang listahan ng file na may laki ng bawat file, at ang buong tracker tier layout. Kapag available, ang live na bilang ng seeders at leechers ay binabasa mula sa tracker.
Tugon
{
"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 — Mga live na bilang mula sa in-house tracker; parehong nagre-report ng 0 kapag ang tracker store ay walang entry para sa info hash na ito o hindi maabot.
ext_seeders, ext_leechers — Pinakamataas na bilang ng seeders at leechers na inulat ng anumang isang panlabas na tracker na na-scrape para sa torrent na ito. Ang mga tracker na nagsusubaybay ng parehong swarm ay nagsasanib, kaya ginagamit ang pinakamataas sa halip na ang kabuuan; pareho silang nag-uulat ng 0 kapag walang tracker na may scrape data para sa info hash na ito.
Mga tugon sa error
| HTTP status | Kahulugan |
|---|---|
400 | Ang torrent id ay dapat na isang 36-character na dashed UUID o isang 32-character na bare hex string. |
401 | Nawawala, nag-expire, o napalitan na bearer token. Mag-authenticate muli sa pamamagitan ng POST /api/v1/auth/token. |
404 | Hindi natagpuan ang torrent. |
429 | Nalampasan ang rate limit. Subukan muli pagkatapos mag-reset ang window. |
503 | Ang site ay nasa maintenance o read-only mode. |
Pagkuha ng mga komento ng torrent
/api/v1/torrents/{id}/commentsKunin ang mga pahina-pahina na komento para sa isang torrent. Ang bilang ng mga komento bawat pahina ay kinokontrol ng setting na COMMENT_PER_PAGE sa .env file ng server (default 20). Ang mga torrent lamang na may pinaganang mga komento ang magbabalik ng mga resulta — lahat ng iba pa ay nagbabalik ng 403.
Mga parameter ng query
| Field | Uri | Kinakailangan | Paglalarawan |
|---|---|---|---|
page | integer | Hindi | Numero ng pahina, nagsisimula sa 1 (default 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"]); }
Tugon
{
"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
}
]
}Ang field na body ay isang walang laman na string kapag ang may-akda ng komento ay na-ban o ang komento ay natanggal. Ang flag na author_banned ang nagpapahiwatig kung alin ang kaso.
Mga tugon sa error
| HTTP status | Kahulugan |
|---|---|
401 | Nawawala, nag-expire, o napalitan na bearer token. Mag-authenticate muli sa pamamagitan ng POST /api/v1/auth/token. |
403 | Ang mga komento ay hindi pinagana para sa torrent na ito. |
404 | Hindi nahanap ang torrent. |
503 | Ang site ay nasa maintenance o read-only mode. |
Paghahanap ng mga anime entry
/api/v1/anime/search?q=<query>Maghanap ng mga anime entry ayon sa pamagat upang makuha ang kanilang UUID. Ang UUID ay maaaring ipasa bilang anime_id sa upload body upang i-link ang isang torrent sa isang anime entry sa oras ng pag-upload, o gamitin kasama ang PUT /api/torrents/{id}/anime pagkatapos mag-upload. Hindi kinakailangan ang pagpapatunay. Napapailalim sa parehong rate limit ng torrent search (default na 60 kahilingan bawat 60 segundo bawat 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"]);
}Mga query parameter
| Field | Uri | Kinakailangan | Paglalarawan |
|---|---|---|---|
q | string | Oo | String na paghahanap ng pamagat (kinakailangan). Itinugma sa pamagat at mga kasingkahulugan. |
page | integer | Hindi | Numero ng pahina, nagsisimula sa 1. |
per_page | integer | Hindi | Mga resulta bawat pahina, 1–50. |
Tugon
{
"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
}
]
}Paglista at pagkuha ng mga grupo
/api/v1/groupsNagbabalik ng paginadong listahan ng mga pampublikong grupo (pinagana at hindi naka-lock). Nangangailangan ng Bearer token authentication.
/api/v1/groups/{id_or_slug}Nagbabalik ng isang pampublikong grupo ayon sa numeric ID o slug. Nagbabalik ng 404 kung ang grupo ay hindi pinagana o naka-lock.
Mga parameter ng query (listahan lamang)
| Field | Uri | Kinakailangan | Paglalarawan |
|---|---|---|---|
q | string | Hindi | I-filter ayon sa pangalan ng grupo (opsyonal, partial match). |
page | integer | Hindi | Numero ng pahina (default 1). |
per_page | integer | Hindi | Mga resulta bawat pahina, 1–100 (default 20). |
sort | string | Hindi | Kolum ng pag-uuri: name | slug | members | torrents | created (default name). |
order | string | Hindi | Direksyon ng pag-uuri: asc o desc (default asc). |
Tugon (listahan)
{
"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"
}
]
}Tugon (iisa)
{
"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"
}Mga tugon sa error
| HTTP status | Kahulugan |
|---|---|
401 | Nawawala, nag-expire, o napalitan na bearer token. Mag-authenticate muli sa pamamagitan ng POST /api/v1/auth/token. |
404 | Hindi nahanap ang grupo o hindi ito naa-access ng publiko. |
429 | Nalampasan ang rate limit. Subukan muli pagkatapos mag-reset ang window. |
503 | Ang site ay nasa maintenance o read-only mode. |
8. Mga Donasyon
Kung nais mong suportahan ang AniRena at tulungan ang pagsaklaw ng gastos sa pagho-host ng aming mga server at serbisyo, malugod naming tinatanggap ang iyong donasyon sa isa sa mga sumusunod na cryptocurrency wallet:
bc1qy2h3ddq6ak5damvnf4r5vu3ydehhxrcq8gllwn0xCbaFe03832F95F86AF2536d52710e78C63b62Cd33ucetj2XDGHQg9PVRPMxerNi7c6kX7GJkjQNg9yjwGegLbpt61yX3RjGtB1Ef8vgVz6Hr6baQsTjVkAng anumang donasyon, malaki man o maliit, ay lubos na pinahahalagahan at direktang napupunta sa pagpapanatili ng AniRena. Salamat sa iyong suporta!
9. Software
Ang AniRena Player ay isang libreng desktop app na nagpapahintulot sa iyo na mag-stream ng video direkta mula sa mga torrent na naka-index sa site na ito — hindi mo na kailangang hintayin matapos ang buong pag-download. I-paste lang ang isang magnet link o buksan ang isang .torrent file, at magsisimula ang playback sa sandaling magkaroon ng sapat na data.
Pareho ng builds ay ganap na standalone — lahat ng dependencies ay nasa loob na ng executable. Walang installer, walang runtime na isasaayos — i-download lang at patakbuhin.
Installer (.exe). Nag-aapdeyt sa sarili sa loob ng app.
Disk image (.dmg) para sa Apple Silicon na Mac (M1 at mas bago). Nag-aapdeyt sa sarili sa loob ng app.
Disk image (.dmg) para sa Intel na Mac. Nag-aapdeyt sa sarili sa loob ng app.
Portable na isang file, hindi nangangailangan ng pag-install. Ang tanging format sa Linux na may in-app auto-update.
Pag-install: sudo apt install ./<file>.deb — nag-aapdeyt sa pamamagitan ng apt o sa pamamagitan ng bagong download, hindi sa loob ng app.
Pag-install: sudo dnf install ./<file>.rpm — nag-aapdeyt sa pamamagitan ng dnf o sa pamamagitan ng bagong download, hindi sa loob ng app.
I-sideload sa 64-bit ARM Android device (karamihan sa mga modernong telepono / tablet). Nag-aapdeyt sa pamamagitan ng pag-download ng bagong APK.
Mga lumang bersyon
I-sideload sa 32-bit na ARM Android na mga device (mga lumang telepono / tablet). Nag-a-update sa pamamagitan ng pag-download ng bagong APK.