Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -511,9 +511,9 @@ def _capture_via_import_pipe(display: str):
|
|
| 511 |
|
| 512 |
def _capture_via_xlib_direct(display: str):
|
| 513 |
"""
|
| 514 |
-
خط الدفاع الثاني
|
| 515 |
-
|
| 516 |
-
|
| 517 |
"""
|
| 518 |
from PIL import Image
|
| 519 |
try:
|
|
@@ -531,17 +531,56 @@ def _capture_via_xlib_direct(display: str):
|
|
| 531 |
return None, 0, 0
|
| 532 |
|
| 533 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 534 |
def _capture_raw(display: str) -> tuple:
|
| 535 |
"""
|
| 536 |
يلتقط الشاشة بأسرع طريقة موثوقة: import-pipe أولاً (سريعة جداً)،
|
| 537 |
-
|
| 538 |
-
ل
|
| 539 |
-
|
| 540 |
-
|
|
|
|
|
|
|
| 541 |
"""
|
| 542 |
for method_name, method in (
|
| 543 |
("import-pipe", _capture_via_import_pipe),
|
| 544 |
("xlib-direct", _capture_via_xlib_direct),
|
|
|
|
| 545 |
):
|
| 546 |
for attempt in range(2):
|
| 547 |
try:
|
|
@@ -555,14 +594,14 @@ def _capture_raw(display: str) -> tuple:
|
|
| 555 |
if attempt == 0:
|
| 556 |
time.sleep(0.3)
|
| 557 |
|
| 558 |
-
print(f"[cap:{display}] ⚠️ All methods failed — placeholder")
|
| 559 |
from PIL import Image as PILImg, ImageDraw
|
| 560 |
sw, sh = _get_screen_size(display)
|
| 561 |
img = PILImg.new("RGB", (sw or 1280, sh or 800), (15, 20, 40))
|
| 562 |
draw = ImageDraw.Draw(img)
|
| 563 |
draw.rectangle([(0, 0), (sw, 55)], fill=(30, 40, 80))
|
| 564 |
draw.text((10, 10), f"⚠️ Screenshot failed — DISPLAY={display}", fill=(255, 120, 80))
|
| 565 |
-
draw.text((10, 32), "Methods tried: import-pipe, xlib-direct", fill=(130, 130, 150))
|
| 566 |
return img, sw or 1280, sh or 800
|
| 567 |
|
| 568 |
|
|
@@ -1505,7 +1544,7 @@ async def health():
|
|
| 1505 |
|
| 1506 |
async def _cleanup_tmp():
|
| 1507 |
"""ينظّف /tmp كل 5 دقائق. ملاحظة v13: محرك الالتقاط
|
| 1508 |
-
الجديد (import-pipe/xlib-direct) لا يكتب أي ملفات zss_* على الإطلاق (كلشيء
|
| 1509 |
في الذاكرة عبر pipe)، فهذه الدالة أصبحت غير ضرورية فعلياً للقطات
|
| 1510 |
الشاشة، لكنها تُرك كشبكة أمان إضافية (مثلاً لو أضيف كود مستقبلاً
|
| 1511 |
يكتب ملفات مؤقتة بنفس البادئة)."""
|
|
|
|
| 511 |
|
| 512 |
def _capture_via_xlib_direct(display: str):
|
| 513 |
"""
|
| 514 |
+
خط الدفاع الثاني: قراءة X11 framebuffer مباشرة عبر python-xlib،
|
| 515 |
+
بدون subprocess إطلاقاً (أسرع من أي أداة خارجية، ويعمل حتى لو
|
| 516 |
+
ImageMagick غير مثبّت على السيرفر).
|
| 517 |
"""
|
| 518 |
from PIL import Image
|
| 519 |
try:
|
|
|
|
| 531 |
return None, 0, 0
|
| 532 |
|
| 533 |
|
| 534 |
+
def _capture_via_xwd(display: str):
|
| 535 |
+
"""
|
| 536 |
+
خط الدفاع الثالث — طريقة جديدة تماماً، مستقلة كلياً عن الطريقتين
|
| 537 |
+
السابقتين في مسارها البرمجي: `xwd` (X Window Dump) هي أداة أصلية من
|
| 538 |
+
حزمة x11-apps الأساسية نفسها (وليست ImageMagick مثل `import`، ولا
|
| 539 |
+
مكتبة python-xlib عبر اتصال socket مباشر مثل الطريقة الثانية) —
|
| 540 |
+
فإذا كان سبب فشل الطريقتين الأخريين متعلقاً تحديداً بـ ImageMagick
|
| 541 |
+
(مفقود/معطوب) أو بمكتبة python-xlib نفسها (تعارض إصدار، اتصال عالق)،
|
| 542 |
+
فإن xwd تسلك مساراً مختلفاً بالكامل في النواة قد ينجح حين تفشل الطريقتان
|
| 543 |
+
الأخريان. تكتب xwd تنسيق XWD الخام إلى stdout مباشرة (بدون ملف مؤقت على
|
| 544 |
+
القرص، بنفس فلسفة import-pipe)، ثم نحوّله عبر PIL.
|
| 545 |
+
"""
|
| 546 |
+
from PIL import Image
|
| 547 |
+
env = {**os.environ, "DISPLAY": display}
|
| 548 |
+
try:
|
| 549 |
+
r = subprocess.run(
|
| 550 |
+
["xwd", "-root", "-display", display, "-silent"],
|
| 551 |
+
env=env, timeout=6, capture_output=True
|
| 552 |
+
)
|
| 553 |
+
if r.returncode != 0 or not r.stdout or len(r.stdout) < 500:
|
| 554 |
+
return None, 0, 0
|
| 555 |
+
# PIL يدعم قراءة تنسيق XWD مباشرة (plugin XVThumb/XWD مدمج)
|
| 556 |
+
img = Image.open(io.BytesIO(r.stdout))
|
| 557 |
+
img = img.convert("RGB")
|
| 558 |
+
w, h = img.size
|
| 559 |
+
if w < 100 or h < 100:
|
| 560 |
+
return None, 0, 0
|
| 561 |
+
return img, w, h
|
| 562 |
+
except FileNotFoundError:
|
| 563 |
+
print(f"[cap:{display}] xwd not installed")
|
| 564 |
+
return None, 0, 0
|
| 565 |
+
except Exception as e:
|
| 566 |
+
print(f"[cap:{display}] xwd: {e}")
|
| 567 |
+
return None, 0, 0
|
| 568 |
+
|
| 569 |
+
|
| 570 |
def _capture_raw(display: str) -> tuple:
|
| 571 |
"""
|
| 572 |
يلتقط الشاشة بأسرع طريقة موثوقة: import-pipe أولاً (سريعة جداً)،
|
| 573 |
+
ثم xlib-direct، وأخيراً xwd كخط دفاع ثالث جديد كلياً بمسار برمجي
|
| 574 |
+
مختلف تماماً عن الطريقتين الأوليين (أداة X11 أصلية أخرى غير
|
| 575 |
+
ImageMagick وغير python-xlib) — هذا يضمن أن فشل مصدر واحد (مثل
|
| 576 |
+
ImageMagick معطوب أو تعارض في مكتبة xlib) لا يعني فشل الالتقاط
|
| 577 |
+
بالكامل، لأن xwd تسلك مساراً مستقلاً تماماً وقد تنجح حين تفشل الأخريان.
|
| 578 |
+
بحد أقصى محاولتين سريعتين لكل طريقة.
|
| 579 |
"""
|
| 580 |
for method_name, method in (
|
| 581 |
("import-pipe", _capture_via_import_pipe),
|
| 582 |
("xlib-direct", _capture_via_xlib_direct),
|
| 583 |
+
("xwd", _capture_via_xwd),
|
| 584 |
):
|
| 585 |
for attempt in range(2):
|
| 586 |
try:
|
|
|
|
| 594 |
if attempt == 0:
|
| 595 |
time.sleep(0.3)
|
| 596 |
|
| 597 |
+
print(f"[cap:{display}] ⚠️ All methods failed (import-pipe, xlib-direct, xwd) — placeholder")
|
| 598 |
from PIL import Image as PILImg, ImageDraw
|
| 599 |
sw, sh = _get_screen_size(display)
|
| 600 |
img = PILImg.new("RGB", (sw or 1280, sh or 800), (15, 20, 40))
|
| 601 |
draw = ImageDraw.Draw(img)
|
| 602 |
draw.rectangle([(0, 0), (sw, 55)], fill=(30, 40, 80))
|
| 603 |
draw.text((10, 10), f"⚠️ Screenshot failed — DISPLAY={display}", fill=(255, 120, 80))
|
| 604 |
+
draw.text((10, 32), "Methods tried: import-pipe, xlib-direct, xwd", fill=(130, 130, 150))
|
| 605 |
return img, sw or 1280, sh or 800
|
| 606 |
|
| 607 |
|
|
|
|
| 1544 |
|
| 1545 |
async def _cleanup_tmp():
|
| 1546 |
"""ينظّف /tmp كل 5 دقائق. ملاحظة v13: محرك الالتقاط
|
| 1547 |
+
الجديد (import-pipe/xlib-direct/xwd) لا يكتب أي ملفات zss_* على الإطلاق (كلشيء
|
| 1548 |
في الذاكرة عبر pipe)، فهذه الدالة أصبحت غير ضرورية فعلياً للقطات
|
| 1549 |
الشاشة، لكنها تُرك كشبكة أمان إضافية (مثلاً لو أضيف كود مستقبلاً
|
| 1550 |
يكتب ملفات مؤقتة بنفس البادئة)."""
|