Hướng dẫn
1. Bắt đầu
AniRena là chỉ mục torrent tập trung vào anime, manga, âm thanh và các phương tiện liên quan. Bạn có thể duyệt và tải torrent mà không cần tài khoản. Cần tài khoản để tải lên torrent, đăng lên nhóm hoặc dùng API.
Thanh điều hướng ở trên cung cấp quyền truy cập vào các khu vực chính của trang:
- Trang chủ — trang danh sách và tìm kiếm torrent.
- Tải lên — gửi torrent mới (yêu cầu đăng nhập).
- Hướng dẫn — trang này.
- Thống kê — thống kê toàn trang (torrent, peer, lượt tải theo thời gian).
- Nhóm — thư mục nhóm phát hành.
- RSS — RSS feed của các tải lên gần đây, có thể lọc theo danh mục.
Menu tài khoản (góc trên phải khi đã đăng nhập) mở bảng hồ sơ để điều chỉnh cài đặt, quản lý bảo mật và truy cập API key.
2. Duyệt & Tìm kiếm
Trang chủ liệt kê tất cả torrent theo thứ tự ngày tải lên. Dùng thanh tìm kiếm ở trên để lọc kết quả.
Tìm kiếm cơ bản
Gõ từ bất kỳ vào thanh tìm kiếm và nhấn Enter (hoặc nhấn biểu tượng tìm kiếm). Kết quả được xếp hạng theo độ liên quan khi có truy vấn.
Toán tử tìm kiếm
Các toán tử sau có thể kết hợp với truy vấn thông thường:
| Toán tử | Ví dụ | Hiệu ứng |
|---|---|---|
user:"name" | user:"SubsPlease" | Chỉ hiển thị torrent tải lên bởi người dùng đó. |
Nhấn tên người tải lên trong danh sách torrent sẽ tự động chạy tìm kiếm người dùng.
Danh mục & danh mục phụ
Dùng bộ chọn danh mục (biểu tượng lưới bên cạnh thanh tìm kiếm) để giới hạn kết quả theo một danh mục. Các danh mục có sẵn:
- Anime
- Manga/Manhwa/Comic
- Âm thanh
- Văn học
- Live Action
- Hình ảnh
- Phần mềm
- Hentai
- Khác
Mỗi danh mục có danh mục phụ (vd. Anime thành RAW, Sub/Audio, Music Video) có thể chọn trong modal danh mục.
Sắp xếp & lọc
Tiêu đề cột trong danh sách torrent có thể nhấn để sắp xếp theo cột đó (tăng hoặc giảm dần). Các cột có thể sắp xếp: ngày, tên, kích thước, lượt tải. Lưu ý: seeder và leecher là giá trị trực tiếp từ Redis và không thể dùng để sắp xếp.
Lọc ngôn ngữ
Dùng bộ chọn ngôn ngữ (biểu tượng cờ) để chỉ hiển thị torrent được gắn thẻ với ngôn ngữ cụ thể.
Nguồn RSS
RSS feed tại /rss cung cấp các tải lên mới nhất. Thêm ?category=anime (hoặc slug danh mục khác) để lọc feed. Hầu hết client torrent hỗ trợ tự động tải từ URL này.
3. Tải Torrent
Nhấn tên bất kỳ torrent để mở bảng chi tiết. Từ đó bạn có thể:
- Tải .torrent — lưu file .torrent trực tiếp. URL trực tiếp là
/torrents/{id}.torrent - Liên kết Magnet — mở trực tiếp trong client torrent qua giao thức magnet URI. URL là
/torrents/{id}/magnet
Bảng chi tiết cũng hiển thị mô tả torrent, danh sách file, danh sách tracker và số seeder/leecher.
Liên kết tải xuống cũ
Các liên kết tải xuống AniRena cũ vẫn được hỗ trợ và tự động chuyển hướng đến file .torrent đúng bằng ID cũ: /dl/{old_id}
Các client BitTorrent được khuyến nghị
Bất kỳ client BitTorrent hiện đại nào cũng hoạt động được. Các client dưới đây được khuyến nghị và hỗ trợ đầy đủ BitTorrent v2 / torrent lai:
4. Tạo tài khoản
Đăng ký
Nhấn Đăng ký trong thanh điều hướng. Chọn tên người dùng, cung cấp địa chỉ email và đặt mật khẩu (độ dài tối thiểu được áp dụng). Bạn phải đọc và chấp nhận điều khoản trước khi tạo tài khoản.
Kích hoạt email
Sau khi đăng ký, email xác minh sẽ được gửi đến địa chỉ của bạn. Nhấn liên kết trong email để kích hoạt tài khoản. Nếu không nhận được, dùng liên kết Kích hoạt tài khoản trên trang đăng nhập để yêu cầu mã mới.
Khôi phục mật khẩu
Nếu quên mật khẩu, nhấn Quên mật khẩu trên trang đăng nhập và nhập địa chỉ email. Liên kết khôi phục sẽ được gửi đến bạn. Liên kết chỉ dùng một lần và hết hạn sau thời gian ngắn.
5. Tải lên Torrent
Điều hướng đến Tải lên trong thanh điều hướng. Bạn phải đăng nhập với tài khoản hoạt động, chưa bị cấm. Trang tải lên có hai tab:
Tab Tải lên — gửi file .torrent hiện có
Kéo thả hoặc chọn file .torrent. Sau khi tải, điền các trường:
| Trường | Bắt buộc | Mô tả |
|---|---|---|
| File Torrent | Có | File .torrent cần tải lên. |
| Tên | Không | Ghi đè tên hiển thị torrent. Nếu để trống, tên nhúng trong file torrent được dùng. |
| Danh mục | Có | Danh mục nội dung (Anime, Manga, Âm thanh, v.v.). |
| Danh mục phụ | Không | Loại cụ thể hơn trong danh mục (vd. RAW, Sub/Audio). |
| Ngôn ngữ | Không | Một hoặc nhiều thẻ ngôn ngữ mô tả ngôn ngữ nội dung. |
| Nhóm | Không | Liên kết phát hành này với nhóm bạn là thành viên. |
| Mô tả | Không | Mô tả định dạng Markdown hiển thị trên trang chi tiết torrent (tối đa 65535 ký tự). |
| Riêng tư | Không | Đặt cờ riêng tư trong torrent, vô hiệu hóa DHT/PEX. Hữu ích cho torrent chỉ dùng tracker. |
| URL Announce | Không | Ghi đè hoặc thêm URL announce tracker chính. |
| Tracker bổ sung | Không | Đọc từ file torrent. Không thể chỉnh sửa trong khi tải lên — dùng tab Tạo nếu bạn muốn tùy chỉnh danh sách tracker. |
| Bình luận | Không | Ghi đè trường bình luận nhúng trong file torrent. |
Torrent của bạn phải có ít nhất một URL tracker AniRena trong danh sách announce (bất kỳ tier nào). Trang web kiểm tra điều này khi tải lên và sẽ từ chối torrent không có tracker AniRena. Nếu bạn tạo torrent mà không thêm tracker AniRena trước, hãy tải lên và tải lại từ trang web — file đã tải sẽ tự động có các tracker đúng.
Tab Tạo — xây dựng torrent mới
Tab Tạo cho phép tạo .torrent mới từ đầu bằng cách chỉ định đường dẫn file, URL tracker và các tham số torrent khác trực tiếp trong trình duyệt. Torrent kết quả được gửi với các trường metadata giống như trên.
Kiểm duyệt
Các tải lên được tự động kiểm tra dựa trên danh sách mẫu nội dung cấm (tên, tên file, mô tả). Torrent khớp với mẫu cấm sẽ bị từ chối. Torrent trùng lặp (cùng info hash) cũng bị từ chối.
6. Tài khoản của bạn
Nhấn tên người dùng ở góc trên phải để mở bảng hồ sơ. Được tổ chức thành các phần có thể thu gọn:
Cài đặt
Thay đổi giao diện, cỡ chữ, bảng màu, ngôn ngữ giao diện và tùy chọn hiển thị liên quan đến torrent. Thay đổi được lưu tự động.
Mật khẩu
Nhập mật khẩu hiện tại và mật khẩu mới hai lần. Mã xác minh được gửi đến email đã đăng ký và phải nhập để xác nhận. Nếu xác thực hai yếu tố đã bật, mã TOTP cũng cần thiết.
Xác thực hai yếu tố (2FA)
Bật xác thực hai yếu tố dựa trên TOTP bằng ứng dụng xác thực bất kỳ (vd. Google Authenticator, Aegis, Bitwarden). Khi bật 2FA:
- Quét mã QR (hoặc nhập thủ công bí mật) trong ứng dụng xác thực.
- Nhập mã 6 chữ số hiển thị trong ứng dụng để xác nhận thiết lập.
- Lưu mã khôi phục được hiển thị — đây là mã một lần để lấy lại quyền truy cập nếu mất thiết bị.
Để tắt 2FA, nhập mã TOTP hiện tại và xác nhận.
Phiên đăng nhập
Xem tất cả phiên đăng nhập đang hoạt động bao gồm trình duyệt, hệ điều hành, địa chỉ IP và thời gian hoạt động cuối. Nhấn Thu hồi trên phiên bạn không nhận ra. Bạn cũng có thể thu hồi tất cả phiên cùng lúc để đăng xuất mọi thiết bị.
Khóa API
Tạo khóa API cá nhân để tải lên torrent theo chương trình qua AniRena API. Nhấn Tạo khóa để tạo — khóa đầy đủ được hiển thị ngay sau khi tạo. Lưu trữ an toàn; sẽ không hiển thị đầy đủ nữa. Dùng Thu hồi để hủy khóa vĩnh viễn.
Xóa tài khoản
Yêu cầu xóa tài khoản bắt đầu thời gian ân hạn 30 ngày. Tài khoản bị vô hiệu hóa ngay lập tức và xóa vĩnh viễn sau 30 ngày. Bạn có thể hủy xóa bất cứ lúc nào trong khoảng thời gian đó.
7. AniRena API
AniRena cung cấp JSON API cho phép tải lên torrent theo chương trình bằng khóa API cá nhân. API áp dụng các quy tắc giống giao diện web: kiểm tra cấm, giới hạn tốc độ và hạn chế chế độ trang đều áp dụng. Mọi tải lên qua API đều được ghi vào nhật ký kiểm tra.
Xác thực
API sử dụng quy trình xác thực hai bước. Đầu tiên đổi API key vĩnh viễn của bạn lấy bearer token ngắn hạn, sau đó truyền token đó vào header Authorization của mọi yêu cầu API.
API key của bạn có tại Tài khoản của bạn > API key. Giữ bí mật — bất kỳ ai có key đều có thể lấy bearer token và tải lên thay mặt bạn. Nếu bị lộ, hãy thu hồi ngay và tạo cái mới.
Bước 1 — Lấy bearer token
/api/v1/auth/tokenGửi yêu cầu POST đến endpoint token với API key trong header Authorization. Không cần request body.
Authorization: ApiKey <your-api-key>
Phản hồi token
{
"token": "<bearer-token>",
"token_type": "Bearer",
"expires_in": 3600
}Thời gian sống của token
Token Bearer vẫn có hiệu lực trong tối đa 3600 giây kể từ khi được cấp và có thể tái sử dụng cho mọi lệnh gọi cho đến khi hết hạn. Khi một token hết hạn, hãy tạo mới qua POST /api/v1/auth/token. Mỗi phản hồi vẫn trả về token hiện tại trong tiêu đề X-New-Token để tương thích ngược.
X-New-Token: <next-bearer-token>
Đăng nhập một yêu cầu (có 2FA)
/api/v1/auth/loginXác thực bằng tên người dùng hoặc email và mật khẩu trong một yêu cầu và nhận token bearer trực tiếp. Nếu tài khoản của bạn đã bật 2FA, hãy đưa mã hiện tại từ ứng dụng xác thực vào totp_code (hoặc mã khôi phục vào recovery_code). Tùy chọn đặt new_api_key thành true để đồng thời tạo một khóa API vĩnh viễn mới trong cùng phản hồi.
Phần thân yêu cầu
{
"login": "username or email",
"password": "your-password",
"totp_code": "123456", // bắt buộc nếu đã bật 2FA (6 chữ số)
"recovery_code": "", // thay thế cho totp_code
"new_api_key": false // đặt true để tạo thêm khóa API mới
}Phản hồi token
{
"ok": true,
"token": "<bearer-token>",
"token_type": "Bearer",
"expires_in": 3600,
"api_key": "<new-api-key>" // chỉ có khi new_api_key là true
}Token bearer hoạt động giống hệt token lấy từ /api/v1/auth/token. Trường api_key chỉ được trả về khi new_api_key là true — hãy lưu ngay vì nó chỉ hiển thị một lần và thay thế mọi khóa trước đó.
Ví dụ — đăng nhập và (tùy chọn) lấy khóa API mới
# 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}"); } }
Bước 2 — Tải lên torrent
/api/v1/torrentsGửi yêu cầu POST JSON đơn giản với bearer token trong header Authorization.
Phần thân yêu cầu
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
torrent | string | Có | Nội dung file .torrent được mã hóa Base64. |
category | string | Có | Slug danh mục: anime, manga, audio, literature, live, pictures, software, hentai, other. |
name | string | Không | Ghi đè tên hiển thị torrent. |
sub_category | string | Không | Slug danh mục phụ (vd. raw, sub-audio). Phải thuộc danh mục đã chọn. |
languages | string[] | Không | Mảng mã ngôn ngữ BCP 47 (vd. en, ja). |
group_id | string | Không | UUID của nhóm bạn là thành viên để liên kết phát hành này. |
description | string | Không | Mô tả phát hành định dạng Markdown (tối đa 65535 ký tự). |
comment | string | Không | Ghi đè trường bình luận nhúng trong torrent. |
is_private | boolean | Không | Đặt true để bật cờ riêng tư trong torrent. |
comments_enabled | boolean | Không | Cho phép bình luận trên torrent này. Mặc định là true (được bật). |
anime_id | string | Không | UUID của một mục anime để liên kết với torrent này. Lấy UUID qua GET /api/v1/anime/search. Trả về 400 nếu UUID không khớp với bất kỳ mục nào đã biết. |
announce | string | Không | Ghi đè hoặc thêm URL announce chính. |
trackers | string | Không | Danh sách URL tracker bổ sung phân tách bằng dòng mới. Dòng trống giữa các URL tạo tầng tracker mới. |
test | boolean | Không | Đặt thành true để thực hiện chạy thử: yêu cầu được xác thực đầy đủ nhưng torrent không được lưu. Sử dụng điều này để xác minh payload của bạn là chính xác trước khi gửi thực sự. |
Phản hồi thành công chạy thử — 200 OK
{
"ok": true,
"test": true,
"name": "My Torrent Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null
}Mã ngôn ngữ có sẵn
abaaafaksqamarar-001anhyasavaeayazbmbaeubebnbhbibsbrbgmyyuecachcenyzhzh-HKzh-Hanszh-SGzh-TWcucvkwcocrhrcsdadvnlnl-BEdzenen-USeoeteefofjfilfifrfr-CAffgllgkadede-ATelgnguhthahehzhihohuisioigidiaieiuikgaitjajvklknkrkskkkmkirwrnkvkgkokjkukylolalvlilnltlulbmkmgmsmlmtgvmimrmhmnnanvngnendsenonbnnocorojomospipsfaplptpt-BRpaqurormrusmsgsascgdsrsr-Latnsniisdsiskslsonrsteses-419es-MXsuswsssvtltytgtatttethbotitotstntrtktwukuruguzvevivowacyfywoxhyiyozazuVí dụ yêu cầu
# 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 }
Phản hồi thành công — 200 OK
{
"ok": true,
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Torrent Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null
}Phản hồi lỗi
| Trạng thái HTTP | Ý nghĩa |
|---|---|
400 | Phần thân yêu cầu không hợp lệ hoặc thiếu trường bắt buộc. |
401 | Bearer token bị thiếu, hết hạn hoặc đã được xoay. Xác thực lại qua POST /api/v1/auth/token. |
403 | Tài khoản bị cấm, tắt hoặc IP bị chặn. |
409 | Torrent trùng lặp — cùng info hash đã tồn tại. |
422 | File torrent không thể phân tích hoặc không qua xác thực (mẫu cấm, cấu trúc không hợp lệ). |
429 | Đã vượt quá giới hạn tốc độ. Thử lại sau khi cửa sổ đặt lại. |
503 | Trang web đang bảo trì hoặc chế độ chỉ đọc. |
Giới hạn tốc độ
Tải lên qua API chịu giới hạn tốc độ có thể cấu hình riêng với giao diện web. Giới hạn và cửa sổ được đặt bởi quản trị viên. Khi vượt quá giới hạn, API trả về 429 Too Many Requests. Giới hạn tính theo khóa API.
Tạo file torrent với torrent-builder
torrent-builder là công cụ CLI mã nguồn mở xây dựng trên libtorrent-rasterbar cho phép tạo file .torrent BitTorrent v1, v2 và hybrid từ dòng lệnh. Nó kết hợp hoàn hảo với AniRena upload API — tạo file cục bộ rồi POST trực tiếp lên tracker. cantalupo555/torrent-builder.
Biên dịch từ mã nguồn
Yêu cầu CMake >= 3.28.3 và libtorrent-rasterbar >= 2.0.11. Clone repository và biên dịch với 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 .
Các cờ chính
| Trường | Mô tả |
|---|---|
--path | Đường dẫn đến file hoặc thư mục cần đóng gói (bắt buộc). |
--output | Tên file .torrent đầu ra (bắt buộc). |
--version | Định dạng BitTorrent — 1 = v1, 2 = v2, 3 = hybrid (mặc định: 3). |
--tracker | Thêm URL announce của tracker. Lặp lại cờ để thêm nhiều tracker. |
--comment | Nhúng chuỗi chú thích metadata vào torrent. |
--private | Đặt cờ private để giới hạn phân phối chỉ cho các tracker được liệt kê. |
--piece-size | Kích thước mảnh tính bằng KB (16-32768). Để trống để tự động chọn. |
-i | Khởi chạy chế độ cấu hình tương tác từng bước. |
Quy trình làm việc đầu cuối: build -> upload
Các ví dụ dưới đây tạo torrent hybrid với torrent-builder, sau đó xác thực với AniRena API và tải kết quả lên trong mộ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"]); }
Tìm kiếm metadata torrent
/api/v1/torrents/searchGửi yêu cầu POST JSON đơn giản để lấy danh sách torrent với các tùy chọn tìm kiếm và lọc tương tự trên website. File .torrent không được trả về — dùng route tải xuống thông thường cho điều đó.
# 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"]); }
Tham số tìm kiếm
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
q | string | Không | Tìm kiếm văn bản tự do. Hỗ trợ tiền tố group:slug, group:"Tên", user:tên. |
category | string | Không | Slug danh mục (vd. "anime"). |
sub_category | string | Không | Slug danh mục phụ (vd. "raw"). |
languages | string[] | Không | Mảng mã ngôn ngữ BCP 47 (vd. en, ja). |
sort | string | Không | Trường sắp xếp: date (mặc định), size, seeders, leechers, completed, title. |
order | string | Không | Hướng sắp xếp: desc (mặc định) hoặc asc. |
page | integer | Không | Số trang, bắt đầu từ 1 (mặc định 1). |
per_page | integer | Không | Kết quả mỗi trang, 1–250 (mặc định 50). |
hide_adult | boolean | Không | Loại trừ torrent danh mục người lớn. Mặc định true cho người dùng thông thường. |
show_dead | boolean | Không | Khi false (mặc định), các torrent cũ hơn khoảng thời gian gia hạn cho torrent chết và không có seeder hoạt động sẽ bị loại trừ. Đặt thành true để bao gồm chúng. |
Phản hồi
{
"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 — Số lượng bình luận chưa bị xóa trên torrent này.
Giới hạn tốc độ tìm kiếm
Yêu cầu tìm kiếm chịu giới hạn tốc độ có thể cấu hình riêng (mặc định 60 yêu cầu mỗi 60 giây mỗi khóa API). Vượt quá giới hạn trả về 429 Too Many Requests. Tài khoản nhân viên được miễn.
Lấy chi tiết torrent
/api/v1/torrent/{id}Lấy đầy đủ metadata cho một torrent đơn lẻ — bao gồm cả các trường mà endpoint tìm kiếm bỏ qua như mô tả Markdown, bình luận .torrent được nhúng, danh sách tệp với kích thước từng tệp, và toàn bộ bố cục tầng tracker. Khi có sẵn, số lượng seeder và leecher trực tiếp được đọc từ tracker.
Phản hồi
{
"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 — Số lượng trực tiếp từ tracker nội bộ; cả hai trả về 0 khi kho tracker không có mục cho info hash này hoặc không thể truy cập.
ext_seeders, ext_leechers — Số seeder và leecher cao nhất được báo cáo bởi bất kỳ tracker bên ngoài đơn lẻ nào đã scrape cho torrent này. Các tracker theo dõi cùng một swarm chồng chéo, vì vậy sử dụng giá trị tối đa thay vì tổng; cả hai trả về 0 khi không có tracker nào có dữ liệu scrape cho info hash này.
Phản hồi lỗi
| Trạng thái HTTP | Ý nghĩa |
|---|---|
400 | Id torrent phải là UUID 36 ký tự có dấu gạch ngang hoặc một chuỗi hex thuần 32 ký tự. |
401 | Bearer token bị thiếu, hết hạn hoặc đã được xoay. Xác thực lại qua POST /api/v1/auth/token. |
404 | Không tìm thấy torrent. |
429 | Đã vượt quá giới hạn tốc độ. Thử lại sau khi cửa sổ đặt lại. |
503 | Trang web đang bảo trì hoặc chế độ chỉ đọc. |
Lấy bình luận torrent
/api/v1/torrents/{id}/commentsLấy bình luận phân trang cho một torrent. Số bình luận mỗi trang được kiểm soát bởi cài đặt COMMENT_PER_PAGE trong file .env của máy chủ (mặc định 20). Chỉ các torrent có bình luận được bật mới trả về kết quả — tất cả các torrent khác trả về 403.
Tham số truy vấn
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
page | integer | Không | Số trang, bắt đầu từ 1 (mặc định 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"]); }
Phản hồi
{
"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
}
]
}Trường body là chuỗi rỗng khi tác giả bình luận bị cấm hoặc bình luận đã bị xóa. Cờ author_banned cho biết trường hợp nào áp dụng.
Phản hồi lỗi
| Trạng thái HTTP | Ý nghĩa |
|---|---|
401 | Bearer token bị thiếu, hết hạn hoặc đã được xoay. Xác thực lại qua POST /api/v1/auth/token. |
403 | Bình luận bị tắt cho torrent này. |
404 | Không tìm thấy torrent. |
503 | Trang web đang bảo trì hoặc chế độ chỉ đọc. |
Tìm kiếm mục anime
/api/v1/anime/search?q=<query>Tìm kiếm các mục anime theo tiêu đề để lấy UUID của chúng. UUID có thể được truyền dưới dạng anime_id trong nội dung tải lên để liên kết torrent với mục anime tại thời điểm tải lên, hoặc sử dụng với PUT /api/torrents/{id}/anime sau khi tải lên. Không cần xác thực. Chịu giới hạn tốc độ tương tự như tìm kiếm torrent (mặc định 60 yêu cầu mỗi 60 giây mỗi 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"]);
}Tham số truy vấn
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
q | string | Có | Chuỗi tìm kiếm tiêu đề (bắt buộc). Khớp với tiêu đề và từ đồng nghĩa. |
page | integer | Không | Số trang, bắt đầu từ 1 (mặc định 1). |
per_page | integer | Không | Kết quả mỗi trang, 1–50 (mặc định 10). |
Phản hồi
{
"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
}
]
}Liệt kê và lấy thông tin nhóm
/api/v1/groupsTrả về danh sách phân trang các nhóm công khai (đã bật và không bị khóa). Yêu cầu xác thực Bearer token.
/api/v1/groups/{id_or_slug}Trả về một nhóm công khai theo ID số hoặc slug. Trả về 404 nếu nhóm bị tắt hoặc bị khóa.
Tham số truy vấn (chỉ danh sách)
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
q | string | Không | Lọc theo tên nhóm (tùy chọn, khớp chuỗi con). |
page | integer | Không | Số trang (mặc định 1). |
per_page | integer | Không | Kết quả mỗi trang, 1–100 (mặc định 20). |
sort | string | Không | Cột sắp xếp: name | slug | members | torrents | created (mặc định name). |
order | string | Không | Hướng sắp xếp: asc hoặc desc (mặc định asc). |
Phản hồi (danh sách)
{
"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"
}
]
}Phản hồi (đơn lẻ)
{
"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"
}Phản hồi lỗi
| Trạng thái HTTP | Ý nghĩa |
|---|---|
401 | Bearer token bị thiếu, hết hạn hoặc đã được xoay. Xác thực lại qua POST /api/v1/auth/token. |
404 | Không tìm thấy nhóm hoặc không thể truy cập công khai. |
429 | Đã vượt quá giới hạn tốc độ. Thử lại sau khi cửa sổ đặt lại. |
503 | Trang web đang bảo trì hoặc chế độ chỉ đọc. |
8. Quyên góp
Nếu bạn muốn hỗ trợ AniRena và giúp trang trải chi phí lưu trữ máy chủ và dịch vụ của chúng tôi, bạn có thể gửi quyên góp đến một trong những ví tiền điện tử sau:
bc1qy2h3ddq6ak5damvnf4r5vu3ydehhxrcq8gllwn0xCbaFe03832F95F86AF2536d52710e78C63b62Cd33ucetj2XDGHQg9PVRPMxerNi7c6kX7GJkjQNg9yjwGegLbpt61yX3RjGtB1Ef8vgVz6Hr6baQsTjVkBất kỳ khoản quyên góp nào, dù lớn hay nhỏ, đều được đánh giá cao và đi trực tiếp vào việc duy trì hoạt động của AniRena. Cảm ơn sự ủng hộ của bạn!
9. Phần mềm
AniRena Player là một ứng dụng máy tính miễn phí cho phép bạn phát trực tiếp video từ các torrent được lập chỉ mục trên trang này — không cần đợi tải xuống hoàn tất. Chỉ cần dán liên kết magnet hoặc mở tệp .torrent, và quá trình phát sẽ bắt đầu ngay khi có đủ dữ liệu.
Cả hai bản đều hoàn toàn độc lập — mọi phụ thuộc đều được đóng gói bên trong tệp thực thi. Không cần trình cài đặt, không cần môi trường thực thi — chỉ cần tải xuống và chạy.
Trình cài đặt (.exe). Tự cập nhật trong ứng dụng.
Ảnh đĩa (.dmg) cho máy Mac Apple Silicon (M1 trở lên). Tự cập nhật trong ứng dụng.
Ảnh đĩa (.dmg) cho máy Mac Intel. Tự cập nhật trong ứng dụng.
Tệp đơn lẻ di động, không cần cài đặt. Định dạng Linux duy nhất có tự động cập nhật trong ứng dụng.
Cài đặt: sudo apt install ./<file>.deb — cập nhật qua apt hoặc tải xuống mới, không phải trong ứng dụng.
Cài đặt: sudo dnf install ./<file>.rpm — cập nhật qua dnf hoặc tải xuống mới, không phải trong ứng dụng.
Sideload trên thiết bị Android ARM 64-bit (hầu hết điện thoại / máy tính bảng hiện đại). Cập nhật bằng cách tải APK mới.
Phiên bản cũ
Cài đặt thủ công trên thiết bị Android ARM 32-bit (điện thoại / máy tính bảng cũ hơn). Cập nhật bằng cách tải xuống APK mới.