🔧 Memory Index + Legal RAG Fixes (2026-06-14 ~01:30 الكويت)
Fix ①②: Memory Index (openai/text-embedding-3-small pinned)
- التشخيص: main.sqlite كان فارغاً (0 chunks) رغم أن status يعرض أرقاماً قديمة. السبب الجذري = عملية reindex زومبي (setsid loop من turn سابق) ضخّمت ملف tmp لـ 200MB+ وتعيد البناء دون إتمام الـ atomic swap → main.sqlite يبقى فارغاً.
- الإصلاح: قتل الزومبي (kill -9) + حذف tmp اليتيمة + حذف main.sqlite الفارغ → إعادة بناء واحدة نظيفة. النتيجة: 854 files / 15110 chunks / meta valid (model=text-embedding-3-small, dims 1536) / integrity ok.
- التحقق:
openclaw memory search(CLI) يرجع نتائج دلالية مسجّلة (scores 0.4-0.6، عربي+إنجليزي) ✅.openclaw memory status --index→ Embeddings ready / Vector store ready / identity valid / dirty no ✅. - ⚠️ CAVEAT صريح: أداة
memory_search(داخل الـ gateway) لا تزال ترجع "index metadata is missing / paused" رغم سلامة الـ index 100%. السبب = bug في طبقة الأداة: الـ cached default manager يقيّم الـ identity بـ provider=null (lazy init) في الـ status snapshot الذي تعتمده الأداة قبل البحث؛search()يبدأ الـ provider خلف بوابةhasIndexedContentفلا يُحدّث الـ cached identity. ليست مشكلة بيانات — الـ CLI يثبت أن الفهرس يعمل. لم أعِد الفهرسة (تسبّب race يمسح الـ meta). يحتاج إصلاحاً على مستوى كود OpenClaw (eager provider init) أو استخدام الـ CLI/الذاكرة المحقونة تلقائياً بدل الأداة.
Fix ③: Legal RAG (skills/legal-rag) → voyage-law-2
- الحالة الفعلية: index.json كان فيه embeddings (gemini 3072-dim) ويعمل — لم يكن "بلا embeddings" كما وُصف (أُصلح جزئياً في 5 يونيو).
- التحسينات المنفّذة: (1) إثراء محتوى القوانين الكويتية (مدني 67/1980 + عمل 6/2010 + أحوال 51/1984 — مواد أكثر). (2) إعادة بناء الفهرس بـ voyage-law-2 (1024-dim، legal-tuned، +35% هامش عربي). (3) إضافة 429 retry/backoff لـ Voyage free tier (3 RPM).
- التحقق: retrieve()+answer يعمل: مكافأة نهاية الخدمة→M.51+M.53 ✅ ، التقادم→M.437(15y)+M.442(5y) ✅. backend=voyage، 7 records، dims 1024.
- backup gemini index محفوظ:
index.json.bak-gemini-.
🎬 Entertainment Hub — 12 Creative Enhancements + Bonus (2026-06-14 ~04:10 الكويت)
د. وائل طلب إضافة 12 فكرة إبداعية (التي اقترحتُها سابقاً في رسالة #11702 المبتورة) + share عليهم كلهم + فحص شامل + توصيات.
المُنفّذ (كله live-verified عبر browser DOM tests على hub.drwaelalkishawi.com):
1. الصفحة الرئيسية = قائمة فقط (note#1): cur="home" + loadHome() dashboard (10 بلاطات + بحث + شريط متابعة). 0 grid cards عند الفتح ✅. 2. multi-source series → episode list (note#2): كان مُنفّذاً سلفاً (renderSeriesPicker/psSeason) — تحقّقت: GoT 10 مصادر → قائمة المواسم 1-8 بدل تشغيل ح1 ✅. 3. 🎲 فاجئني (surpriseMe) — اختيار عشوائي من الكتالوج. 4. 🌙 مؤقّت النوم (setSleep) — إيقاف تلقائي بعد 15/30/45/60/90د + عدّاد حي ✅. 5. 🎚️ مبدّل الترجمة + الصوت (setSub/setAud) — HLS subtitleTracks/audioTracks. 6. 🔆 تحكم الصورة (picAdj/picFill) — سطوع/تباين/ملء الشاشة ✅ (brightness(1.2) applied). 7. 🔢 سجل المشاهدة (loadHistory) — تبويب 🕒 السجل، منفصل عن "تابع المشاهدة" ✅. 8. ♿ A11y: شريط ثابت A+/A-/تباين عالٍ، محفوظ في localStorage (font 16→17.6px) ✅. 9. ⏭️ next-episode overlay — كان موجوداً (_playNextEpisode) ضمن psPlay. 10-12. تكاملت ضمن الأعلى (extra-controls bar موحّد على كل مشغّل عبر playerHtml/mountPlayer wrap).Bonus #13 (اكتُشف من console): Mixed-Content logos fix
- شعارات القنوات تُخدم http:// → محجوبة على صفحة https → أيقونات فارغة (مئات الأخطاء).
- الحل: MutationObserver عام يعيد توجيه أي img http:// عبر /api/proxy تلقائياً (يغطي الحالي + المستقبلي).
- تحقّق حي: 248 شعار proxied، 0 متبقٍ http، 99+ حُمّلت فعلاً (naturalWidth=595). proxy يخدم image/png 200 ✅.
الفحص الشامل (كله ✅):
- node --check على JS المستخرج = SYNTAX_OK. div balance 204/204. 0 jinja {{/{%.
- 0 console JS errors (الباقي = mixed-content cosmetic، أُصلح بالـ bonus).
- endpoints محلية 7/7 = 200. HTTPS hub/status/ask = 200.
- threads ثابتة 3، RSS 2537MB (catalog mmap)، FDs=5 لا تسرّب، single instance.
- TEMPLATES_AUTO_RELOAD=True → لا restart مطلوب، no-cache headers → TV يلتقط فوراً عند إعادة الفتح.
- backups: index.html.bak-12ideas-<ts> + .bak-12ideas-final-<ts>. hub PID 338066.
🎬 Entertainment Hub — عدد الحلقات الكلي بجانب كل مصدر (مسلسلات) (2026-06-14 ~04:17 الكويت)
طلب د. وائل (صوت): في نتائج بحث المسلسلات، بجانب كل مصدر (مرتّب الأسرع أولاً) يظهر العدد الكلي للحلقات = مجموع حلقات كل المواسم. ينطبق على متعدد المصادر (لكل مصدر عدده) + المصدر الواحد (عدده أيضاً). إن كان فيه مواسم → المجموع الكلي عبر كل المواسم.
التشخيص:
- search hits للمسلسلات لا تحتوي عدد الحلقات (Xtream get_series لا يرجعه؛ يحتاج get_series_info لكل مسلسل).
- index-time counting مرفوض (آلاف الـ API calls وقت الفهرسة).
- الحل: lazy count on demand + cache.
التنفيذ (app.py):
- endpoint
/api/catalog/epcount/<sub>/<sid>— يرجّع episodes (مجموع كل المواسم) + seasons. - endpoint
/api/catalog/epcount_batch?items=sub:sid,...(cap 24/req) — batch للنتائج على الشاشة. - in-memory cache
_EPCOUNT_CACHETTL 12h (cap 4000). استخدمت_time(global، ليس baretime).
التنفيذ (index.html):
_fillEpCounts(root)— يجمع.ep-cntslots على الشاشة، batch في chunks 12، cache عميل__epCountCache، يملأ<b>N حلقة</b>.- مدمج في 3 مواضع: (1) بطاقة البحث (subLine لكل مصدر فريد — single+multi)، (2) قائمة المصادر الموسّعة (toggleSources)، (3) source picker rows (openSourcePicker). كلها series-only.
- CSS
.ep-cnt(أصفر، tabular-nums).
التحقق الحي (browser DOM، hub.drwaelalkishawi.com):
- بطاقة GoT: Lion 73 حلقة · xiptv 73 · Adam gold 73 · Bazoka 74 · Adam vip new 73 (الأسرع أولاً) ✅. 52 slot، تملأ batch تدريجياً.
- source picker GoT: 10 صفوف، كل صف "Lion → 73 حلقة" ✅.
- single-source series (Breaking Bad): يظهر العدد أيضاً ✅.
- 0 console errors. endpoints batch+single 200. cache warm=1-11ms.
- hub PID 384841 ثابت (3 threads، 2.5GB، single instance، uptime 232s). HTTPS 200.
- backups: index.html.bak-epcount-<ts> + app.py.bak-epcount-<ts>. لا restart مطلوب للـ template (auto-reload)؛ app.py أُعيد تشغيله مرة (PID 384841).
🎬 Entertainment Hub — التوصيات الأربع مُنفّذة (2026-06-14 ~04:25 الكويت)
د. وائل وافق على التوصيات الأربع السابقة وطلب تنفيذها كلها + فحص شامل + توصيات جديدة.
المُنفّذ (كله live-verified browser DOM على hub.drwaelalkishawi.com):
1) ☁️ المزامنة السحابية (TV↔phone):
- backend:
/api/sync/pull/<code>+/api/sync/push/<code>(POST). تخزين JSON فيsync/sync_<code>.json، merge newest-wins (resume بالـ ts، fav/history union+dedupe). cap (resume 300، fav 200، history 150). - frontend: رمز مزامنة سري لكل جهاز (localStorage hub_sync_code)، auto pull on load، auto push debounced 3s عند تغيّر resume/fav/history (wrap على _resumeSave/_lsSet/_histSave). dialog openSyncSettings + زر على الـ home.
- verified: push→clear local→pull→استرجاع كامل (resume "Sync Test Movie" + fav "Test Fav Channel") ✅.
- loadRecs(): seeds من history+fav، _seedTerm (أول كلمتين)، بحث related، استبعاد المُشاهَد، عرض strips على الـ home.
- verified: history=GoT+Breaking Bad → قسمان "✨ لأنك شاهدت «Game Thrones»" + «Breaking Bad» + 24 بطاقة ✅.
- voiceSearch() lang=ar-SA (يلتقط عربي+إنجليزي)، أزرار 🎤 على الـ home + شريط البحث، pulse أحمر أثناء الاستماع، يوجّه للبحث تلقائياً.
- verified: _voiceSupported()=true، الأزرار حاضرة، الدوال معرّفة ✅.
- بنيتُ EPG أولاً (كان فارغاً): trigger reindex_epg → 545,283 برنامج (epg_ready=True).
- _fillEpgNow(): يجلب /api/epg/channel/<sub>/<sid> (instant DB)، يعرض ▶ الآن + ⏭ التالي + الوقت، lazy+cached على بطاقات live search.
- verified حي: "▶ Gassal 03:50 ⏭ Haiti-İskoçya 04:00" · "▶ Haber 04 ⏭ Haber 05" ✅.
Bonus: قوّيت إصلاح الشعارات المحجوبة (Mixed-Content) — أضفت global error-capture retry عبر proxy (يلتقط الصور التي تسبق الـ observer).
الفحص الشامل (كله ✅):
- 0 JS console errors (الباقي = mixed-content/502 logos من مزودي IPTV ميتين، cosmetic، onerror يخفيها).
- node --check سليم · div 211/211 · endpoints 9/9 = 200 · HTTPS hub/status/ask=200.
- الأداء: home 16ms · search 322ms · EPG 22ms · sync 2ms · epcount 1ms.
- الاستقرار: نسخة واحدة فعلية (PID 385809، 3 threads، uptime ثابت، ppid=1). transients من single-instance guard تموت <1s (by design).
- RSS 2961MB (بعد تحميل EPG 545K — متوقع).
- backups: index.html.bak-4recs-<ts> + app.py.bak-4recs-<ts>. app.py أُعيد تشغيله مرة (routes جديدة).
🎬 Entertainment Hub — logo cache + EPG record + voice commands + cron verification (2026-06-14 ~04:50 الكويت)
د. وائل طلب تنفيذ 3 تحسينات: (1) تنظيف الشعارات الميتة + cache، (2) الضغط على EPG next → خيار تسجيل مع تأكيد، (3) بحث صوتي بأوامر. وطلب تأكيد auto-update للـ EPG/catalog + شرح أيقونات الواجهة.
1) Logo cache / dead logo cleanup ✅
- backend:
/api/logo?u=...— يخزّن الصور فيlogocache/keyed by SHA1، يخدم cached copy أسبوع، ويُرجع SVG placeholder للروابط الميتة مع negative cache 6h. يدعم http+https، cap 3MB. - frontend:
_imgSrc(u)render-time يحوّل كل الصور الخارجية إلى/api/logoقبل أن يراها المتصفح (حل جذري لـ Mixed Content race). observer/error fallback بقي كحماية ثانوية. - verification: TRT search: 106 images عبر
/api/logo, 0 raw http, 0 console errors. cached logo endpoint = 2ms ✅.
2) EPG → schedule recording ✅
_renderEpgيضيف زر🔴 سجّلبجانب البرنامج التالي.recordEpgProg(idx)يعرض dialog تأكيد قبل أي تسجيل (كما طلب د. وائل): الاسم + من/إلى + مدة + source._doRecEpgيستدعي/api/rec/schedule?sub=...&kind=live&sid=...&start_ts=...&duration=...&name=....- verification: ضغط زر TRT next → dialog: "Haiti - İskoçya, 04:00→06:00, K8" + أزرار نعم/إلغاء ✅. لم يتم schedule فعلياً أثناء الاختبار (اكتفينا بالـ confirm dialog).
3) Voice commands ✅
_voiceRoute(raw)يدعم:
- fix: كان
window.qلا يغيّر lexicalq→ أصلحته إلىq=term. وكان regex «افتح قناة TRT» يتركة TRT→ أصلحته بأولوية channel-search قبل navMap. - verification: «افتح قناة TRT» → q=TRT + 123 result. «شغل TRT» → فتح modal: TR- TRT Spor HD ✅.
4) Auto-update verification ✅
- EPG cron موجود وفعّال:
c0ff96fb-aad8-4e7b-b093-3fabdd18ada7, schedule30 /3Asia/Kuwait = كل 3 ساعات (أفضل من 4h)، lastRun ok 60.6s. - Catalog cron موجود وفعّال:
a52c22e6-9b94-4cd9-a2c7-34f5ea029350, schedule0 4Asia/Kuwait = كل 24 ساعة، lastRun ok 58.5s.
5) Home icons explanation ✅
- البلاطات الثابتة في واجهة home تأتي من
loadHome()→home-tiles→ دالةtile(tab, emoji, label, color). ليست API ولا load خارجي. - أسفل الواجهة المتغيّر: continue strip من
hub_resume، recommendations منhub_history+fav_items، cloud sync button ثابت.
Final checks ✅
- endpoints: home/status/epg/logo/scheduled/search all HTTP 200.
- performance: home 13ms · search TRT 54ms · EPG 21ms · cached logo 2ms · scheduled 1ms.
- stability: hub PID 387740, uptime 442s, 3 threads, RSS 3220MB (catalog+EPG mmap), FDs=4.
- backups:
templates/index.html.bak-logo-epgvoice-1781401879,app.py.bak-logo-epgvoice-1781401879.
🎬 Entertainment Hub — Clean Home + Record Now verification/fix (2026-06-14 ~05:03 الكويت)
طلب د. وائل: (1) زر "سجّل الآن" المفروض موجود — تحقق/أخبرني ولا تضف من الصفر؛ (2) الصفحة الرئيسية تكون نظيفة ولا تُحمّل أي items تلقائياً؛ (3) full check.
Home cleanup ✅
- استبدلت
loadHome()بواجهة نظيفة جداً:
home-tiles عناصر ظاهرة.
- لا homeRecs.
- لا Continue strip.
- لا زر sync أسفل الصفحة.
- فقط عنوان + صندوق بحث + زر mic + hint: "لا يوجد تحميل تلقائي هنا".
- verified browser:
homeTiles=0,homeRecs=false,cards=0,cw=0,syncShortcut=false✅.
Record Now ✅
- التشخيص: زر التسجيل الفوري كان موجوداً في مسار IPTV/اشتراكاتي (
dvrBar) لكن كان ناقصاً في مسار نتائج البحث متعدد المصادر/source picker. - أصلحت source picker: بعد اختيار مصدر قابل للتشغيل يُضاف
dvrBar(...)أيضاً. - غيّرت تسمية زر التسجيل الفوري لتكون واضحة:
🔴 سجّل الآن (60ث)بدلسجّل 60ث. - verified browser على TRT من البحث: modal TR- TRT Spor HD،
hasDvr=true,hasRecordNow=true, text:📸 لقطة 🔴 سجّل الآن (60ث) 🔴 5دق ⏰ جدولة 📁 تسجيلاتي✅. - verified API فعلياً: start recording 1s (server min=5s) على أول TRT source → file
VERIFY_RECORD_NOW_1S_1781402540.mp4ظهر في downloads ✅ ثم حُذف بنجاح عبر/api/rec/delete✅.
Final checks ✅
- endpoints all 200: home/status/search/logo/epg/rec jobs/downloads.
- perf: home 18ms · search 30ms · logo 3ms · EPG 24ms · downloads 2ms.
- stability: PID 387740, uptime 1149s, threads 4, RSS 3240MB, FDs 7.
- browser console: only upstream stream 503 from provider
xvip.produring channel playback (not code/UI), no Mixed Content/logo errors. - backup:
templates/index.html.bak-cleanhome-recordnow-1781402586,app.py.bak-cleanhome-recordnow-1781402586. - 05:00 Weekly full audit: CHANGES_COUNT=8; updated npm CLIs (mcporter, Claude Code, OpenClaw, Codex, Kilo), Hermes; gh update available; Python still has 196 outdated packages due pypfopt resolution issue.
- New models logged in MODEL_REGISTRY.md: claude-fable-5, kimi-k2.7-code, OpenRouter additions; no config.patch applied because none replaces primary Opus 4.8 yet.
🎬 Entertainment Hub — DVR Center + Now-On-Air + recovery verify (2026-06-14 ~05:55 الكويت)
(1) Recovery cron b37d2662 — verified post-restart ✅
- ran ok at 05:00 (2026-06-14 02:34Z): built encrypted brain point → R2 restore-points/ → emailed (emailed=1). SUMMARY: recovery-20260614-023419 | 1.8G | sha 7cf5eeed94de. lastRunStatus=ok, lastDelivered=true, consecutiveErrors=0. NO json5 error anywhere in the run (grep clean في build_recovery_point.sh + weekly_recovery_point.sh).
(2) DVR features completed ✅
- مدة حرة: كانت موجودة (doRecMin + input دقائق) — مؤكدة.
- «حتى نهاية البرنامج»: موجود (doRecUntilEnd → /api/rec/until_end يحسب من EPG channel_now + pad). مؤكد.
- DVR Center موحّد (جديد): tab
dvr🎬 مركز التسجيل → loadDvrCenter() يجمع 3 أقسام في صفحة واحدة: 🔴 جارٍ (مع إيقاف) · ⏰ مجدول (مع إلغاء) · ✅ محفوظ (فتح/حذف). يستهلك /api/rec/jobs + /api/rec/scheduled. زر «تسجيلاتي» في dvrBar صار يفتح DVR Center. - البحث الصوتي يفتح EPG Live (جديد): أمر «ماذا يعرض الآن / يُعرض الآن / على الهواء / EPG live» → switchTab('onair') + فلترة اختيارية بالباقي. + navMap fallback. مؤكد بالمتصفح: cur='onair'.
- وضع Now-On-Air (جديد): tab
onair🔴 يُعرض الآن → loadOnAir() + endpoint جديد /api/epg/onair (catalog_search.epg_onair) يسرد كل البرامج on-air الآن بلا بحث (dedup per channel, sorted). مؤكد: 371 قناة 🔴.
(3) الهب 8899 + القالب الجديد ✅
- single instance مستقر (PID launched by keepalive cron 31398c3f), 200/200 على 6-10 محاولات. كل endpoints 200 (root/jobs/scheduled/downloads/onair/program_end/epg-search). القالب الجديد محمّل (data-s=onair/dvr + loadOnAir/loadDvrCenter في HTML المُقدّم).
- backups: app.py.bak-dvrcenter-1781404983 · index.html.bak-dvrcenter-1781404983.
🐛 Root-cause fix (keepalive duplicate-hub churn) — durable
- السبب: daemons_keepalive.sh §69 كان فيه حارس مكسور
pgrep -f "entertainment-hub/app.py"— الهب يعمل cwd-based كـpython3 app.pyفالنمط لا يطابق أبداً → كان يُطلق نسخة مكرّرة كل tick (single-instance guard يقتلها = churn + port races). أزلتُ الحارس المكسور (block 1) وأبقيتُ الحارس port-based الصحيح (block 2). - + Grace: أضفتُ 3-try probe (3s بين كل) قبل إعلان الهب «down» في block 2 — يمنع قتله أثناء نافذة prewarm/bind (~2-5s) عند الإقلاع. مؤكد bash -n OK.
- درس: أي هب يُطلق من داخل exec-tool session يموت عند انتهاء الـ session (setsid لا يكفي). الإطلاق الموثوق الوحيد = keepalive cron (PPID=1 مستقل). للمستقبل: لا تطلق الهب يدوياً من exec — شغّل keepalive cron أو انتظر دورته (كل 5min).
🎬 Entertainment Hub — Upgrade + Hardening (2026-06-14 ~05:10-06:00)
د. وائل طلب فحص ترسانة الترفيه + تطوير. نُفّذ بالكامل وتم التحقق الحي:
تحسينات الأداء:
1. Lazy one-page render (templates/index.htmlrenderGroupedSearch): بدل حقن innerHTML ضخم (آلاف cards = تجمّد S24)، الآن paint chunked 60/دفعة + IntersectionObserver infinite-scroll. كل النتائج في صفحة واحدة (لا pagination — قرار د. وائل صريح).
2. اعتزال /api/search القديم (live على 12 اشتراك = 5s): صار delegation فوري لـ catalog DB المفهرس (5s→0.09s). helpers unified_search.py باقية (يستخدمها indexer).ميزات جديدة:
3. Auto source-failover (offerFailover+switchProvider(i,auto)+_autoNext+_armAutoHop): عند فشل بث → تبديل تلقائي لأسرع مصدر بديل (fastest-first)، يتسلسل تلقائياً لو فشل التالي. يحقق «لا توقف أبداً».
4. مدة تسجيل: حقل دقائق حر (doRecMin) + «حتى نهاية البرنامج» من EPG (/api/rec/until_end + /api/rec/program_end، recorder cap رُفع 60min→4h). + جدولة 3h/4h.
5. DVR Center موحّد (loadDvrCenter — كان tab معرّف لكن الدالة مفقودة!): live recording + scheduled + saved files + delete في صفحة واحدة.
6. Voice→EPG-Live (_voiceOpenEpgNow): «شغّل مباراة الآن»/«وش شغال» → يفتح EPG بفلتر الآن.
7. Now-On-Air grid (loadOnAir — كان tab معرّف والدالة مفقودة!): شبكة برامج على الهواء + شريط تقدّم + صورة.إصلاحات:
- Recovery cron json5 error: السبب = تحديث OpenClaw 2026.6.6 الساعة 05:07 ثبّت json5/tslog لكن عملية gateway القديمة بقيت بكاش وحدات قديم. الحل: gateway restart → الكرون صار status:ok, emailed=1 (recovery-20260614-023419, 1.8G). الوحدات سليمة على القرص.
- tar rc=2 في full_recovery_snapshot.sh: أُضيف
--ignore-failed-read --warning=no-file-changed+ استثناء .lock/.sock/hub logs/db-wal → rc=0 (race على ملفات حية = حميد).
🔑 درس مهم — Hub instability كان self-inflicted:
الهب كان "يموت" أثناء الاختبار. الحقيقة (أثبتها monitor 60s بلا لمس = ALIVE): (1) kill loops يدوية أصابت grep-shells بدل الهب، (2) heavy query (bein limit5000 cold ~11s) تجاوز keepalive's 5s/ health-check → watchdog قتله mid-request.
الإصلاح الدائم: أُضيف /healthz (no template/no DB, 1.8ms) + keepalive guard صار يفحصه بـ 8s timeout + 3-try grace + port-wait loop قبل restart (TIME_WAIT يصل 21s). الهب الآن مستقر (نجا من heavy queries + 60s untouched).قاعدة: لا تستخدم pgrep -f "...app.py" للقتل (يطابق shell نفسه). استخدم pgrep -x python3 + cwd match. ولا تكرّر kill+restart بسرعة (port TIME_WAIT ~20s يسبّب single-instance-guard exit).
verify_agreements false-positive:
cron: weekly-arsenal-audit not registered = فحص يبحث في /data/.openclaw/cron/jobs.json القديم الذي رحّلته 2026.6.6 (الآن jobs-state.json.migrated). الكرون موجود + enabled (cron get f4a87c82 يؤكد). يحتاج تحديث مسار الفحص لاحقاً (ليس عاجلاً).🎬 Entertainment Hub — DVR delete/cancel bug FIXED (2026-06-14 ~08:15 الكويت)
شكوى د. وائل (صوت): في section التسجيل بترسانة الترفيه، اختار delete/إلغاء → لا يتم الإلغاء، اللستة تبقى موجودة.
التشخيص (root cause): الـ jobs المنتهية (status:"done") في recordings/_jobs.json كانت بلا أي endpoint حذف — تتراكم للأبد حتى بعد حذف الملف الفعلي. + schedule_cancel كان يضع status="cancelled" فقط (لا حذف فعلي). + rec/delete و downloads() كانا يقبلان .mp4/.jpg فقط (يفشلان صامتاً على .png/.ts/.mkv).
الإصلاح (3 ملفات، host: /docker/openclaw-4x4t/.../projects/entertainment-hub):
recorder.py: أضيفjob_delete(jid)+jobs_clear()(حذف فعلي للسجل+الملف) ·schedule_cancelصارdel _SCHED[sid](حذف نهائي) ·downloads()وسّع الامتدادات (.jpeg/.png/.ts/.mkv/.webm).app.py: endpoints جديدة/api/rec/jobs/delete+/api/rec/jobs/clear· وسّع امتداداتrec/delete.templates/index.html: قسم "✅ تسجيلات منتهية" في مركز DVR + أزرار 🗑 حذف فردي + 🧹 مسح الكل (deleteJobDvr/clearJobsDvr).
_jobs.json على القرص = {} · endpoints HTTP 200 · الواجهة تخدم الدوال · page load 12ms.ملاحظات بنية: الـ hub يعمل داخل container openclaw-4x4t (root)، يُطلق عبر docker exec / keepalive (السطر 492). أُعيد تشغيله يدوياً بعد patch. backups: .bak-recfix-1781424631.
صحة النظام العامة: كل الـ containers Up · كل HTTPS 200 · disk 72% · load 1.39 · RAM 11/15GB (ضيق نسبياً، 1GB free + 3.2GB cache).
🎬 Entertainment Hub — 3 ميزات جديدة (2026-06-14 ~12:30 الكويت)
د. وائل وافق على #2+#3 من اقتراحاتي + طلب تصنيفات EPG. نُفّذت كلها + verified حياً.
1. تصنيفات EPG (أفلام/مسلسلات/رياضة/أخبار/علمي/ديني/أطفال/ثقافي/أخرى):
epg.py: أضيف_classify()(keyword AR+EN + native <category>) + حقلcatلكل برنامج. unit test 8/8 صحيح.indexer.py: عمودcat+ ALTER migration للجداول القديمة + INSERT يشمله. أُعيد بناء الفهرس: 562,671 برنامج مصنّف (sports 69K, culture 48K, news 41K, kids 34K, science 34K, movies 14K, series 8K, religion 5K, other 310K).catalog_search.py: SELECTp.cat+ يرجعه في hits.index.html: شرائح تصنيف أعلى EPG (الكل افتراضياً) + فلترة client-side. verified: q=m → 9 sports ✅.
#recStrip ثابت بعد البحث + pollRecStrip() كل 5s + زر إيقاف فوري لكل تسجيل. يظهر فقط عند وجود تسجيل نشط.3. مؤشر مساحة التسجيلات في مركز DVR: recorder.usage() + /api/rec/usage (bytes/files/free_gb/disk_gb) + بار تدرّج بنفسجي-سماوي في رأس DVR.
التحقق الحي: كل endpoints 200 · HTML يخدم recStrip/pollRecStrip/epgCatChips/EPG_CATS/usage · single hub proc · page 108ms · صفر أخطاء لوج · كل الـ containers Up · كل HTTPS 200.
ملاحظة موارد: RAM صار 12/15GB (590MB free + 3.5GB cache) — أضيق قليلاً بعد reindex، قابل للاسترداد، أراقبه.
backups: epg.py.bak-cats / indexer.py.bak-cats / catalog_search.py.bak-cats / index.html.bak-cats (ts 1781428739-1781429138). الإطلاق عبر docker exec -d (HUB_PORT=8899, HUB_SECRET=changeme123).
🎬 Entertainment Hub — جولة ثالثة (2026-06-14 ~13:00 الكويت)
د. وائل وافق على فكرتين من اقتراحاتي: تصنيفات في "يُعرض الآن" + رفع RAM للـ VPS.
🚨 اكتشاف مهم (يصحّح ادعاء سابق): index.html فيه تعريفان لكل من loadDvrCenter (سطر 473 + 690) وloadOnAir (584 + 660). في JS التعريف الأخير يفوز. إصلاحاتي في الجولة السابقة (jobs-delete + storage meter) دخلت في النسخة الأولى المُلغاة → لم تكن فعّالة في الواجهة الحقيقية! الـ DVR النشط (690) كان يستخدم dvrDelete(file) يحذف الملف لكن يُبقي سجل الـ job → نفس البق الأصلي لد. وائل ظل قائماً جزئياً. الدرس: عند تعديل دالة، ابحث عن كل تعريفاتها (grep -n) — قد يكون آخرها هو الفعّال.
ما نُفّذ في النسخ الفعّالة (690/660):
1. DVR delete جذري: dvrDeleteJob(id) يستدعي /api/rec/jobs/delete (يحذف السجل+الملف فعلياً) بدل dvrDelete(file) + زر "🧹 مسح الكل" (dvrClearAll→/api/rec/jobs/clear).
2. مؤشر المساحة في الـ DVR النشط (usage fetch + بار).
3. تصنيفات "يُعرض الآن": epg_onair يرجع cat + 9 شرائح تصنيف (نفس EPG) + فلترة client-side. verified بالمتصفح: رياضة → 142 قناة، صفر console errors.
⚡ إصلاح أداء كبير: /api/epg/onair كان 17.6 ثانية (full scan على 562K برنامج). أضفت index idx_prog_onair(stop,start) → صار 0.18 ثانية (~100×). ثُبّت في _epg_schema (indexer.py) ليبقى بعد إعادة الفهرسة اليومية.
التحقق بالمتصفح الحقيقي: صفر console errors عند التحميل + التنقل · 9 شرائح تصنيف تعمل · فلترة رياضة=142 · مؤشر مساحة يظهر · page 82ms · onair 0.18s · RAM رجعت 11/15GB (4.1GB available).
backups: index.html.bak-activedvr-1781430855 · catalog_search.py / indexer.py محدّثة.
📌 PENDING: رفع RAM الـ VPS من 16GB → 32GB (طلب د. وائل 2026-06-14)
- VPS: Hostinger KVM4 (srv1659934 / 76.13.41.228) — حالياً 4 vCPU / 16GB / 200GB.
- الترقية تحتاج إجراء عبر لوحة Hostinger (hpanel) → upgrade plan (KVM4→KVM8 أو ترقية RAM) = قرار/فاتورة من د. وائل.
- لا أقدر أرفع RAM برمجياً — يتطلب موافقته + دفع في hpanel. جهّزت له الخطوات.
🧊 Blender On-Demand — تحليل عميق + تنفيذ (2026-06-14 ~13:15 الكويت)
د. وائل طلب نقده باحترافية قبل التنفيذ: هل يؤثر على الترسانة/الاستقرار/الأداء؟
التحليل (تحقّق حي، صفر افتراض):
- Blender = حاوية
blender-3rkb-blender-1(linuxserver/blender, GUI port 37423→3000, Traefik → render.drwaelalkishawi.com). كانتrestart: unless-stopped، تستهلك 3.678GiB ثابتة 24/7. - قدرات الترسانة 3D الأساسية (trimesh/pyvista/cadquery/ezdxf) = مكتبات Python داخل حاوية openclaw — لا تحتاج Blender إطلاقاً. Blender فقط لـ: (1) rendering فوتوريالستي CLI، (2) GUI تفاعلي. كلاهما عرضي لا مستمر.
- openclaw container: لا docker.sock (عزل أمني) لكن يملك host SSH key → الوكيل يتحكم بالحاوية عبر ssh. on-demand مجدٍ 100%.
- قياسات فعلية: stop = 5s يحرر 3.7GB (available 4180→7910MB). start = 2s. CLI ready = 2s. اختبار end-to-end: من حالة stopped،
renderauto-started + رسم مكعب + حفظ PNG بنجاح (31s إجمالي). صفر فقدان قدرة.
/docker/blender-3rkb/blender_ondemand.sh— {ensure|stop|render|idle-stop|status}. ensure يبدأ+ينتظر CLI-ready. render يضمن ثم ينفّذ.- compose:
restart: unless-stopped→restart: "no"(يبقى متوقفاً بعد reboot حتى الحاجة). - cron host كل 5min:
idle-stop 20(يوقفها بعد 20د خمول — belt&suspenders لو الوكيل نسي). skills/3d-arsenal/SKILL.mdمحدّث: كل استخدام Blender عبر الـ wrapper.
backups: docker-compose.yml.bak-ondemand · SKILL.md.bak-ondemand.
✅ تثبيت نهائي + قرار د. وائل (2026-06-14 ~13:20 الكويت)
قرار د. وائل: ننتظر أسبوعاً ونراقب الأداء قبل قرار ترقية KVM4→KVM8. الوضع الآن مريح بعد توفير Blender.
التثبيت المنجز:
- ✅ cron مراجعة أسبوعية (id
5d27fd28-4bd1-48bf-a8d2-651f6172f47e) — 2026-06-21 07:00 الكويت (04:00 UTC) — isolated agentTurn، يجمع RAM/load/Blender-log/OOM/hub-health ويعطي توصية ترقية مبنية على بيانات فعلية، deleteAfterRun. - ✅ كل backend الـ hub (app/recorder/epg/indexer/catalog_search) compile OK 5/5.
- ✅ hub مستقر (up 24min بلا أعطال) · Blender exited(restart=no) · RAM 7.6GB متاحة · load 0.79 · كل HTTPS 200.
- ✅ R2 backup:
workspace_backup_20260614_102032.tar.gz(952 ملف، 433.7MB). - ✅ idle-stop cron host كل 5min (Blender بعد 20د خمول).
weekly-arsenal-auditcron غير مسجّل.- cron(s) عرضة لـ M-033 leak (تحذير قديم).
الحالة: كل عمل اليوم مثبّت ومستقر. جاهز لـ /new.
🔧 إصلاح خرقَي verify_agreements + فحص النظام الشامل (2026-06-14 ~13:35 الكويت)
د. وائل طلب إصلاح الخرقين + فحص النظام والترسانة ككل قبل /new.
الخرق #1 (weekly-arsenal-audit "غير مسجّل") = false positive:
- السبب الجذري: تخزين الـ cron هاجر من
/data/.openclaw/cron/jobs.json(ميت) إلى SQLitecron_jobstable في/data/.openclaw/state/openclaw.sqlite. الـ verify كان يقرأ المسار الميت → fail دائم. - الواقع: الـ cron
weekly-arsenal-audit(id f4a87c82) موجود + enabled + مجدول الأحد 05:00 الكويت طوال الوقت. - (أنشأتُ duplicate بالخطأ ثم حذفته فوراً عند اكتشاف الأصل.)
- الإصلاح: حدّثت verify_agreements.sh §9 ليقرأ SQLite cron_jobs بدل الـ JSON الميت.
- §30 كان يقرأ نفس المسار الميت. صحّحته ليقرأ
job_jsonمن SQLite. - بعد التصحيح ظهرت 3 crons "at risk" — لكنها كلها محمية فعلاً بصياغات guard لم تكن في قائمة التعرّف (مثل "announce يتولّى"، "message tool calls"، "tool calls للـ message"). وسّعت قائمة الـ guard phrases لتشملها.
- النتيجة: verify_agreements الآن exit=0 — ALL VERIFIED ✅.
- ✅ host: RAM 7.6GB متاحة · load 0.58 · disk 72% · 31/32 container Up (Blender عمداً down).
- ✅ كل الترسانة الأساسية 200: hub · RAG/ask · n8n/MCP · invest · eng · status · studio · cv · twin · go · code · files · root.
- ✅ wiki/sync = 401 (محمية بـ auth — طبيعي).
- ⚠️ panel + grafana = NXDOMAIN (مشكلة سابقة لا من عملي): سجلات DNS مفقودة في Cloudflare. أصلحتها: أضفت A records (panel/grafana → 76.13.41.228 proxied). DNS صار live عالمياً (1.1.1.1 = 104.21.13.85). لكن Traefik يحتاج cert من Let's Encrypt وضرب rate-limit (429، 5 failed auth/ساعة بسبب غياب DNS سابقاً) → يحصل على الشهادة تلقائياً بعد انتهاء النافذة (~ساعة). الحاويتان داخلياً 200/302 سليمتان. المراقبة (prometheus/cadvisor/node-exporter) تجمع بلا انقطاع.
🎬🇸🇦 Entertainment Hub — الترجمة + الدبلجة العربية (VOD) — مرحلة 1 منفّذة ومختبرة حياً (2026-06-14 ~14:43)
د. وائل طلب ترجمة/دبلجة عربية فورية للأفلام/المسلسلات/البث. بدأنا بمرحلة 1 (VOD) كـ proof.
المعمارية (side-channel معزولة تماماً — تحترم الخطوط الحمراء):
translate_dub.py(جديد، 17KB): وحدة مستقلة، import-safe، لا عمل وقت الاستيراد.
subs_cache/
- audio pull = ffmpeg صوت فقط 16k mono (~RAM ضئيل)، singleton، لا يلمس البث
- routes في app.py (قبل
if __name__):/api/td/start(POST) ·/api/td/status/<job>·/api/td/vtt/<key>·/api/td/dub/<key>— كلها معزولة،_td=Noneلو فشل الاستيراد. - UI في index.html: شريط
#tdbarداخل playerHtml() — زرّان OFF افتراضياً (🇸🇦 ترجمة / 🎙️ دبلجة) +tdToggle()/_tdApply()معزولة. subtitles عبر<track>، dub عبر<audio>overlay + كتم الأصلي.
✅ مُختبر حياً (proof فعلي):
- Sintel trailer (EN، 52s) → ترجمة عربية مؤقتة WebVTT في ~9s، ترجمة دقيقة ("ما الذي أتى بك إلى أرض حراس البوابة؟").
- CACHE: الطلب الثاني = فوري 1s (cached=True).
- DUB: dub_ok=True، MP3 43s، transcribe-back = عربي مفهوم تماماً.
- ZERO-IMPACT: home/games/catalog = 200، ffmpeg procs=0 بعد الانتهاء، RAM حرة 1.3GB/7.4GB available، hub RSS طبيعي.
دروس/فخاخ هذه الجلسة:
- الهاب يعمل كـ root (PPID 418890→418898) بينما أنا node →
kill -9من exec يفشل (Operation not permitted)؛ الحلsudo kill. لكن sudo-relaunch فشل (Flask غير موجود في root env بشكل متقطّع) → الحل: إطلاق كـ node (Flask مثبّت لـ node). - single-instance guard في app.py (
os._exit(0)لو :8899 محجوز) → أي relaunch قبل قتل القديم = ينتحر صامتاً. لازم قتل القديم أولاً ثم إطلاق. pgrep -f app.pyفي حلقة kill يطابق الـ subshell نفسه → SIGKILL يقتل جلسة exec. الحل: استثنِ$$+ طابق بالـ cwd readlink._ffbinيجب أن يطابق app.py (shutil.which() or /data/linuxbrew/.linuxbrew/bin/<name>) — ffmpeg ليس في /usr/bin.- Big Buck Bunny 1MB sample = بلا صوت → فشل audio pull (ليس bug). اختبر دائماً بعينة فيها صوت (Sintel).
المتبقّي (للموافقة):
- مرحلة 2: البث المباشر (live subtitle + live voice-over) فوق نفس البنية — بعد اعتماد د. وائل.
- تحسين اختياري: ElevenLabs Dubbing v2 API للأفلام (lip-aware) بدل per-segment TTS عند الحاجة لجودة أعلى.
🔐 panel + grafana 526 → حُلّ جذرياً عبر DNS-01 (Cloudflare) — 2026-06-14 ~14:55 الكويت
الشكوى: panel.drwaelalkishawi.com + grafana = 526 مستمر. وحدة hostopenclaw اقترحت 3 خيارات (DNS-only / DNS-01 / استثناء ACME).
التشخيص الجذري (بالأدلة الحية — صحّح تشخيص الوحدة الأصلي):
- DNS panel/grafana صحيح (76.13.41.228 proxied، مثل 23 نطاقاً شغّالاً) — ليس IP خاطئ كما ظنّت الوحدة.
- شهادة الأصل = "TRAEFIK DEFAULT CERT" (self-signed) → CF يرفضها بـ 526.
- السبب الفعلي (traefik logs):
429 too many failed authorizations (5)+Cannot retrieve the ACME challenge ... (token "test"). تحدّي HTTP-01 يفشل لأن redirect إجباري :80→:443 + CF proxy يمنع وصول/.well-known/acme-challenge/. الـ23 الأخرى أُصدرت في دفعة أبكر قبل الحظر. - النقطة الحاسمة: الـ proxy ليس المشكلة (23 proxied يعمل) — المشكلة HTTP-01 تحديداً لـ panel/grafana دخلا حظر LE.
القرار (دراسة 3 خيارات):
- ❌ DNS-only: يفقد حماية CF + يكسر التناسق + خطر أمني (panel لوحة حساسة). مرفوض.
- ✅ DNS-01 عبر Cloudflare (الموصى به): مناعة تامة ضد redirect+proxy+rate-limit، يبقي حماية CF، جذري دائم لأي نطاق قادم.
- ❌ استثناء ACME من redirect: ترقيع هش.
التنفيذ (SSH host، مع backups):
- أضفت
CF_DNS_API_TOKEN(=CLOUDFLARE_ZONE_TOKEN، مُتحقَّق DNS-01 بإنشاء+حذف TXT فعلي) لـ/docker/traefik/.env. - أضفت resolver ثانٍ
cfdns(dnschallenge=cloudflare، resolvers 1.1.1.1+8.8.8.8، storage acme-dns.json) في compose — دون لمس resolverletsencryptالأصلي (الـ23 سليمة). - بدّلت
certresolver=letsencrypt→cfdnsلـ panel (/docker/panel) + grafana (/docker/monitoring) فقط. docker compose up -dلـ traefik ثم panel + monitoring.
✅ النتيجة (verified live):
- panel = 200 (كان 526) · grafana = 302 (login) · شهادات LE صحيحة (CN صحيح، صالحة حتى Sep 12).
- Zero regression: wiki/ask/hub/status/code = سليمة.
- مكسب دائم: أي نطاق جديد الآن يستطيع استخدام
cfdnsresolver = لا rate-limit HTTP-01 بعد اليوم.
Backups (للرجوع):
- /docker/traefik/docker-compose.yml.bak-dns01- · /docker/panel/.bak-dns01- · /docker/monitoring/.bak-dns01-
🎙️ الدبلجة — إصلاح 3 bugs كشفها د. وائل + إضافة روابط panel/grafana (2026-06-14 ~16:35)
روابط الترسانة:
- أُضيف panel + grafana لـ portal.html (قسم الأدوات) في /docker/landing/site/ — verified حي على drwaelalkishawi.com/portal.html. backup: portal.html.bak-panelgrafana-.
3 مشاكل دبلجة كشفها د. وائل (كلها صحيحة):
1. التكلفة: الترجمة النصية ~مجانية (Groq STT free + ترجمة). الدبلجة مكلفة ~18k credit/فيلم. باقة ElevenLabs Creator: 121k credit، مستهلك 36.5k → ~4-5 أفلام دبلجة/شهر. القرار: الترجمة للاستخدام اليومي، الدبلجة للأفلام المهمة. 2. صوت موحّد + خليجي: كان صوت واحد (Eric) + flash_v2_5 (يميل خليجي). الإصلاح: gender detection (pitch autocorrelation عبر ffmpeg+numpy، ~50ms/segment، CPU-cheap) → صوتين: George (ذكر) + Lama (أنثى) + model=eleven_multilingual_v2 (فصحى أنظف). verified: Sintel → male/female/male/male صحيح + تشكيل فصحى. 3. 🔴 تضارب الصوتين (bug خطير):v.muted=true غير موثوق على HLS/mpegts (MSE) → سُمع الصوتان معاً. الإصلاح الجذري: Web Audio API — createMediaElementSource(v) → GainNode.gain=0.08 (hard-duck الأصلي، تبقى الموسيقى خافتة، يختفي الكلام الإنجليزي) + fallback لـ volume=0. tdReset يعيد gain=1. درس: اختبار توليد الملف ≠ اختبار التشغيل الفعلي بالصوت — قصور في QC الأول.الملفات:
- translate_dub.py:
detect_gender()+_tts_elevenlabs(text,gender)+ VOICE_MALE/FEMALE + DUB_MODEL=multilingual_v2 + gender persist في segs.json. - index.html:
_tdApplydub branch = WebAudio GainNode ducking + tdReset un-duck.
verified حياً:
- gender: male/female/male/male (Sintel) ✅ · تشكيل فصحى ✅ · WebAudio served (createMediaElementSource=1, gain 0.08=1) ✅
- regression: home/games/catalog=200 · RAM free 3.1GB · load 0.38 · zero ffmpeg lingering ✅
معلّق (عرضته كخيار مستقبلي، لم يُبنَ):
- "دبلجة فائقة" = ElevenLabs Dubbing API (/v1/dubbing=200، فصل مصادر + diarization + multi-voice تلقائي + حذف أصلي + إبقاء موسيقى) — زر منفصل للأفلام المهمة، يُحسب من الباقة. demucs غير مثبّت (ثقيل على CPU بلا GPU) فاكتفينا بـ WebAudio ducking.
فخ تشغيلي (تكرر):
- إعادة تشغيل الهاب: single-instance guard + سباق launches → "port already owned" + healthz=000. الحل: قتل بالـ cwd readlink (استثناء $$) ثم انتظار release كامل ثم launch واحد ثم انتظار ~30s لتحميل catalog (1M عنصر).
🔧 panel + grafana — حل عالقَيْن جذرياً (2026-06-14 ~17:15 الكويت)
1) Panel "Type error: failed to fetch" في كل شي — CORS:
- الجذر: panel (nginx static في /docker/panel/site/index.html) يستدعي 3 APIs cross-origin مباشرة: status.drwael/api/status + ask.drwael/api/semantic + studio.drwael/hook — كلها بلا CORS header → المتصفح يحجب = "failed to fetch".
- الإصلاح (same-origin proxy): أضفت لـ /docker/panel/default.conf مواقع proxy:
/px/status→status,/px/ask→ask/semantic (مع resolver 127.0.0.11+1.1.1.1 + set-var upstream للـ dynamic DNS),/hook/→host.docker.internal:8910 (arsenal-hooks، موجود). بدّلت JS لمسارات same-origin. - فخ: sed مزدوج الـ escape كسر
try_files $uri→\$uri→ 500 rewrite cycle. الحل: نقل الكونفيغ عبر base64 (بلا escaping). + nginx proxy_pass بمتغير يحتاجresolverdirective (بدونه 502 "no resolver defined"). - verified: home/px-status/px-ask/hook-capability/hook-rebuild/hook-ci = كلها 200. الأزرار كلها تعمل.
- backups: default.conf.bak- + index.html.bak-.
2) Grafana auth → موحّد على admin + كلمة السر المشتركة (مثل wiki/files):
- الجذر: Grafana له login خاص (GF_SECURITY_ADMIN_PASSWORD، default arsenal2026) منفصل عن admin المعمّم.
- القرار: كلمة السر المشتركة محفوظة مع د. وائل فقط (ليست في ذاكرتي — قرار خصوصية 2026-06-10). wiki يستخدم Traefik basicauth بـ bcrypt hash في /docker/wiki-proxy. أعدتُ استخدام نفس الـ hash بلا الحاجة للـ plaintext.
- الإصلاح: /docker/monitoring → grafana: أضفت Traefik middleware
grafana-auth.basicauth.users=admin:$2y$05$ch3FF...(نفس hash wiki بالضبط) + GF_AUTH_ANONYMOUS_ENABLED=true + ORG_ROLE=Admin + DISABLE_LOGIN_FORM=true + BASIC_ENABLED=false → بوابة واحدة فقط (Traefik)، بعدها Grafana يفتح Admin مباشرة بلا login ثانٍ. - verified: grafana no-auth=401 (محمي، realm="traefik" مطابق wiki تماماً)، wrong-pass=401. نفس hash wiki ⟹ نفس admin+password يفتحه.
- backup: monitoring/docker-compose.yml.bak-auth-.
regression: wiki=401 files=200 status=200 hub=200 ask=200 — صفر تأثير.
🔴 Dubbing silent-voice bug — ROOT CAUSE + FIX (17:30-17:45)
Symptom (د. وائل): دبلجة تكمل، الملف مخزّن (رجل/امرأة فصحى)، لكن عند التشغيل: الصوت الأصلي يضعف جداً + صوت الدبلجة لا يظهر إطلاقاً. Diagnosis (3-layer): 1. Backend OK — dub MP3 real: 12-37MB, 25min, mean -31dB peaks -2dB (1069 voice clips mixed via ffmpeg). Credits NOT wasted — file is perfect. 2. Root cause = FRONTEND playback only: -_tdAudio (dub) played on DEFAULT output while video ran via separate path → autoplay policy silently BLOCKED it (no dub sound).
- crossOrigin='anonymous' + streamed response (no Content-Length) → browser refused decode.
Fix:
- Frontend (index.html): route BOTH video AND dub through SAME AudioContext graph. Video ducked to 0.08, dub via own GainNode at 1.0 → dub GUARANTEED audible when ctx running. Removed crossOrigin. Added canplay/error listeners for real status.
- Backend (app.py): dub endpoint now
send_file(conditional=True)→ Content-Length + Accept-Ranges (was stream_with_context, no length → undecodable).
🔴 Dubbing fix #2 — abandoned Web Audio for simple method (17:56)
First fix (WebAudio dual-routing) STILL failed: original ducked but Arabic dub never audible. Root: createMediaElementSource + 2nd routed Audio node unreliable; context not resumed by direct gesture blocked dub. NEW approach (bulletproof): VOD movies use plain <video src> (NOT MSE) → v.muted=true is 100% reliable. So: tear down any WebAudio graph + close ctx, mute video directly, play dub via plain Audio at volume 1, kick .play() inside user's dub-button click. tdReset restores muted=false/volume=1. Verified: TEMPLATES_AUTO_RELOAD=True (no restart needed), 3 new markers served live, dub file 64MB valid mp3 22050Hz, headers Content-Length+Accept-Ranges, range req 206 OK. Lesson: don't over-engineer with Web Audio when v.muted + plain Audio suffices on non-MSE sources.🔴 Dubbing fix #3 — gesture-unlock the dub audio (18:15)
Fix#2: video now muted correctly BUT Arabic dub STILL silent. Verified server+network 100% fine (dub serves 200 via hub.drwaelalkishawi.com, Content-Length 64MB, range 206). ROOT: _tdApply (creates Audio + play()) runs inside async setInterval polling = OUTSIDE the click gesture → browser autoplay-blocks _tdAudio.play() silently. FIX: in tdToggle (the actual click handler), create _tdAudio NOW + unlock via muted play of a tiny silent wav data-uri. _tdApply then REUSES that blessed element (swaps .src) instead of creating a new one. Final play() reports real result (surfaces autoplay block instead of hiding). Still-open hypothesis: if Dr Wael uses Telegram IN-APP browser, it may not allow simultaneous <video>+<audio> playback → second pauses first. Need to ask which browser. Verified: syntax OK, 4 new markers served live via production domain.✅ Dubbing STATUS (end of session 18:44) — WORKING, 2 fixes deployed, pending live confirm
الدبلجة العربية تعمل فعلاً (د. وائل أكّد: ظهر الصوت). آخر إصلاحين (لم يُختبرا بعد — د. وائل غادر):- Fix#4: continuous resync (relock every timeupdate if drift>0.35s) + hard watchdog setInterval 2s + waiting/playing buffer handlers → يحل توقف بعد 5 دقائق (drift+stall).
- Fix#5: duck original to v.volume=0.18 بدل mute كامل → الخلفية تبقى خافتة وفوقها العربي.
🔴 PENDING للجلسة القادمة (د. وائل طلبها 18:44 قبل /new):
1. Portal غريب: عند الضغط على أي بطاقة (صور/بحث/فحص السلامة) في البورتال، بدل فتح الوظيفة يعرض حقول JSON خام (action, capability, domain, research, result / temp,arsenal,drift,rebuild,gallery,39 items). أي: الـ frontend يعرض مفاتيح الـ API response بدل render الوظيفة. يحتاج فحص portal frontend (أي مشروع؟ portal-apk أو خدمة منفصلة) + إصلاح الـ click handler/template. 2. Grafana: د. وائل يسأل ما وظيفته/فائدته/أين يُستخدم في الترسانة. (أجبته نصياً هذه الجلسة — راجع الرد).✅ Portal fix + full infra health (19:22-19:35) — كل شيء perfect 100%
Portal (panel.drwaelalkishawi.com) — السبب + الإصلاح:
المشكلة: الضغط على صور/بحث/فحص السلامة كان يعرض JSON خام (o.textContent=t.slice(0,800)) لأن /hook/ ترجع JSON والـ frontend يطبعه نصاً. الإصلاح: أعدتُ كتابة /docker/panel/site/index.html (host, root-owned) — أضفتُ hookJSON() يـ parse الرد ويستدعي renderer مخصص لكل نوع:- capability {action,domain,result} → بطاقة المجال + النص المنسّق
- rebuild {result:"gallery: N items"} → "✅ تم تحديث المعرض · عدد الصور N" + رابط studio
- ci {pass,ran_at,tail} → badge ✅/❌ + الأسطر مُنسّقة
- search → بطاقات نظيفة. backup: index.html.bak-<ts>.
CI cache كان قديماً (2026-06-10 pass=false بسبب /tmp permission denied — بيئة قديمة):
شغّلتُ verify_agreements.sh حياً = exit 0 "ALL VERIFIED". كتبتُ الناتج الطازج إلى memory/.ci_verify_result.txt (root via host SSH). الآن panel CI = pass=True ran=2026-06-14.Full subdomain sweep: 24/24 ✅ (0 failures):
أصلحتُ خدمتين كانتا down:- obsidian (502): obsidian-viewer:8908 داخل container openclaw كان ميتاً → أعدت تشغيله، 200 الآن، محروس بـ keepalive §497.
- render (404): blender-3rkb container كان Exited(0) — restart:"no" (on-demand desktop ثقيل) → docker compose up -d، 401 الآن (محمي = حي).
⏳ متبقّي للجلسة القادمة (بعد عودة د. وائل):
- اختبار الدبلجة الحي (هل استمرت >5min + الخلفية خافتة + التزامن) — آخر إصلاحين لم يُختبرا.