added flip and reverse
fix camera scan for first time with no auto-scan
This commit is contained in:
+2
-1
@@ -25,7 +25,8 @@ class StreamNodeHeader(CozyImageNode):
|
||||
|
||||
return deep_merge(d, {
|
||||
"optional": {
|
||||
# "WH": ("VEC2INT", {"default": [640, 480], "mij": 160, "tooltip": "width and height"}),
|
||||
"FLIP": ("BOOLEAN", {"default": False, "tooltip": "Flip image top-to-bottom"}),
|
||||
"REVERSE": ("BOOLEAN", {"default": False, "tooltip": "reverse image left-to-right"}),
|
||||
"FPS": ("INT", {"default": 30, "min": 1, "max": 60,
|
||||
"tooltip": "Framerate to attempt when capturing"}),
|
||||
"BATCH": ("INT", {"default": 1, "min": 1,
|
||||
|
||||
@@ -96,12 +96,14 @@ Capture frames from a desktop monitor. Supports batch processing, allowing multi
|
||||
fps = parse_param(kw, "FPS", EnumConvertType.INT, 30)
|
||||
xy = parse_param(kw, "XY", EnumConvertType.VEC2INT, [(0,0)], 0)
|
||||
wh = parse_param(kw, "WH", EnumConvertType.VEC2INT, [(0,0)], 0)
|
||||
flip = parse_param(kw, "FLIP", EnumConvertType.BOOLEAN, False)
|
||||
reverse = parse_param(kw, "REVERSE", EnumConvertType.BOOLEAN, False)
|
||||
|
||||
pbar = ProgressBar(batch_size)
|
||||
size = [batch_size] * batch_size
|
||||
params = list(zip_longest_fill(monitor, fps, xy, wh, size))
|
||||
params = list(zip_longest_fill(monitor, fps, xy, wh, flip, reverse, size))
|
||||
with mss.mss() as screen:
|
||||
for idx, (monitor, fps, xy, wh, size) in enumerate(params):
|
||||
for idx, (monitor, fps, xy, wh, flip, reverse, size) in enumerate(params):
|
||||
|
||||
try:
|
||||
monitor = int(monitor.split('-')[0].strip())
|
||||
@@ -127,9 +129,12 @@ Capture frames from a desktop monitor. Supports batch processing, allowing multi
|
||||
'width': width,
|
||||
'height': height
|
||||
}
|
||||
print(region)
|
||||
img = screen.grab(region)
|
||||
img = cv2.cvtColor(np.array(img, dtype=np.uint8), cv2.COLOR_RGB2BGR)
|
||||
if flip:
|
||||
img = cv2.flip(img, 0)
|
||||
if reverse:
|
||||
img = cv2.flip(img, 1)
|
||||
|
||||
images.append(cv_to_tensor_full(img))
|
||||
pbar.update_absolute(idx)
|
||||
|
||||
+40
-52
@@ -1,12 +1,10 @@
|
||||
"""
|
||||
Jovi_Capture - http://www.github.com/amorano/Jovi_Capture
|
||||
REMOTE -- Capture remove URL
|
||||
Capture remote URL
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Dict, Tuple
|
||||
from typing import Dict
|
||||
|
||||
import cv2
|
||||
import torch
|
||||
|
||||
from comfy.utils import ProgressBar
|
||||
@@ -14,17 +12,19 @@ from comfy.utils import ProgressBar
|
||||
from cozy_comfyui import \
|
||||
EnumConvertType, \
|
||||
logger, \
|
||||
deep_merge, parse_param
|
||||
deep_merge, parse_param, zip_longest_fill
|
||||
|
||||
from cozy_comfyui import RGBAMaskType
|
||||
from cozy_comfyui.image.convert import cv_to_tensor_full
|
||||
|
||||
from . import StreamNodeHeader
|
||||
from . import VideoStreamNodeHeader
|
||||
from .stream import MediaStreamBase
|
||||
|
||||
# ==============================================================================
|
||||
# === NODE ===
|
||||
# ==============================================================================
|
||||
|
||||
class RemoteSteamReader(StreamNodeHeader):
|
||||
class RemoteSteamReader(VideoStreamNodeHeader):
|
||||
NAME = "REMOTE"
|
||||
DESCRIPTION = """
|
||||
Capture frames from a URL. Supports batch processing, allowing multiple frames to be captured simultaneously. The node provides options for configuring the source, resolution, frame rate, zoom, orientation, and interpolation method. Additionally, it supports capturing frames from multiple monitors or windows simultaneously.
|
||||
@@ -40,55 +40,43 @@ Capture frames from a URL. Supports batch processing, allowing multiple frames t
|
||||
}
|
||||
}, d)
|
||||
|
||||
def __init__(self, *arg, **kw) -> None:
|
||||
super().__init__(*arg, **kw)
|
||||
self.__url = ""
|
||||
self.__device = None # MediaStreamURL
|
||||
def run(self, **kw) -> RGBAMaskType:
|
||||
# need to see if we have a device...
|
||||
if self.device is None:
|
||||
self.device = MediaStreamBase()
|
||||
|
||||
def run(self, **kw) -> Tuple[torch.Tensor, torch.Tensor]:
|
||||
wait = parse_param(kw, "WAIT", EnumConvertType.BOOLEAN, False)[0]
|
||||
if wait:
|
||||
return self.__last
|
||||
images = []
|
||||
batch_size, rate = parse_param(kw, "BATCH", EnumConvertType.VEC2INT, [(1, 30)], 1)[0]
|
||||
self.device.url = parse_param(kw, "URL", EnumConvertType.STRING, "")[0]
|
||||
self.device.fps = parse_param(kw, "FPS", EnumConvertType.INT, 30)[0]
|
||||
batch_size = parse_param(kw, "BATCH", EnumConvertType.INT, 1, 1)[0]
|
||||
if parse_param(kw, "PAUSE", EnumConvertType.BOOLEAN, False)[0]:
|
||||
self.device.pause()
|
||||
else:
|
||||
self.device.play()
|
||||
self.device.timeout = parse_param(kw, "TIMEOUT", EnumConvertType.INT, 5, 1, 30)[0]
|
||||
flip = parse_param(kw, "FLIP", EnumConvertType.BOOLEAN, False)
|
||||
reverse = parse_param(kw, "REVERSE", EnumConvertType.BOOLEAN, False)
|
||||
|
||||
rate = 1. / self.device.fps
|
||||
pbar = ProgressBar(batch_size)
|
||||
rate = 1. / rate
|
||||
batch_size = [batch_size] * batch_size
|
||||
params = list(zip_longest_fill(batch_size, flip, reverse))
|
||||
for idx, (batch_size, flip, reverse) in enumerate(params):
|
||||
start_time = time.perf_counter()
|
||||
self.device.flip = flip
|
||||
self.device.reverse = reverse
|
||||
while True:
|
||||
if not (img := self.device.frame) is None and img.sum() > 0:
|
||||
break
|
||||
if time.perf_counter() - start_time > self.device.timeout:
|
||||
logger.error("could not capture device")
|
||||
img = self.empty
|
||||
break
|
||||
|
||||
url = parse_param(kw, "URL", EnumConvertType.STRING, "")[0]
|
||||
url = url.split('-')[0].strip()
|
||||
try:
|
||||
_ = int(url)
|
||||
url = str(url)
|
||||
except: url = ""
|
||||
|
||||
# timeout and try again?
|
||||
if self.__capturing > 0 and time.perf_counter() - self.__capturing > 3000:
|
||||
logger.error(f'timed out {self.__url}')
|
||||
self.__capturing = 0
|
||||
self.__url = ""
|
||||
|
||||
if self.__device is not None:
|
||||
self.__capturing = 0
|
||||
|
||||
if wait:
|
||||
self.__device.pause()
|
||||
else:
|
||||
self.__device.play()
|
||||
|
||||
fps = parse_param(kw, "FPS", EnumConvertType.INT, 30)[0]
|
||||
self.__device.fps = fps
|
||||
self.__device.zoom = parse_param(kw, "ZOOM", EnumConvertType.FLOAT, 0, 0, 1)[0]
|
||||
|
||||
for idx in range(batch_size):
|
||||
img = self.__device.frame
|
||||
if img is None:
|
||||
images.append(self.__empty)
|
||||
else:
|
||||
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGRA)
|
||||
images.append(cv_to_tensor_full(img))
|
||||
pbar.update_absolute(idx)
|
||||
if batch_size > 1:
|
||||
time.sleep(rate)
|
||||
images.append(cv_to_tensor_full(img))
|
||||
if batch_size > 1:
|
||||
time.sleep(rate)
|
||||
pbar.update_absolute(idx)
|
||||
|
||||
if len(images) == 0:
|
||||
images.append(self.__empty)
|
||||
|
||||
+14
-29
@@ -15,7 +15,7 @@ from server import PromptServer
|
||||
from cozy_comfyui import \
|
||||
EnumConvertType, \
|
||||
logger, \
|
||||
deep_merge, parse_param
|
||||
deep_merge, parse_param, zip_longest_fill
|
||||
|
||||
from cozy_comfyui import RGBAMaskType
|
||||
from cozy_comfyui.image.convert import cv_to_tensor_full
|
||||
@@ -38,7 +38,7 @@ def camera_list() -> List[str]:
|
||||
idx = 0
|
||||
failed = 0
|
||||
camera_list = []
|
||||
while failed < 2:
|
||||
while failed < 1:
|
||||
cap = cv2.VideoCapture(idx)
|
||||
if cap.isOpened():
|
||||
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
||||
@@ -60,9 +60,11 @@ def camera_list() -> List[str]:
|
||||
|
||||
@PromptServer.instance.routes.get(f"/{PACKAGE.lower()}/camera")
|
||||
async def route_cameraList(req) -> Any:
|
||||
# load the camera list here..
|
||||
force = req.query_string == "force=true"
|
||||
if force and not JOV_SCAN_DEVICES:
|
||||
return web.json_response(["NONE"])
|
||||
CameraStreamReader.CAMERAS = camera_list()
|
||||
return web.json_response(CameraStreamReader.CAMERAS)
|
||||
return web.json_response(CameraStreamReader.CAMERAS, content_type='application/json')
|
||||
|
||||
# ==============================================================================
|
||||
# === CLASS ===
|
||||
@@ -74,28 +76,8 @@ class MediaStreamCamera(MediaStreamBase):
|
||||
self.__focus = 0
|
||||
self.__exposure = 1
|
||||
self.__zoom = 0
|
||||
self.__flip: bool = False
|
||||
super().__init__(fps=fps)
|
||||
|
||||
@property
|
||||
def frame(self):
|
||||
frame = super().frame
|
||||
try:
|
||||
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGRA)
|
||||
if self.__flip:
|
||||
frame = cv2.flip(frame, 1)
|
||||
except:
|
||||
pass
|
||||
return frame
|
||||
|
||||
@property
|
||||
def flip(self) -> bool:
|
||||
return self.__flip
|
||||
|
||||
@flip.setter
|
||||
def flip(self, flip: bool) -> None:
|
||||
self.__flip = flip
|
||||
|
||||
@property
|
||||
def zoom(self) -> float:
|
||||
return self.__zoom
|
||||
@@ -146,12 +128,11 @@ Capture frames from a web camera. Supports batch processing, allowing multiple f
|
||||
d = super().INPUT_TYPES()
|
||||
|
||||
if cls.CAMERAS is None:
|
||||
cls.CAMERAS = camera_list() if JOV_SCAN_DEVICES else ["NONE"]
|
||||
cls.CAMERAS = camera_list() if JOV_SCAN_DEVICES else ["0 -NONE"]
|
||||
|
||||
return deep_merge({
|
||||
"optional": {
|
||||
"CAMERA": (cls.CAMERAS, {"default": cls.CAMERAS[0], "tooltip": "The camera from the auto-scanned list"}),
|
||||
"FLIP": ("BOOLEAN", {"default": False, "tooltip": "Camera flip image left-to-right"}),
|
||||
"ZOOM": ("INT", {"default": 0, "min": 0, "max": 100, "step": 1, "tooltip": "Camera zoom"}),
|
||||
"FOCUS": ("INT", {"default": 0, "min": 0, "max": 100, "step": 1, "tooltip": "Camera focus"}),
|
||||
"EXPOSURE": ("INT", {"default": 50, "min": 0, "max": 100, "step": 1, "tooltip": "Camera exposure"})
|
||||
@@ -181,16 +162,20 @@ Capture frames from a web camera. Supports batch processing, allowing multiple f
|
||||
self.device.pause()
|
||||
else:
|
||||
self.device.play()
|
||||
|
||||
self.device.flip = parse_param(kw, "FLIP", EnumConvertType.BOOLEAN, False)[0]
|
||||
self.device.zoom = parse_param(kw, "ZOOM", EnumConvertType.INT, 0, 0, 100)[0] / 100.
|
||||
self.device.focus = parse_param(kw, "FOCUS", EnumConvertType.INT, 0, 0, 100)[0] / 100.
|
||||
self.device.exposure = parse_param(kw, "EXPOSURE", EnumConvertType.INT, 0, 0, 100)[0] / 100.
|
||||
flip = parse_param(kw, "FLIP", EnumConvertType.BOOLEAN, False)
|
||||
reverse = parse_param(kw, "REVERSE", EnumConvertType.BOOLEAN, False)
|
||||
|
||||
rate = 1. / self.device.fps
|
||||
pbar = ProgressBar(batch_size)
|
||||
for idx in range(batch_size):
|
||||
batch_size = [batch_size] * batch_size
|
||||
params = list(zip_longest_fill(batch_size, flip, reverse))
|
||||
for idx, (batch_size, flip, reverse) in enumerate(params):
|
||||
start_time = time.perf_counter()
|
||||
self.device.flip = flip
|
||||
self.device.reverse = reverse
|
||||
while True:
|
||||
if not (img := self.device.frame) is None and img.sum() > 0:
|
||||
break
|
||||
|
||||
+14
-15
@@ -6,6 +6,7 @@ import time
|
||||
import platform
|
||||
from typing import Any, Dict, Optional, Tuple
|
||||
|
||||
import cv2
|
||||
import torch
|
||||
import numpy as np
|
||||
import pywinctl as pwc
|
||||
@@ -109,7 +110,7 @@ def window_capture(hwnd: int, client_area_only: bool=False, region: Optional[Tup
|
||||
width = max_width if rw == 0 else min(rw, max_width - x)
|
||||
height = max_height if rh == 0 else min(rh, max_height - y)
|
||||
|
||||
logger.info(f"Capture region: pos=({x},{y}) size=({width},{height})")
|
||||
# logger.info(f"Capture region: pos=({x},{y}) size=({width},{height})")
|
||||
|
||||
img = None
|
||||
try:
|
||||
@@ -120,17 +121,6 @@ def window_capture(hwnd: int, client_area_only: bool=False, region: Optional[Tup
|
||||
bitmap.CreateCompatibleBitmap(dc, width, height)
|
||||
compatible_dc.SelectObject(bitmap)
|
||||
|
||||
# Set the correct source coordinates for BitBlt
|
||||
"""
|
||||
compatible_dc.BitBlt(
|
||||
(0, 0),
|
||||
(width, height),
|
||||
dc,
|
||||
(capture_left, capture_top),
|
||||
win32con.SRCCOPY
|
||||
)
|
||||
"""
|
||||
|
||||
result = windll.user32.PrintWindow(hwnd, compatible_dc.GetSafeHdc(), 0)
|
||||
if result is None:
|
||||
return None
|
||||
@@ -138,6 +128,8 @@ def window_capture(hwnd: int, client_area_only: bool=False, region: Optional[Tup
|
||||
img = np.frombuffer(bmpstr, dtype='uint8')
|
||||
img = img.reshape((height, width, 4))
|
||||
img = img[y:y+height, x:x+width]
|
||||
img = img[..., [2, 1, 0, 3]]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
finally:
|
||||
@@ -256,7 +248,7 @@ def window_capture(hwnd: int, client_area_only: bool=False, region: Optional[Tup
|
||||
@PromptServer.instance.routes.get(f"/{PACKAGE.lower()}/window")
|
||||
async def route_windowList(req) -> Any:
|
||||
WindowStreamReader.WINDOWS = window_list()
|
||||
return web.json_response(WindowStreamReader.WINDOWS)
|
||||
return web.json_response(WindowStreamReader.WINDOWS, content_type='application/json')
|
||||
|
||||
# ==============================================================================
|
||||
# === NODE ===
|
||||
@@ -299,10 +291,12 @@ Capture frames from a dekstop window. Supports batch processing, allowing multip
|
||||
xy = parse_param(kw, "XY", EnumConvertType.VEC2INT, [(0,0)], 0)
|
||||
wh = parse_param(kw, "WH", EnumConvertType.VEC2INT, [(0,0)], 0)
|
||||
client = parse_param(kw, "CLIENT", EnumConvertType.BOOLEAN, False)
|
||||
flip = parse_param(kw, "FLIP", EnumConvertType.BOOLEAN, False)
|
||||
reverse = parse_param(kw, "REVERSE", EnumConvertType.BOOLEAN, False)
|
||||
pbar = ProgressBar(batch_size)
|
||||
size = [batch_size] * batch_size
|
||||
params = list(zip_longest_fill(window, fps, xy, wh, client, size))
|
||||
for idx, (window, fps, xy, wh, client, size) in enumerate(params):
|
||||
params = list(zip_longest_fill(window, fps, xy, wh, client, flip, reverse, size))
|
||||
for idx, (window, fps, xy, wh, client, flip, reverse, size) in enumerate(params):
|
||||
try:
|
||||
window = self.WINDOWS[window]
|
||||
except Exception as e:
|
||||
@@ -312,6 +306,11 @@ Capture frames from a dekstop window. Supports batch processing, allowing multip
|
||||
region = (xy[0], xy[1], wh[0], wh[1])
|
||||
if (img := window_capture(window, client, region)) is None:
|
||||
img = self.empty
|
||||
else:
|
||||
if flip:
|
||||
img = cv2.flip(img, 0)
|
||||
if reverse:
|
||||
img = cv2.flip(img, 1)
|
||||
|
||||
images.append(cv_to_tensor_full(img))
|
||||
if batch_size > 1:
|
||||
|
||||
+36
-9
@@ -25,14 +25,16 @@ class MediaStreamBase:
|
||||
self.__frame = None
|
||||
self.__source = None
|
||||
self.__url = None
|
||||
self.__reverse: bool = False
|
||||
self.__flip: bool = False
|
||||
self.__height = 0
|
||||
self.__width = 0
|
||||
self.__thread = threading.Thread(target=self.__run, daemon=True)
|
||||
self.__thread.start()
|
||||
|
||||
def __run(self) -> None:
|
||||
start_time = time.perf_counter()
|
||||
while not self.__quit:
|
||||
start_time = time.perf_counter()
|
||||
if not self.__source or not self.__source.isOpened():
|
||||
logger.error("waiting on device")
|
||||
time.sleep(0.5)
|
||||
@@ -46,12 +48,17 @@ class MediaStreamBase:
|
||||
while True:
|
||||
ret, frame = self.__source.read()
|
||||
if ret and frame is not None and frame.sum() > 0:
|
||||
if self.__flip:
|
||||
frame = cv2.flip(frame, 0)
|
||||
if self.__reverse:
|
||||
frame = cv2.flip(frame, 1)
|
||||
self.__frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGRA)
|
||||
break
|
||||
if time.perf_counter() - start_time > self.__timeout:
|
||||
elif time.perf_counter() - start_time > self.__timeout:
|
||||
logger.error("could not capture frame")
|
||||
self.__quit = True
|
||||
break
|
||||
self.__frame = frame
|
||||
|
||||
"""
|
||||
if not ret:
|
||||
count = int(self.__source.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||
@@ -59,19 +66,24 @@ class MediaStreamBase:
|
||||
if pos >= count:
|
||||
self.__source.set(cv2.CAP_PROP_POS_FRAMES, 0)
|
||||
ret, self.__frame = self.__source.read()
|
||||
https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4
|
||||
"""
|
||||
|
||||
elapsed = time.perf_counter() - start_time
|
||||
time.sleep(max(delta - elapsed, 0))
|
||||
start_time = time.perf_counter()
|
||||
self.__end()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.__class__.__name__
|
||||
|
||||
def __end(self) -> None:
|
||||
self.__quit = True
|
||||
if self.__thread:
|
||||
self.__thread.join(timeout=self.__timeout)
|
||||
try:
|
||||
self.__thread.join(timeout=self.__timeout)
|
||||
except RuntimeError as e:
|
||||
pass
|
||||
self.__quit = True
|
||||
if self.__source is not None:
|
||||
self.__source.release()
|
||||
self.__source = None
|
||||
@@ -99,10 +111,9 @@ class MediaStreamBase:
|
||||
if new_source.isOpened():
|
||||
self.__source = new_source
|
||||
self.__url = url
|
||||
logger.info(f"Captured camera device: {self.__url}")
|
||||
return
|
||||
|
||||
logger.error(f"Failed to open camera source: {url}")
|
||||
logger.info(f"captured url: {self.__url}")
|
||||
else:
|
||||
logger.error(f"failed to open source: {url}")
|
||||
|
||||
@property
|
||||
def source(self) -> cv2.VideoCapture:
|
||||
@@ -151,3 +162,19 @@ class MediaStreamBase:
|
||||
if self.__source is not None:
|
||||
self.__height = max(1, height)
|
||||
self.__source.set(cv2.CAP_PROP_FRAME_HEIGHT, self.__height)
|
||||
|
||||
@property
|
||||
def flip(self) -> bool:
|
||||
return self.__flip
|
||||
|
||||
@flip.setter
|
||||
def flip(self, flip: bool) -> None:
|
||||
self.__flip = flip
|
||||
|
||||
@property
|
||||
def reverse(self) -> bool:
|
||||
return self.__reverse
|
||||
|
||||
@flip.setter
|
||||
def reverse(self, reverse: bool) -> None:
|
||||
self.__reverse = reverse
|
||||
+15
-7
@@ -15,18 +15,26 @@ app.registerExtension({
|
||||
return
|
||||
}
|
||||
|
||||
const onNodeCreated = nodeType.prototype.onNodeCreated
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
const me = onNodeCreated?.apply(this);
|
||||
const refresh_cameras = async(widget, force=false) => {
|
||||
let url = "/jov_capture/camera"
|
||||
if (force) {
|
||||
url += "?force=true";
|
||||
}
|
||||
var data = await api_get(url);
|
||||
widget.options.values = data;
|
||||
widget.value = data[0];
|
||||
app.canvas.setDirty(true);
|
||||
}
|
||||
|
||||
const onNodeCreated = nodeType.prototype.onNodeCreated
|
||||
nodeType.prototype.onNodeCreated = async function () {
|
||||
const me = onNodeCreated?.apply(this);
|
||||
const widget_camera = this.widgets.find(w => w.name == 'CAMERA');
|
||||
|
||||
this.addWidget('button', 'REFRESH CAMERA LIST', 'refresh', async () => {
|
||||
var data = await api_get("/jov_capture/camera");
|
||||
widget_camera.options.values = data;
|
||||
widget_camera.value = data[0];
|
||||
app.canvas.setDirty(true);
|
||||
await refresh_cameras(widget_camera);
|
||||
});
|
||||
await refresh_cameras(widget_camera, true);
|
||||
return me;
|
||||
}
|
||||
|
||||
|
||||
+11
-8
@@ -15,19 +15,22 @@ app.registerExtension({
|
||||
return
|
||||
}
|
||||
|
||||
const onNodeCreated = nodeType.prototype.onNodeCreated
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
const me = onNodeCreated?.apply(this);
|
||||
const refresh_windows = async(widget) => {
|
||||
var data = await api_get("/jov_capture/window");
|
||||
widget.options.values = Object.keys(data);
|
||||
widget.value = widget.options.values[0];
|
||||
app.canvas.setDirty(true);
|
||||
}
|
||||
|
||||
const onNodeCreated = nodeType.prototype.onNodeCreated
|
||||
nodeType.prototype.onNodeCreated = async function () {
|
||||
const me = onNodeCreated?.apply(this);
|
||||
const widget_window = this.widgets.find(w => w.name == 'WINDOW');
|
||||
|
||||
this.addWidget('button', 'REFRESH WINDOW LIST', 'refresh', async () => {
|
||||
var data = await api_get("/jov_capture/window");
|
||||
widget_window.options.values = Object.keys(data);
|
||||
widget_window.value = widget_window.options.values[0];
|
||||
console.info(widget_window)
|
||||
app.canvas.setDirty(true);
|
||||
refresh_windows(widget_window);
|
||||
});
|
||||
await refresh_windows(widget_window);
|
||||
return me;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -37,7 +37,8 @@ export async function api_post(route, id, cmd) {
|
||||
|
||||
export async function api_get(route) {
|
||||
var response = await api.fetchApi(route, { cache: "no-store" });
|
||||
return await response.json()
|
||||
var text = await response.text();
|
||||
return JSON.parse(text);
|
||||
}
|
||||
|
||||
function widgetHide(node, widget, suffix = '') {
|
||||
|
||||
Reference in New Issue
Block a user