webatem 2.0.3__tar.gz → 2.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {webatem-2.0.3 → webatem-2.0.4}/PKG-INFO +1 -1
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/uploader.py +96 -10
- {webatem-2.0.3 → webatem-2.0.4}/pyproject.toml +1 -1
- {webatem-2.0.3 → webatem-2.0.4}/webatem.egg-info/PKG-INFO +1 -1
- {webatem-2.0.3 → webatem-2.0.4}/LICENSE +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/README.md +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/__init__.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/activity.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/apps.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/control/__init__.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/control/activity.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/control/commands.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/control/consumer.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/control/device_api.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/control/logging.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/control/views.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/discovery.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/hooks.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/hyperdeck/__init__.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/hyperdeck/connection.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/hyperdeck/views.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/ip_upload_lock.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/media_pool/__init__.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/media_pool/broadcast.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/media_pool/views.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/media_pool/watcher.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/migrations/0001_initial.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/migrations/0002_legacy_log.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/migrations/__init__.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/models.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/netutil.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/profile/__init__.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/profile/dialog.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/profile/export.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/profile/views.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/routing.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/sightings.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/apple-touch-icon.png +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/brand.css +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/favicon-32.png +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/favicon.ico +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/Archivo-400-latin-ext.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/Archivo-400-latin.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/Archivo-500-latin-ext.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/Archivo-500-latin.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/Archivo-600-latin-ext.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/Archivo-600-latin.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/Archivo-800-latin-ext.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/Archivo-800-latin.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/IBMPlexMono-400-latin.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/IBMPlexMono-500-latin-ext.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/IBMPlexMono-500-latin.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/IBMPlexMono-600-latin-ext.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/IBMPlexMono-600-latin.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/OFL-Archivo.txt +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/OFL-IBMPlexMono.txt +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/icon-192.png +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/icon-512.png +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/icon-maskable-512.png +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/manifest.webmanifest +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/mark.svg +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/tray/linux-24.png +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/tray/mac-22.png +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/tray/mac-44.png +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/tray/win-16.png +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/tray/win-32.png +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/css/atem_connect.css +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/css/atem_control.css +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/icon.png +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/js/atem_connect.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/js/atem_control.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/js/atem_control_page.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/js/atem_discovery.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/js/atem_hyperdeck.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/js/atem_profile.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/js/atem_realtime_slider.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/js/custom-scrollbar.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/js/recent_label.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/js/wa-select.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/vendor/README.md +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/vendor/alpine.min.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/vendor/alpinejs-collapse-3.14.3.min.js +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/vendor/bootstrap-icons/bootstrap-icons.min.css +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/static/vendor/webatem.css +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/storage.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/tally.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/connect.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_atem_info.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_fade_to_black.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_fairlight.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_header.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_hyperdeck_panel.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_macros.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_media_pool.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_profile_modal.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_settings_dsk.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_settings_transition.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_settings_usk.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_slider.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_transition_controls.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_transition_style.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_usk_fly.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_usk_keyframe.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_usk_mask.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control/_usk_slider.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templates/control.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templatetags/__init__.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/templatetags/static_v.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/atem_control/urls.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/setup.cfg +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/__init__.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/__main__.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/applog.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/asgi.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/context.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/launcher.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/server.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/settings.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/templates/base.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/templates/brand/_mark.svg +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/templates/launcher.html +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/uninstall.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/updates.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/urls.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/views.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem/websocket.py +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem.egg-info/SOURCES.txt +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem.egg-info/dependency_links.txt +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem.egg-info/entry_points.txt +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem.egg-info/requires.txt +0 -0
- {webatem-2.0.3 → webatem-2.0.4}/webatem.egg-info/top_level.txt +0 -0
|
@@ -65,6 +65,10 @@ CONNECT_RETRY_DELAY = 2.0
|
|
|
65
65
|
UPLOAD_TIMEOUT = 90.0
|
|
66
66
|
HASH_SETTLE_TIMEOUT = 10.0
|
|
67
67
|
REUPLOAD_SETTLE = 1.0
|
|
68
|
+
# A tally check that finds no switcher state (the session re-handshaking after
|
|
69
|
+
# a drop, or its new dump still arriving) waits this long for the state before
|
|
70
|
+
# it refuses the upload: the budget the connect gives the first dump.
|
|
71
|
+
STATE_READY_TIMEOUT = CONNECTION_TIMEOUT
|
|
68
72
|
|
|
69
73
|
# Tally cycle-wait timings + the shared cold->hot->cold loop live in
|
|
70
74
|
# ``content_change.tally`` so the media-pool and HyperDeck paths can't drift.
|
|
@@ -200,7 +204,55 @@ def _source_on_air(mixerstate, ids: set) -> bool:
|
|
|
200
204
|
return False
|
|
201
205
|
|
|
202
206
|
|
|
203
|
-
|
|
207
|
+
class _StateNotReady(Exception):
|
|
208
|
+
"""The switcher's state did not come back within STATE_READY_TIMEOUT, so
|
|
209
|
+
nothing can say the slot is off air. ``_upload_one`` refuses the item."""
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _pooled(conn) -> bool:
|
|
213
|
+
"""A pooled ``ATEMConnection`` (how a host calls ``_is_slot_safe``), not
|
|
214
|
+
the uploader's own ``AtemProtocol``: its worker thread pumps the loop and
|
|
215
|
+
tracks the session, so it is asked rather than pumped."""
|
|
216
|
+
return hasattr(conn, 'is_connected')
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _state_ready(conn) -> bool:
|
|
220
|
+
"""The switcher's state is there to read: its dump has finished and
|
|
221
|
+
carried a video mode, the test ``atemwire.ready.wait_ready`` uses. A
|
|
222
|
+
dropped session empties ``mixerstate`` while the transport re-handshakes
|
|
223
|
+
in place, and the new dump refills it field by field, so anything short of
|
|
224
|
+
this can be missing exactly the field that says the slot is on air."""
|
|
225
|
+
if 'video-mode' not in conn.mixerstate:
|
|
226
|
+
return False
|
|
227
|
+
if _pooled(conn):
|
|
228
|
+
# is_ready (bmdwire >= 1.3) is False through a re-handshake, when
|
|
229
|
+
# is_connected stays True; the media-pool watcher asks the same.
|
|
230
|
+
return bool(getattr(conn, 'is_ready', conn.is_connected))
|
|
231
|
+
# Set at the end-of-dump marker, cleared on a drop.
|
|
232
|
+
return bool(getattr(conn, 'initialized', False))
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _await_state(conn, timeout: float,
|
|
236
|
+
is_cancelled: Optional[Callable[[], bool]] = None) -> bool:
|
|
237
|
+
"""Wait until the state is ready (True), or until ``timeout`` seconds pass
|
|
238
|
+
or ``is_cancelled`` says so (False). A bare protocol is pumped, ticked so
|
|
239
|
+
a quiet wire cannot hold one pump past the deadline; a pooled connection's
|
|
240
|
+
own worker is pumping it already."""
|
|
241
|
+
deadline = time.monotonic() + timeout
|
|
242
|
+
while not _state_ready(conn):
|
|
243
|
+
if time.monotonic() >= deadline:
|
|
244
|
+
return False
|
|
245
|
+
if is_cancelled is not None and is_cancelled():
|
|
246
|
+
return False
|
|
247
|
+
if _pooled(conn):
|
|
248
|
+
time.sleep(0.02)
|
|
249
|
+
else:
|
|
250
|
+
ticked_pump(conn, idle_sleep=0.02)
|
|
251
|
+
return True
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _is_slot_safe(protocol, slot_0_indexed: int,
|
|
255
|
+
is_cancelled: Optional[Callable[[], bool]] = None) -> bool:
|
|
204
256
|
"""Safe to overwrite a media-pool slot when no media player currently
|
|
205
257
|
showing that slot (as a still) is live on PROGRAM output.
|
|
206
258
|
|
|
@@ -214,7 +266,24 @@ def _is_slot_safe(protocol, slot_0_indexed: int) -> bool:
|
|
|
214
266
|
Only if tally hasn't arrived yet (rare — it's in the connect state-dump) do
|
|
215
267
|
we fall back to an ME1 program-path reconstruction, so we neither overwrite
|
|
216
268
|
blind nor hang waiting for tally.
|
|
269
|
+
|
|
270
|
+
Only a state that is there can say a slot is safe. An empty one (the
|
|
271
|
+
session reconnecting) or a dump still arriving has no media players and no
|
|
272
|
+
tally in it, which reads as "nothing on air"; until 2.0.4 that let an
|
|
273
|
+
upload through into a live slot. So the check first waits up to
|
|
274
|
+
STATE_READY_TIMEOUT for the state and raises ``_StateNotReady`` if it does
|
|
275
|
+
not come back. A cancel ends that wait the same way; the caller checks for
|
|
276
|
+
the cancel first. It raises rather than answering False because "cannot
|
|
277
|
+
tell" means different things to different callers: to an upload it is a
|
|
278
|
+
refusal, to a host watching for a slot to go on air it is "not live".
|
|
217
279
|
"""
|
|
280
|
+
if not _await_state(protocol, STATE_READY_TIMEOUT, is_cancelled):
|
|
281
|
+
raise _StateNotReady(
|
|
282
|
+
f"switcher state not ready after {STATE_READY_TIMEOUT:.0f}s "
|
|
283
|
+
f"(session reconnecting); cannot confirm slot {slot_0_indexed + 1} "
|
|
284
|
+
f"is off air")
|
|
285
|
+
# Read after the wait: a reconnect REPLACES mixerstate, so a reference
|
|
286
|
+
# taken before it would be the old, empty dict.
|
|
218
287
|
mixerstate = protocol.mixerstate
|
|
219
288
|
mps = mixerstate.get('mediaplayer-selected') or {}
|
|
220
289
|
if not isinstance(mps, dict):
|
|
@@ -250,15 +319,22 @@ def _wait_for_safe_upload_window(protocol, slot_0_indexed: int,
|
|
|
250
319
|
"""Cycle-wait for tally safety before overwriting a media-pool slot. Thin
|
|
251
320
|
wrapper over the shared ``wait_for_safe_cycle`` (content_change.tally) with
|
|
252
321
|
the media-pool slot liveness predicate, so the cold->hot->cold loop is
|
|
253
|
-
identical to the HyperDeck path.
|
|
322
|
+
identical to the HyperDeck path. ``_StateNotReady`` from the predicate is
|
|
323
|
+
not caught here: it ends the cycle at once, a refusal rather than a wait
|
|
324
|
+
that runs out the tally timeout as if the slot had stayed live."""
|
|
254
325
|
slot_user = slot_0_indexed + 1
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
326
|
+
if not _state_ready(protocol):
|
|
327
|
+
source = (f"not ready (session reconnecting), waiting up to "
|
|
328
|
+
f"{STATE_READY_TIMEOUT:.0f}s for the switcher's state")
|
|
329
|
+
elif isinstance(getattr(protocol.mixerstate.get('tally-source'), 'tally', None), dict):
|
|
330
|
+
source = 'present (authoritative)'
|
|
331
|
+
else:
|
|
332
|
+
source = 'ABSENT — using ME1 fallback'
|
|
333
|
+
log_append(f"slot {slot_user}: tally source {source}")
|
|
259
334
|
return wait_for_safe_cycle(
|
|
260
335
|
protocol,
|
|
261
|
-
is_live=lambda: not _is_slot_safe(protocol, slot_0_indexed
|
|
336
|
+
is_live=lambda: not _is_slot_safe(protocol, slot_0_indexed,
|
|
337
|
+
is_cancelled=canceller.is_set),
|
|
262
338
|
is_cancelled=canceller.is_set,
|
|
263
339
|
log=log_append,
|
|
264
340
|
label=f'slot {slot_user}',
|
|
@@ -339,9 +415,19 @@ def _upload_one(protocol, slot: int, image_path: str, width: int, height: int,
|
|
|
339
415
|
if canceller.is_set():
|
|
340
416
|
return ItemResult(slot=slot, image_path=image_path, success=False,
|
|
341
417
|
error="cancelled before tally check")
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
418
|
+
not_ready = None
|
|
419
|
+
try:
|
|
420
|
+
safe = _wait_for_safe_upload_window(protocol, slot, canceller, log_append)
|
|
421
|
+
except _StateNotReady as e:
|
|
422
|
+
safe, not_ready = False, str(e)
|
|
423
|
+
if not safe:
|
|
424
|
+
if canceller.is_set():
|
|
425
|
+
err = "cancelled during tally wait"
|
|
426
|
+
elif not_ready:
|
|
427
|
+
err = not_ready
|
|
428
|
+
log_append(f"slot {slot_user}: FAIL — {err}")
|
|
429
|
+
else:
|
|
430
|
+
err = f"tally timeout: slot {slot_user} stayed live > {TALLY_TIMEOUT:.0f}s"
|
|
345
431
|
return ItemResult(slot=slot, image_path=image_path, success=False, error=err)
|
|
346
432
|
|
|
347
433
|
if canceller.is_set():
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "webatem"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.4"
|
|
8
8
|
description = "Browser-based control for Blackmagic ATEM switchers: run it, open the browser, your switchers are there"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/IBMPlexMono-400-latin-ext.woff2
RENAMED
|
File without changes
|
|
File without changes
|
{webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/IBMPlexMono-500-latin-ext.woff2
RENAMED
|
File without changes
|
|
File without changes
|
{webatem-2.0.3 → webatem-2.0.4}/atem_control/static/brand/fonts/IBMPlexMono-600-latin-ext.woff2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{webatem-2.0.3 → webatem-2.0.4}/atem_control/static/vendor/bootstrap-icons/bootstrap-icons.min.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|