دليل
1. البدء
AniRena هو فهرس تورنت يركّز على الأنمي والمانغا والصوتيات والوسائط ذات الصلة. يمكنك تصفح التورنتات وتنزيلها بدون حساب. يلزم وجود حساب لرفع التورنتات أو النشر في المجموعات أو استخدام واجهة برمجة التطبيقات.
شريط التنقل في الأعلى يوفر الوصول إلى المناطق الرئيسية للموقع:
- الرئيسية — صفحة قائمة التورنتات والبحث.
- رفع — إرسال تورنت جديد (يتطلب تسجيل الدخول).
- دليل — هذه الصفحة.
- إحصائيات — إحصائيات الموقع الكاملة (التورنتات والمستخدمون وعمليات الرفع عبر الزمن).
- مجموعات — دليل مجموعات الإصدار.
- RSS — خلاصة RSS لأحدث عمليات الرفع، قابلة للتصفية حسب الفئة.
قائمة حسابك (الزاوية العلوية اليمنى عند تسجيل الدخول) تفتح لوحة الملف الشخصي حيث يمكنك ضبط الإعدادات وإدارة خيارات الأمان والوصول إلى مفتاح API.
2. التصفح والبحث
تعرض الصفحة الرئيسية جميع التورنتات مرتبةً حسب تاريخ الرفع. استخدم شريط البحث في الأعلى لتصفية النتائج.
البحث الأساسي
اكتب أي كلمات في شريط البحث واضغط Enter (أو انقر على أيقونة البحث). يتم ترتيب النتائج حسب الصلة عند تفعيل استعلام.
عوامل البحث
يمكن دمج العوامل التالية مع استعلام منتظم:
| العامل | مثال | التأثير |
|---|---|---|
user:"name" | user:"SubsPlease" | عرض التورنتات المرفوعة بواسطة ذلك المستخدم فقط. |
النقر على اسم الرافع في قائمة التورنتات يشغّل تلقائياً بحث المستخدم.
الفئات والفئات الفرعية
استخدم محدد الفئة (أيقونة الشبكة بجانب شريط البحث) لتقييد النتائج بفئة واحدة. الفئات المتاحة هي:
- أنمي
- مانغا/مانهوا/كوميك
- صوتيات
- أدب
- عروض حية
- صور
- برامج
- هنتاي
- أخرى
كل فئة لها فئات فرعية (مثل الأنمي إلى RAW وSub/Audio وفيديو موسيقي) قابلة للاختيار داخل مربع حوار الفئة.
الترتيب والفلاتر
رؤوس أعمدة قائمة التورنتات قابلة للنقر للترتيب حسب تلك العمود (تصاعدي أو تنازلي). أعمدة الترتيب المتاحة: التاريخ والاسم والحجم وعمليات التنزيل المكتملة. ملاحظة: المبذرون والمنزلون قيم حية من Redis ولا يمكن استخدامها للترتيب.
فلتر اللغة
استخدم محدد اللغة (أيقونة العلم) لعرض التورنتات المُعلَّمة بلغة محددة فقط.
خلاصة RSS
توفر خلاصة RSS على /rss أحدث عمليات الرفع. أضف ?category=anime (أو أي slug فئة آخر) لتصفية الخلاصة. معظم برامج تورنت تدعم التنزيل التلقائي عبر RSS مباشرةً من هذا العنوان URL.
3. تنزيل التورنتات
انقر على أي اسم تورنت لفتح لوحة التفاصيل. من هناك يمكنك:
- تنزيل .torrent — يحفظ ملف .torrent مباشرةً. عنوان URL المباشر هو
/torrents/{id}.torrent - الرابط المغناطيسي — يفتح مباشرةً في برنامج التورنت الخاص بك عبر بروتوكول URI المغناطيسي. العنوان هو
/torrents/{id}/magnet
تعرض لوحة التفاصيل أيضاً وصف التورنت وقائمة الملفات وقائمة المتتبعات وعدد المبذرين والمنزلين.
روابط التنزيل القديمة
روابط تنزيل AniRena القديمة لا تزال مدعومة وتعيد التوجيه تلقائياً إلى ملف .torrent الصحيح باستخدام المعرّف القديم: /dl/{old_id}
عملاء BitTorrent الموصى بهم
أي عميل BitTorrent حديث يعمل. العملاء أدناه موصى بهم ويدعمون بالكامل BitTorrent v2 / التورنتات الهجينة:
4. إنشاء حساب
التسجيل
انقر على إنشاء حساب في شريط التنقل. اختر اسم مستخدم وأدخل عنوان بريد إلكتروني وعيّن كلمة مرور (الحد الأدنى للطول مُطبَّق). يجب قراءة شروط الموقع والموافقة عليها قبل إنشاء حسابك.
تفعيل البريد الإلكتروني
بعد التسجيل، يُرسَل بريد إلكتروني للتحقق إلى عنوانك. انقر على الرابط في البريد الإلكتروني لتفعيل حسابك. إذا لم تستلمه، استخدم رابط تفعيل حسابك في صفحة تسجيل الدخول لطلب رمز جديد.
استعادة كلمة المرور
إذا نسيت كلمة مرورك، انقر على نسيت كلمة المرور في صفحة تسجيل الدخول وأدخل عنوان بريدك الإلكتروني. سيُرسَل إليك رابط للاسترداد. الرابط للاستخدام مرة واحدة وينتهي بعد وقت قصير.
5. رفع التورنتات
انتقل إلى رفع في شريط التنقل. يجب أن تكون مسجلاً دخولك بحساب نشط غير محظور. صفحة الرفع تحتوي على تبويبين:
تبويب الرفع — إرسال ملف .torrent موجود
اسحب وأفلت أو اختر ملف .torrent. بعد التحميل، أكمل الحقول:
| الحقل | مطلوب | الوصف |
|---|---|---|
| ملف التورنت | نعم | ملف .torrent للرفع. |
| الاسم | لا | تجاوز اسم عرض التورنت. إذا تُرك فارغاً، يُستخدم الاسم المدمج في ملف التورنت. |
| الفئة | نعم | فئة المحتوى (أنمي، مانغا، صوتيات، إلخ). |
| الفئة الفرعية | لا | نوع أكثر تحديداً داخل الفئة (مثل RAW، Sub/Audio). |
| اللغات | لا | علامة لغة واحدة أو أكثر تصف لغة المحتوى. |
| المجموعة | لا | ربط هذا الإصدار بمجموعة أنت عضو فيها. |
| الوصف | لا | وصف بتنسيق Markdown يظهر في صفحة تفاصيل التورنت (الحد الأقصى 65535 حرفاً). |
| خاص | لا | تعيين علامة الخصوصية في التورنت، مع تعطيل DHT/PEX. مفيد للتورنتات الخاصة بالمتتبع فقط. |
| عنوان URL للإعلان | لا | تجاوز أو إضافة عنوان URL للإعلان الرئيسي للمتتبع. |
| متتبعات إضافية | لا | يُقرأ من ملف التورنت. لا يمكن تعديله أثناء الرفع — استخدم تبويب الإنشاء إذا كنت تريد تخصيص قائمة المتتبعات. |
| التعليق | لا | تجاوز حقل التعليق المدمج في التورنت. |
يجب أن يتضمن التورنت الخاص بك على الأقل رابط متتبع AniRena واحد في قائمة الإعلان (أي طبقة). يتحقق الموقع من ذلك عند الرفع وسيرفض التورنتات التي لا تتضمن متتبع AniRena. إذا أنشأت التورنت دون إضافة متتبع AniRena أولاً، قم برفعه ثم أعد تنزيله من الموقع — سيحتوي الملف المُنزَّل على المتتبعات الصحيحة مُضافةً تلقائياً.
تبويب الإنشاء — بناء تورنت جديد
يتيح لك تبويب الإنشاء توليد .torrent جديد من الصفر بتحديد مسارات الملفات وعناوين URL للمتتبع وإعدادات التورنت الأخرى مباشرةً في المتصفح. يُرسَل التورنت الناتج مع نفس حقول البيانات الوصفية أعلاه.
الإشراف
تُفحص عمليات الرفع تلقائياً مقابل قائمة من أنماط المحتوى المحظورة (الأسماء وأسماء الملفات والأوصاف). ستُرفض التورنتات التي تطابق نمطاً محظوراً. تُرفض أيضاً التورنتات المكررة (نفس info hash).
6. حسابك
انقر على اسم مستخدمك في الزاوية العلوية اليمنى لفتح لوحة الملف الشخصي. وهي منظمة في أقسام قابلة للطي:
الإعدادات
غيّر سمة واجهة المستخدم وحجم الخط ونظام الألوان ولغة الواجهة وتفضيلات العرض المتعلقة بالتورنت. تُحفظ التغييرات تلقائياً.
كلمة المرور
أدخل كلمة مرورك الحالية وكلمة المرور الجديدة مرتين. يُرسَل رمز التحقق إلى عنوان بريدك الإلكتروني المسجّل ويجب إدخاله لتأكيد التغيير. إذا كانت المصادقة الثنائية مفعّلة، يُطلب أيضاً رمز TOTP.
المصادقة الثنائية (2FA)
فعّل المصادقة الثنائية المستندة إلى TOTP باستخدام أي تطبيق مصادقة (مثل Google Authenticator وAegis وBitwarden). عند تفعيل 2FA:
- امسح رمز QR (أو أدخل السر يدوياً) في تطبيق المصادقة.
- أدخل الرمز المكون من 6 أرقام المعروض في تطبيقك لتأكيد الإعداد.
- احفظ رموز الاستعادة المعروضة — هذه رموز للاستخدام مرة واحدة لاستعادة الوصول إذا فقدت جهازك.
لتعطيل 2FA، أدخل رمز TOTP الحالي وأكّد.
الجلسات النشطة
اعرض جميع جلسات تسجيل الدخول النشطة حالياً بما فيها المتصفح ونظام التشغيل وعنوان IP ووقت آخر نشاط. انقر على إلغاء في أي جلسة لا تتعرف عليها. يمكنك أيضاً إلغاء جميع الجلسات دفعة واحدة لتسجيل الخروج من كل الأجهزة.
مفتاح API
أنشئ مفتاح API شخصياً يُستخدم لرفع التورنتات برمجياً عبر واجهة برمجة تطبيقات AniRena. انقر على توليد مفتاح لإنشاء مفتاح — يُعرض المفتاح الكامل مرة واحدة فور الإنشاء. احفظه بأمان؛ لن يُعرض بالكامل مرة أخرى. استخدم إلغاء لإبطال المفتاح نهائياً.
حذف الحساب
طلب حذف الحساب يبدأ فترة سماح مدتها 30 يوماً. يتم تعطيل حسابك فوراً وحذفه نهائياً بعد 30 يوماً. يمكنك إلغاء الحذف في أي وقت خلال تلك الفترة بتسجيل الدخول والنقر على إلغاء الحذف.
7. واجهة برمجة تطبيقات AniRena
يوفر AniRena واجهة برمجة تطبيقات JSON تتيح لك رفع التورنتات برمجياً باستخدام مفتاح API شخصي. تطبّق واجهة برمجة التطبيقات نفس القواعد كواجهة الويب: فحوصات الحظر وحدود المعدل وقيود وضع الموقع تسري. كل عملية رفع عبر API تُسجَّل في سجل التدقيق.
المصادقة
تستخدم واجهة برمجة التطبيقات نظام مصادقة من خطوتين. أولاً، استبدل مفتاح API الدائم بـ رمز حامل (Bearer Token) قصير الأجل، ثم مرر هذا الرمز في رأس Authorization لكل طلب API.
مفتاح API الخاص بك متاح من خلال حسابك > مفتاح API. احتفظ به سراً — أي شخص يمتلكه يمكنه الحصول على رموز حامل والرفع باسمك. إذا تعرّض للاختراق، ألغِه فوراً وأنشئ مفتاحاً جديداً.
الخطوة 1 — احصل على رمز حامل
/api/v1/auth/tokenأرسل طلب POST إلى نقطة نهاية الرمز مع مفتاح API في رأس Authorization. لا يُطلب جسم طلب.
Authorization: ApiKey <your-api-key>
استجابة الرمز
{
"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>
تسجيل دخول بطلب واحد (مع المصادقة الثنائية)
/api/v1/auth/loginسجّل الدخول باسم المستخدم أو البريد الإلكتروني وكلمة المرور في طلب واحد واحصل على رمز Bearer مباشرة. إذا كانت المصادقة الثنائية مفعّلة على حسابك، فأدرج رمز المصادقة الحالي في totp_code (أو رمز استرداد في recovery_code). اختيارياً اضبط new_api_key على true لإنشاء مفتاح API دائم جديد في الاستجابة نفسها.
جسم الطلب
{
"login": "username or email",
"password": "your-password",
"totp_code": "123456", // مطلوب إذا كانت المصادقة الثنائية مفعّلة (6 أرقام)
"recovery_code": "", // بديل عن totp_code
"new_api_key": false // اضبطه على true لإنشاء مفتاح API جديد
}استجابة الرمز
{
"ok": true,
"token": "<bearer-token>",
"token_type": "Bearer",
"expires_in": 3600,
"api_key": "<new-api-key>" // يظهر فقط عندما يكون new_api_key بقيمة true
}يعمل رمز Bearer تماماً مثل الرمز الذي يتم الحصول عليه من /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 — رفع تورنت
/api/v1/torrentsأرسل طلب POST بتنسيق JSON عادي مع رمز الحامل في رأس 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 | رمز الحامل مفقود أو منتهي الصلاحية أو تم تدويره بالفعل. أعد المصادقة عبر POST /api/v1/auth/token. |
403 | الحساب محظور أو معطّل أو IP محظور. |
409 | تورنت مكرر — نفس info hash موجود بالفعل. |
422 | لا يمكن تحليل ملف التورنت أو فشل التحقق (نمط محظور أو بنية غير صالحة). |
429 | تجاوزت حد المعدل. أعد المحاولة بعد انتهاء الفترة الزمنية. |
503 | الموقع في وضع الصيانة أو القراءة فقط. |
حد المعدل
عمليات رفع API تخضع لحد معدل قابل للتكوين منفصل عن واجهة الويب. يُحدَّد الحد والفترة بواسطة مدير الموقع. عند تجاوز حد المعدل، تُعيد API رمز 429 Too Many Requests. الحد مطبّق لكل مفتاح API.
إنشاء ملفات التورنت باستخدام torrent-builder
torrent-builder هو أداة CLI مفتوحة المصدر مبنية على libtorrent-rasterbar تتيح لك إنشاء ملفات .torrent بصيغ BitTorrent v1 وv2 وhybrid من سطر الأوامر. تتكامل بشكل مثالي مع AniRena upload API — أنشئ الملف محلياً ثم POST مباشرةً إلى المتتبع. cantalupo555/torrent-builder.
البناء من المصدر
يتطلب CMake >= 3.28.3 وlibtorrent-rasterbar >= 2.0.11. انسخ المستودع وابنِه باستخدام 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 لإعلان المتتبع. كرر العلم لإضافة متتبعات متعددة. |
--comment | تضمين سلسلة تعليق بيانات وصفية في التورنت. |
--private | تعيين علم الخصوصية لتقييد التوزيع على المتتبعات المدرجة فقط. |
--piece-size | حجم القطعة بالكيلوبايت (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أرسل طلب POST بتنسيق JSON عادي لاسترداد قوائم التورنت مع نفس خيارات البحث والتصفية المتاحة على الموقع. ملف .torrent نفسه غير مُعاد — استخدم مسار التنزيل العادي لذلك.
# 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:"الاسم" وuser:الاسم. |
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 (الافتراضي 1). |
per_page | integer | لا | النتائج لكل صفحة، 1–250 (الافتراضي 50). |
hide_adult | boolean | لا | استبعاد تورنتات فئة البالغين. الافتراضي true للمستخدمين العاديين. |
show_dead | boolean | لا | عند تعيينها على false (الافتراضي)، يتم استبعاد التورنتات الأقدم من فترة سماح التورنت الميت والتي لا يوجد لها بذور نشطة. اضبطها على 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). تجاوز الحد يُعيد 429 Too Many Requests. حسابات الفريق معفاة.
الحصول على تفاصيل التورنت
/api/v1/torrent/{id}استرجع البيانات الوصفية الكاملة لتورنت واحد — بما في ذلك الحقول التي يحذفها نقطة بحث التورنت مثل وصف Markdown، وتعليق ملف .torrent المضمن، وقائمة الملفات مع حجم كل ملف، والتخطيط الكامل لطبقات المتعقب. يتم قراءة أعداد البذور والآخذين الحية من المتعقب عند توفرها.
الاستجابة
{
"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 عندما لا يحتوي مخزن المتعقب على إدخال لهذا التجزئة المعلوماتية أو يتعذر الوصول إليه.
ext_seeders, ext_leechers — أعلى عدد للبذور والآخذين الذي أبلغ عنه أي متعقب خارجي تم استطلاعه لهذا التورنت. تتداخل المتعقبات التي تتعقب نفس السرب، لذا يُستخدم الحد الأقصى بدلاً من المجموع؛ يُبلغ كلاهما عن 0 عندما لا يحتوي أي متعقب على بيانات استطلاع لهذا التجزئة المعلوماتية.
استجابات الخطأ
| حالة HTTP | المعنى |
|---|---|
400 | يجب أن يكون معرف التورنت إما UUID مكون من 36 حرفًا مع شرطات أو سلسلة سداسية عشرية مكونة من 32 حرفًا. |
401 | رمز الحامل مفقود أو منتهي الصلاحية أو تم تدويره بالفعل. أعد المصادقة عبر 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 | رمز الحامل مفقود أو منتهي الصلاحية أو تم تدويره بالفعل. أعد المصادقة عبر 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 (الافتراضي 1). |
per_page | integer | لا | النتائج لكل صفحة، 1–50 (الافتراضي 10). |
الاستجابة
{
"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}يُرجع مجموعة عامة واحدة حسب المعرف الرقمي أو 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 | رمز الحامل مفقود أو منتهي الصلاحية أو تم تدويره بالفعل. أعد المصادقة عبر POST /api/v1/auth/token. |
404 | المجموعة غير موجودة أو غير متاحة للعموم. |
429 | تجاوزت حد المعدل. أعد المحاولة بعد انتهاء الفترة الزمنية. |
503 | الموقع في وضع الصيانة أو القراءة فقط. |
8. تبرعات
إذا كنت ترغب في دعم AniRena والمساعدة في تغطية تكاليف استضافة خوادمنا وخدماتنا، يسعدنا استقبال تبرعك على أحد المحافظ الرقمية التالية:
bc1qy2h3ddq6ak5damvnf4r5vu3ydehhxrcq8gllwn0xCbaFe03832F95F86AF2536d52710e78C63b62Cd33ucetj2XDGHQg9PVRPMxerNi7c6kX7GJkjQNg9yjwGegLbpt61yX3RjGtB1Ef8vgVz6Hr6baQsTjVkأي تبرع، كبيراً كان أم صغيراً، موضع تقدير كبير ويذهب مباشرة نحو استمرار AniRena. شكراً لدعمك!
9. البرامج
AniRena Player تطبيق سطح مكتب مجاني يتيح لك بث الفيديو مباشرة من التورنتات المفهرسة على هذا الموقع — دون الحاجة إلى انتظار اكتمال التنزيل. ما عليك سوى لصق رابط مغناطيسي أو فتح ملف .torrent، ويبدأ التشغيل بمجرد توفر بيانات كافية.
كلا الإصدارين مستقلان تمامًا — جميع التبعيات مضمنة داخل الملف التنفيذي. لا حاجة إلى مثبت أو بيئة تشغيل، فقط نزّل وشغّل.
مثبت (.exe). يقوم بتحديث نفسه داخل التطبيق.
صورة قرص (.dmg) لأجهزة Mac بمعالج Apple Silicon (M1 وأحدث). يقوم بتحديث نفسه داخل التطبيق.
صورة قرص (.dmg) لأجهزة Mac بمعالج Intel. يقوم بتحديث نفسه داخل التطبيق.
ملف واحد محمول، لا حاجة للتثبيت. التنسيق الوحيد على لينكس مع التحديث التلقائي داخل التطبيق.
التثبيت: sudo apt install ./<file>.deb — يتم التحديث عبر apt أو بتنزيل جديد، ليس داخل التطبيق.
التثبيت: sudo dnf install ./<file>.rpm — يتم التحديث عبر dnf أو بتنزيل جديد، ليس داخل التطبيق.
ثبّت يدويًا على أجهزة أندرويد ARM 64 بت (معظم الهواتف / الأجهزة اللوحية الحديثة). يتم التحديث بتنزيل APK جديد.
إصدارات أقدم
ثبّت يدويًا على أجهزة أندرويد ARM 32 بت (الهواتف / الأجهزة اللوحية الأقدم). يتم التحديث بتنزيل APK جديد.