THEZYZSTUDIO commited on
Commit
825664d
·
verified ·
1 Parent(s): e247cba

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +151 -81
app.py CHANGED
@@ -23,7 +23,9 @@ import io
23
  import json
24
  import os
25
  import re
 
26
  import subprocess
 
27
  import time
28
  import urllib.parse
29
  import threading
@@ -415,31 +417,32 @@ def _is_black_screen(img) -> bool:
415
  return False
416
 
417
 
418
- def _capture_raw(display: str) -> tuple:
419
- """يلتقط الشاشة من display محدد."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  from PIL import Image
421
  env = {**os.environ, "DISPLAY": display}
422
  ts = int(time.time() * 1000)
423
- # استخدم display number في اسم الملف لتفادي التعارض
424
  disp_safe = display.replace(":", "")
425
  tmp_base = f"/tmp/zss_{disp_safe}_{ts}"
426
  created_files = []
427
 
428
- def _try_load(path) -> tuple:
429
- if not path or not os.path.exists(path):
430
- return None, 0, 0
431
- if os.path.getsize(path) < 1024:
432
- return None, 0, 0
433
- try:
434
- img = Image.open(path).convert("RGB")
435
- w, h = img.size
436
- if w < 100 or h < 100:
437
- return None, 0, 0
438
- return img, w, h
439
- except Exception as ex:
440
- print(f"[cap:{display}] load error: {ex}")
441
- return None, 0, 0
442
-
443
  def _cleanup_files():
444
  for p in created_files:
445
  try:
@@ -448,76 +451,144 @@ def _capture_raw(display: str) -> tuple:
448
  except Exception:
449
  pass
450
 
451
- for attempt in range(3):
452
- if attempt > 0:
453
- time.sleep(0.8)
454
- print(f"[cap:{display}] retry attempt {attempt+1} (black screen)")
455
  try:
456
- # Method 1: scrot
457
- p1 = f"{tmp_base}_a{attempt}_scrot.png"
458
- created_files.append(p1)
459
- try:
460
- subprocess.run(["scrot", "-q", "95", p1],
461
- env=env, timeout=8, capture_output=True)
462
- img, w, h = _try_load(p1)
463
- if img and not _is_black_screen(img):
464
- return img, w, h
465
- except Exception as e:
466
- print(f"[cap:{display}] scrot: {e}")
467
 
468
- # Method 2: ImageMagick import
469
- p2 = f"{tmp_base}_a{attempt}_im.png"
470
- created_files.append(p2)
471
- try:
472
- subprocess.run(["import", "-window", "root", "-silent", p2],
473
- env=env, timeout=10, capture_output=True)
474
- img, w, h = _try_load(p2)
475
- if img and not _is_black_screen(img):
476
- return img, w, h
477
- except Exception as e:
478
- print(f"[cap:{display}] import: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
479
 
480
- # Method 3: ffmpeg x11grab
481
- p3 = f"{tmp_base}_a{attempt}_ff.png"
482
- created_files.append(p3)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
483
  try:
484
- sw, sh = _get_screen_size(display)
485
- subprocess.run([
486
- "ffmpeg", "-y", "-f", "x11grab",
487
- "-video_size", f"{sw}x{sh}",
488
- "-i", display,
489
- "-vframes", "1", "-q:v", "1", p3
490
- ], env=env, timeout=12, capture_output=True)
491
- img, w, h = _try_load(p3)
492
- if img and not _is_black_screen(img):
493
- return img, w, h
494
- except Exception as e:
495
- print(f"[cap:{display}] ffmpeg: {e}")
496
 
497
- # Method 4: python-xlib
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
498
  try:
499
- from Xlib import display as Xdisp, X
500
- xd = Xdisp.Display(display)
501
- root = xd.screen().root
502
- geom = root.get_geometry()
503
- w, h = geom.width, geom.height
504
- raw = root.get_image(0, 0, w, h, X.ZPixmap, 0xFFFFFFFF)
505
- data = raw.data
506
- pixels = bytearray(len(data) // 4 * 3)
507
- for i in range(0, len(data) - 3, 4):
508
- b, g, r_c = data[i], data[i+1], data[i+2]
509
- j = (i // 4) * 3
510
- pixels[j], pixels[j+1], pixels[j+2] = r_c, g, b
511
- img = Image.frombytes("RGB", (w, h), bytes(pixels))
512
- if not _is_black_screen(img):
513
  return img, w, h
514
  except Exception as e:
515
- print(f"[cap:{display}] xlib: {e}")
516
 
517
- finally:
518
- _cleanup_files()
519
-
520
- # Placeholder
521
  print(f"[cap:{display}] ⚠️ All methods failed — placeholder")
522
  from PIL import Image as PILImg, ImageDraw
523
  sw, sh = _get_screen_size(display)
@@ -525,10 +596,9 @@ def _capture_raw(display: str) -> tuple:
525
  draw = ImageDraw.Draw(img)
526
  draw.rectangle([(0, 0), (sw, 55)], fill=(30, 40, 80))
527
  draw.text((10, 10), f"⚠️ Screenshot failed — DISPLAY={display}", fill=(255, 120, 80))
528
- draw.text((10, 32), "Methods: scrot, import, ffmpeg, xlib (3 attempts)", fill=(130, 130, 150))
529
  return img, sw or 1920, sh or 1080
530
 
531
-
532
  def _get_screen_size(display: str) -> tuple:
533
  try:
534
  r = subprocess.run(
 
23
  import json
24
  import os
25
  import re
26
+ import shutil
27
  import subprocess
28
+ import sys
29
  import time
30
  import urllib.parse
31
  import threading
 
417
  return False
418
 
419
 
420
+ def _load_capture_image(path: str):
421
+ from PIL import Image
422
+ if not path or not os.path.exists(path):
423
+ return None, 0, 0
424
+ if os.path.getsize(path) < 1024:
425
+ return None, 0, 0
426
+ try:
427
+ img = Image.open(path).convert("RGB")
428
+ w, h = img.size
429
+ if w < 100 or h < 100:
430
+ return None, 0, 0
431
+ return img, w, h
432
+ except Exception as ex:
433
+ print(f"[cap] load error for {path}: {ex}")
434
+ return None, 0, 0
435
+
436
+
437
+ def _capture_via_x11_stack(display: str):
438
+ """الطريقة الأولى: scrot → ImageMagick import → ffmpeg x11grab → python-xlib."""
439
  from PIL import Image
440
  env = {**os.environ, "DISPLAY": display}
441
  ts = int(time.time() * 1000)
 
442
  disp_safe = display.replace(":", "")
443
  tmp_base = f"/tmp/zss_{disp_safe}_{ts}"
444
  created_files = []
445
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
  def _cleanup_files():
447
  for p in created_files:
448
  try:
 
451
  except Exception:
452
  pass
453
 
454
+ try:
455
+ p1 = f"{tmp_base}_scrot.png"
456
+ created_files.append(p1)
 
457
  try:
458
+ subprocess.run(["scrot", "-q", "95", p1], env=env, timeout=8, capture_output=True)
459
+ img, w, h = _load_capture_image(p1)
460
+ if img and not _is_black_screen(img):
461
+ return img, w, h
462
+ except Exception as e:
463
+ print(f"[cap:{display}] scrot: {e}")
 
 
 
 
 
464
 
465
+ p2 = f"{tmp_base}_im.png"
466
+ created_files.append(p2)
467
+ try:
468
+ subprocess.run(["import", "-window", "root", "-silent", p2], env=env, timeout=10, capture_output=True)
469
+ img, w, h = _load_capture_image(p2)
470
+ if img and not _is_black_screen(img):
471
+ return img, w, h
472
+ except Exception as e:
473
+ print(f"[cap:{display}] import: {e}")
474
+
475
+ p3 = f"{tmp_base}_ff.png"
476
+ created_files.append(p3)
477
+ try:
478
+ sw, sh = _get_screen_size(display)
479
+ subprocess.run([
480
+ "ffmpeg", "-y", "-f", "x11grab",
481
+ "-video_size", f"{sw}x{sh}",
482
+ "-i", display,
483
+ "-vframes", "1", "-q:v", "1", p3
484
+ ], env=env, timeout=12, capture_output=True)
485
+ img, w, h = _load_capture_image(p3)
486
+ if img and not _is_black_screen(img):
487
+ return img, w, h
488
+ except Exception as e:
489
+ print(f"[cap:{display}] ffmpeg: {e}")
490
+
491
+ try:
492
+ from Xlib import display as Xdisp, X
493
+ xd = Xdisp.Display(display)
494
+ root = xd.screen().root
495
+ geom = root.get_geometry()
496
+ w, h = geom.width, geom.height
497
+ raw = root.get_image(0, 0, w, h, X.ZPixmap, 0xFFFFFFFF)
498
+ data = raw.data
499
+ pixels = bytearray(len(data) // 4 * 3)
500
+ for i in range(0, len(data) - 3, 4):
501
+ b, g, r_c = data[i], data[i+1], data[i+2]
502
+ j = (i // 4) * 3
503
+ pixels[j], pixels[j+1], pixels[j+2] = r_c, g, b
504
+ img = Image.frombytes("RGB", (w, h), bytes(pixels))
505
+ if not _is_black_screen(img):
506
+ return img, w, h
507
+ except Exception as e:
508
+ print(f"[cap:{display}] xlib: {e}")
509
+
510
+ return None, 0, 0
511
+ finally:
512
+ _cleanup_files()
513
 
514
+
515
+ def _capture_via_xwd(display: str):
516
+ """الطريقة الثانية: xwd ثم convert إلى PNG."""
517
+ env = {**os.environ, "DISPLAY": display}
518
+ ts = int(time.time() * 1000)
519
+ disp_safe = display.replace(":", "")
520
+ xwd_path = f"/tmp/zss_{disp_safe}_{ts}.xwd"
521
+ png_path = f"/tmp/zss_{disp_safe}_{ts}.png"
522
+ try:
523
+ with open(xwd_path, "wb") as f:
524
+ subprocess.run(["xwd", "-root", "-silent"], env=env, stdout=f, stderr=subprocess.PIPE, timeout=12)
525
+ subprocess.run(["convert", xwd_path, png_path], env=env, capture_output=True, timeout=15)
526
+ img, w, h = _load_capture_image(png_path)
527
+ if img and not _is_black_screen(img):
528
+ return img, w, h
529
+ except FileNotFoundError as e:
530
+ print(f"[cap:{display}] xwd/convert not found: {e}")
531
+ except Exception as e:
532
+ print(f"[cap:{display}] xwd: {e}")
533
+ finally:
534
+ for p in (xwd_path, png_path):
535
  try:
536
+ if os.path.exists(p):
537
+ os.unlink(p)
538
+ except Exception:
539
+ pass
540
+ return None, 0, 0
 
 
 
 
 
 
 
541
 
542
+
543
+ def _capture_via_pyscreenshot(display: str):
544
+ """الطريقة الثالثة: pyscreenshot backend من داخل Python."""
545
+ ts = int(time.time() * 1000)
546
+ disp_safe = display.replace(":", "")
547
+ png_path = f"/tmp/zss_{disp_safe}_{ts}_pyshot.png"
548
+ env = {**os.environ, "DISPLAY": display}
549
+ try:
550
+ code = """import sys
551
+ from pyscreenshot import grab
552
+ out = sys.argv[1]
553
+ img = grab()
554
+ img.save(out)
555
+ """
556
+ subprocess.run([sys.executable, "-c", code, png_path], env=env, capture_output=True, timeout=18)
557
+ img, w, h = _load_capture_image(png_path)
558
+ if img and not _is_black_screen(img):
559
+ return img, w, h
560
+ except FileNotFoundError as e:
561
+ print(f"[cap:{display}] pyscreenshot not available: {e}")
562
+ except Exception as e:
563
+ print(f"[cap:{display}] pyscreenshot: {e}")
564
+ finally:
565
+ try:
566
+ if os.path.exists(png_path):
567
+ os.unlink(png_path)
568
+ except Exception:
569
+ pass
570
+ return None, 0, 0
571
+
572
+
573
+ def _capture_raw(display: str) -> tuple:
574
+ """يلتقط الشاشة من display محدد عبر 3 طرق مستقلة."""
575
+ for attempt in range(3):
576
+ if attempt > 0:
577
+ time.sleep(0.8)
578
+ print(f"[cap:{display}] retry attempt {attempt+1}")
579
+ for method_name, method in (
580
+ ("x11-stack", _capture_via_x11_stack),
581
+ ("xwd", _capture_via_xwd),
582
+ ("pyscreenshot", _capture_via_pyscreenshot),
583
+ ):
584
  try:
585
+ img, w, h = method(display)
586
+ if img and not _is_black_screen(img):
587
+ print(f"[cap:{display}] {method_name} succeeded on attempt {attempt+1}")
 
 
 
 
 
 
 
 
 
 
 
588
  return img, w, h
589
  except Exception as e:
590
+ print(f"[cap:{display}] {method_name}: {e}")
591
 
 
 
 
 
592
  print(f"[cap:{display}] ⚠️ All methods failed — placeholder")
593
  from PIL import Image as PILImg, ImageDraw
594
  sw, sh = _get_screen_size(display)
 
596
  draw = ImageDraw.Draw(img)
597
  draw.rectangle([(0, 0), (sw, 55)], fill=(30, 40, 80))
598
  draw.text((10, 10), f"⚠️ Screenshot failed — DISPLAY={display}", fill=(255, 120, 80))
599
+ draw.text((10, 32), "Methods: x11-stack, xwd+convert, pyscreenshot (3 attempts)", fill=(130, 130, 150))
600
  return img, sw or 1920, sh or 1080
601
 
 
602
  def _get_screen_size(display: str) -> tuple:
603
  try:
604
  r = subprocess.run(