
منصة تحكم ذاتية الاستضافة وسطح مكتب عن بعد لمحطات عمل لينكس عبر Tailscale، مع بث WebRTC، التحكم الصوتي باستخدام LLM محلي، وحدات ماكرو للمشاهد، إدخال افتراضي، نقل الملفات، وقياس حيوي للنظام.
حوّل هاتف Android احتياطي (أو أي جهاز بمتصفح) إلى لوحة تحكم مستضاف ذاتياً وسطح مكتب بعيد لمحطة عمل Linux الخاصة بك — عبر شبكة Tailscale الخاصة بك، دون أي تطبيقات طرف ثالث.
لقد بدأ الأمر كسؤال «ماذا أفعل بهاتف قديم؟» وأصبح طبقة تحكم لنظام Hyprland: التحكم في النوافذ/مساحات العمل، وحدات الماكرو للمشاهد، موجه صوت بالضغط للتحدث مع مساعد LLM محلي، تحكمات سياقية داخل التطبيق، بث صوتي + شاشة ثنائي الاتجاه، سطح مكتب بعيد يعمل باللمس، لوحة مفاتيح/فأرة افتراضية، نقل الملفات + مشاركة من الهاتف إلى الحاسوب، وقياسات حية — كل ذلك يُقدّم كتطبيق ويب تقدمي (PWA) مثبت بمظهر طرفي فوسفوري.
ملاحظة حول قابلية النقل. بني هذا الإعداد لإعداد محدد: Linux قائم على Arch (Garuda) + Hyprland + PipeWire + NVIDIA + Tailscale، مع ملفات نقطة end-4 / illogical-impulse. البنية عامة، لكن العديد من التكاملات خاصة بالبيئة (أسماء الشاشات، ربط مساحات العمل، مسار ثيم matugen،
cpupower/nvidia-smi). عامله كمرجع عملي للتكييف، وليس كحزمة جاهزة.
الواجهة هي تطبيق ويب داكن، أفقي، مع علامات تبويب (متزامن مع ثيم سطح المكتب):
| التبويب | ما يفعله |
|---|---|
| مساحات العمل (Workspaces) | شبكة مساحات عمل حية لكل شاشة (اضغط للتبديل)، قائمة نوافذ حية (اضغط للتركيز)، تبديل DPMS لكل شاشة + سطوع ddcutil |
| التحكم عن بُعد (Remote) | لوحة لمس على الشاشة (سحب/نقر/إصبعين) + لوحة مفاتيح افتراضية مع معدّلات واختصارات، عبر جهاز uinput kernel |
| الأنماط (Modes) | وحدات ماكرو مشهد بنقرة واحدة — تشغيل/إغلاق/ترتيب تخطيطات تطبيقات كاملة عبر الشاشات (مثل «عمل» / «حر») |
| الصوت (Voice) | موجه صوت بالضغط للتحدث (faster-whisper، CPU): مسارات كلمة رئيسية — macro (تشغيل نمط/أمر)، type (إملاء)، input (عبارة → سلسلة مفاتيح) — مع تأكيد قبل التنفيذ، بالإضافة إلى «friday»، مجيب LLM محلي للقراءة فقط (Ollama + Qwen) مع بحث ويب مستضاف ذاتياً ووعي بحالة النظام الحية |
| الصوتيات (Audio) | كتم الميكروفون/مكبر الصوت، مستوى الصوت، منتقي أجهزة الإخراج والإدخال، نقل playerctl + غلاف الألبوم (يتتبع مشغل MPRIS النشط) |
| البث (Stream) | صوت WebRTC ثنائي الاتجاه (الحاسوب ↔ الهاتف، مع استخدام الهاتف كميكروفون وإخراج للهاتف فقط) + فيديو الشاشة، واضغط للتحكم في الشاشة المُبثَّة = سطح مكتب بعيد حقيقي |
| النظام (System) | تبديل وضع الأداء، تبديل الثيم الحي، حالة Tailscale، العمليات العليا (اضغط للقتل)، القفل، إعادة تشغيل NetworkManager، الإسبات/إعادة التشغيل/إيقاف التشغيل |
| الملفات (Files) | التقط لقطة شاشة لشاشة → عرض/تنزيل على الهاتف؛ إسقاط ملف من الهاتف إلى الحاسوب |
| الإعدادات (Config) | تحرير ملفات الإعدادات commands.json / modes.json (والسياق والصوت) من الهاتف (تم التحقق من JSON) |
دائماً في الأعلى، فوق علامات التبويب — شريط سياق يعرض ما يحدث الآن: مكالمة نشطة (كتم / الانتقال إليها)، وسائط قيد التشغيل + النقل، وتحكمات لوحة المفاتيح داخل التطبيق للتطبيق المركز (YouTube / Brave / Teams)، تُقدّم دون سرقة التركيز.
اثنان آخران، خارج علامات التبويب:
بالإضافة إلى: تسجيل دخول PIN بلوحة أرقام على الشاشة، قفل الشاشة من الاستيقاظ، PWA أفقي ملء الشاشة، وقفل الدخول بعد محاولات متكررة على تسجيل الدخول.
phone / laptop (browser PWA)
│ HTTPS + WSS (Tailscale-only)
▼
tailscale serve ──► FastAPI web app ── Unix socket ──► deckd
(real TLS cert) (runs as your user) (action names) (runs as root)
│ │
hyprctl · pactl · ddcutil · grim · fixed allowlist of
wf-recorder · uinput · WebRTC privileged commands
(cpupower, nvidia-smi,
systemctl, …)
عمليتان:
app/ — تطبيق الويب يعمل كمستخدمك العادي. يقوم بكل ما لا يحتاج صلاحيات الجذر: التحكم في Hyprland، الصوت، السطوع، التقاط الشاشة، الإدخال الافتراضي، بث WebRTC، نقل الملفات.deckd/ — مساعد جذر صغير (مكتبة قياسية فقط، بلا تبعيات) للإجراءات القليلة التي تحتاج صلاحيات. لا يرسل تطبيق الويب له سلاسل شل أبداً — بل فقط أسماء إجراءات من قائمة مسموحة ثابتة (governor_performance، gpu_power_limit، suspend، …)، تم التحقق منها في deckd/actions.py قبل تنفيذ أي شيء. حتى لو تم اختراق تطبيق الويب بالكامل، فإن نصف قطر الانفجار هو بالضبط الإجراءات المسموحة، دون أي حقن وسيط. المقبس هو root:<group> في الوضع 0660.tailscale serve يعرضه على اسم MagicDNS الخاص بك مع شهادة Let's Encrypt حقيقية؛ لا يرتبط أبداً بـ 0.0.0.0.يمكن لتطبيق الويب تشغيل أوامر الشل المُهيئة وحقن الإدخال كمستخدمك — فهو، بالتصميم، جهاز تحكم عن بُعد لجهازك. احتفظ به على شبكة ذيلك، خلف PIN، ولا تعرضه للجمهور.
pactl/توافق PulseAudio)hyprctl, pactl / pw-record / pw-play, playerctl, ddcutil,
wf-recorder, grim, cpupower, nvidia-smi, kitty (أو محطة طرفية)input (لـ ) ومجموعة (لـ )git clone <your-repo-url> phone-deck
cd phone-deck
uv sync # ينشئ .venv ويُثبّت التبعيات
uv run python -m app.set_pin # تعيين PIN فتح القفل
deckd)حرّر systemd/deckd.service أولاً — عيّن المسارات وDECK_SOCKET_GROUP لمجموعة ينتمي إليها مستخدمك (عادة مجموعتك الأساسية):
sudo cp systemd/deckd.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now deckd
deckd يعمل بنظام Python (مكتبة قياسية فقط — لا حاجة لـ venv).
شغّله مباشرة للتطوير:
uv run uvicorn app.main:app --host 127.0.0.1 --port 8765
…أو كخدمة مستخدم. حرّر مسارات systemd/phone-deck.service أولاً، ثم ثبّته.
مهم: في إعداد يتم فيه تشغيل Hyprland ليس عبر uwsm، لا يتم تنشيط graphical-session.target لنظام systemd، لذا لن تبدأ وحدة المستخدم تلقائياً عند تسجيل الدخول. الإصلاح الموثوق هو بدء تشغيله من Hyprland مع استيراد بيئة الجلسة — أضف إلى بدء التشغيل التلقائي لـ Hyprland (مثلاً ~/.config/hypr/custom/execs.conf في end-4):
exec-once = systemctl --user import-environment WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_RUNTIME_DIR DBUS_SESSION_BUS_ADDRESS XDG_CURRENT_DESKTOP && systemctl --user start phone-deck
فعّل الشهادات مرة واحدة: وحدة تحكم Tailscale الإدارية → DNS → Enable HTTPS Certificates.
قدّم التطبيق بشهادة حقيقية:
sudo tailscale serve --bg 127.0.0.1:8765
عيّن DECK_SECURE_COOKIES=1 في بيئة تطبيق الويب بمجرد تفعيل HTTPS.
افتح https://<your-host>.<your-tailnet>.ts.net/ في Chrome على الهاتف (يجب أن يكون على شبكة ذيلك)، سجل الدخول، ثم ⋮ → Install app. ينطلق بملء الشاشة، بقفل أفقي، مع إبقاء الشاشة مستيقظة. HTTPS مطلوب لمستخدم الخدمة العاملة PWA + قفل الاستيقاظ.
يعمل من أي جهاز في شبكة الذيل — بما في ذلك أجهزة الكمبيوتر المحمولة (تستخدم أسطح اللمس أحداث المؤشر، لذا يعمل الفأرة أيضاً). بث WebRTC هو نظير واحد (مشاهد واحد في كل مرة).
جميع إعدادات وقت التشغيل موجودة في ~/.config/phone-deck/ ويمكن تحريرها من علامة التبويب Config (تم التحقق من JSON، يحتفظ بنسخة احتياطية .bak). تدخل التغييرات حيز التنفيذ مع الإجراء التالي — لا حاجة لإعادة التشغيل.
commands.json — إجراءات شل مخصصة[
{ "id": "reload_wm", "label": "إعادة تحميل مدير النوافذ", "run": "hyprctl reload" },
{ "id": "deploy", "label": "نشر الموقع", "run": "cd /srv/app && ./deploy.sh",
"confirm": true, "timeout": 120 }
]
run قد تكون سلسلة (تُنفذ عبر bash -lc) أو قائمة (argv، بدون شل). تُشغّل هذه كمستخدمك — إنها ملف محلي موثوق.
modes.json — وحدات ماكرو للمشاهدكل نمط هو قائمة مرتبة من الخطوات تُنفذ عبر hyprctl:
launch {cmd, workspace, match?, once?} — افتح تطبيقاً على مساحة عمل. مع match (صنف النافذة) + once، لن يتكرر، ويعيد توجيه النافذة إذا هبطت على مساحة عمل خاطئة (مطلوب لتطبيقات مثل PWAs المتصفح التي تأتي نافذتها من عملية موجودة).close {match, workspaces?} — أغلق نوافذ من صنف معين، اختيارياً فقط على مساحات العمل المذكورة.move {match, workspace} — انقل النوافذ المتطابقة إلى مساحة عمل.focus {workspace} — بدّل مساحة عمل إلى العرض (مثلاً إعادة كل شاشة إلى مساحة عملها الرئيسية).موضع النمط محدد فقط إذا كانت مساحات عملك مثبتة على الشاشات. أضف روابط إلى إعداد Hyprland (اضبط أرقام مساحات العمل وأسماء الشاشات حسب أجهزتك):
workspace = 1, monitor:DP-3, default:true
workspace = 2, monitor:DP-3
# … إلخ
ترتدي اللوحة مظهراً فوسفورياً طرفياً مع أربعة ملفات ألوان قابلة للتبديل الحي — أخضر (افتراضي)، عنبر، جليدي، وتلقائي (يستمد درجة الفوسفور من لوحة خلفية matugen الخاصة بك، ~/.local/state/quickshell/user/generated/colors.json). بدّل في علامة التبويب System؛ يستمر الاختيار في ~/.config/phone-deck/theme.json. يخدمه app/theme.py كـ /theme.css. مهلة خمول المفكر المحيط وسطر الليتورجيا قابلة للتكوين هنا أيضاً.
WebRTC ثنائي الاتجاه عبر aiortc + PyAV، مربوط بـ PipeWire/Hyprland بأنابيب subprocess (يتجنب ربط أجهزة I/O الهشة):
.monitor مع parec → Opus.wf-recorder شاشة → aiortc، مع إعدادات جودة (540p / 720p / 1080p) للحفاظ على معدل البت معقولاً عبر الاتصالات غير المستقرة.hyprctl movecursor) + نقرات uinput. النقرة = نقر، السحب = تحريك، الضغط الطويل = نقر يمين.قيود: زمن انتقال ~150–300 مللي ثانية؛ موثوق فقط عندما يكون PWA في المقدمة (Android يُعلّق علامات التبويب الخلفية)؛ استخدم سماعات لتجنب الصدى؛ نظير بث واحد في كل مرة؛ لا يمكن للمتصفح التقاط صوت تطبيق الهاتف الخاص (ميكروفون فقط).
tailscale serve لـ HTTPS/WSS)uv run pytest
تغطي قائمة deckd المسموحة، JWT + قفل تسجيل الدخول، تجزئة PIN، محرر إعدادات التحقق، تحليل الأنماط، منطق جودة البث/الأوامر، ولوحة المفاتيح المدخلة. يتم التحقق من مسارات WebRTC/PipeWire/Hyprland الحية عبر حلقة إرجاع أثناء التطوير.
app/ تطبيق ويب FastAPI
main.py المسارات + WebSockets
hypr.py Hyprland (لقطة، إرسال، مقبس حدث، مؤشر)
audio.py التحكم في أجهزة PipeWire + playerctl
audio_rtc.py جسر WebRTC الصوت + فيديو الشاشة
hid.py لوحة المفاتيح/الفأرة الافتراضية عبر uinput
modes.py محرك وحدات الماكرو للمشهد
brightness.py ddcutil
grab.py لقطة شاشة + تحميل ملف
theme.py matugen → CSS
...
deckd/ مساعد جذر (مكتبة قياسية فقط) + قائمة إجراءات مسموحة
systemd/ وحدات الخدمة
tests/ مجموعة اختبارات pytest
MIT — انظر LICENSE (أضف واحداً قبل النشر إذا كنت تريد ترخيصاً مختلفاً).
بُني لـ Hyprland، PipeWire، Tailscale، aiortc، وملفات النقطة end-4.
/dev/uinputi2cddcutilaiortc + PyAV (مثبت عبر uv) لبث الصوت/الفيديو