Halcyon سے Jellyfin کو 1990s ویڈیو اسٹور بنائیں
Halcyon، Jellyfin لائبریری کو browser میں گھومنے پھرنے والی 1990s rental store بناتا ہے۔ Docker command، reverse proxy اور README میں درج حقیقی caveats جانیں۔
Halcyon آپ کی Jellyfin لائبریری کے ساتھ کیا کرتا ہے
Halcyon Video آپ کی Jellyfin لائبریری کو browser میں 1990 کی دہائی کی ایک ایسی video store میں تبدیل کرتا ہے جس میں گھوما جا سکتا ہے۔ آپ کی ہر film shelf پر ایک case بن جاتی ہے۔ آپ strip lights کے نیچے aisles میں چلتے ہیں، shelf سے box اتارتے ہیں، اسے پلٹ کر پچھلی طرف موجود specifications پڑھتے ہیں، اور playback شروع کرنے کے لیے اسے counter تک لے جاتے ہیں۔ Playback کے start، progress اور stop events واپس Jellyfin کو بھیجے جاتے ہیں، اس لیے resume points اور watch history درست رہتے ہیں۔
Halcyon موجودہ Jellyfin server سے Jellyfin API کے ذریعے data پڑھتا ہے اور اپنی کوئی library محفوظ نہیں رکھتا۔ یہ guide فرض کرتی ہے کہ Jellyfin پہلے ہی چل رہا ہے اور library کو درست طور پر scan کر رہا ہے۔ اگر ایسا نہیں ہے تو پہلے VPS پر Jellyfin کو media server کے طور پر ترتیب دیں اور اس وقت واپس آئیں جب normal web client میں آپ کی library درست نظر آنے لگے۔ اسے اس لیے install کیا جاتا ہے کہ library پہلے سے موجود ہے، نہ کہ اس لیے کہ آپ کو اپنی self hosting list میں ایک اور service درکار تھی۔
یہ project GPL-3.0 کے تحت جاری کیا گیا ہے اور اسے ایک شخص نے لکھا ہے۔ README میں واضح طور پر درج ہے کہ یہ pull requests قبول نہیں کرتا۔ Development تیزی سے آگے بڑھتی ہے اور regression پکڑنے کے لیے دوسرا maintainer موجود نہیں ہے، اس لیے store کسی اور کو دکھانے سے پہلے image version pin کریں۔ آخری section میں اس کا طریقہ بیان کیا گیا ہے۔
رینڈرنگ کہاں ہوتی ہے؟
براؤزر میں۔ Halcyon، Vite اور TypeScript ایپ ہے جو three.js پر مبنی ہے۔ three.js ایک JavaScript لائبریری ہے جو WebGL (web graphics library، یعنی براؤزر کا GPU کے ساتھ انٹرفیس) کے ذریعے 3D گرافکس بناتی ہے۔ اسٹور کی geometry اور box art اسی مشین پر composite ہوتی ہیں جو اسکرین چلا رہی ہوتی ہے۔
Container بہت کم کام کرتا ہے۔ یہ npm run serve چلاتا ہے، جو vite preview --port 1420 --strictPort --host ہے، اور built files کے ساتھ چند چھوٹے middleware routes فراہم کرتا ہے۔ Halcyon کوئی transcoding نہیں کرتا اور server پر کوئی engine نہیں چلاتا۔
اس لیے GPU سے متعلق سوال client کے بارے میں ہے۔ ایک چھوٹا VPS یہ کام آسانی سے انجام دے سکتا ہے، کیونکہ اس کا مطلب HTTP کے ذریعے static files فراہم کرنا ہے۔ اصل فیصلہ وہ laptop، tablet یا television کرتا ہے جس پر براؤزر چل رہا ہو کہ اسٹور روانی سے چلے گا یا بہت سست ہو جائے گا۔
ایک feature اس اصول سے مستثنیٰ ہے۔ Remote Play server پر headless Chromium instances چلاتا ہے اور rendered store کو WebRTC (web real time communication) کے ذریعے phone یا set top box تک stream کرتا ہے۔ اس راستے میں rendering server پر ہوتی ہے۔ پہلے سے زیادہ سے زیادہ 2 instances کی اجازت ہے، جسے REMOTE_PLAY_MAX_INSTANCES کے ذریعے تبدیل کیا جا سکتا ہے۔ /dev/dri device کو map نہ کیا گیا ہو تو یہ instances CPU پر render کرتے ہیں، اس لیے 2 core VPS پر ہر اضافی viewer کا اثر محسوس ہوتا ہے۔
آپ کی library سے store کیا معلومات حاصل کرتا ہے
Aisles Jellyfin کی اپنی structure سے آتے ہیں۔ Halcyon آپ کی libraries اور genres سے sections ترتیب دیتا ہے، اور آپ کے BoxSets سے sequels کو group کرتا ہے۔ ہر case کی پشت پر چھپی specs MediaStreams metadata سے آتی ہیں جسے Jellyfin پہلے ہی محفوظ رکھتا ہے۔ اس کا مطلب ہے کہ Jellyfin میں جو معلومات missing ہوں گی، shelf پر بھی وہ موجود نہیں ہوں گی۔
اس طرح store آپ کے metadata کا ایک درست عکس بن جاتا ہے۔ Docker Compose میں ایک arr stack سے حاصل کی گئی library، جس میں artwork اور genres پہلے ہی مکمل ہوں، یہاں generic names والی loose files کے folder کے مقابلے میں کہیں بہتر دکھائی دیتی ہے۔ Photo libraries بھی انہیں index کرنے والے software پر اسی طرح منحصر ہوتی ہیں۔ اس بات کو یاد رکھیں جب آپ اسی server پر موجود تصاویر کے لیے PhotoPrism اور Immich کا تقابل کریں۔
انسٹال کرنے سے پہلے video store کا ڈیمو آزمائیں
پروجیکٹ پوری store کو ایک synthetic library کے ساتھ hosted demo پر چلاتا ہے۔ اپنے deployment میں کسی بھی Halcyon URL کے آخر میں ?demo=1 شامل کرنے سے یہی کام ہوتا ہے۔
اسے hardware test کے طور پر استعمال کریں۔ ڈیمو library میں تقریباً 2,000 titles ہیں اور اسے browser کی تقریباً 2 GB memory درکار ہوتی ہے، جو زیادہ تر ذاتی libraries سے زیادہ ہے۔ اگر آپ جس device سے browse کرنے کا ارادہ رکھتے ہیں اس پر ڈیمو رک رک کر چلے، تو آپ کی اپنی library بھی رک رک کر چلے گی۔ اس کا حل بڑا VPS نہیں بلکہ نیچے بیان کیا گیا 2.5D mode ہے۔
Docker کے ساتھ چلائیں
یہ وہ command ہے جسے upstream documentation میں درج کیا گیا ہے۔
docker run -d --name halcyon --network host --restart unless-stopped \
ghcr.io/halcyon-video/halcyon-videoاس کے بعد تصدیق کریں کہ یہ شروع ہو گئی ہے۔
docker logs halcyon
curl -I http://127.0.0.1:1420log میں preview server کو port 1420 پر listening دکھائی دینا چاہیے، اور curl کو HTTP/1.1 200 OK کا جواب دینا چاہیے۔ جو container چند seconds کے اندر exit ہو جائے، اس کی وجہ تقریباً ہمیشہ port ہوتا ہے۔ --strictPort کا مطلب ہے کہ 1420 مصروف ہونے پر server خود کو 1421 پر منتقل کرنے سے انکار کرتا ہے، اس لیے بند ہو جاتا ہے۔
--network host Remote Play کے لیے ہے، store کے لیے نہیں۔ WebRTC کو stream حاصل کرنے والے device کے لیے machine کا حقیقی address advertise کرنا ہوتا ہے۔ default Docker bridge کے پیچھے container صرف اپنا 172.x address جانتا ہے، جس تک آپ کے network کا کوئی phone رسائی نہیں کر سکتا، اس لیے stream کبھی connect نہیں ہوتی۔ اگر آپ صرف browser میں store استعمال کرنا چاہتے ہیں تو port publish کریں۔
docker run -d --name halcyon -p 1420:1420 --restart unless-stopped \
ghcr.io/halcyon-video/halcyon-videoVPS پر یہ بہتر default ہے، کیونکہ host networking container کو machine کے ہر interface پر رکھتی ہے، جس میں public interface بھی شامل ہے۔ VPS پر Docker چلانا اس trade-off کی باقی تفصیل بیان کرتا ہے۔ --restart unless-stopped reboot کے بعد store کو دوبارہ چلاتا ہے۔ یہ وہی تصور ہے جو boot پر شروع ہونے والی Compose services میں استعمال ہوتا ہے۔
repository کو clone کرکے docker compose up -d چلانے سے image مقامی طور پر build ہوتی ہے۔ committed Compose file default طور پر source سے build کرتی ہے اور پہلے سے build شدہ image: line کو comment out رکھتی ہے۔ اگر آپ Compose کے تحت published image استعمال کرنا چاہتے ہیں تو اس line کا comment ہٹا دیں۔
August 2026 تک ایک اہم حد موجود ہے: published image صرف linux/amd64 ہے۔ multi architecture push کا arm64 حصہ emulation کے تحت ناکام ہو گیا، اور native arm runners دستیاب ہونے کا انتظار ہے۔ arm64 VPS پر pull کرنے سے no matching manifest for linux/arm64/v8 in the manifest list entries کے ساتھ failure ہو گی۔ ایسی صورت میں clone سے build کرنا ہی عملی راستہ ہے۔
اپنے Jellyfin سرور کا پتہ درج کریں
http://<host>:1420 کھولیں اور اپنے Jellyfin سرور کا پتہ، username اور password درج کرکے لاگ ان کریں۔ repository میں موجود .env.local.example فائل صرف local development کے لیے ہے۔ Vite ان variables کو client-side code کے لیے دستیاب کرتا ہے جن کے نام VITE_ سے شروع ہوتے ہیں، اس لیے وہاں درج Jellyfin password JavaScript bundle میں شامل ہو جاتا ہے، جسے ہر visitor download کرتا ہے۔ ایسے سرور پر جس تک دوسرے لوگ بھی رسائی حاصل کر سکتے ہوں، interface کے ذریعے لاگ ان کریں۔
browser براہ راست Jellyfin سے رابطہ کرتا ہے۔ Halcyon کا container Jellyfin API کے لیے proxy فراہم نہیں کرتا۔ شروع کرنے سے پہلے اس کے دو اہم نتائج سمجھ لیں۔
اول، Jellyfin کی رسائی browser سے ہونی چاہیے، صرف اس VPS سے نہیں جو Halcyon فراہم کرتا ہے۔ 127.0.0.1:8096 پر bind کیا گیا Jellyfin local test کے لیے درست ہے، لیکن باقی تمام صارفین کے لیے shelves خالی رہیں گی۔
دوم، یہ call cross-origin ہے، یعنی Halcyon کے address سے Jellyfin کے address تک جاتی ہے۔ Jellyfin بطور default API requests کا جواب Access-Control-Allow-Origin: * کے ساتھ دیتا ہے، اس لیے اضافی configuration کے بغیر کام ہو جاتا ہے۔ اگر آپ نے یہ setting محدود کر دی ہو، یا Jellyfin API کے سامنے authentication proxy رکھی ہو، تو browser console blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource دکھاتا ہے اور store خالی shelves کے ساتھ load ہوتا ہے۔
اسے authentication کے ساتھ reverse proxy کے پیچھے رکھیں
vite preview ایک preview server ہے۔ یہ TLS (transport layer security) کو terminate نہیں کرتا اور اس کا اپنا access control بھی نہیں ہے، اس لیے public استعمال کی صورت میں اسے nginx یا Caddy کے پیچھے ہونا چاہیے۔
server {
listen 443 ssl;
server_name halcyon.example.com;
location / {
proxy_pass http://127.0.0.1:1420;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Container کے سامنے domain name استعمال کرنے کے لیے ایک اور setting درکار ہے۔ DNS rebinding سے تحفظ کے لیے Halcyon، localhost، raw IP addresses اور اس machine کے ناموں پر جواب دیتا ہے جس پر یہ چل رہا ہے۔ Container کے اندر وہ machine خود container ہوتا ہے، اس لیے اس کا hostname آپ کا hostname نہیں ہوتا۔ halcyon.example.com کے طور پر آنے والی request مسترد کر دی جاتی ہے، اور response میں مسترد کیے گئے host کا نام دیا جاتا ہے۔ وہ نام شامل کریں۔
docker run -d --name halcyon -p 127.0.0.1:1420:1420 --restart unless-stopped \
-e HALCYON_ALLOWED_HOSTS=halcyon.example.com \
ghcr.io/halcyon-video/halcyon-videoیہ value comma separated ہوتی ہے۔ .example.com جیسا ابتدائی dot subdomains سے match کرتا ہے، جبکہ all check کو بند کر دیتا ہے۔ all صرف ایسی machine پر استعمال کریں جس تک باہر سے کوئی رسائی نہ رکھتا ہو۔
جب store کو https:// کے ذریعے serve کیا جائے تو login کے وقت درج کیا جانے والا Jellyfin address بھی https:// ہونا چاہیے۔ HTTPS page سے کی جانے والی plain http:// API call کو browser block کر دیتا ہے، اور console میں Mixed Content: The page at 'https://halcyon.example.com/' was loaded over HTTPS, but requested an insecure resource دکھائی دیتا ہے۔ Login ناکام ہو جاتا ہے، اور Halcyon کے اندر اس کی کوئی وضاحت نہیں ملتی۔ دونوں کو TLS کے ذریعے serve کریں، یا private network کے اندر دونوں کو plain HTTP پر رکھیں۔
اب authentication کی بات۔ Store، Jellyfin credentials طلب کرتا ہے، اس لیے URL تلاش کرنے والے اجنبی کو login screen نظر آتی ہے۔ ایک feature اس صورتِ حال کو بدل دیتا ہے۔ Settings اور پھر Connection کے تحت Remote Play فعال کرنے سے آپ کا Jellyfin session server کو مل جاتا ہے۔ اس کے بعد /remote.html پر آنے والے visitors کو آپ کی اصل library کی اپنی instance مل جاتی ہے۔ یہی اس feature کا مقصد ہے، اور اس کا مطلب یہ ہے کہ URL کی رازداری ہی internet اور آپ کی films کے درمیان رکاوٹ رہ جاتی ہے۔ اگر Remote Play فعال کریں تو پورے site کے سامنے Authentik کو self-hosted SSO gateway کے طور پر single sign-on رکھیں، یا public hostname ختم کر کے store تک wg-easy کے ذریعے managed WireGuard tunnel سے رسائی حاصل کریں۔
اس کے ساتھ دو تفصیلات اہم ہیں۔ Reverse proxy صرف store کی traffic لے کر جاتا ہے۔ Remote Play stream WebRTC over UDP ہے اور HTTP proxy سے نہیں گزرتی، اس لیے 3478/udp اور، جب bundled TURN relay استعمال ہو، 49200 سے 49260/udp پر اس کے لیے الگ path درکار ہوتا ہے۔ نیز، اوپر دیا گیا plain docker run کوئی volume محفوظ نہیں رکھتا، اس لیے Remote Play seed docker rm کے بعد برقرار نہیں رہتا۔ Compose file اسی وجہ سے halcyon-data volume کو /data پر mount کرتی ہے اور REMOTE_PLAY_SEED کو /data/remote-play-seed.json پر set کرتی ہے۔
جب store خراب کارکردگی دکھائے تو کیا کریں
Halcyon ضرورت کے وقت rendering کرتا ہے۔ idle store کوئی frame composite نہیں کرتا، اور window focus ختم ہونے پر animation loop رک جاتا ہے۔ اسی لیے کھلا ہوا tab laptop کی battery کو مسلسل استعمال نہیں کرتا۔ اس سے ایسے machine کو مدد ملتی ہے جو صرف کمزور کارکردگی کی حد پر ہو۔ لیکن ایسی machine کے لیے یہ کچھ نہیں کرتا جو store کو بالکل render نہ کر سکے۔
ایسے clients کے لیے 2.5D mode موجود ہے۔ یہ سادہ HTML اور CSS استعمال کرتا ہے اور WebGL استعمال نہیں کرتا۔ اسے Raspberry Pi جتنے محدود hardware کے لیے بنایا گیا ہے۔ آپ page reload کیے بغیر settings یا power menu سے 3D اور 2.5D کے درمیان تبدیل کر سکتے ہیں۔ اس لیے ایک ہی device پر دونوں modes آزمانے میں صرف چند seconds لگتے ہیں۔ توقعات حقیقت پسندانہ رکھیں۔ مصنف flat mode کو rough اور ابھی زیرِ تکمیل قرار دیتا ہے۔ اسے کمزور clients کے لیے fallback سمجھیں۔
جب کوئی client 3D store چلانے کے لیے بہت کمزور ہو تو failure واضح ہوتا ہے۔ tab خود reload ہو جاتا ہے، یا browser lost WebGL context کی اطلاع دیتا ہے، عموماً اس وقت جب shelves ابھی بھر رہی ہوتی ہیں۔ اپنی library کم کرنے کے بجائے اس device کو 2.5D پر منتقل کریں۔
image کو pin کریں، اور pull کرنے سے پہلے جانچ کریں
اس حصے کو سنجیدگی سے لیں۔ v0.1.0 سے v0.3.1 تک کے tags چند ہی دنوں کے اندر جاری ہوئے، اور v0.2.1 صرف اس لیے موجود ہے کہ v0.2.0 کے لیے image push ناکام ہو گیا تھا۔ Upstream کو bug reports بھیجنا خوش آئند ہے، لیکن patches نہیں؛ اس لیے release stream ایک فرد کی working state ہے۔
docker pull کی عادت کے ساتھ latest چلانے کا مطلب ہے کہ کسی بھی عام منگل کو store آپ کے نیچے تبدیل ہو سکتا ہے۔ digest کے ذریعے pin کریں، کیونکہ یہی واحد reference ہے جو تبدیل نہیں ہو سکتا۔
docker buildx imagetools inspect ghcr.io/halcyon-video/halcyon-video:0.3.1یہ tag کے پیچھے موجود digest دکھاتا ہے۔ اسے tag کی جگہ استعمال کریں۔
docker run -d --name halcyon -p 1420:1420 --restart unless-stopped \
ghcr.io/halcyon-video/halcyon-video@sha256:747dcc821a3d2fa318b50e76024783c1835609047e84f502e23d021bc1898b2010 August 2026 کو یہ digest 0.3.1 تھا۔ اسے نقل کرنے کے بجائے موجودہ digest خود پڑھیں، اور تبدیلی سے پہلے release notes بھی پڑھیں، کیونکہ یہاں patch release میں fixes کے ساتھ store layout کی تبدیلیاں بھی شامل ہو سکتی ہیں۔
FAQ
کیا Halcyon کو میرے VPS پر GPU درکار ہے؟
عام استعمال کے لیے نہیں۔ اسٹور کو browser میں three.js render کرتا ہے، اس لیے rendering client machine پر ہوتی ہے اور container صرف port 1420 پر static files فراہم کرتا ہے۔ استثنا Remote Play ہے، جو server پر headless Chromium چلاتا ہے اور نتیجہ stream کرتا ہے۔ یہ عمل CPU پر render ہوتا ہے، جب تک کہ hardware acceleration کے لیے /dev/dri کو container میں map نہ کیا جائے۔
کیا میں Halcyon کو public internet پر رکھ سکتا ہوں؟
صرف authentication کے پیچھے۔ اسٹور Jellyfin credentials طلب کرتا ہے، لیکن Remote Play فعال کرنے سے آپ کا Jellyfin session server کو دے دیا جاتا ہے۔ اس لیے /remote.html کھولنے والا کوئی بھی شخص login کیے بغیر آپ کی اصل library کی ایک instance حاصل کر سکتا ہے۔ اس کے سامنے single sign-on والا reverse proxy رکھیں، یا hostname کو public DNS سے باہر رکھیں اور VPN کے ذریعے اسٹور تک رسائی حاصل کریں۔
login کرنے کے بعد shelves خالی کیوں ہیں؟
browser براہ راست Jellyfin API کو call کرتا ہے، اس لیے Jellyfin کا browser سے reachable ہونا ضروری ہے، صرف VPS سے نہیں۔ browser console کھولیں۔ blocked by CORS policy کا مطلب ہے کہ Jellyfin، Halcyon کے address سے آنے والی request قبول نہیں کر رہا۔ Mixed Content message کا مطلب ہے کہ page HTTPS پر ہے، جبکہ آپ کا درج کردہ Jellyfin address plain HTTP ہے۔
کیا مجھے --network host درکار ہے؟
صرف Remote Play کے لیے۔ WebRTC کو machine کا حقیقی address advertise کرنا ہوتا ہے، لیکن Docker bridge کے پیچھے container صرف 172.x address فراہم کر سکتا ہے، جس تک آپ کے network کا کوئی phone نہیں پہنچ سکتا۔ browser میں اسٹور browse کرنے کے لیے -p 1420:1420 کافی ہے اور host کا بہت کم حصہ expose کرتا ہے۔
مجھے کون سا image tag استعمال کرنا چاہیے؟
latest کے بجائے digest کو pin کریں۔ docker buildx imagetools inspect ghcr.io/halcyon-video/halcyon-video:0.3.1 والی version کا digest پڑھیں، وہ digest چلائیں، اور release notes پڑھنے کے بعد ہی اسے تبدیل کریں۔ August 2026 تک published image صرف linux/amd64 ہے، اس لیے arm64 host کو clone سے docker compose up -d کے ساتھ build کرنا ہوگا۔