Persian Streams
مستندات پروژه · افزونهٔ غیررسمی Stremio
افزونهٔ غیررسمی استرمیو (Stremio) برای پخش فیلم و سریالهای ایرانی با زیرنویس فارسی.
اگر این افزونه برایتان مفید بوده، با حمایتتان کمک کنید پروژه زنده، سریع و بهروز بماند. ❤️
حمایت از پروژه
Stremio Addon · Node.js · Cloudflare Workers · Apache-2.0
📖 معرفی#
Persian Streams یک افزونهٔ غیررسمی برای Stremio است که با دریافت شناسهٔ IMDb از استرمیو، صفحهٔ محتوای متناظر را در منبع ایرانیِ تنظیمشده پیدا میکند و لینکهای مستقیم پخش و دانلود را به استرمیو برمیگرداند.
جریان کار نسخهٔ فعلی:
- استرمیو شناسهٔ
tt...را به افزونه میفرستد. - افزونه آن را به اندپوینت
quick-searchمنبع میفرستد و نتیجهای را انتخاب میکند کهimdb_idآن دقیقاً با درخواست برابر باشد. - صفحهٔ محتوا با Cheerio خوانده و پارس میشود.
- لینکهای قابل پخش برای فیلم یا قسمت سریال استخراج میشوند و بههمراه برچسب کیفیت، انکودر و وضعیت دوبله برگردانده میشوند.
⚠️ این پروژه هیچ فایل ویدیویی، زیرنویس یا محتوای رسانهای را میزبانی نمیکند و تنها لینکهایی را که منبع پیکربندیشده در اختیار میگذارد پردازش میکند. مسئولیت رعایت قوانین کپیرایت و مقررات محلی بر عهدهٔ کاربر است.
✨ قابلیتها#
- 🎬 پشتیبانی از فیلم و سریال از طریق منبعی از نوع
stream - 🔎 تطبیق مستقیم با IMDb با استفاده از
/quick-search?q={imdbId}&sort=modified_at%3Adesc - 📺 استخراج فصل و قسمت از شناسههای استاندارد استرمیو مانند
tt1234567:1:3 - 🏷️ نمایش برچسب کیفیت واقعی منبع (مثلاً
WEB-DL 4K 2160p 10bit HDR) بهجای سادهسازی آن به یک1080pعمومی - 🧑💻 تشخیص انکودر از روی برچسبهایی مانند
انکودر : PSAو نمایش آن در توضیح استریم - 💬 تشخیص وضعیت زیرنویس فارسی (دارد / ندارد) با الگوهای فارسی و انگلیسی
- 🔊 تشخیص نسخهٔ دوبله با کلیدواژههای
Dubbed،Dooble،دوبله،Farsi DubوPersian Dub - 🔢 پشتیبانی از اعداد فارسی و عربی-هندی در تشخیص فصل و قسمت
- 🗂️ fallback دایرکتوری باز فصل: اگر صفحه ساختار باکس دانلود نداشته باشد، لینک پوشهٔ فصل (
/S02/) دنبال میشود و فایل قسمت از روی نام فایل (S02E05،2x05،E05) پیدا میشود - 🎞️ تشخیص heuristic کیفیت از URL و متن پیرامون:
4K،1080p،720p،480p،360pیاUnknown - 🧩 استخراج لینک از ساختارهای رایج صفحهٔ دانلود شامل
handleDownloadClick(...)، لینک مستقیم وiframe - 🖼️ لوگوی مطلق در manifest که بهصورت خودکار از میزبان درخواست ساخته میشود
- 📦 دو runtime: اجرای Node.js/Express (
server.js) و Cloudflare Workers (worker.js) با هستهٔ مشترکaddon.js - ⚡ بیلدر سبک (
stremio-builder.js) بهجای SDK رسمی، برای جلوگیری از باندلشدن Express در Workers
🗂️ ساختار پروژه#
ساختار واقعی و بهروز پروژه (خروجی ls -R):
.
├── .gitignore
├── .github/
│ └── workflows/
│ └── deploy-streams.yml # دیپلوی خودکار Worker به Cloudflare
├── LICENSE # Apache License 2.0
├── README.md # راهنمای کاربر و راهاندازی
├── addon.js # هسته: manifest، استخراج stream، getStreams
├── stremio-builder.js # بیلدر سبک Stremio (جایگزین SDK رسمی در Workers)
├── server.js # سرور Node.js / Express (main در package.json)
├── worker.js # آداپتور Cloudflare Workers (main در wrangler.jsonc)
├── wrangler.jsonc # پیکربندی Worker: alias، assets، vars.BASE_URL
├── package.json # اسکریپتها و وابستگیهای Node.js
├── package-lock.json # نسخههای قفلشده وابستگیها
├── assets/
│ └── icons/
│ ├── logo.png # لوگوی استفادهشده در manifest
│ └── player-fa.png # فایل استاتیک اضافی
└── docs/
└── DOCUMENTATION.md # مستندات فنی کامل مطابق ساختار فعلی کد
| مسیر | نقش |
|---|---|
addon.js |
هستهٔ استخراج؛ تمام توابع fetch*، extract*، detect* بههمراه manifest و defineStreamHandler. خروجی: { ...addonInterface, getStreams } |
stremio-builder.js |
کلاس سبک AddonBuilder با defineStreamHandler و getInterface()؛ در wrangler.jsonc با alias جایگزین stremio-addon-sdk میشود |
server.js |
سرور Node؛ dotenv، Express، getRouter(addonInterface) از SDK رسمی، ساخت لوگوی مطلق با x-forwarded-proto و سرو assets/icons |
worker.js |
Worker؛ پارس مسیرهای /streams/...، تولید JSON با CORS، سرو asset از env.ASSETS و فراخوانی مستقیم getStreams |
wrangler.jsonc |
نام Worker، alias، assets.directory، vars.BASE_URL و compatibility_date |
.github/workflows/deploy-streams.yml |
دیپلوی خودکار Worker هنگام push به main |
پروژه در حال حاضر فایل تست، پیکربندی lint، Dockerfile یا
.env.exampleندارد.
🚀 نصب و راهاندازی محلی#
پیشنیازها#
- Node.js نسخهٔ ۲۰٫۱۸٫۱ یا بالاتر — دلیل: نسخهٔ قفلشدهٔ
cheerioدرpackage-lock.jsonمقدارengines.node >= 20.18.1را الزامی میکند. - npm
- برای حالت Worker: Wrangler (
npx wrangler) - برنامهٔ Stremio برای تست نصب افزونه
۱. دریافت کد#
git clone https://github.com/alirostami01/Persian-Streams.git
cd Persian-Streams
۲. نصب وابستگیها#
npm install
۳. ساخت فایل .env (برای Node)#
در ریشهٔ پروژه یک فایل .env بسازید:
PORT=8000
BASE_URL=https://www.example.com
| متغیر | وضعیت | پیشفرض | محل مصرف | توضیح |
|---|---|---|---|---|
BASE_URL |
اجباری | — | addon.js |
آدرس پایهٔ منبع ایرانی. اگر تنظیم نشود، برنامه با پیام خطا متوقف میشود |
PORT |
اختیاری | 8000 |
server.js |
پورت سرور HTTP |
ℹ️ در نسخهٔ Node فقط همین دو متغیر خوانده میشوند. URL مطلق لوگو بهصورت خودکار از
x-forwarded-protoوHostدرخواست ساخته میشود.
برای Cloudflare Workers مقدار BASE_URL در بخش vars فایل wrangler.jsonc قرار دارد و در داشبورد Cloudflare قابل override است:
"vars": { "BASE_URL": "https://f2my.top" }
میتوانید بدون فایل .env هم اجرا کنید:
BASE_URL=https://www.example.com PORT=8000 node server.js
۴. اجرای برنامه#
حالت Node.js (پیشنهادی برای توسعهٔ محلی):
npm start # اجرای معمولی: node server.js
npm run dev # اجرای توسعه با watch mode: node --watch server.js
خروجی موفق:
Persian Streams running on port 8000
Manifest: http://localhost:8000/manifest.json
اگر پورت اشغال باشد:
Port 8000 is already in use.
راهحل:
PORT=8001 npm start
حالت Cloudflare Workers (Edge):
npx wrangler dev
# Manifest: http://localhost:8787/streams/manifest.json
۵. نصب در Stremio#
نسخهٔ Node:
stremio://localhost:8000/manifest.json
نسخهٔ Workers (لوکال):
stremio://localhost:8787/streams/manifest.json
یا ابتدا manifest را در مرورگر بررسی کنید:
http://localhost:8000/manifest.json
http://localhost:8787/streams/manifest.json
☁️ استقرار (Deployment)#
گزینهٔ A: میزبانی Node.js (VPS، Railway، Render، Fly.io، Heroku)#
- Node.js نسخهٔ ۲۰٫۱۸٫۱ یا بالاتر روی محیط اجرا فعال باشد.
- وابستگیها را با
npm installنصب کنید. - دستور اجرا را روی
npm start(یعنیnode server.js) بگذارید؛mainدرpackage.jsonهمین است. BASE_URLرا در Environment Variables تنظیم کنید (بدون آن سرویس بالا نمیآید).PORTمعمولاً توسط خودِ میزبان تزریق میشود و کد آن را میخواند.
آدرس نصب پس از استقرار:
stremio://YOUR_DOMAIN/manifest.json
مسیرهای ضروری: /manifest.json، /stream/...، /assets/icons/logo.png
گزینهٔ B: Cloudflare Workers (پیشنهادی برای Edge، رایگان)#
wrangler.jsonc مقدار vars.BASE_URL را دارد و میتوان آن را در داشبورد override کرد.
npm install
npx wrangler deploy
یا بهصورت خودکار از طریق GitHub Actions (push به main با تغییر در worker.js، addon.js، stremio-builder.js، wrangler.jsonc یا assets/**).
آدرس نصب پس از استقرار:
stremio://<worker>.workers.dev/streams/manifest.json
مسیرهای ضروری Worker: /streams/manifest.json، /streams/stream/... و /streams/assets/icons/logo.png. همهٔ پاسخهای JSON هدر access-control-allow-origin: * دارند.
نکات HTTPS و Proxy:
- Node: سرور هدر
x-forwarded-protoرا میخواند تا پشت TLS proxy آدرس لوگوhttpsشود. اگر پراکسی شما این هدر را ست نمیکند،app.set('trust proxy', true)را اضافه کنید یا مطمئن شوید مقدارlogoدر/manifest.jsonدرست است. - Workers:
url.originهمیشه scheme درست را دارد و تنظیم اضافهای لازم نیست.
🎯 نحوهٔ استفاده#
پس از نصب افزونه در استرمیو:
- یک فیلم یا سریال دارای شناسهٔ IMDb را باز کنید.
- استرمیو درخواست
streamرا به افزونه میفرستد. - افزونه با شناسهٔ IMDb در منبع پیکربندیشده جستوجو میکند.
- برای فیلمها، لینکهای دانلود و پخش صفحهٔ فیلم استخراج میشوند.
- برای سریالها، فصل و قسمت انتخابشده پیدا میشود و لینک همان قسمت برگردانده میشود؛ اگر ساختار باکس دانلود پیدا نشود، دایرکتوری فصل بهعنوان fallback بررسی میشود.
- لینکها با برچسب کیفیت و در صورت تشخیص، با
• دوبلهو• encoder: ...در فهرست استریمها نمایش داده میشوند.
نمونهٔ خروجی در فهرست استریمها:
WEB-DL 1080p x265 → S1E3 - WEB-DL 1080p x265 • encoder: PSA
720p • دوبله → 720p
1080p NF WEB-DL x265 10bit → S2E5 - 1080p NF WEB-DL x265 10bit
🔌 مسیرها و API#
Node.js (server.js)#
| مسیر | توضیح |
|---|---|
GET / |
صفحهٔ سادهٔ معرفی افزونه و لینک نصب محلی |
GET /manifest.json |
manifest افزونه با URL مطلق لوگو |
GET /assets/icons/logo.png |
لوگوی افزونه |
GET /stream/movie/{imdbId}.json |
استریمهای فیلم؛ مثال: /stream/movie/tt1234567.json |
GET /stream/series/{imdbId}:{season}:{episode}.json |
استریم یک قسمت سریال؛ مثال: /stream/series/tt1234567:1:3.json |
Cloudflare Workers (worker.js)#
| مسیر | توضیح |
|---|---|
GET / |
پاسخ وضعیت JSON: { name, status:'ok', manifest:'/streams/manifest.json' } |
GET /streams یا /streams/ |
ریدایرکت 302 به /streams/manifest.json |
GET /streams/manifest.json |
manifest با لوگوی مطلق https://<origin>/streams/assets/icons/logo.png |
GET /streams/assets/icons/logo.png |
لوگوی افزونه (از env.ASSETS) |
GET /streams/stream/movie/{imdbId}.json |
استریم فیلم در Worker |
GET /streams/stream/series/{imdbId}:{season}:{episode}.json |
استریم سریال در Worker |
مسیر جداگانهای به نام
/healthدر کد وجود ندارد و404برمیگرداند؛ برای health check از/manifest.jsonیا/streams/manifest.jsonاستفاده کنید.
بررسی سریع با curl:
# Node
curl http://localhost:8000/manifest.json
curl http://localhost:8000/stream/movie/tt1234567.json
curl http://localhost:8000/stream/series/tt1234567:1:3.json
# Workers
curl http://localhost:8787/streams/manifest.json
curl http://localhost:8787/streams/stream/movie/tt1234567.json
curl http://localhost:8787/streams/stream/series/tt1234567:1:3.json
⚙️ خلاصهٔ عملکرد فنی#
معماری ماژولار#
stremio-builder.js (بیلدر سبک)
│
wrangler.jsonc ───┼─── addon.js (هسته: manifest + getStreams + extract*)
alias SDK → builder │ │
│ ├── server.js (Express + getRouter)
│ └── worker.js (Cloudflare adapter)
│
Stremio → /stream/... یا /streams/stream/... → getStreams()
جریان هسته (addon.js)#
Stremio request
↓
builder.defineStreamHandler(args) ← از stremio-builder.js در Worker، یا SDK رسمی در Node via getRouter
↓
getStreams(type, imdbId, season, episode)
├─ fetchTitleFromMeta(...) ← Cinemeta (نتیجه فعلاً استفاده نمیشود)
├─ resolveViaQuickSearch(imdbId) ← GET {BASE_URL}/quick-search?q={imdbId}
├─ fetchPage(contentUrl) ← HTML + cheerio.load
└─ extractMovieStreams($)
یا extractSeriesStreams($, S, E)
└─ fallback: extractLegacySeriesStreams → extractStreamsFromSeasonDirectory
↓
{ streams: [...] }
جزئیات مهم:
- تنها راه تطبیق محتوا در نسخهٔ فعلی،
quick-searchمبتنی بر IMDb است؛ fallback مبتنی بر عنوان یا slug وجود ندارد. - افزونه catalog، meta یا subtitle ارائه نمیکند و فقط منبعی از نوع
streamدارد. - منبع باید خروجی
quick-searchرا بهصورت آرایهٔ JSON با فیلدهایimdb_idوurlبرگرداند. - لینکهای فیلم از
.download-list،.download-boxو.dl-boxخوانده میشوند. - لینکهای سریال از
.download-seasonو.series-downloaditems .d-flexخوانده میشوند. - کیفیت ابتدا از برچسب متنی صفحه (
کیفیت : ...) و در نبود آن با heuristic از URL و متن تشخیص داده میشود. - در صورت خطا یا پیدا نشدن محتوا، پاسخ افزونه
{ "streams": [] }است. addon.jsدیگر سرور ندارد؛server.jsنقطهٔ ورود Node وworker.jsنقطهٔ ورود Edge است.wrangler.jsoncباalias: { "stremio-addon-sdk": "./stremio-builder.js" }از باندلشدن Express در Workers جلوگیری میکند.
برای توضیح دقیق تکتک توابع، selectorها و مسائل شناختهشده، فایل docs/DOCUMENTATION.md را ببینید.
🐛 عیبیابی#
پیام BASE_URL is not set میبینم#
- Node: فایل
.envوجود ندارد یاBASE_URLدر آن تعریف نشده است. مقدار را اضافه کنید و دوباره اجرا کنید. توجه کنید این بررسی حتی هنگامimportکردنaddon.jsهم اجرا میشود. - Workers: مقدار
vars.BASE_URLدرwrangler.jsoncیا داشبورد Cloudflare را بررسی کنید.
پیام Port 8000 is already in use#
پورت دیگری انتخاب کنید:
PORT=8001 npm start
هیچ استریمی نمایش داده نمیشود#
- ممکن است محتوا در منبع پیکربندیشده وجود نداشته باشد.
- ممکن است خروجی
/quick-searchهیچimdb_idمطابقی نداشته باشد. - ممکن است ساختار HTML صفحهٔ منبع تغییر کرده باشد.
- لاگهای سرور را بررسی کنید؛ مراحل Quick-search، Resolved، Fetch و تعداد استریمها چاپ میشوند.
در لاگ خطای TypeError: $ is not a function میبینم#
یعنی quick-search محتوایی پیدا نکرده و صفحهای برای parse وجود نداشته است. پاسخ HTTP همچنان {"streams":[]} است و کاربر خطایی نمیبیند؛ این مورد در بخش «مسائل شناختهشده» مستندات فنی توضیح داده شده است.
برچسب زیرنویس فارسی نمایش داده نمیشود#
وضعیت زیرنویس تشخیص داده میشود، اما تابع formatSubtitleLabel در نسخهٔ فعلی عمداً رشتهٔ خالی برمیگرداند و برچسبی به خروجی اضافه نمیکند.
لوگو در استرمیو نمایش داده نمیشود#
- Node: مطمئن شوید
/assets/icons/logo.pngاز بیرون قابل دسترسی است. در استقرار پشت HTTPS، مقدارlogoدر/manifest.jsonرا بررسی کنید؛ اگرhttp://بود، بایدx-forwarded-protoدرست تنظیم شود. - Workers: آدرس
https://<worker>/streams/assets/icons/logo.pngرا بررسی کنید.
لینک نصب روی صفحهٔ اصلی هنوز localhost است#
صفحهٔ / فقط یک صفحهٔ کمکی است و لینک نصب آن در کد به localhost اشاره میکند. برای نسخهٔ مستقرشده مستقیماً از آدرس عمومی خودتان استفاده کنید:
# Node
stremio://YOUR_DOMAIN/manifest.json
# Workers
stremio://YOUR_DOMAIN/streams/manifest.json
Worker دیپلوی نمیشود#
- آیا
CLOUDFLARE_API_TOKENوCLOUDFLARE_ACCOUNT_IDدر secrets گیتهاب تنظیم شدهاند؟ - نسخهٔ Wrangler در workflow روی
4.128.0پین شده است؛ لاگ Action را بررسی کنید.
🤝 مشارکت#
Pull Requestها و Issueها برای بهبود استخراج لینک، سازگاری با ساختارهای HTML جدید، افزودن تست و بهبود مستندات با آغوش باز پذیرفته میشوند.
پیش از تغییر منطق استخراج، بخشهای «نقشهٔ ماژولها» و «مسائل شناختهشده و بدهی فنی» در docs/DOCUMENTATION.md را مطالعه کنید؛ چند مورد کوچک و آماده برای شروع مشارکت آنجا فهرست شدهاند.
📄 مجوز#
فایل LICENSE این مخزن Apache License 2.0 است.
ساخته شده با ❤️ برای جامعهٔ فارسیزبان Stremio — حمایت از ادامهٔ مسیر