API و ساخت اپلیکیشن

راهنمای احراز هویت، ثبت و پیگیری دانلود، وب‌هوک، پخش فایل و فضای برنامه

۲۰ دقیقه مطالعه

با API پارس‌گت می‌توانید دانلود ثبت کنید، پیشرفت آن را پیگیری کنید و فایل آماده را در برنامه خود دانلود یا پخش کنید. آدرس پایه نسخه اول https://api.parsget.com/api/v1 است. endpointهای OAuth زیر این آدرس پایه نیستند؛ در مثال‌ها آدرس کامل آن‌ها آمده است.

کلیدهای شخصی و برنامه‌های OAuth را در تنظیمات API پنل می‌سازید و در صورت نیاز غیرفعال می‌کنید. endpointهای داشبورد که با نشست کاربر کار می‌کنند، جزو API نیستند.

انتخاب روش احراز هویت

کاربردانتخاب مناسب
اسکریپت، کار زمان‌بندی‌شده یا اتصال سرور به حساب خودتانPersonal API Key با پیشوند pgk_
برنامه وب، موبایل یا سرویسی که از طرف کاربران پارس‌گت کار می‌کندOAuth Authorization Code + PKCE S256
CLI، تلویزیون یا دستگاهی که ورود در آن دشوار استOAuth Device Authorization

Personal API Key و Access Token هر دو با Authorization: Bearer ارسال می‌شوند. کلید شخصی، Client Secret و webhook secret فقط هنگام ساخت یا تعویض نمایش داده می‌شوند؛ آن‌ها را در محل امنی مانند secret manager نگه دارید.

سریع‌ترین شروع با Personal API Key

یک Personal API Key در پنل بسازید و با GET /account اتصال را بررسی کنید. این درخواست مشخصات حساب را برمی‌گرداند:

export PARSGET_API_KEY='pgk_REPLACE_WITH_YOUR_KEY'

curl https://api.parsget.com/api/v1/account \
  -H "Authorization: Bearer $PARSGET_API_KEY" \
  -H 'Accept: application/json'
{
  "data": {
    "id": "01KYYDZ820A6D9K3N5R7T8VBCQ",
    "name": "کاربر پارس‌گت",
    "email": "developer@example.com",
    "email_verified": true,
    "created_at": "2026-08-01T10:30:00.000000Z"
  }
}

ورود کاربران با Authorization Code و PKCE

برای برنامه‌ای که از طرف کاربران پارس‌گت کار می‌کند، یک کلاینت OAuth در پنل بسازید و Redirect URI را ثبت کنید. برای هر بار ورود، یک code_verifier تصادفی و code_challenge متناظر با روش S256 بسازید. مقدار state را هم برای بررسی پاسخ برگشتی نگه دارید. سپس مرورگر کاربر را به آدرس زیر هدایت کنید. این آدرس برای خوانایی در چند خط آمده است. هنگام استفاده، آن را در یک خط بنویسید و مقادیر نمونه را با اطلاعات برنامه خود جایگزین کنید:

https://panel.parsget.com/oauth/authorize
  ?response_type=code
  &client_id=7f43a8c2-6b8d-4e1f-9a52-3d0c7b6e41f9
  &redirect_uri=https%3A%2F%2Fapp.example.dev%2Foauth%2Fcallback
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
  &state=RANDOM_CSRF_VALUE

پس از بازگشت کاربر به Redirect URI، ابتدا مطمئن شوید state با مقدار ارسالی شما برابر است. سپس code دریافتی را همراه با همان code_verifier به توکن تبدیل کنید:

curl -X POST https://api.parsget.com/oauth/token \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'client_id=7f43a8c2-6b8d-4e1f-9a52-3d0c7b6e41f9' \
  --data-urlencode 'redirect_uri=https://app.example.dev/oauth/callback' \
  --data-urlencode 'code=CODE_FROM_CALLBACK' \
  --data-urlencode 'code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'
{
  "token_type": "Bearer",
  "expires_in": 1800,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJwYXJzZ2V0In0.sample-signature",
  "refresh_token": "def50200sample-refresh-token"
}

Access Token را مانند کلید شخصی در هدر Authorization: Bearer بفرستید. برای تمدید، از Refresh Token استفاده کنید؛ پس از تمدید، refresh_token قبلی باطل می‌شود و باید مقدار جدید پاسخ را جایگزین کنید.

برنامه موبایل یا کد داخل مرورگر نمی‌تواند Client Secret را محرمانه نگه دارد و به‌عنوان Public client ثبت می‌شود. اگر برنامه شما Confidential client است، Client Secret را فقط از backend بفرستید. در نسخه اول، دسترسی‌ها یا scopeها از قبل مشخص شده‌اند و در صفحه تأیید دسترسی به کاربر نمایش داده می‌شود؛ لازم نیست پارامتر scope بفرستید.

پاسخ‌ها و مدیریت خطا

پاسخ‌های موفق JSON معمولاً داده را در data و اطلاعات تکمیلی را در meta برمی‌گردانند. در فهرست‌های صفحه‌بندی‌شده، data آرایه است. پاسخ‌های 204 و 304 بدنه ندارند و پاسخ‌های OAuth ساختار جداگانه دارند.

برای مدیریت خطاهای API، ابتدا کد وضعیت HTTP و سپس error.code را بررسی کنید. error.message توضیح انگلیسی خطاست و error.details در صورت نیاز اطلاعات تکمیلی دارد. در پاسخ درخواست‌ها، وضعیت دانلود و وب‌هوک، کدهای خطا یکسان هستند و به خطاهای داخلی سرویس‌های دانلود وابسته نیستند.

مقدار هدر X-Request-ID پاسخ را در لاگ نگه دارید و هنگام گزارش خطا برای پشتیبانی بفرستید. پاسخ‌های خطای API Cache-Control: private, no-store دارند. پاسخ 401 هدر WWW-Authenticate: Bearer دارد؛ در خطای insufficient_scope، همین هدر دسترسی لازم را مشخص می‌کند. در خطای اعتبارسنجی، error.details.fields نام فیلدهای نامعتبر را نشان می‌دهد:

{
  "error": {
    "code": "validation_failed",
    "message": "The request contains invalid fields.",
    "details": {
      "fields": {
        "url": ["The field is invalid."]
      }
    }
  }
}

اگر پاسخ هدر Retry-After دارد، پیش از درخواست بعدی به اندازه آن صبر کنید. این هدر فقط زمان انتظار را مشخص می‌کند؛ پیش از تکرار عملیات، کد خطا و وضعیت دانلود را بررسی کنید. برای درخواست‌های دریافت اطلاعات، فاصله بین تلاش‌ها را به‌تدریج بیشتر کنید و کمی تأخیر تصادفی به آن اضافه کنید تا همه برنامه‌ها هم‌زمان درخواست نفرستند.

برنامه‌های داخل مرورگر می‌توانند هدرهای X-Request-ID، Retry-After، Location، ETag، WWW-Authenticate و محدودیت تعداد درخواست را از طریق CORS بخوانند.

محدودیت تعداد درخواست‌ها

محدودیت تعداد درخواست برای هر Personal API Key جدا محاسبه می‌شود. در OAuth، درخواست‌های یک کاربر از یک برنامه سهم مشترک دارند؛ گرفتن Access Token تازه سهم جدا ایجاد نمی‌کند. درخواست‌های دریافت اطلاعات، از جمله زیرنویس‌ها، سقف مشترک ۱۲۰ درخواست در دقیقه دارند. /cache/check سهم جداگانه‌ای با همین سقف دارد. ایجاد و تغییر دانلود و ساخت لینک به ۶۰ درخواست در دقیقه محدود است. App Storage هم سقف جداگانه ۱۲۰ درخواست در دقیقه دارد. با رسیدن به سقف، پاسخ 429 و هدر Retry-After دریافت می‌کنید.

جزئیات OAuth و Device Flow

Redirect URI باید دقیقاً با مقدار ثبت‌شده مطابقت داشته باشد، HTTPS باشد و userinfo، fragment یا ویرگول نداشته باشد. فقط Public client برای callback محلی می‌تواند از HTTP با آدرس IP 127.0.0.1 یا [::1] استفاده کند.

Authorization Code ده دقیقه اعتبار دارد. اعتبار پیش‌فرض Access Token سی دقیقه و Refresh Token سی روز است؛ برای Access Token همیشه مقدار واقعی expires_in پاسخ را مبنا بگیرید. آدرس endpointها و روش‌های پشتیبانی‌شده را از Discovery بخوانید:

https://api.parsget.com/.well-known/oauth-authorization-server

ورود در CLI و دستگاه‌ها

در Device Flow، کاربر می‌تواند ورود و تأیید دسترسی را در مرورگر دستگاه دیگری انجام دهد. این روش فقط برای Public client در دسترس است و باید Device Flow را در تنظیمات کلاینت در پنل فعال کنید. دستگاه ابتدا کدهای لازم را می‌گیرد:

curl -X POST https://api.parsget.com/oauth/device/authorize \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'client_id=7f43a8c2-6b8d-4e1f-9a52-3d0c7b6e41f9'
{
  "device_code": "7Wq9N2mP4xR6tV8yB3dF5hJ7kL9sC2eG4iM6oQ8uA1wE3rT5yU7pI9oS2dF4gH6j",
  "user_code": "ABCD-EFGH",
  "verification_uri": "https://api.parsget.com/auth/device",
  "verification_uri_complete": "https://api.parsget.com/auth/device?user_code=ABCD-EFGH",
  "expires_in": 600,
  "interval": 5
}

آدرس verification_uri_complete را به کاربر نشان دهید یا برای او باز کنید. همچنین می‌توانید verification_uri و user_code را نمایش دهید تا کاربر کد را دستی وارد کند. دستگاه با device_code و حداقل فاصله interval ثانیه، دریافت توکن را از endpoint زیر پیگیری می‌کند:

curl -X POST https://api.parsget.com/oauth/token \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \
  --data-urlencode 'client_id=7f43a8c2-6b8d-4e1f-9a52-3d0c7b6e41f9' \
  --data-urlencode 'device_code=DEVICE_CODE_FROM_PREVIOUS_RESPONSE'

اگر authorization_pending گرفتید، کاربر هنوز تأیید نکرده است؛ با همان فاصله ادامه دهید. با هر slow_down، پنج ثانیه به فاصله درخواست‌های بعدی اضافه کنید. با access_denied یا expired_token استعلام را متوقف کنید. با هر Device Code فقط یک بار می‌توانید توکن بگیرید.

برای دریافت کد ورود، هر IP می‌تواند حداکثر ۳۰ درخواست در دقیقه بفرستد. پاسخ ساخت کد و پاسخ موفق دریافت توکن قابل کش نیستند. پاسخ‌های خطای endpoint توکن ساختار JSON مخصوص OAuth دارند؛ آن‌ها را مانند error.code در API پردازش نکنید.

ثبت و پیگیری دانلود

POST /downloads برای ثبت دانلود از لینک است و فقط JSON می‌پذیرد. یک URL با HTTP/HTTPS یا لینک مگنت را در url بفرستید؛ سرور هاست یا سرویس مرتبط با لینک را تشخیص می‌دهد.

برای ارتباط دانلود با داده‌های برنامه خود، client_reference اختیاری را تا ۱۲۸ کاراکتر بفرستید؛ مثلاً شناسه قسمت یک مجموعه. چند دانلود می‌توانند برچسب یکسان داشته باشند. برای دریافت نتیجه از طریق وب‌هوک، webhook_url را هم بفرستید. جزئیات دریافت و اعتبارسنجی رویدادها در بخش وب‌هوک آمده است.

برای ثبت دانلود از فایل، از POST /downloads/upload با multipart/form-data استفاده کنید. فیلد file یک فایل .torrent، .nzb یا .xml تا ۴۰ MiB می‌پذیرد. سرور نوع تورنت یا یوزنت را تشخیص می‌دهد؛ type و file_type نفرستید. ساختار نتیجه و رفتار وب‌هوک در هر دو روش یکسان است. POST /downloads برای Content-Type نامعتبر پاسخ 415 می‌دهد.

بررسی نتیجه و انتخاب فایل

ابتدا data.kind را بخوانید. پاسخ 201 با data.kind="download" یعنی دانلود ثبت شده و مشخصات آن در data.download است؛ فایل هنوز لزوماً آماده نیست. با شناسه دانلود، وضعیت را از GET /downloads/{download} پیگیری کنید.

ایجاد دانلود برای بعضی از لینک‌ها به انتخاب کاربر نیاز دارد. برای مثال، پس از ارسال لینک یوتیوب، ابتدا کیفیت‌های موجود نمایش داده می‌شوند و دانلود تا زمان انتخاب کیفیت آغاز نمی‌شود. در این حالت، پاسخ شامل data.kind="selection" است و گزینه‌های قابل انتخاب را در data.selection.items برمی‌گرداند. کد وضعیت این پاسخ 200 است.

گزینه‌ها داخل یک آرایه قرار دارند و هر گزینه با parent_id مشخص می‌کند زیرمجموعه کدام گزینه است. کاربر فقط می‌تواند گزینه‌هایی را انتخاب کند که selectable=true دارند.

برای ادامه، شناسه یک گزینه را در item_id به POST /download-selections/{selection}/choices بفرستید. به‌جای {selection}، مقدار data.selection.id را قرار دهید. پاسخ می‌تواند دانلود ایجادشده یا مرحله انتخاب بعدی باشد؛ تا دریافت kind="download" همین روند را با اطلاعات مرحله جدید ادامه دهید. client_reference و تنظیمات وب‌هوک در طول مراحل حفظ می‌شوند.

اگر برنامه دوباره باز شد، با GET /download-selections/{selection} گزینه‌های مرحله‌ای را بگیرید که هنوز انتخاب آن ثبت نشده است. از همان حساب و همان برنامه OAuth یا Personal API Key استفاده کنید که مرحله را ایجاد کرده است. شناسه نامعتبر، منقضی یا متعلق به کلید یا برنامه دیگر، خطای 404 download_selection_not_found می‌دهد. مرحله‌ای که انتخاب آن قبلاً ثبت شده است هم 409 download_selection_already_resolved برمی‌گرداند.

شروع دوباره دانلود ناموفق

اگر can_retry=true باشد، می‌توانید دانلود را دوباره شروع کنید. برای این کار، POST /downloads/{download}/retry را فراخوانی کنید. با شروع موفق تلاش جدید، شناسه دانلود ثابت می‌ماند و attempt افزایش می‌یابد. وضعیت را با GET /downloads/{download} پیگیری کنید.

دریافت نتیجه با وب‌هوک

برای دریافت نتیجه دانلود، شامل تکمیل، خطا یا لغو آن، هنگام ایجاد دانلود webhook_url عمومی با HTTPS بفرستید. پیش از آن برای کلید شخصی یا برنامه OAuth خود webhook secret بسازید. پارس‌گت در هر تلاش تحویل، DNS آدرس را دوباره بررسی می‌کند، IPهای خصوصی و رزروشده را رد می‌کند و تغییر مسیر HTTP را دنبال نمی‌کند.

فقط رویدادهای download.completed، download.failed و download.canceled ارسال می‌شوند. data همان ساختار جزئیات دانلود را در زمان رویداد دارد، شامل نام، اندازه، نوع فایل، file_id، پیشرفت، خطا و زمان‌ها. data.attempt شماره تلاش دانلود را مشخص می‌کند. اگر دانلود پس از شروع دوباره باز هم با خطا متوقف شود، رویداد آن شناسه جدیدی دارد.

ممکن است یک رویداد چند بار برسد یا ترتیب دریافت رویدادها با زمان وقوع آن‌ها فرق داشته باشد. شناسه رویدادهای پردازش‌شده را نگه دارید تا یک رویداد دوباره اعمال نشود. رویداد متعلق به attempt قدیمی را روی وضعیت تلاش جدید اعمال نکنید. اگر وب‌هوک نرسید، وضعیت دانلود را استعلام کنید. endpoint جداگانه‌ای برای ثبت وب‌هوک یا دریافت تاریخچه رویدادها وجود ندارد.

اعتبارسنجی امضا

بدنه اصلی درخواست را پیش از parse کردن نگه دارید؛ امضا را روی همین بایت‌ها بررسی کنید. پیشوند whsec_ را از secret بردارید، باقی آن را Base64 decode کنید و از آن به‌عنوان کلید HMAC-SHA256 استفاده کنید:

signed = webhook-id + "." + webhook-timestamp + "." + raw_body
expected = "v1," + base64(HMAC-SHA256(base64decode(secret after whsec_), signed))

هنگام تعویض secret، هدر webhook-signature ممکن است دو امضا با فاصله داشته باشد؛ کافی است یکی معتبر باشد. زمان هدر webhook-timestamp را هم بررسی کنید تا درخواست قدیمی پذیرفته نشود.

تأیید دریافت و ارسال مجدد

پس از پردازش رویداد یا ذخیره مطمئن آن برای پردازش بعدی، پاسخ 2xx بدهید. تا دریافت این پاسخ، پارس‌گت ارسال رویداد را بدون محدودیت تعداد تلاش یا مهلت زمانی تکرار می‌کند. با حذف یا غیرفعال شدن کلید یا برنامه OAuth، یا نبودن webhook secret، ارسال متوقف می‌شود. بدنه رویداد ثابت می‌ماند، اما زمان و امضای هر ارسال تازه می‌شود.

خطای اتصال و پاسخ‌های 408، 425، 429 و 5xx باعث می‌شوند همه رویدادهای همان endpoint با فاصله افزایشی دوباره ارسال شوند. در هر نوبت فقط یک درخواست برای بررسی در دسترس بودن دوباره endpoint ارسال می‌شود. فاصله از حدود یک دقیقه شروع می‌شود و با کمی تأخیر تصادفی تا یک ساعت افزایش می‌یابد. Retry-After تا ۲۴ ساعت رعایت می‌شود. پس از موفقیت درخواست، ارسال رویدادهای منتظر ادامه پیدا می‌کند.

سایر پاسخ‌های غیر 2xx هم برای همان رویداد تکرار می‌شوند، اما مانع ارسال رویدادهای دیگر نیستند. برای هر origin فقط یک درخواست هم‌زمان ارسال می‌شود و بین درخواست‌ها حداقل یک ثانیه فاصله است. اگر اختلالی در صف ارسال رخ دهد، رویدادهای ارسال‌نشده به‌صورت دوره‌ای دوباره بررسی می‌شوند.

فایل‌ها و پخش رسانه

برای مرور فایل‌ها از GET /files استفاده کنید. بدون parent_id و download_id، فایل‌ها و پوشه‌های سطح اول حساب برمی‌گردند. برای محتوای پوشه، parent_id و برای فایل‌های یک دانلود، download_id را بفرستید. با kind=video می‌توانید فهرست را به ویدیوها محدود کنید.

برای دریافت مواردی که بعد از زمان مشخصی تغییر کرده‌اند، updated_after را بفرستید. مقدار باید زمان کامل RFC 3339 همراه با منطقه زمانی باشد، مانند 2026-08-26T12:00:00Z. مقدار خالی یا نسبی مثل tomorrow با خطای 422 رد می‌شود. با این فیلتر، ترتیب بر اساس updated_at و سپس id، صعودی است؛ بدون آن، ترتیب شناسه‌ها نزولی است. این فیلتر حذف‌ها را گزارش نمی‌کند و به‌تنهایی برای همگام‌سازی کامل کافی نیست.

برای صفحه بعد، meta.next_cursor را بدون تغییر در cursor بفرستید. meta.has_more=false یعنی به انتهای فهرست رسیده‌اید.

مشخصات رسانه، پوستر و زیرنویس

فهرست فایل‌ها اطلاعات خلاصه رسانه را دارد. برای جزئیات ویدیو، ترک‌های صوتی و زیرنویس‌های داخل فایل، GET /files/{file} را فراخوانی کنید. وضعیت رسانه یکی از pending، ready یا unavailable است. برای تشخیص وجود پوستر، poster !== null را بررسی کنید؛ فیلدی به نام media.poster_available وجود ندارد.

پوستر یک تصویر WebP با عرض حداکثر ۶۴۰ پیکسل است و می‌توانید آن را مستقیم در برنامه نمایش دهید. نشانی آن عمومی است، توکن دانلود ندارد و expires_at آن null است. دریافت تصویر به احراز هویت یا اعتبار دانلود نیاز ندارد. نشانی شامل شناسه تصویر و هش محتوای آن است و با تغییر محتوا تغییر می‌کند.

حذف فایل از فهرست یک کاربر، نشانی پوستر مشترک را باطل نمی‌کند. با حذف خود پوستر، درخواست جدید ممکن است 404 بگیرد؛ نسخه کش‌شده تصویر ممکن است تا یک سال باقی بماند.

برای زیرنویس‌های جدا از ویدیو، GET /files/{file}/subtitles را بخوانید. هر زیرنویس لینک دانلود با اعتبار یک ساعت دارد؛ expires_at همان مورد را مبنا بگیرید. برای زیرنویس‌های داخل ویدیو، مشخصات هر ترک در جزئیات فایل آمده است.

دریافت لینک دانلود یا پخش

POST /files/{file}/download-link لینک فایل اصلی را می‌سازد. برای پخش در برنامه خود از POST /files/{file}/playback استفاده کنید؛ پاسخ شامل لینک فایل با همان فرمت و کیفیت اصلی است. مقدار source.supports_byte_ranges=true یعنی می‌توانید با درخواست Range بخش مشخصی از فایل را دریافت کنید. اگر locked=true باشد، ساخت لینک دانلود یا پخش مجاز نیست.

مدت اعتبار لینک به حساب بستگی دارد. expires_at پاسخ لینک دانلود و source.expires_at پاسخ پخش را بررسی کنید.

ساخت پوشه و حذف فایل‌ها

برای ساخت پوشه، name و در صورت نیاز parent_id را به POST /files/folder بفرستید. اگر parent_id را نفرستید یا null بگذارید، پوشه در سطح اول حساب ایجاد می‌شود.

برای حذف گروهی، بین ۱ تا ۱۰۰ شناسه را در ids به POST /files/delete بفرستید. پاسخ 200 برای هر شناسه، به ترتیب ورودی، یک { file_id, status } دارد. deleted یعنی مورد حذف شده یا قبلاً برای حذف ثبت شده است. not_found یعنی شناسه برای این کاربر پیدا نشده است؛ شناسه متعلق به کاربر دیگر هم همین نتیجه را دارد. resource_locked یعنی فایل، پوشه یا یکی از موارد داخل آن قفل است و حذف نشده است. حذف پوشه شامل محتوای آن هم می‌شود.

دریافت پاسخ 200 به معنی حذف همه موارد نیست؛ نتیجه هر شناسه را جداگانه بررسی کنید. ساخت پوشه و حذف به files:write نیاز دارند. در نسخه اول این scope در دسترسی‌های کلید شخصی و برنامه OAuth قرار دارد و انتخاب جداگانه ندارد.

دانلود چند فایل در یک ZIP

با POST /files/zip می‌توانید چند فایل یا پوشه را با یک لینک دانلود کنید. بین ۱ تا ۱۰۰ شناسه را در ids بفرستید؛ filename اختیاری نام ZIP را تعیین می‌کند. سرور تشخیص می‌دهد هر شناسه متعلق به فایل است یا پوشه.

لینک در همان پاسخ برمی‌گردد؛ endpoint جداگانه‌ای برای وضعیت ساخت یا دریافت لینک ZIP وجود ندارد. expires_at را برای زمان انقضا بررسی کنید؛ مقدار null یعنی برای لینک انقضای زمانی تعیین نشده است.

سرویس‌ها و بررسی کش

GET /services کد، نام، نوع، وضعیت و دامنه‌های سرویس‌های پشتیبانی‌شده را برمی‌گرداند. برای دریافت الگوهای RegEx و تشخیص هاست یا سرویس مرتبط با هر لینک، include=url_patterns را اضافه کنید و هر الگو را با new RegExp(source, flags) در JavaScript بسازید. اگر برای سرویسی الگوی سازگار وجود نداشته باشد، url_patterns آن آرایه خالی است. meta.pattern_version نسخه مجموعه الگوها را مشخص می‌کند.

پاسخ با الگوهای RegEx و پاسخ بدون آن‌ها ETag جداگانه دارند و تا ۶۰ ثانیه به‌صورت private کش می‌شوند. برای بررسی تغییرات، ETag پاسخ قبلی را در If-None-Match بفرستید. پاسخ 304 یعنی از نسخه کش‌شده استفاده کنید.

پیش از ثبت تورنت، با POST /cache/check موجود بودن آن در کش را بررسی کنید. بین ۱ تا ۱۰۰ Info Hash با فرمت Hex یا Base32 بفرستید. پاسخ data به‌شکل { "submitted-hash": true } است؛ کلید دقیقاً همان مقدار ارسالی شماست. هش تکراری، حتی با تفاوت حروف بزرگ و کوچک، خطای 422 می‌دهد.

این درخواست فقط موجود بودن تورنت در کش را بررسی می‌کند. اعتبار مصرف نمی‌شود و دانلودی ایجاد نمی‌شود. true موجود بودن در لحظه بررسی را نشان می‌دهد؛ برای دانلود همچنان باید درخواست ایجاد دانلود بفرستید.

App Storage

برای ذخیره تنظیمات هر کاربر، مانند زبان برنامه یا ترجیحات اعلان‌ها، از App Storage استفاده کنید. هر کاربر در هر برنامه OAuth فضای جداگانه‌ای دارد. کاربران و برنامه‌های دیگر به داده‌های این فضا دسترسی ندارند.

این بخش فقط با OAuth کار می‌کند. storage:read برای خواندن و storage:write برای نوشتن و حذف است. Personal API Key خطای 403 oauth_required می‌گیرد.

کاردرخواست
فهرست کلیدها، مقادیر و مصرف سهمیهGET /app-storage
خواندن یک مقدار و ETag آنGET /app-storage/{key}
ساخت کلید یا جایگزینی مقدارPUT /app-storage/{key}
حذف کلید و مقدارDELETE /app-storage/{key}

فهرست صفحه‌بندی دارد و مصرف سهمیه در meta.quota می‌آید. کلید باید با الگوی [A-Za-z0-9_-]{1,128} مطابقت داشته باشد. مقدار، هر JSON معتبر تا ۶۴ KiB است و در فیلد value ارسال می‌شود. هدر Content-Type: application/json لازم است. ساختار JSON و فاصله‌های داخل مقادیر متنی حفظ می‌شوند؛ {}، [] و null هم مقادیر متفاوتی هستند. سقف هر کاربر در هر برنامه، ۲۵۶ کلید و مجموعاً ۵ MiB است.

جلوگیری از بازنویسی تغییرات هم‌زمان

فرض کنید کاربر تنظیمات برنامه را هم روی موبایل و هم روی کامپیوتر تغییر می‌دهد. اگر هر دستگاه فقط مقدار جدید را بفرستد، ممکن است تغییرات دستگاه دیگر را ناخواسته بازنویسی کند. برای جلوگیری از بازنویسی ناخواسته، ابتدا مقدار را با GET بخوانید و هدر ETag پاسخ را نگه دارید. سپس هنگام PUT یا DELETE همان ETag را در If-Match بفرستید. اگر مقدار تغییر کرده باشد، درخواست با 412 precondition_failed رد می‌شود؛ مقدار فعلی را دوباره دریافت کنید و تغییرات مورد نظرتان را بر اساس آن بفرستید.

ETag را کامل، همراه با علامت نقل‌قول، کپی کنید؛ آن را از version نسازید. حذف و ساخت دوباره کلید، ETag قدیمی را معتبر نمی‌کند. If-Match یک ETag، فهرست ETagها یا * برای شرط وجود کلید را می‌پذیرد؛ ETagهایی که با W/ شروع می‌شوند، با نسخه فعلی برابر در نظر گرفته نمی‌شوند. قالب نامعتبر هدر خطای 400 می‌دهد.

برای ساخت کلید فقط در صورت نبودن آن، PUT را با If-None-Match: * بفرستید. مثلاً این بدنه را برای player_preferences بفرستید:

{
  "value": {
    "autoplay": false,
    "subtitle_language": "fa"
  }
}

اگر کلید از قبل وجود داشته باشد، پاسخ 412 می‌گیرید و مقدار قبلی حفظ می‌شود. بدون If-Match و If-None-Match، هر درخواست مقدار موجود را جایگزین می‌کند.

خطاهای اندازه و سهمیه

اگر با ذخیره مقدار، تعداد کلیدها یا حجم کل داده‌ها از سقف مجاز بیشتر شود، پاسخ 422 app_storage_quota_exceeded می‌گیرید. مقدار بزرگ‌تر از ۶۴ KiB هم پاسخ 422 دارد، اما کد آن validation_failed است و جزئیات در error.details.fields.value می‌آید. این خطاها با تکرار خودکار حل نمی‌شوند؛ ابتدا حجم مقدار ارسالی را کم کنید یا داده‌های اضافی را حذف کنید. خطای 412 هم به بررسی نسخه فعلی داده نیاز دارد.

کاهش حجم پاسخ فایل‌ها

در GET /files و GET /files/{file}، فیلدهای poster، media و app_state به‌صورت پیش‌فرض در پاسخ نمی‌آیند. هر بخش را فقط هنگام نیاز درخواست کنید:

GET /api/v1/files?include_poster=true&include_media=true&include_state=true

هر گزینه را می‌توانید جداگانه بفرستید. مقدارهای پذیرفته‌شده true، false، 1 و 0 هستند. دریافت پوستر و مشخصات ویدیو فقط به files:read نیاز دارد. برای دریافت داده‌های برنامه، باید توکن OAuth با دسترسی‌های files:read و storage:read داشته باشید. اگر پوستر را درخواست کنید اما موجود نباشد، poster برابر null است. برای فایل‌های غیر ویدیویی هم مقدار media برابر null است.

با include_media=true، پاسخ GET /files خلاصه مشخصات صوتی و تصویری ویدیو را دارد. برای جزئیات کامل ترک‌ها از GET /files/{file} استفاده کنید. خلاصه مشخصات پخش، مانند کدک صوت و تصویر، در media.playback و در پاسخ GET /files/{file}/media می‌آید. برای دریافت لینک پخش همراه با این مشخصات، از POST /files/{file}/playback استفاده کنید.

فهرست ویدیوها در همه پوشه‌ها

برای نمایش همه ویدیوهای حساب، از درخواست زیر استفاده کنید. ویدیوهای داخل پوشه‌ها و زیرپوشه‌ها هم در فهرست می‌آیند و نیازی نیست محتوای هر پوشه را جداگانه درخواست کنید.

GET /api/v1/files?flatten=true&kind=video

با حذف kind=video، همه نوع فایل و پوشه را دریافت می‌کنید. مقدار پیش‌فرض flatten برابر false است؛ اگر فقط kind=video بفرستید، ویدیوهای داخل زیرپوشه‌ها به فهرست اضافه نمی‌شوند.

هنگام استفاده از flatten=true، شناسه پوشه در parent_id نفرستید؛ ترکیب این دو پاسخ 422 دارد. برای محدود کردن نتایج به فایل‌های یک دانلود، می‌توانید download_id بفرستید. مقدار parent_id در هر نتیجه نشان می‌دهد آن فایل یا پوشه داخل کدام پوشه قرار دارد.

برای دریافت صفحه بعد، مانند سایر فهرست‌ها از next_cursor استفاده کنید. سایر فیلترها، ترتیب نتایج و گزینه‌های دریافت پوستر، مشخصات ویدیو و داده‌های برنامه نیز در دسترس هستند.

ذخیره داده‌های برنامه برای فایل و پوشه

برای داده‌هایی مثل موقعیت پخش، انتخاب ترک صوتی یا تنظیمات نمایش پوشه، از /files/{file}/state استفاده کنید. هر فایل و پوشه برای هر برنامه OAuth یک شیء JSON مستقل تا ۶۴ KiB دارد. حجم این داده‌ها از سهمیه ۲۵۶ کلید و ۵ MiB فضای برنامه کم نمی‌شود و سهمیه مشترک دیگری هم ندارد.

عملیاتendpoint
خواندن داده‌های ذخیره‌شده برنامه شماGET /files/{file}/state
ساخت یا جایگزینی کامل داده‌هاPUT /files/{file}/state
پاک کردن داده‌ها بدون حذف فایلDELETE /files/{file}/state

شناسه {file} می‌تواند متعلق به فایل یا پوشه باشد. این endpointها فقط OAuth می‌پذیرند. برای خواندن، دسترسی‌های files:read و storage:read و برای نوشتن یا پاک کردن، files:read و storage:write لازم است. به files:write نیاز ندارید. برنامه‌ها و کاربران دیگر به این داده‌ها دسترسی ندارند.

بدنه درخواست PUT:

{
  "value": {
    "playback": { "position_seconds": 1234, "completed": false },
    "audio_track": 2
  }
}

value باید یک شیء JSON باشد؛ {} معتبر است، اما آرایه، رشته یا null در سطح اول پذیرفته نمی‌شود. آرایه و null داخل شیء مجاز است. سقف اندازه بر اساس بایت‌های JSON شیء با UTF-8 و بدون escape کردن حروف Unicode و / محاسبه می‌شود. مقدار بزرگ‌تر پاسخ 422 validation_failed دارد. بدنه خام درخواست تا ۵۱۲ KiB مجاز است و بدنه بزرگ‌تر پاسخ 413 request_too_large می‌گیرد. نویسه null و عدد نامتناهی پذیرفته نمی‌شود.

اگر فایل در دسترس باشد اما هنوز داده‌ای ذخیره نشده باشد، GET پاسخ 200 با data: null و بدون ETag می‌دهد. برای فایل حذف‌شده، علامت‌گذاری‌شده برای حذف یا متعلق به کاربر دیگر، پاسخ 404 است. پاک کردن داده‌هایی که وجود ندارند با DELETE هم 204 می‌دهد.

PUT کل شیء را جایگزین می‌کند. برای جلوگیری از بازنویسی تغییرات دستگاه دیگر، ETag کامل پاسخ را در If-Match بفرستید؛ برای ساخت فقط در صورت نبود داده‌ها، If-None-Match: * بفرستید. اگر شرط برقرار نباشد، پاسخ 412 می‌گیرید و تغییری ذخیره نمی‌شود. این شرط در DELETE هم بررسی می‌شود، حتی اگر داده‌ها دیگر وجود نداشته باشد. بدون هدر شرطی، آخرین درخواست ذخیره، مقدار قبلی را جایگزین می‌کند.

با حذف یا پاک‌سازی فایل منقضی‌شده، داده‌های آن خودکار پاک می‌شود. حذف پوشه، داده‌های همه موارد حذف‌شده زیر آن را هم پاک می‌کند. تغییر نام و جابه‌جایی، داده‌ها را حفظ می‌کند؛ کپی جدید یا فایل و پوشه بازیابی‌شده، داده‌های قبلی را ندارد. تغییر یا لغو توکن به‌تنهایی داده‌ها را پاک نمی‌کند. ذخیره داده‌ها، مهلت نگهداری فایل را تمدید نمی‌کند.

سقف مشترک GET، PUT و DELETE داده‌ها برای هر کاربر در هر برنامه ۱۲۰۰ درخواست در دقیقه است و بین همه توکن‌ها و دستگاه‌های همان برنامه تقسیم می‌شود. هنگام 429، پیش از تکرار درخواست به اندازه Retry-After صبر کنید.

برای دریافت داده‌ها همراه فهرست یا جزئیات فایل، include_state=true بفرستید. فیلد app_state شامل داده‌های ذخیره‌شده برنامه شما و etag مخصوص آن است؛ نبود داده‌ها با null مشخص می‌شود. این گزینه هم فقط با OAuth و دسترسی storage:read در کنار files:read کار می‌کند. سقف معمول درخواست‌های خواندن فایل همچنان برقرار است. برای داده‌های حجیم، اندازه صفحه را کمتر کنید؛ داده‌های ۱۰۰ فایل با حداکثر حجم مجاز، بدون احتساب سایر فیلدهای پاسخ، حدود ۶٫۲۵ MiB حجم دارند. تغییر داده‌ها در فیلتر updated_after فایل‌ها ظاهر نمی‌شود.

سازگاری برنامه با API

جزئیات درخواست‌ها، پاسخ‌ها و schemaها در مرجع API آمده است. API برای همه originها CORS دارد و فقط Bearer token می‌پذیرد؛ cookie احراز هویت نفرستید. توکن برنامه‌های OAuth به endpointهای داشبورد دسترسی ندارد.

در نسخه فعلی ممکن است فیلدهای اختیاری اضافه شوند. فیلدهای ناشناخته را نادیده بگیرید و برای کد خطا یا مقدار enum ناشناخته، رفتار پیش‌فرض در نظر بگیرید. حذف یا تغییر معنای فیلدهای موجود و دیگر تغییرات ناسازگار به نسخه جدید API نیاز دارند.

مطالب مرتبط