গাইড
1. শুরু করা
AniRena হল অ্যানিমে, মাঙ্গা, অডিও এবং সম্পর্কিত মিডিয়ার জন্য একটি টরেন্ট ইনডেক্স। অ্যাকাউন্ট ছাড়াই টরেন্ট ব্রাউজ এবং ডাউনলোড করা যায়। টরেন্ট আপলোড, গ্রুপে পোস্ট বা API ব্যবহারের জন্য অ্যাকাউন্ট প্রয়োজন।
উপরের নেভিগেশন বার থেকে সাইটের প্রধান অংশগুলোতে প্রবেশ করা যায়:
- হোম — টরেন্ট তালিকা ও অনুসন্ধান পৃষ্ঠা।
- আপলোড — নতুন টরেন্ট জমা দিন (লগইন প্রয়োজন)।
- গাইড — এই পৃষ্ঠা।
- পরিসংখ্যান — সাইটব্যাপী পরিসংখ্যান (টরেন্ট, পিয়ার, আপলোড সময়কাল)।
- গ্রুপ — রিলিজ গ্রুপ ডিরেক্টরি।
- RSS — সাম্প্রতিক আপলোডের RSS ফিড, ক্যাটাগরি অনুযায়ী ফিল্টারযোগ্য।
লগইন করলে উপরের ডানদিকে অ্যাকাউন্ট মেনু দেখা যাবে। এখান থেকে প্রোফাইল প্যানেল খুলে সেটিংস পরিবর্তন, নিরাপত্তা বিকল্প পরিচালনা এবং API কী অ্যাক্সেস করা যাবে।
2. ব্রাউজিং ও অনুসন্ধান
হোম পেজে সমস্ত টরেন্ট আপলোডের তারিখ অনুযায়ী তালিকাভুক্ত। ফলাফল ফিল্টার করতে উপরের সার্চ বার ব্যবহার করুন।
সাধারণ অনুসন্ধান
সার্চ বারে শব্দ টাইপ করে Enter চাপুন (বা সার্চ আইকনে ক্লিক করুন)। কোয়েরি সক্রিয় থাকলে ফলাফল প্রাসঙ্গিকতা অনুযায়ী সাজানো হয়।
অনুসন্ধান অপারেটর
নিম্নলিখিত অপারেটরগুলো সাধারণ কোয়েরির সাথে ব্যবহার করা যায়:
| অপারেটর | উদাহরণ | প্রভাব |
|---|---|---|
user:"name" | user:"SubsPlease" | শুধুমাত্র ওই ব্যবহারকারীর আপলোড করা টরেন্ট দেখায়। |
টরেন্ট তালিকায় আপলোডারের নামে ক্লিক করলে স্বয়ংক্রিয়ভাবে ব্যবহারকারী অনুসন্ধান চালু হয়।
ক্যাটাগরি ও সাব-ক্যাটাগরি
সার্চ বারের পাশের গ্রিড আইকন (ক্যাটাগরি সিলেক্টর) ব্যবহার করে ফলাফল একটি ক্যাটাগরিতে সীমাবদ্ধ করুন। উপলব্ধ ক্যাটাগরিসমূহ:
- অ্যানিমে
- মাঙ্গা/মানহ্বা/কমিক
- অডিও
- সাহিত্য
- লাইভ অ্যাকশন
- ছবি
- সফটওয়্যার
- হেনতাই
- অন্যান্য
প্রতিটি ক্যাটাগরিতে সাব-ক্যাটাগরি আছে (যেমন অ্যানিমে থেকে RAW, সাব/অডিও, মিউজিক ভিডিও)। ক্যাটাগরি মডালের ভেতরে নির্বাচন করা যায়।
সাজানো ও ফিল্টার
টরেন্ট তালিকার কলাম হেডারে ক্লিক করে সেই কলাম অনুযায়ী সাজানো (আরোহী বা অবরোহী) যায়। উপলব্ধ সাজানো কলাম: তারিখ, নাম, আকার, সম্পন্ন ডাউনলোড। দ্রষ্টব্য: সিডার এবং লিচার সংখ্যা Redis থেকে লাইভ আসে এবং সাজানোর জন্য ব্যবহার করা যায় না।
ভাষা ফিল্টার
ভাষা সিলেক্টর (পতাকা আইকন) ব্যবহার করে নির্দিষ্ট ভাষায় ট্যাগ করা টরেন্ট দেখান।
RSS ফিড
/rss-এ RSS ফিড সর্বশেষ আপলোড প্রদান করে। ফিড ফিল্টার করতে ?category=anime (বা অন্য ক্যাটাগরি স্লাগ) যোগ করুন। বেশিরভাগ টরেন্ট ক্লায়েন্ট এই URL থেকে সরাসরি RSS স্বয়ংক্রিয় ডাউনলোড সমর্থন করে।
3. টরেন্ট ডাউনলোড
ডিটেইল প্যানেল খুলতে যেকোনো টরেন্টের নামে ক্লিক করুন। সেখান থেকে:
- .torrent ডাউনলোড — .torrent ফাইল সরাসরি সংরক্ষণ করে। সরাসরি URL হল
/torrents/{id}.torrent - ম্যাগনেট লিঙ্ক — ম্যাগনেট URI প্রোটোকলের মাধ্যমে আপনার টরেন্ট ক্লায়েন্টে সরাসরি খোলে। URL হল
/torrents/{id}/magnet
ডিটেইল প্যানেলে টরেন্টের বিবরণ, ফাইল তালিকা, ট্র্যাকার তালিকা এবং সিডার/লিচার সংখ্যাও দেখা যায়।
পুরনো ডাউনলোড লিঙ্ক
পুরনো AniRena ডাউনলোড লিঙ্কগুলো এখনও সমর্থিত এবং লেগেসি ID ব্যবহার করে সঠিক .torrent ফাইলে স্বয়ংক্রিয়ভাবে রিডাইরেক্ট হয়: /dl/{old_id}
প্রস্তাবিত BitTorrent ক্লায়েন্ট
যেকোনো আধুনিক BitTorrent ক্লায়েন্ট কাজ করে। নিচের ক্লায়েন্টগুলি প্রস্তাবিত এবং BitTorrent v2 / হাইব্রিড টরেন্ট সম্পূর্ণ সমর্থন করে:
4. অ্যাকাউন্ট তৈরি
নিবন্ধন
নেভিগেশন বারে Sign Up-এ ক্লিক করুন। একটি ইউজারনেম বেছে নিন, ইমেইল ঠিকানা দিন এবং পাসওয়ার্ড সেট করুন (ন্যূনতম দৈর্ঘ্য প্রযোজ্য)। অ্যাকাউন্ট তৈরির আগে সাইটের শর্তাবলী পড়ে সম্মতি দিতে হবে।
ইমেইল যাচাইকরণ
সাইন আপের পরে আপনার ঠিকানায় একটি যাচাইকরণ ইমেইল পাঠানো হবে। অ্যাকাউন্ট সক্রিয় করতে ইমেইলের লিঙ্কে ক্লিক করুন। না পেলে লগইন পেজের Account Activate লিঙ্ক থেকে নতুন কোড অনুরোধ করুন।
পাসওয়ার্ড পুনরুদ্ধার
পাসওয়ার্ড ভুলে গেলে সাইন ইন পেজে Forgot password-এ ক্লিক করে ইমেইল ঠিকানা দিন। আপনার কাছে একটি পুনরুদ্ধার লিঙ্ক পাঠানো হবে। লিঙ্কটি একবারের জন্য কার্যকর এবং অল্প সময়ের মধ্যে মেয়াদ শেষ হয়।
5. টরেন্ট আপলোড
নেভিগেশন বারে Upload-এ যান। একটি সক্রিয়, ব্যান না হওয়া অ্যাকাউন্টে লগইন থাকতে হবে। আপলোড পেজে দুটি ট্যাব আছে:
আপলোড ট্যাব — বিদ্যমান .torrent ফাইল জমা দিন
.torrent ফাইল ড্র্যাগ-এন্ড-ড্রপ করুন অথবা নির্বাচন করুন। লোড হলে ফিল্ডগুলো পূরণ করুন:
| ফিল্ড | প্রয়োজনীয় | বিবরণ |
|---|---|---|
| টরেন্ট ফাইল | হ্যাঁ | আপলোড করার .torrent ফাইল। |
| নাম | না | টরেন্টের প্রদর্শন নাম পরিবর্তন করুন। খালি রাখলে টরেন্ট ফাইলে এমবেড করা নাম ব্যবহার হবে। |
| ক্যাটাগরি | হ্যাঁ | কন্টেন্টের ক্যাটাগরি (অ্যানিমে, মাঙ্গা, অডিও ইত্যাদি)। |
| সাব-ক্যাটাগরি | না | ক্যাটাগরির মধ্যে আরও নির্দিষ্ট ধরন (যেমন RAW, সাব/অডিও)। |
| ভাষা | না | কন্টেন্টের ভাষা নির্দেশকারী এক বা একাধিক ভাষা ট্যাগ। |
| গ্রুপ | না | আপনি যে গ্রুপের সদস্য তার সাথে এই রিলিজ যুক্ত করুন। |
| বিবরণ | না | টরেন্ট ডিটেইল পেজে প্রদর্শিত Markdown ফর্ম্যাটের বিবরণ (সর্বোচ্চ ৬৫৫৩৫ অক্ষর)। |
| প্রাইভেট | না | টরেন্টে প্রাইভেট ফ্ল্যাগ সেট করে DHT/PEX নিষ্ক্রিয় করে। ট্র্যাকার-শুধু টরেন্টের জন্য উপযোগী। |
| অ্যানাউন্স URL | না | প্রাথমিক ট্র্যাকার অ্যানাউন্স URL পরিবর্তন বা যোগ করুন। |
| অতিরিক্ত ট্র্যাকার | না | টরেন্ট ফাইল থেকে পড়া হয়। আপলোডের সময় পরিবর্তন করা যাবে না — ট্র্যাকার তালিকা কাস্টমাইজ করতে Create ট্যাব ব্যবহার করুন। |
| মন্তব্য | না | ফাইলে এমবেড করা টরেন্টের মন্তব্য ফিল্ড পরিবর্তন করুন। |
আপনার টরেন্টে অ্যানাউন্স তালিকায় (যেকোনো tier-এ) অন্তত একটি AniRena ট্র্যাকার URL থাকতে হবে। সাইট আপলোডের সময় এটি পরীক্ষা করে এবং AniRena ট্র্যাকার না থাকলে টরেন্ট প্রত্যাখ্যান করবে। যদি AniRena ট্র্যাকার না যোগ করে টরেন্ট তৈরি করে থাকেন, তাহলে আপলোড করুন এবং সাইট থেকে পুনরায় ডাউনলোড করুন — ডাউনলোড করা ফাইলে সঠিক ট্র্যাকারগুলো স্বয়ংক্রিয়ভাবে যুক্ত থাকবে।
তৈরি ট্যাব — নতুন টরেন্ট তৈরি করুন
তৈরি ট্যাব ব্যবহার করে ব্রাউজারে সরাসরি ফাইল পাথ, ট্র্যাকার URL এবং অন্যান্য প্যারামিটার নির্দিষ্ট করে স্ক্র্যাচ থেকে নতুন .torrent তৈরি করা যায়। ফলে তৈরি টরেন্ট উপরের একই মেটাডেটা ফিল্ড সহ জমা দেওয়া হয়।
মডারেশন
আপলোডগুলো স্বয়ংক্রিয়ভাবে নিষিদ্ধ কন্টেন্ট প্যাটার্নের (নাম, ফাইলনাম, বিবরণ) তালিকার বিরুদ্ধে যাচাই করা হয়। নিষিদ্ধ প্যাটার্নের সাথে মিলে যাওয়া টরেন্ট প্রত্যাখ্যাত হবে। একই ইনফো হ্যাশের টরেন্ট (ডুপ্লিকেট) প্রত্যাখ্যাত হবে।
6. আপনার অ্যাকাউন্ট
প্রোফাইল প্যানেল খুলতে উপরের ডানদিকে ইউজারনেমে ক্লিক করুন। এটি ভাঁজযোগ্য বিভাগে সাজানো:
সেটিংস
UI থিম, ফন্ট সাইজ, কালার স্কিম, ইন্টারফেস ভাষা এবং টরেন্ট সম্পর্কিত প্রদর্শন পছন্দ পরিবর্তন করুন। পরিবর্তনগুলো স্বয়ংক্রিয়ভাবে সংরক্ষিত হয়।
পাসওয়ার্ড
বর্তমান পাসওয়ার্ড এবং নতুন পাসওয়ার্ড দুবার লিখুন। পরিবর্তন নিশ্চিত করতে নিবন্ধিত ইমেইল ঠিকানায় একটি যাচাইকরণ কোড পাঠানো হবে। দুই-ফ্যাক্টর প্রমাণীকরণ সক্রিয় থাকলে TOTP কোডও প্রয়োজন।
দ্বি-ফ্যাক্টর প্রমাণীকরণ (2FA)
যেকোনো অথেনটিকেটর অ্যাপ ব্যবহার করে TOTP-ভিত্তিক দ্বি-ফ্যাক্টর প্রমাণীকরণ সক্রিয় করুন (যেমন Google Authenticator, Aegis, Bitwarden)। 2FA সক্রিয় করার সময়:
- অথেনটিকেটর অ্যাপে QR কোড স্ক্যান করুন (বা ম্যানুয়ালি সিক্রেট লিখুন)।
- সেটআপ নিশ্চিত করতে অ্যাপে দেখানো ৬ সংখ্যার কোড লিখুন।
- দেখানো রিকভারি কোডগুলো সংরক্ষণ করুন — ডিভাইস হারালে অ্যাক্সেস ফিরে পেতে এগুলো একবার ব্যবহারযোগ্য কোড।
2FA নিষ্ক্রিয় করতে বর্তমান TOTP কোড লিখে নিশ্চিত করুন।
সক্রিয় সেশন
ব্রাউজার, OS, IP ঠিকানা এবং সর্বশেষ দেখার সময় সহ সমস্ত বর্তমান লগইন সেশন দেখুন। অপরিচিত সেশনে Revoke ক্লিক করুন। সব ডিভাইস থেকে লগআউট করতে একসাথে সমস্ত সেশন বাতিল করতে পারবেন।
API কী
AniRena API-এর মাধ্যমে প্রোগ্রামিকভাবে টরেন্ট আপলোড করতে ব্যক্তিগত API কী তৈরি করুন। তৈরি করতে Generate Key ক্লিক করুন — পূর্ণ কী শুধুমাত্র একবার তৈরির পরপরই দেখানো হবে। নিরাপদে সংরক্ষণ করুন; এরপর পূর্ণ আকারে আর দেখানো হবে না। কী স্থায়িভাবে বাতিল করতে Revoke ব্যবহার করুন।
অ্যাকাউন্ট মুছুন
অ্যাকাউন্ট মুছে ফেলার অনুরোধ করলে ৩০ দিনের অনুগ্রহকাল শুরু হয়। আপনার অ্যাকাউন্ট তাৎক্ষণিকভাবে নিষ্ক্রিয় এবং ৩০ দিন পরে স্থায়িভাবে মুছে যাবে। এই সময়কালের মধ্যে লগইন করে Cancel deletion ক্লিক করে যেকোনো সময় মুছে ফেলা বাতিল করা যাবে।
7. AniRena API
AniRena একটি JSON API প্রদান করে যা ব্যক্তিগত API কী ব্যবহার করে প্রোগ্রামিকভাবে টরেন্ট আপলোড করতে দেয়। API ওয়েব ইন্টারফেসের মতো একই নিয়ম প্রয়োগ করে: ব্যান চেক, রেট লিমিট এবং সাইট-মোড বিধিনিষেধ সব প্রযোজ্য। প্রতিটি API আপলোড অডিট লগে রেকর্ড করা হয়।
প্রমাণীকরণ
API দুই-ধাপের প্রমাণীকরণ প্রবাহ ব্যবহার করে। প্রথমে আপনার স্থায়ী API কী একটি স্বল্পমেয়াদী bearer token এর বিনিময়ে দিন, তারপর প্রতিটি API অনুরোধের Authorization হেডারে সেই token পাস করুন।
আপনার API কী আপনার অ্যাকাউন্ট > API কী-তে পাওয়া যাবে। এটি গোপন রাখুন — যে কেউ এটি দিয়ে bearer token পেতে এবং আপনার পক্ষে আপলোড করতে পারবে। যদি ফাঁস হয়, তাৎক্ষণিক বাতিল করুন এবং নতুন তৈরি করুন।
ধাপ ১ — একটি bearer token নিন
/api/v1/auth/tokenAuthorization হেডারে আপনার API কী সহ token এন্ডপয়েন্টে POST অনুরোধ পাঠান। কোনো 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 টোকেন পান। আপনার অ্যাকাউন্টে 2FA সক্রিয় থাকলে totp_code-এ আপনার বর্তমান অথেন্টিকেটর কোড (অথবা recovery_code-এ একটি রিকভারি কোড) দিন। ঐচ্ছিকভাবে new_api_key true করলে একই উত্তরে একটি নতুন স্থায়ী API কী-ও তৈরি হবে।
রিকোয়েস্ট বডি
{
"login": "username or email",
"password": "your-password",
"totp_code": "123456", // 2FA সক্রিয় থাকলে প্রয়োজন (৬ অঙ্ক)
"recovery_code": "", // totp_code-এর বিকল্প
"new_api_key": false // নতুন API কী তৈরি করতে true দিন
}Token প্রতিক্রিয়া
{
"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}"); } }
ধাপ ২ — একটি torrent আপলোড করুন
/api/v1/torrentsAuthorization হেডারে bearer token সহ একটি সাধারণ JSON POST অনুরোধ পাঠান।
রিকোয়েস্ট বডি
| ফিল্ড | ধরন | প্রয়োজনীয় | বিবরণ |
|---|---|---|---|
torrent | string | হ্যাঁ | .torrent ফাইলের Base64-এনকোডেড বিষয়বস্তু। |
category | string | হ্যাঁ | ক্যাটাগরি স্লাগ: anime, manga, audio, literature, live, pictures, software, hentai, other। |
name | string | না | টরেন্টের প্রদর্শন নাম পরিবর্তন করুন। |
sub_category | string | না | সাব-ক্যাটাগরি স্লাগ (যেমন raw, sub-audio)। নির্বাচিত ক্যাটাগরির অন্তর্গত হতে হবে। |
languages | string[] | না | BCP 47 ভাষা কোডের অ্যারে (যেমন en, ja)। |
group_id | string | না | এই রিলিজ যুক্ত করার গ্রুপের UUID (সদস্য হতে হবে)। |
description | string | না | Markdown ফর্ম্যাটের রিলিজ বিবরণ (সর্বোচ্চ ৬৫৫৩৫ অক্ষর)। |
comment | string | না | টরেন্টে এমবেড করা মন্তব্য ফিল্ড পরিবর্তন করুন। |
is_private | boolean | না | টরেন্টে প্রাইভেট ফ্ল্যাগ সক্রিয় করতে true সেট করুন। |
comments_enabled | boolean | না | এই টরেন্টে মন্তব্যের অনুমতি দিন। ডিফল্ট true (সক্রিয়)। |
anime_id | string | না | এই টরেন্টের সাথে লিঙ্ক করতে একটি অ্যানিমে এন্ট্রির UUID। GET /api/v1/anime/search-এর মাধ্যমে UUID পান। UUID কোনো পরিচিত এন্ট্রির সাথে না মিললে 400 ফেরত দেয়। |
announce | string | না | প্রাথমিক অ্যানাউন্স URL পরিবর্তন বা যোগ করুন। |
trackers | string | না | অতিরিক্ত ট্র্যাকার URL-এর নিউলাইন-বিভক্ত তালিকা। 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 | ডুপ্লিকেট টরেন্ট — একই ইনফো হ্যাশ আগে থেকে আছে। |
422 | টরেন্ট ফাইল পার্স বা ভ্যালিডেশন ব্যর্থ (নিষিদ্ধ প্যাটার্ন, অকার্যকর কাঠামো)। |
429 | রেট লিমিট অতিক্রান্ত। উইন্ডো রিসেটের পরে আবার চেষ্টা করুন। |
503 | সাইট রক্ষণাবেক্ষণ বা শুধুমাত্র-পড়া মোডে আছে। |
রেট লিমিটিং
API আপলোড ওয়েব ইন্টারফেস থেকে আলাদা একটি কনফিগারযোগ্য রেট লিমিটের অধীন। সীমা এবং উইন্ডো সাইট প্রশাসক নির্ধারণ করেন। রেট লিমিট অতিক্রান্ত হলে API 429 Too Many Requests ফেরত দেয়। সীমা API কী প্রতি।
torrent-builder দিয়ে টরেন্ট ফাইল তৈরি করা
torrent-builder হলো libtorrent-rasterbar-এর উপর নির্মিত একটি ওপেন-সোর্স CLI টুল যা কমান্ড লাইন থেকে BitTorrent v1, v2 এবং hybrid .torrent ফাইল তৈরি করতে দেয়। এটি 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 | ধাপে ধাপে ইন্টারেক্টিভ কনফিগারেশন মোড চালু করুন। |
সম্পূর্ণ ওয়ার্কফ্লো: বিল্ড -> আপলোড
নিচের উদাহরণগুলি torrent-builder দিয়ে একটি hybrid টরেন্ট তৈরি করে, তারপর 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ওয়েবসাইটে উপলব্ধ একই অনুসন্ধান ও ফিল্টার বিকল্পগুলি দিয়ে torrent তালিকা পুনরুদ্ধার করতে একটি সাধারণ JSON POST অনুরোধ পাঠান। .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:"Name", user:name উপসর্গ সমর্থিত। |
category | string | না | ক্যাটাগরি স্লাগ (যেমন "anime")। |
sub_category | string | না | সাব-ক্যাটাগরি স্লাগ (যেমন "raw")। |
languages | string[] | না | BCP 47 ভাষা কোডের অ্যারে (যেমন en, ja)। |
sort | string | না | সর্ট ফিল্ড: date (ডিফল্ট), size, seeders, leechers, completed, title। |
order | string | না | সর্ট দিক: desc (ডিফল্ট) অথবা asc। |
page | integer | না | পেজ নম্বর, ১ থেকে শুরু (ডিফল্ট ১)। |
per_page | integer | না | প্রতি পেজে ফলাফল, ১–২৫০ (ডিফল্ট ৫০)। |
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 — এই টরেন্টে অ-মুছে ফেলা মন্তব্যের সংখ্যা।
অনুসন্ধান রেট লিমিটিং
অনুসন্ধান অনুরোধগুলি একটি পৃথক কনফিগারযোগ্য রেট লিমিটের অধীন (ডিফল্ট প্রতি API কীতে ৬০ সেকেন্ডে ৬০ অনুরোধ)। সীমা অতিক্রান্ত হলে 429 Too Many Requests ফেরত দেয়। স্টাফ অ্যাকাউন্ট ছাড়।
টরেন্ট বিস্তারিত নিন
/api/v1/torrent/{id}একটি একক টরেন্টের সম্পূর্ণ মেটাডেটা আনুন — অনুসন্ধান এন্ডপয়েন্ট বাদ দেয় এমন ক্ষেত্রগুলি সহ যেমন মার্কডাউন বর্ণনা, এমবেডেড .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 | টরেন্ট আইডি অবশ্যই একটি 36-অক্ষরের ড্যাশযুক্ত UUID বা একটি 32-অক্ষরের বেয়ার হেক্স স্ট্রিং হতে হবে। |
401 | Bearer token নেই, মেয়াদ শেষ হয়েছে বা ইতিমধ্যে পরিবর্তিত হয়েছে। POST /api/v1/auth/token এর মাধ্যমে পুনরায় প্রমাণীকরণ করুন। |
404 | টরেন্ট পাওয়া যায়নি। |
429 | রেট লিমিট অতিক্রান্ত। উইন্ডো রিসেটের পরে আবার চেষ্টা করুন। |
503 | সাইট রক্ষণাবেক্ষণ বা শুধুমাত্র-পড়া মোডে আছে। |
টরেন্টের মন্তব্য আনা
/api/v1/torrents/{id}/commentsএকটি টরেন্টের পৃষ্ঠাভিত্তিক মন্তব্য পুনরুদ্ধার করুন। প্রতি পৃষ্ঠায় মন্তব্যের সংখ্যা সার্ভারের .env ফাইলের COMMENT_PER_PAGE সেটিং দ্বারা নিয়ন্ত্রিত (ডিফল্ট 20)। শুধুমাত্র মন্তব্য সক্ষম টরেন্টগুলি ফলাফল ফেরত দেবে — বাকি সবগুলি 403 ফেরত দেয়।
কোয়েরি প্যারামিটার
| ফিল্ড | ধরন | প্রয়োজনীয় | বিবরণ |
|---|---|---|---|
page | integer | না | পৃষ্ঠা নম্বর, ১ থেকে শুরু (ডিফল্ট ১)। |
# 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-এর সাথে ব্যবহার করা যায়। কোনো প্রমাণীকরণের প্রয়োজন নেই। টরেন্ট অনুসন্ধানের মতো একই রেট সীমার অধীন (ডিফল্ট প্রতি 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 | না | পেজ নম্বর, ১ থেকে শুরু (ডিফল্ট ১)। |
per_page | integer | না | প্রতি পেজে ফলাফল, ১–৫০ (ডিফল্ট ১০)। |
প্রতিক্রিয়া
{
"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 টোকেন প্রমাণীকরণ প্রয়োজন।
/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 একটি ফ্রি ডেস্কটপ অ্যাপ যা আপনাকে এই সাইটে ইনডেক্স করা টরেন্ট থেকে সরাসরি ভিডিও স্ট্রিম করতে দেয় — সম্পূর্ণ ডাউনলোড শেষ হওয়ার অপেক্ষা করতে হবে না। শুধু একটি ম্যাগনেট লিংক পেস্ট করুন বা একটি .torrent ফাইল খুলুন, এবং পর্যাপ্ত ডেটা পাওয়া গেলেই প্লে শুরু হবে।
উভয় বিল্ডই সম্পূর্ণ স্বনির্ভর — সমস্ত ডিপেন্ডেন্সি এক্সিকিউটেবলের ভেতরে বান্ডেল করা আছে। কোনো ইনস্টলার বা রানটাইম সেটআপের প্রয়োজন নেই, কেবল ডাউনলোড করুন এবং চালান।
ইনস্টলার (.exe)। অ্যাপের মধ্যেই নিজেকে আপডেট করে।
ডিস্ক ইমেজ (.dmg) Apple Silicon Mac-এর জন্য (M1 ও নতুন)। অ্যাপের মধ্যেই নিজেকে আপডেট করে।
ডিস্ক ইমেজ (.dmg) Intel Mac-এর জন্য। অ্যাপের মধ্যেই নিজেকে আপডেট করে।
পোর্টেবল একক ফাইল, ইনস্টল করার দরকার নেই। অ্যাপের মধ্যে অটো-আপডেট সহ একমাত্র Linux ফরম্যাট।
ইনস্টল: sudo apt install ./<file>.deb — apt-এর মাধ্যমে বা নতুন ডাউনলোডের মাধ্যমে আপডেট হয়, অ্যাপের মধ্যে নয়।
ইনস্টল: sudo dnf install ./<file>.rpm — dnf-এর মাধ্যমে বা নতুন ডাউনলোডের মাধ্যমে আপডেট হয়, অ্যাপের মধ্যে নয়।
৬৪-বিট ARM Android ডিভাইসে সাইডলোড করুন (বেশিরভাগ আধুনিক ফোন / ট্যাবলেট)। নতুন APK ডাউনলোড করে আপডেট হয়।
পুরোনো সংস্করণ
৩২-বিট ARM Android ডিভাইসে সাইডলোড করুন (পুরোনো ফোন / ট্যাবলেট)। নতুন APK ডাউনলোড করে আপডেট হয়।