คู่มือ
1. เริ่มต้น
AniRena เป็นดัชนีทอร์เรนต์ที่เน้นอนิเมะ มังงะ เสียง และสื่อที่เกี่ยวข้อง คุณสามารถเรียกดูและดาวน์โหลดทอร์เรนต์โดยไม่ต้องมีบัญชี บัญชีจำเป็นสำหรับการอัปโหลดทอร์เรนต์ โพสต์ในกลุ่ม หรือใช้ API
แถบนำทางด้านบนให้เข้าถึงพื้นที่หลักของเว็บไซต์:
- หน้าแรก — หน้ารายการและค้นหาทอร์เรนต์
- อัปโหลด — ส่งทอร์เรนต์ใหม่ (ต้องเข้าสู่ระบบ)
- คู่มือ — หน้านี้
- สถิติ — สถิติทั่วเว็บไซต์
- กลุ่ม — ไดเรกทอรีกลุ่มปล่อย
- RSS — ฟีด RSS ของการอัปโหลดล่าสุด
เมนูบัญชีของคุณ (มุมขวาบนเมื่อเข้าสู่ระบบ) เปิดแผงโปรไฟล์สำหรับปรับการตั้งค่าและจัดการตัวเลือกความปลอดภัย
2. การเรียกดูและค้นหา
หน้าแรกแสดงทอร์เรนต์ทั้งหมดเรียงตามวันที่อัปโหลด ใช้แถบค้นหาด้านบนเพื่อกรองผลลัพธ์
การค้นหาขั้นพื้นฐาน
พิมพ์คำใดก็ได้ในแถบค้นหาแล้วกด Enter (หรือคลิกไอคอนค้นหา)
ตัวดำเนินการค้นหา
ตัวดำเนินการต่อไปนี้สามารถใช้ร่วมกับคำค้นหาปกติ:
| ตัวดำเนินการ | ตัวอย่าง | ผล |
|---|---|---|
user:"name" | user:"SubsPlease" | แสดงเฉพาะทอร์เรนต์ที่อัปโหลดโดยผู้ใช้นั้น |
การคลิกชื่อผู้อัปโหลดในรายการทอร์เรนต์จะค้นหาผู้ใช้นั้นโดยอัตโนมัติ
หมวดหมู่และหมวดหมู่ย่อย
ใช้ตัวเลือกหมวดหมู่เพื่อจำกัดผลลัพธ์เป็นหมวดหมู่เดียว
- อนิเมะ
- มังงะ/มันฮวา/การ์ตูน
- เสียง
- วรรณกรรม
- Live Action
- รูปภาพ
- ซอฟต์แวร์
- Hentai
- อื่นๆ
แต่ละหมวดหมู่มีหมวดหมู่ย่อย
การเรียงและกรอง
ส่วนหัวคอลัมน์สามารถคลิกเพื่อเรียงตามคอลัมน์นั้น หมายเหตุ: จำนวน seeders และ leechers มาจาก Redis แบบเรียลไทม์ ไม่สามารถใช้ในการเรียงลำดับได้
ตัวกรองภาษา
ใช้ตัวเลือกภาษาเพื่อแสดงเฉพาะทอร์เรนต์ที่ติดแท็กด้วยภาษาที่ระบุ
ฟีด RSS
ฟีด RSS ที่ /rss ให้การอัปโหลดล่าสุด ต่อท้าย ?category=anime เพื่อกรองฟีด
3. การดาวน์โหลดทอร์เรนต์
คลิกชื่อทอร์เรนต์เพื่อเปิดแผงรายละเอียด จากที่นั้นคุณสามารถ:
- ดาวน์โหลด .torrent — บันทึกไฟล์ .torrent โดยตรง URL โดยตรงคือ
/torrents/{id}.torrent - ลิงก์แม่เหล็ก — เปิดโดยตรงในโปรแกรมทอร์เรนต์ผ่านโปรโตคอล magnet URI URL คือ
/torrents/{id}/magnet
แผงรายละเอียดยังแสดงคำอธิบาย รายการไฟล์ รายการตัวติดตาม และจำนวนซีดเดอร์/ลีชเชอร์
ลิงก์ดาวน์โหลดเดิม
ลิงก์ดาวน์โหลด AniRena เดิมยังคงรองรับและเปลี่ยนเส้นทางอัตโนมัติ /dl/{old_id}
ไคลเอนต์ BitTorrent ที่แนะนำ
ไคลเอนต์ BitTorrent สมัยใหม่ใดก็ได้ใช้งานได้ ไคลเอนต์ด้านล่างนี้แนะนำและรองรับ BitTorrent v2 / ทอร์เรนต์แบบไฮบริดอย่างสมบูรณ์:
4. การสร้างบัญชี
การลงทะเบียน
คลิก สมัครสมาชิก ในแถบนำทาง เลือกชื่อผู้ใช้ ป้อนอีเมล และตั้งรหัสผ่าน
การเปิดใช้งานอีเมล
หลังสมัคร อีเมลยืนยันจะถูกส่งไปยังที่อยู่ของคุณ คลิกลิงก์ในอีเมลเพื่อเปิดใช้งานบัญชี
การกู้คืนรหัสผ่าน
หากลืมรหัสผ่าน คลิก ลืมรหัสผ่าน ในหน้าเข้าสู่ระบบและป้อนอีเมล
5. การอัปโหลดทอร์เรนต์
ไปที่ อัปโหลด ในแถบนำทาง คุณต้องเข้าสู่ระบบด้วยบัญชีที่ใช้งานได้
แท็บอัปโหลด — ส่งไฟล์ .torrent ที่มีอยู่
ลากและวางหรือเลือกไฟล์ .torrent
| ช่อง | จำเป็น | คำอธิบาย |
|---|---|---|
| ไฟล์ทอร์เรนต์ | ใช่ | ไฟล์ .torrent ที่จะอัปโหลด |
| ชื่อ | ไม่ | แทนที่ชื่อแสดงผลของทอร์เรนต์ |
| หมวดหมู่ | ใช่ | หมวดหมู่เนื้อหา (อนิเมะ มังงะ เสียง ฯลฯ) |
| หมวดหมู่ย่อย | ไม่ | ประเภทเฉพาะเจาะจงภายในหมวดหมู่ |
| ภาษา | ไม่ | แท็กภาษาหนึ่งหรือมากกว่า |
| กลุ่ม | ไม่ | เชื่อมโยงการปล่อยนี้กับกลุ่มที่คุณเป็นสมาชิก |
| คำอธิบาย | ไม่ | คำอธิบายรูปแบบ Markdown (สูงสุด 65535 ตัวอักษร) |
| ส่วนตัว | ไม่ | ตั้งแฟล็กส่วนตัวในทอร์เรนต์ ปิดใช้ DHT/PEX |
| URL ประกาศ | ไม่ | แทนที่หรือเพิ่ม URL ประกาศตัวติดตามหลัก |
| ตัวติดตามเพิ่มเติม | ไม่ | อ่านจากไฟล์ทอร์เรนต์ ไม่สามารถแก้ไขได้ระหว่างการอัปโหลด — ใช้แท็บสร้างหากต้องการปรับแต่งรายการทราคเกอร์ |
| ความคิดเห็น | ไม่ | แทนที่ช่องความคิดเห็นที่ฝังในไฟล์ |
ทอร์เรนต์ของคุณต้องมี URL ทราคเกอร์ AniRena อย่างน้อยหนึ่งรายการในรายการประกาศ (tier ใดก็ได้) เว็บไซต์จะตรวจสอบสิ่งนี้เมื่ออัปโหลดและจะปฏิเสธทอร์เรนต์ที่ไม่มีทราคเกอร์ AniRena หากคุณสร้างทอร์เรนต์โดยไม่ได้เพิ่มทราคเกอร์ AniRena ก่อน ให้อัปโหลดและดาวน์โหลดใหม่จากเว็บไซต์ — ไฟล์ที่ดาวน์โหลดจะมีทราคเกอร์ที่ถูกต้องโดยอัตโนมัติ
แท็บสร้าง — สร้างทอร์เรนต์ใหม่
แท็บสร้างช่วยให้คุณสร้าง .torrent ใหม่จากศูนย์
การกลั่นกรอง
การอัปโหลดจะถูกตรวจสอบกับรูปแบบเนื้อหาต้องห้าม ทอร์เรนต์ซ้ำก็จะถูกปฏิเสธด้วย
6. บัญชีของคุณ
คลิกชื่อผู้ใช้ที่มุมขวาบนเพื่อเปิดแผงโปรไฟล์
การตั้งค่า
เปลี่ยนธีม UI ขนาดตัวอักษร ชุดสี ภาษาอินเทอร์เฟส และการตั้งค่าการแสดงผล
รหัสผ่าน
ป้อนรหัสผ่านปัจจุบันและรหัสผ่านใหม่สองครั้ง รหัสยืนยันจะถูกส่งไปยังอีเมลที่ลงทะเบียน
การยืนยันสองขั้นตอน (2FA)
เปิดใช้การยืนยันสองขั้นตอนผ่าน TOTP โดยใช้แอปยืนยันใดก็ได้
- สแกน QR code (หรือป้อนรหัสลับด้วยตนเอง) ในแอปยืนยัน
- ป้อนรหัส 6 หลักที่แสดงในแอปเพื่อยืนยันการตั้งค่า
- บันทึกรหัสกู้คืนที่แสดง — รหัสเหล่านี้ใช้ครั้งเดียวเพื่อกู้คืนการเข้าถึง
ในการปิดใช้ 2FA ให้ป้อนรหัส TOTP ปัจจุบันและยืนยัน
เซสชันที่ใช้งานอยู่
ดูเซสชันเข้าสู่ระบบที่ใช้งานอยู่ทั้งหมด รวมถึงเบราว์เซอร์ ระบบปฏิบัติการ ที่อยู่ IP และเวลาที่เห็นล่าสุด
คีย์ API
สร้างคีย์ API ส่วนตัวสำหรับอัปโหลดทอร์เรนต์ผ่านโปรแกรม
ลบบัญชี
การขอลบบัญชีเริ่มต้นระยะเวลา 30 วัน บัญชีของคุณจะถูกปิดใช้งานทันทีและถูกลบอย่างถาวรหลังจาก 30 วัน
7. API ของ AniRena
AniRena มี JSON API สำหรับอัปโหลดทอร์เรนต์ผ่านโปรแกรมโดยใช้คีย์ API ส่วนตัว
การยืนยันตัวตน
API ใช้กระบวนการยืนยันตัวตนสองขั้นตอน ขั้นแรกแลก API key ถาวรของคุณกับ bearer token อายุสั้น จากนั้นส่ง token นั้นในส่วนหัว Authorization ของทุก API request
API key ของคุณอยู่ที่บัญชีของคุณ > API key เก็บเป็นความลับ — ใครก็ตามที่มี key สามารถรับ bearer token และอัปโหลดในนามคุณได้ หากถูกเปิดเผย ให้ยกเลิกทันทีและสร้างใหม่
ขั้นตอนที่ 1 — รับ bearer token
/api/v1/auth/tokenส่ง POST request ไปยัง token endpoint พร้อม API key ของคุณในส่วนหัว Authorization ไม่ต้องการ request body
Authorization: ApiKey <your-api-key>
การตอบกลับ token
{
"token": "<bearer-token>",
"token_type": "Bearer",
"expires_in": 3600
}อายุของโทเค็น
โทเค็น Bearer ยังคงใช้งานได้นานสูงสุด 3600 วินาทีนับจากเวลาที่ออก และสามารถนำกลับมาใช้ในทุกการเรียกใช้จนกว่าจะหมดอายุ เมื่อโทเค็นหมดอายุ ให้สร้างโทเค็นใหม่ผ่าน POST /api/v1/auth/token แต่ละการตอบกลับยังคงคืนค่าโทเค็นปัจจุบันในส่วนหัว X-New-Token เพื่อความเข้ากันได้กับเวอร์ชันก่อนหน้า
X-New-Token: <next-bearer-token>
เข้าสู่ระบบในคำขอเดียว (รองรับ 2FA)
/api/v1/auth/loginยืนยันตัวตนด้วยชื่อผู้ใช้หรืออีเมลและรหัสผ่านในคำขอเดียวและรับ bearer token โดยตรง หากบัญชีของคุณเปิดใช้ 2FA ให้ใส่รหัสจากแอป Authenticator ปัจจุบันใน totp_code (หรือรหัสกู้คืนใน recovery_code) คุณสามารถตั้งค่า new_api_key เป็น true เพื่อสร้างคีย์ API ถาวรใหม่ในคำตอบเดียวกันได้
เนื้อหาคำขอ
{
"login": "username or email",
"password": "your-password",
"totp_code": "123456", // จำเป็นหากเปิดใช้ 2FA (6 หลัก)
"recovery_code": "", // ทางเลือกแทน totp_code
"new_api_key": false // ตั้งเป็น true เพื่อสร้างคีย์ API ใหม่ด้วย
}การตอบกลับ token
{
"ok": true,
"token": "<bearer-token>",
"token_type": "Bearer",
"expires_in": 3600,
"api_key": "<new-api-key>" // มีอยู่เฉพาะเมื่อ new_api_key เป็น true
}bearer token ทำงานเหมือนกับที่ได้จาก /api/v1/auth/token ทุกประการ ฟิลด์ api_key จะถูกส่งกลับเฉพาะเมื่อ new_api_key เป็น true — โปรดบันทึกทันที เพราะจะแสดงเพียงครั้งเดียวและจะแทนที่คีย์เดิมทั้งหมด
ตัวอย่าง — เข้าสู่ระบบและ (ทางเลือก) รับคีย์ API ใหม่
# 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}"); } }
ขั้นตอนที่ 2 — อัปโหลด torrent
/api/v1/torrentsส่ง JSON POST request ธรรมดาพร้อม bearer token ในส่วนหัว Authorization
เนื้อหาคำขอ
| ช่อง | ประเภท | จำเป็น | คำอธิบาย |
|---|---|---|---|
torrent | string | ใช่ | เนื้อหาไฟล์ .torrent เข้ารหัส Base64 |
category | string | ใช่ | slug หมวดหมู่: anime, manga, audio, literature, live, pictures, software, hentai, other |
name | string | ไม่ | แทนที่ชื่อแสดงผลของทอร์เรนต์ |
sub_category | string | ไม่ | slug หมวดหมู่ย่อย (เช่น raw, sub-audio) |
languages | string[] | ไม่ | อาร์เรย์รหัสภาษา BCP 47 (เช่น en, ja) |
group_id | string | ไม่ | UUID ของกลุ่มที่คุณเป็นสมาชิก |
description | string | ไม่ | คำอธิบายรูปแบบ Markdown (สูงสุด 65535 ตัวอักษร) |
comment | string | ไม่ | แทนที่ช่องความคิดเห็นที่ฝังในทอร์เรนต์ |
is_private | boolean | ไม่ | ตั้งเป็น true เพื่อเปิดใช้แฟล็กส่วนตัว |
comments_enabled | boolean | ไม่ | อนุญาตให้แสดงความคิดเห็นบนทอร์เรนต์นี้ ค่าเริ่มต้นคือ true (เปิดใช้งาน) |
anime_id | string | ไม่ | UUID ของรายการอนิเมะที่จะเชื่อมโยงกับทอร์เรนต์นี้ รับ UUID ผ่าน GET /api/v1/anime/search คืนค่า 400 หาก UUID ไม่ตรงกับรายการที่รู้จัก |
announce | string | ไม่ | แทนที่หรือเพิ่ม URL ประกาศหลัก |
trackers | string | ไม่ | รายการ URL ตัวติดตามเพิ่มเติมคั่นด้วยบรรทัดใหม่ |
test | boolean | ไม่ | ตั้งค่าเป็น true เพื่อทำการทดสอบแบบไม่บันทึก: คำขอจะถูกตรวจสอบอย่างสมบูรณ์แต่ไม่มีการบันทึกทอร์เรนต์ ใช้สิ่งนี้เพื่อตรวจสอบว่าข้อมูลของคุณถูกต้องก่อนส่งจริง |
การตอบสนองความสำเร็จแบบไม่บันทึก — 200 OK
{
"ok": true,
"test": true,
"name": "My Torrent Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null
}รหัสภาษาที่ใช้ได้
abaaafaksqamarar-001anhyasavaeayazbmbaeubebnbhbibsbrbgmyyuecachcenyzhzh-HKzh-Hanszh-SGzh-TWcucvkwcocrhrcsdadvnlnl-BEdzenen-USeoeteefofjfilfifrfr-CAffgllgkadede-ATelgnguhthahehzhihohuisioigidiaieiuikgaitjajvklknkrkskkkmkirwrnkvkgkokjkukylolalvlilnltlulbmkmgmsmlmtgvmimrmhmnnanvngnendsenonbnnocorojomospipsfaplptpt-BRpaqurormrusmsgsascgdsrsr-Latnsniisdsiskslsonrsteses-419es-MXsuswsssvtltytgtatttethbotitotstntrtktwukuruguzvevivowacyfywoxhyiyozazuตัวอย่างคำขอ
# 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 }
การตอบกลับสำเร็จ — 200 OK
{
"ok": true,
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Torrent Title",
"info_hash_v1": "aabbccddeeff...",
"info_hash_v2": null
}การตอบกลับข้อผิดพลาด
| สถานะ HTTP | ความหมาย |
|---|---|
400 | เนื้อหาคำขอไม่ถูกต้องหรือขาดช่องที่จำเป็น |
401 | Bearer token หายไป หมดอายุ หรือหมุนเวียนแล้ว ยืนยันตัวตนใหม่ผ่าน POST /api/v1/auth/token |
403 | บัญชีถูกแบน ปิดใช้งาน หรือ IP ถูกบล็อก |
409 | ทอร์เรนต์ซ้ำ — info hash เดียวกันมีอยู่แล้ว |
422 | ไม่สามารถแยกวิเคราะห์ไฟล์ทอร์เรนต์หรือผ่านการตรวจสอบล้มเหลว |
429 | เกินขีดจำกัด ลองใหม่หลังหน้าต่างรีเซ็ต |
503 | เว็บไซต์อยู่ในโหมดบำรุงรักษาหรืออ่านอย่างเดียว |
การจำกัดอัตรา
การอัปโหลด API อยู่ภายใต้การจำกัดอัตราที่ตั้งค่าได้แยกจากอินเทอร์เฟซเว็บ
สร้างไฟล์ทอร์เรนต์ด้วย torrent-builder
torrent-builder เป็นเครื่องมือ CLI โอเพนซอร์สที่สร้างบน libtorrent-rasterbar ช่วยให้คุณสร้างไฟล์ .torrent แบบ BitTorrent v1, v2 และ hybrid จากบรรทัดคำสั่ง เข้ากันได้อย่างสมบูรณ์แบบกับ AniRena upload API — สร้างไฟล์ในเครื่องแล้ว POST ตรงไปยัง tracker cantalupo555/torrent-builder.
สร้างจากซอร์สโค้ด
ต้องการ CMake >= 3.28.3 และ libtorrent-rasterbar >= 2.0.11 โคลน repository แล้วสร้างด้วย 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 .
ค่าสถานะหลัก
| ช่อง | คำอธิบาย |
|---|---|
--path | เส้นทางไปยังไฟล์หรือไดเรกทอรีที่จะบรรจุ (จำเป็น) |
--output | ชื่อไฟล์ .torrent ที่ส่งออก (จำเป็น) |
--version | รูปแบบ BitTorrent — 1 = v1, 2 = v2, 3 = hybrid (ค่าเริ่มต้น: 3) |
--tracker | เพิ่ม URL ประกาศ tracker ทำซ้ำค่าสถานะเพื่อเพิ่มหลาย tracker |
--comment | ฝังสตริงความคิดเห็นเมทาดาทาลงในทอร์เรนต์ |
--private | ตั้งค่าสถานะส่วนตัวเพื่อจำกัดการแจกจ่ายเฉพาะ tracker ที่ระบุไว้เท่านั้น |
--piece-size | ขนาดชิ้นส่วนเป็น KB (16-32768) เว้นไว้โดยไม่ตั้งค่าสำหรับการเลือกอัตโนมัติ |
-i | เปิดโหมดการตั้งค่าแบบโต้ตอบทีละขั้นตอน |
เวิร์กโฟลว์แบบครบวงจร: สร้าง -> อัปโหลด
ตัวอย่างด้านล่างสร้างทอร์เรนต์ hybrid ด้วย torrent-builder จากนั้นยืนยันตัวตนกับ AniRena API และอัปโหลดผลลัพธ์ในสคริปต์เดียว
# 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"]); }
การค้นหาข้อมูลเมตาทอร์เรนต์
/api/v1/torrents/searchส่ง JSON POST request ธรรมดาเพื่อดึงรายการ torrent ด้วยตัวเลือกการค้นหาและกรองเดียวกันกับที่มีอยู่ในเว็บไซต์ ไฟล์ .torrent เองจะไม่ถูกส่งกลับ — ใช้ route ดาวน์โหลดปกติสำหรับสิ่งนั้น
# 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"]); }
พารามิเตอร์การค้นหา
| ช่อง | ประเภท | จำเป็น | คำอธิบาย |
|---|---|---|---|
q | string | ไม่ | การค้นหาข้อความอิสระ รองรับ group:slug, group:"Name", user:name |
category | string | ไม่ | slug หมวดหมู่ (เช่น "anime") |
sub_category | string | ไม่ | slug หมวดหมู่ย่อย (เช่น "raw") |
languages | string[] | ไม่ | อาร์เรย์รหัสภาษา BCP 47 (เช่น en, ja) |
sort | string | ไม่ | ช่องเรียง: date (ค่าเริ่มต้น), size, seeders, leechers, completed, title |
order | string | ไม่ | ทิศทางเรียง: desc (ค่าเริ่มต้น) หรือ asc |
page | integer | ไม่ | หมายเลขหน้า เริ่มที่ 1 |
per_page | integer | ไม่ | ผลลัพธ์ต่อหน้า 1–250 |
hide_adult | boolean | ไม่ | ยกเว้นทอร์เรนต์หมวดผู้ใหญ่ |
show_dead | boolean | ไม่ | เมื่อเป็น false (ค่าเริ่มต้น) ทอร์เรนต์ที่เก่ากว่าระยะผ่อนผันสำหรับทอร์เรนต์ที่ตายแล้วและไม่มี seeder ที่ใช้งานอยู่จะถูกตัดออก ตั้งเป็น true เพื่อรวมไว้ |
การตอบกลับ
{
"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 — จำนวนความคิดเห็นที่ยังไม่ถูกลบในทอร์เรนต์นี้
การจำกัดอัตราการค้นหา
คำขอค้นหาอยู่ภายใต้การจำกัดอัตราที่ตั้งค่าได้แยกต่างหาก (ค่าเริ่มต้น 60 คำขอต่อ 60 วินาทีต่อคีย์ API)
รับรายละเอียดทอร์เรนต์
/api/v1/torrent/{id}ดึงข้อมูลเมตาฉบับสมบูรณ์ของทอร์เรนต์เดี่ยว — รวมถึงฟิลด์ที่จุดสิ้นสุดการค้นหาไม่ส่งคืน เช่น คำอธิบาย Markdown ความคิดเห็น .torrent ที่ฝังอยู่ รายการไฟล์พร้อมขนาดต่อไฟล์ และเลย์เอาต์ระดับแทร็กเกอร์ทั้งหมด เมื่อมีข้อมูลจะอ่านจำนวน seeder และ leecher แบบสดจากแทร็กเกอร์
การตอบกลับ
{
"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 — จำนวนแบบสดจากแทร็กเกอร์ภายใน ทั้งสองรายงานเป็น 0 เมื่อที่เก็บแทร็กเกอร์ไม่มีรายการสำหรับ info hash นี้หรือเข้าถึงไม่ได้
ext_seeders, ext_leechers — จำนวน seeder และ leecher สูงสุดที่รายงานโดยแทร็กเกอร์ภายนอกใด ๆ ที่ scrape สำหรับทอร์เรนต์นี้ แทร็กเกอร์ที่ติดตาม swarm เดียวกันจะซ้อนทับกัน จึงใช้ค่าสูงสุดแทนผลรวม ทั้งสองรายงานเป็น 0 เมื่อไม่มีแทร็กเกอร์ใดมีข้อมูล scrape สำหรับ info hash นี้
การตอบกลับข้อผิดพลาด
| สถานะ HTTP | ความหมาย |
|---|---|
400 | รหัสทอร์เรนต์ต้องเป็น UUID 36 ตัวอักษรพร้อมเครื่องหมายขีดกลาง หรือสตริงเลขฐานสิบหก 32 ตัวอักษร |
401 | Bearer token หายไป หมดอายุ หรือหมุนเวียนแล้ว ยืนยันตัวตนใหม่ผ่าน POST /api/v1/auth/token |
404 | ไม่พบทอร์เรนต์ |
429 | เกินขีดจำกัด ลองใหม่หลังหน้าต่างรีเซ็ต |
503 | เว็บไซต์อยู่ในโหมดบำรุงรักษาหรืออ่านอย่างเดียว |
ดึงความคิดเห็นทอร์เรนต์
/api/v1/torrents/{id}/commentsดึงความคิดเห็นแบบแบ่งหน้าสำหรับทอร์เรนต์ จำนวนความคิดเห็นต่อหน้าถูกควบคุมโดยการตั้งค่า COMMENT_PER_PAGE ในไฟล์ .env ของเซิร์ฟเวอร์ (ค่าเริ่มต้น 20) เฉพาะทอร์เรนต์ที่เปิดใช้งานความคิดเห็นเท่านั้นที่จะคืนผลลัพธ์ — ส่วนอื่นทั้งหมดคืน 403
พารามิเตอร์คิวรี
| ช่อง | ประเภท | จำเป็น | คำอธิบาย |
|---|---|---|---|
page | integer | ไม่ | หมายเลขหน้า เริ่มต้นที่ 1 (ค่าเริ่มต้น 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"]); }
การตอบกลับ
{
"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
}
]
}ช่อง body เป็นสตริงว่างเมื่อผู้เขียนความคิดเห็นถูกแบนหรือความคิดเห็นถูกลบ ค่าสถานะ author_banned ระบุว่ากรณีใดใช้บังคับ
การตอบกลับข้อผิดพลาด
| สถานะ HTTP | ความหมาย |
|---|---|
401 | Bearer token หายไป หมดอายุ หรือหมุนเวียนแล้ว ยืนยันตัวตนใหม่ผ่าน POST /api/v1/auth/token |
403 | ความคิดเห็นถูกปิดใช้งานสำหรับทอร์เรนต์นี้ |
404 | ไม่พบทอร์เรนต์ |
503 | เว็บไซต์อยู่ในโหมดบำรุงรักษาหรืออ่านอย่างเดียว |
ค้นหารายการอนิเมะ
/api/v1/anime/search?q=<query>ค้นหารายการอนิเมะตามชื่อเรื่องเพื่อรับ UUID ของรายการนั้น UUID สามารถส่งเป็น anime_id ในเนื้อหาการอัปโหลดเพื่อเชื่อมโยงทอร์เรนต์กับรายการอนิเมะในขณะอัปโหลด หรือใช้กับ PUT /api/torrents/{id}/anime หลังการอัปโหลด ไม่จำเป็นต้องมีการตรวจสอบสิทธิ์ อยู่ภายใต้ขีดจำกัดอัตราเดียวกับการค้นหาทอร์เรนต์ (ค่าเริ่มต้น 60 คำขอต่อ 60 วินาทีต่อ 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"]);
}พารามิเตอร์คำค้นหา
| ช่อง | ประเภท | จำเป็น | คำอธิบาย |
|---|---|---|---|
q | string | ใช่ | สตริงค้นหาชื่อเรื่อง (จำเป็น) จับคู่กับชื่อเรื่องและคำพ้องความหมาย |
page | integer | ไม่ | หมายเลขหน้า เริ่มที่ 1 |
per_page | integer | ไม่ | ผลลัพธ์ต่อหน้า 1–50 |
การตอบสนอง
{
"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
}
]
}แสดงรายการและดึงข้อมูลกลุ่ม
/api/v1/groupsส่งคืนรายการกลุ่มสาธารณะแบบแบ่งหน้า (เปิดใช้งานและไม่ถูกล็อก) ต้องมีการยืนยันตัวตน Bearer token
/api/v1/groups/{id_or_slug}ส่งคืนกลุ่มสาธารณะเดียวตาม ID ตัวเลขหรือ slug คืน 404 หากกลุ่มถูกปิดใช้งานหรือถูกล็อก
พารามิเตอร์คำค้นหา (รายการเท่านั้น)
| ช่อง | ประเภท | จำเป็น | คำอธิบาย |
|---|---|---|---|
q | string | ไม่ | กรองตามชื่อกลุ่ม (ไม่บังคับ จับคู่สตริงย่อย) |
page | integer | ไม่ | หมายเลขหน้า (ค่าเริ่มต้น 1) |
per_page | integer | ไม่ | ผลลัพธ์ต่อหน้า 1–100 (ค่าเริ่มต้น 20) |
sort | string | ไม่ | คอลัมน์การเรียงลำดับ: name | slug | members | torrents | created (ค่าเริ่มต้น name) |
order | string | ไม่ | ทิศทางการเรียงลำดับ: asc หรือ desc (ค่าเริ่มต้น asc) |
การตอบสนอง (รายการ)
{
"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"
}
]
}การตอบสนอง (เดี่ยว)
{
"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"
}การตอบกลับข้อผิดพลาด
| สถานะ HTTP | ความหมาย |
|---|---|
401 | Bearer token หายไป หมดอายุ หรือหมุนเวียนแล้ว ยืนยันตัวตนใหม่ผ่าน POST /api/v1/auth/token |
404 | ไม่พบกลุ่มหรือไม่สามารถเข้าถึงได้สาธารณะ |
429 | เกินขีดจำกัด ลองใหม่หลังหน้าต่างรีเซ็ต |
503 | เว็บไซต์อยู่ในโหมดบำรุงรักษาหรืออ่านอย่างเดียว |
8. การบริจาค
หากคุณต้องการสนับสนุน AniRena และช่วยครอบคลุมค่าใช้จ่ายในการโฮสต์เซิร์ฟเวอร์และบริการของเรา คุณสามารถส่งการบริจาคไปยังกระเป๋าเงินคริปโตใดกระเป๋าหนึ่งต่อไปนี้:
bc1qy2h3ddq6ak5damvnf4r5vu3ydehhxrcq8gllwn0xCbaFe03832F95F86AF2536d52710e78C63b62Cd33ucetj2XDGHQg9PVRPMxerNi7c6kX7GJkjQNg9yjwGegLbpt61yX3RjGtB1Ef8vgVz6Hr6baQsTjVkการบริจาคใดๆ ไม่ว่าจะมากหรือน้อย ล้วนได้รับการชื่นชมอย่างยิ่งและนำไปใช้โดยตรงในการดำเนินงาน AniRena ขอบคุณสำหรับการสนับสนุนของคุณ!
9. ซอฟต์แวร์
AniRena Player เป็นแอปเดสก์ท็อปฟรีที่ให้คุณสตรีมวิดีโอได้โดยตรงจากทอร์เรนต์ที่ถูกจัดทำดัชนีในเว็บไซต์นี้ — โดยไม่ต้องรอให้ดาวน์โหลดเสร็จสมบูรณ์ เพียงวางลิงก์ magnet หรือเปิดไฟล์ .torrent การเล่นจะเริ่มทันทีที่มีข้อมูลเพียงพอ
ทั้งสองรุ่นทำงานได้แบบสแตนด์อโลนอย่างสมบูรณ์ — การพึ่งพาทั้งหมดถูกรวมอยู่ในไฟล์ปฏิบัติการแล้ว ไม่ต้องติดตั้ง ไม่ต้องตั้งค่ารันไทม์ แค่ดาวน์โหลดและรัน
ตัวติดตั้ง (.exe) อัปเดตตัวเองภายในแอป
ดิสก์อิมเมจ (.dmg) สำหรับ Mac ที่ใช้ Apple Silicon (M1 ขึ้นไป) อัปเดตตัวเองภายในแอป
ดิสก์อิมเมจ (.dmg) สำหรับ Mac ที่ใช้ Intel อัปเดตตัวเองภายในแอป
ไฟล์เดียวพกพาได้ ไม่ต้องติดตั้ง รูปแบบเดียวบน Linux ที่อัปเดตอัตโนมัติภายในแอปได้
ติดตั้ง: sudo apt install ./<file>.deb — อัปเดตผ่าน apt หรือดาวน์โหลดใหม่ ไม่ใช่ภายในแอป
ติดตั้ง: sudo dnf install ./<file>.rpm — อัปเดตผ่าน dnf หรือดาวน์โหลดใหม่ ไม่ใช่ภายในแอป
ติดตั้งด้วยตนเองบนอุปกรณ์ Android ARM 64 บิต (โทรศัพท์ / แท็บเล็ตรุ่นใหม่ส่วนใหญ่) อัปเดตโดยดาวน์โหลด APK ใหม่
เวอร์ชันเก่า
ติดตั้งด้วยตนเองบนอุปกรณ์ Android ARM 32 บิต (โทรศัพท์ / แท็บเล็ตรุ่นเก่า) อัปเดตโดยดาวน์โหลด APK ใหม่