Coverage for selenible/modules/screencast.py: 12%
69 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-05 14:24 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-05 14:24 +0000
1import io
2import threading
3import time
4from logging import getLogger
6from PIL import Image
9class screencast(threading.Thread):
10 def __init__(self, drvobj, crop, interval=1.0, thumbnail=None):
11 super().__init__()
12 self.drvobj = drvobj
13 if crop is None:
14 self.crop = crop
15 else:
16 self.crop = tuple(crop)
17 self.thumbnail = thumbnail
18 self.log = getLogger(self.name)
19 self.stop = False
20 self.interval = interval
21 self.frames = []
23 def run(self):
24 self.start_ts = time.time()
25 while not self.stop:
26 t1 = time.time()
27 with self.drvobj.lock:
28 p = self.drvobj.saveshot()
29 self.log.info("shot: %d bytes, %f sec", len(p), time.time() - t1)
30 if len(p) != 0:
31 img = Image.open(io.BytesIO(p))
32 if self.crop is not None:
33 self.log.info("crop %s, %f sec", self.crop, time.time() - t1)
34 img = img.crop(self.crop)
35 if self.thumbnail is not None:
36 img.thumbnail(self.thumbnail, Image.ANTIALIAS)
37 self.frames.append(img)
38 td = time.time() - t1
39 if self.interval is not None and self.interval > td:
40 self.log.info("sleep %f - %f", self.interval, td)
41 time.sleep(self.interval - td)
42 self.finished_ts = time.time()
44 def savefile(self, output_fn, optimize=False, loop=0, speed=1.0):
45 if len(self.frames) == 0:
46 raise Exception("no image found")
47 d = 1000 * (self.finished_ts - self.start_ts) / len(self.frames) / speed
48 self.log.info(
49 "%d frames, %d sec. duration=%f(ms)",
50 len(self.frames),
51 self.finished_ts - self.start_ts,
52 d,
53 )
54 self.frames[0].save(
55 output_fn,
56 save_all=True,
57 duration=d,
58 optimize=optimize,
59 loop=loop,
60 append_images=self.frames[1:],
61 )
64scr_th = None
67def Base_screencast(self, param):
68 """
69 - name: start screencast
70 screencast:
71 interval: 0.5
72 thumbnail: [100, 100]
73 - name: sleep
74 sleep: 3
75 - name: save screencast
76 screencast: output.gif
77 """
78 global scr_th
79 if isinstance(param, dict) and "output" not in param:
80 if scr_th is not None:
81 raise Exception("screencast already working")
82 scr_th = screencast(
83 self, param.get("crop"), param.get("interval"), param.get("thumbnail")
84 )
85 scr_th.start()
86 return "started"
87 if scr_th is None:
88 raise Exception("screencast is not working")
89 self.log.debug("stop cast")
90 scr_th.stop = True
91 scr_th.join(2)
92 if scr_th.is_alive():
93 self.log.warning("cannot stop screencast thread.")
94 else:
95 self.log.debug("done join. saving")
96 if isinstance(param, str):
97 self.log.info("save to %s", param)
98 scr_th.savefile(param)
99 elif isinstance(param, dict):
100 output = param.get("output")
101 assert output is not None
102 self.log.info("save to %s", output)
103 scr_th.savefile(
104 output,
105 optimize=param.get("optimize", False),
106 loop=param.get("loop", 0),
107 speed=param.get("speed", 1.0),
108 )
109 scr_th = None
110 return "finished"