second commit

This commit is contained in:
2026-04-13 23:14:05 +02:00
parent 1c031ebf63
commit e08597fc72
125 changed files with 26221 additions and 0 deletions
@@ -0,0 +1,128 @@
{% extends 'base.html' %}
{% load i18n home_tags %}
{% block header %}
<div class="w3-bar w3-dark-light">
<a href="#" class="w3-bar-item w3-mobile w3-btn w3-hover-opacity w3-xlarge w3-text-yellow" onclick="toggleSidebar()" title="{% trans 'Barre de côté' %}">
<i class="fa-solid fa-right-left"></i>
</a>
<div class="w3-bar-item w3-btn w3-hover-opacity w3-xlarge">
{{ choice_title }}
</div>
<a href="#" class="w3-bar-item w3-mobile w3-btn w3-hover-opacity w3-right w3-xlarge w3-text-green" onclick="goFullscreen()" title="{% trans 'Ecran plein' %}">
<i class="fa-solid fa-maximize"></i>
</a>
</div>
{% endblock %}
{% block sidebar %}
<div class="w3-dark-xlight w3-border-bottom">
<div class="w3-large w3-bold">
<a href="/" class="w3-btn w3-hover-opacity w100 w3-left-align">{{ app_title }}<br>
<span class="w3-tiny">{{ app_sub_title }}</span>
</a>
</div>
<form method="post" action="{% url 'logout' %}" class="w3-padding-small">
{% csrf_token %}
<button class="w3-bar-item w3-btn w3-hover-opacity" type="submit" title="{% trans 'Déconnexion' %}">
{{ request.user.username }}<i class="fa-solid fa-right-from-bracket w3-right"></i>
</button>
</form>
</div>
{% block system %}
<div class="w3-light-blue w3-padding-large">
<div id="shm-used" class="w3-green w3-round" style="height:0.5em; width: var(--shm-used, 0%);" title="{% trans 'Mémoire partagée' %}"></div>
<div id="ramdisk-used" class="w3-purple w3-round" style="height:0.5em;width: var(--ramdisk-used, 0%); margin: 0.35em 0" title="{% trans 'Disque RAM' %}"></div>
<div id="mem-used" class="w3-deep-orange w3-round" style="height:0.5em;width: var(--mem-used, 0%); margin: 0.35em 0" title="{% trans 'Mémoire RAM' %}"></div>
<div id="cpu-used" class="w3-indigo w3-round" style="height:0.5em;width: var(--cpu-used, 0%); margin: 0.35em 0" title="{% trans 'Charge CPU' %}"></div>
<div id="disk-used" class="w3-amber w3-round" style="height:0.5em;width: var(--disk-used, 0%); margin: 0.35em 0" title="{% trans 'Disque /' %}"></div>
</div>
{% endblock %}
{% block columns %}
<div class="w3-dark-light">
<div class=" w3-padding w3-border-bottom">
<div>{% trans "Grille" %}</div>
<div style="width:100%">
{% x_range 1 13 as cols %}
{% for c in cols %}
<button id="swap-{{ c }}" class="w3-btn w3-badge w3-padding-small w3-sand w3-tiny" onclick="setGridColumns({{ c }})">{{ c }}</button>
{% endfor %}
</div>
</div>
</div>
<script>
function updateActiveButton(n) {
document.querySelectorAll('[id^="swap-"]').forEach(btn => {
btn.classList.remove('w3-blue', 'w3-sand'); btn.classList.add('w3-sand');
});
const active = sId('swap-'+ n);
if (active) { active.classList.remove('w3-sand'); active.classList.add('w3-blue');
}
}
</script>
{% endblock %}
{% block sidebar_list %}
<div class="w3-dark-light w3-padding-small">
{% block sidebar_command %}{% endblock %}
{% if request.user.is_superuser %}
<div>
<div class="w3-dark-light w3-margin-top-6">
<a href="#" class="w3-btn w3-padding-small" onclick="toggleDisplay(sId('_admin'))"><span class="w3-text-orange w3-xlarge">&#x26F6;</span>
{% trans "Administration" %}
</a>
</div>
<div id="_admin" style="display:none">
<a href="{% url 'scanner:admin' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
<i class="fa-solid fa-gear w3-text-pink"></i> {% trans "Administration base de données" %}
</a>
<a href="{% url 'scanner:reductstore' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
<img class="w3-no-padding" src="/static/img/reductstore.png" style="width: 24px"> {% trans "Base de données Reductstore" %}
</a>
<!--a href="{% url 'scanner:adminer' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
<img class="w3-no-padding" src="/static/img/adminer.png" style="width: 28px"> {% trans "Base de données mariadb" %}
</a-->
<!--a href="{% url 'scanner:portainer' %}" class="w3-bar-item w3-btn w3-hover-opacity" w3-margin-left>
<img class="w3-no-padding" src="/static/img/portainer.png" style="width: 28px"> {% trans "Portainer" %}
</a-->
<a href="{% url 'scanner:supervisor' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
<i class="fa-solid fa-gears w3-text-purple"></i> {% trans "Supervisor" %}
</a>
<a href="{% url 'scanner:logs_scheduler' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
<i class="fa-regular fa-file-lines w3-text-orange"></i> {% trans "Logs des planifications" %}
</a>
<a href="{% url 'scanner:logs_worker' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
<i class="fa-regular fa-file-lines w3-text-amber"></i> {% trans "Logs des workers" %}
</a>
<a href="{% url 'scanner:calibration' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-left">
<i class="fa-solid fa-wrench w3-text-red"></i> {% trans "Calibration" %}
</a>
</div>
</div>
{% endif %}
{% block sidebar_smenu %}
<a href="{% url 'scanner:main' %}" class="w3-bar-item w3-btn w3-hover-opacity">
<i class="fa-solid fa-film w3-text-green"></i> {% trans "Balayage multi-puits" %}
</a>
<a href="{% url 'scanner:images' %}" class="w3-bar-item w3-btn w3-hover-opacity">
<i class="fa-regular fa-images w3-text-cyan"></i> {% trans "Gestionnaire d'images" %}
</a>
<a href="{% url 'scanner:replay' %}" class="w3-bar-item w3-btn w3-hover-opacity">
<i class="fa-solid fa-podcast w3-text-amber"></i> {% trans "Redifusion vidéos" %}
</a>
{% endblock %}
</div>
{% endblock %}
{% endblock %}
{% block content %}{% endblock %}
{% block js_footer %}
{{ block.super }}
<script>
const stats_endpoint = "{% url 'scanner:api_stats' %}";
</script>
<script src="/static/scanner/js/stats.js"></script>
{% endblock %}
@@ -0,0 +1,122 @@
{% extends 'scanner/base.html' %}
{% load i18n home_tags %}
{% block styles %}
{{ block.super }}
<link href="/static/scanner/css/calibration.css" rel="stylesheet">
{% endblock %}
{% block columns %}{% endblock %}
{% block content %}
<div class="container w3-black">
<div class="header">
<div class="w3-row w3-row-padding">
<div class="w3-col" style="width:30%">
{% trans 'Position multi-puit' %}<br>
<select id="_well" class="w3-select">
{% for w in wells %}
<option value="{{ w.position }}" {% if w.position == 'HG' %}selected{% endif %}>{{ w }}</option>
{% endfor %}
</select>
</div>
<div class="w3-col" style="width:20%">
<div>{% trans 'Vitesse' %}</div>
<select id="_feed" class="w3-select">
<option value="500">500 mm/mn</option>
<option value="750">750 mm/mn</option>
<option value="1000" selected>1000 mm/mn</option>
<option value="1200">1200 mm/mn</option>
<option value="1500">1500 mm/mn</option>
<option value="2000">2000 mm/mn</option>
<option value="3000">3000 mm/mn</option>
</select>
</div>
<div class="w3-col" style="width:20%">
<div>{% trans 'Pas' %}</div>
<select id="_step" class="w3-select">
<option value="0.1">0.1 mm</option>
<option value="0.25">0.25 mm</option>
<option value="0.5">0.5 mm</option>
<option value="1.0" selected>1.0 mm</option>
<option value="1.5">1.5 mm</option>
<option value="2.0">2.0 mm</option>
<option value="2.5">2.5 mm</option>
<option value="5.0">5.0 mm</option>
<option value="10.0">10.0 mm</option>
<option value="20.0">20.0 mm</option>
<option value="30.0">30.0 mm</option>
<option value="40.0">40.0 mm</option>
<option value="50.0">50.0 mm</option>
</select>
</div>
<div class="w3-col" style="width:30%">
<div class="w3-margin-top w3-padding w3-right">
<span id="_ts"></span><br>
</div>
</div>
</div>
</div>
<div class="move w3-padding-small w3-center">
<div class="w3-row">
<div class="w3-half">{% trans 'dx' %}<br><input id="_dx" type="number" min="15.0" max="25.0" step="0.01" value=""/></div>
<div class="w3-half">{% trans 'dy' %}<br><input id="_dy" type="number" min="15.0" max="25.0" step="0.01" value=""/></div>
</div>
<button id="_xy-step" class="w3-button w3-warning w3-round-large w3-block w3-large">
<i class="fa-solid fa-left-right"></i> {% trans 'Définir (dx, dy)' %}
</button>
<hr>
<div><button id="_up" class="w3-button w3-dark-xlight w3-round-large w3-margin-small w3-block">&#x2191; {% trans 'En haut' %}</button></div>
<div><button id="_left" class="w3-button w3-dark-xlight w3-round-large w3-margin-small w3-block">&#x2190; {% trans 'A gauches' %}</button></div>
<div><button id="_right" class="w3-button w3-dark-xlight w3-round-large w3-margin-small w3-block">&#x2192; {% trans 'A droite' %}</button></div>
<div><button id="_down" class="w3-button w3-dark-xlight w3-round-large w3-margin-small w3-block">&#x2193; {% trans 'En Bas' %}</button></div>
<hr>
<button id="_xy-base" class="w3-button w3-warning w3-round-large w3-margin-small w3-block">{% trans 'Définir base ' %}</button>
</div>
<div class="scan w3-center">
<div class="w3-row">
<div class="w3-half">X<br><span id="_x"></span></div>
<div class="w3-half">Y<br><span id="_y"></span></div>
</div>
<button id="_goto-0" class="w3-button w3-light-blue w3-round w3-round-large w3-margin-small w3-block">Origine (0, 0)</button>
<button id="_goto-xy" class="w3-button w3-light-blue w3-round-large w3-margin-small w3-block w3-margin-bottom">
{% trans 'Aller à la base' %}<br>(<span id="_xbase"></span>, <span id="_ybase"></span>)
</button>
<hr>
<button id="_median" class="w3-button w3-teal w3-round-large w3-margin-small w3-block"><i class="fa-solid fa-crosshairs"></i> {% trans 'Axes' %}</button>
<button id="_crop" class="w3-button w3-teal w3-round-large w3-margin-small w3-block w3-margin-bottom"><i class="fa-solid fa-crop"></i> {% trans 'Recadrer' %}</button>
<span>
{% trans 'Rayon' %}: <input id="_crop_radius" type="number" min="100" max="1200" step="1" value="{{ conf.calibration_crop_radius }}" title="{% trans 'Rayon de cadrage' %}"/>
</span>
<hr>
<button id="_test" class="w3-button w3-warning w3-round-large w3-margin-small w3-block">{% trans 'Tester le cirduit' %}</button>
<button id="_halt" class="w3-button w3-red w3-round-large w3-margin-small w3-block"><i class="fa-solid fa-hand"></i> {% trans 'ARRET' %}</button>
</div>
<div class="scanner"><img id="scan-img" class="w3-image"></div>
</div>
<ul id="_debug" class="w3-scroll-y" style="height: 30vh"></ul>
{% endblock %}
{% block js_footer %}
{{ block.super }}
<script src="/static/scanner/js/calibration.js"></script>
<script>
const container = sId("scan-img");
const ws_route = "{{ ws_route }}";
// ---- Point d'entrée ----
(async () => {
const manager = new ScannerManager(container);
const protocol = location.protocol === "https:" ? "wss" : "ws";
const wsUrl = `${protocol}://${location.host}/${ws_route}`;
const socket = new MetadataSocket(wsUrl);
socket.setManager(manager);
socket.connect();
manager.registerSocket(socket);
})();
</script>
{% endblock %}
@@ -0,0 +1,6 @@
{% extends 'scanner/base.html' %}
{% block columns %}{% endblock %}
{% block content %}
<iframe width="100%" src="{{ link }}" style="border:none; height:90vh;display:block;"></iframe>
{% endblock %}
@@ -0,0 +1,14 @@
<div class="w3-modal" id="imagemodal" style="z-index: 200;">
<div class="w3-modal-content w3-border w3-dark-medium" style="max-width: 640px">
<button onclick="sId('imagemodal').style.display='none'" class="w3-button w3-round w3-round-xxlarge w3-text-red w3-display-topright w3-xlarge">&#x2716;</button>
<div class="w3-card-4">
<div class="w3-bar w3-dark-xlight" style="padding-right: 4em">
<span class="w3-bar-item" id="imagepreview-uuid"></span>
<span class="w3-bar-item" id="imagepreview-ts"></span>
<span class="w3-bar-item w3-right" id="imagepreview-index"></span>
</div>
<img id="imagepreview" style="width: 100%">
</div>
</div>
</div>
@@ -0,0 +1,114 @@
{% extends 'scanner/base.html' %}
{% load i18n home_tags scanner_tags %}
{% block styles %}
{{ block.super }}
<link href="/static/scanner/css/images.css" rel="stylesheet">
{% endblock %}
{% block sidebar_list %}
<a href="/" class="w3-bar-item w3-btn w3-hover-opacity"><i class="fa-solid fa-house w3-text-orange"></i> {% trans "Retour accueil" %}</a>
<form method="post" class="w3-bar-item" action="">
{% csrf_token %}
<select id="_sid" name="_sid" class="w3-select w3-margin-bottom" onchange="this.form.submit()">
<option value="0">---- {% trans "Session d'observations" %}</option>
{% for s in sessions %}
<option value="{{ s.id }}" {% if s.id == cursid %}selected{% endif %}>{{ s.name }}</option>
{% endfor %}
</select>
{% if cursid %}
<div class="multiwell_cards">
{% multiwell_cards cursid observations %}
</div>
{% endif %}
</form>
{% if cursid %}
<a href="#" class="w3-bar-item w3-btn w3-hover-opacity" onclick="download_all_images()">
<i class="fa-solid fa-file-export w3-text-red"></i> {% trans "Exporter l'ensemble des images" %}
</a>
{% endif %}
{% endblock %}
{% block content %}
<div id="image-grid">
{% if images %}
{% for img in images %}
<div class="w3-card-4 w3-border">
<div class="w3-padding-small w3-dark-xlight w3-tiny">
<span>{{ img.uuid }}</span>
<span class="w3-right">{{ img.index }}</span>
</div>
<img class="w3-image" src="{{ img.content }}" onclick="image_preview(this, '{{ img.uuid }}', '{{ img.index }}', '{{ img.ts }}')">
<div class="w3-container w3-dark-xlight w3-tiny">
<button class="w3-button w3-round w3-warning w3-padding-1"
onclick="image_save('{{ img.uuid }}.jpg', '{{ img.content }}')" title="{% trans 'Télécharger' %}">&nbsp;&#x2B07&nbsp;
</button>
<span class="w3-right">{{ img.ts }}</span>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% endblock %}
{% block modal %}
{% include "scanner/image-preview.html" %}
{% endblock %}
{% block js_footer %}
{{ block.super }}
<script>
const container= sId("image-grid");
const columns = "{{ conf.default_grid_columns }}";
const duration = parseInt("{{ duration }}");
const uuid_btn = sId("btn-" + "{{ uuid }}");
const image_endpoint = "{% url 'scanner:export_api' %}";
const sid = parseInt("{{ cursid }}");
function setGridColumns(col) { container.style.setProperty("--grid-columns", col); updateActiveButton(col); }
function handleMultiwell(b) { b.classList.add('w3-green'); }
function image_preview(img, uuid, index, ts) {
imagemodal.style.display='block';
sId('imagepreview').src = img.src;
sId('imagepreview-uuid').textContent = uuid;
sId('imagepreview-index').textContent = index;
sId('imagepreview-ts').textContent = ts;
}
function image_save(name, img) {
const ok = confirm(`Télécharger le fichier ?\n\n${name}`);
if (!ok) return false;
fetch(img)
.then(res => res.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = name;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
});
}
function download_all_images() {
fetch(image_endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'export_images',
sid: sid,
})
}).then(res => {
console.log(res);
}).catch(error => {
console.error('Erreur:', error);
});
}
setGridColumns(columns);
if (uuid_btn)
handleMultiwell(uuid_btn);
</script>
{% endblock %}
@@ -0,0 +1,63 @@
{% extends 'scanner/base.html' %}
{% load i18n home_tags %}
{% block styles %}
{{ block.super }}
<link href="/static/scanner/css/main.css" rel="stylesheet">
{% endblock %}
{% block columns %}{% endblock %}
{% block content %}
<div class="container w3-black">
<div class="header">
<div class="w3-row w3-row-padding">
<div class="w3-half">
<div>{% trans "Choix de la session" %}</div>
<select id="_session" class="w3-select">
{% for s in sessions %}
<option value="{{ s.id }}">{{ s.name }}</option>
{% endfor %}
</select>
</div>
<div class="w3-half">
<div class="w3-margin-top w3-padding w3-right">
<span id="_ts"></span><br>
(<span id="_x"></span>, <span id="_y"></span>)
</div>
</div>
</div>
</div>
<div class="scan">
<button id="_median" class="w3-button w3-teal w3-round-large w3-margin-small w3-block"><i class="fa-solid fa-crosshairs"></i> {% trans 'Axes' %}</button>
<button id="_crop" class="w3-button w3-teal w3-round-large w3-margin-small w3-block w3-margin-bottom"><i class="fa-solid fa-crop"></i> {% trans 'Recadrer' %}</button>
<hr>
<button id="_scan" class="w3-button w3-warning w3-round-large w3-large w3-block">
<i class="fa-solid fa-camera"></i><br>{% trans 'Lancer le balayage' %}
</button>
<button id="_halt" class="w3-button w3-red w3-round-large w3-padding-16 w3-block w3-margin-top"><i class="fa-solid fa-hand"></i><br>{% trans 'ARRET' %}</button>
</div>
<div class="scanner"><img id="scan-img" class="w3-image"></div>
</div>
<ul id="_debug" class="w3-scroll-y" style="height: 50vh"></ul>
{% endblock %}
{% block js_footer %}
{{ block.super }}
<script src="/static/scanner/js/main.js"></script>
<script>
const container = sId("scan-img");
const ws_route = "{{ ws_route }}";
// ---- Point d'entrée ----
(async () => {
const manager = new ScannerManager(container);
const protocol = location.protocol === "https:" ? "wss" : "ws";
const wsUrl = `${protocol}://${location.host}/${ws_route}`;
const socket = new MetadataSocket(wsUrl);
socket.setManager(manager);
socket.connect();
manager.registerSocket(socket);
})();
</script>
{% endblock %}
@@ -0,0 +1,22 @@
<div class="slider-container" id="scannerSlider">
<div class="display-range w3-small w3-margin-bottom"></div>
<div class="range-wrap slider" data-min="1680307200" data-max="1680998400">
<div class="track"></div>
<div class="range-highlight"></div>
<input class="min-range" type="range" min="1680307200" max="1680998400" value="1680307200" step="100" aria-label="valeur minimale">
<input class="max-range" type="range" min="1680307200" max="1680998400" value="1680998400" step="100" aria-label="valeur maximale">
</div>
<div class="w3-row w3-margin-top">
<div class="w3-half">
<span>Min (ms)</span>
<input class="min-number" type="number" min="1680307200" max="1680998400" value="1680307200" step="100">
</div>
<div class="w3-half w3-right-align">
<span>Max (ms)</span>
<input class="max-number" type="number" min="1680307200" max="1680998400" value="1680998400" step="100">
</div>
</div>
</div>
@@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="refresh" content="0; url={{ link }}" />
</head>
<body></body>
</html>
@@ -0,0 +1,134 @@
{% extends 'scanner/base.html' %}
{% load i18n home_tags scanner_tags %}
{% block styles %}
{{ block.super }}
<link href="/static/scanner/css/replay.css" rel="stylesheet">
{% endblock %}
{% block columns %}{% endblock %}
{% block sidebar_list %}
<a href="/" class="w3-bar-item w3-btn w3-hover-opacity"><i class="fa-solid fa-house w3-text-orange"></i> {% trans "Retour accueil" %}</a>
<form method="post" class="w3-bar-item" action="">
{% csrf_token %}
<select id="_sid" name="_sid" class="w3-select w3-margin-bottom" onchange="this.form.submit()">
<option value="0">---- {% trans "Session d'observations" %}</option>
{% for s in sessions %}
<option value="{{ s.id }}" {% if s.id == cursid %}selected{% endif %}>{{ s.name }}</option>
{% endfor %}
</select>
{% if cursid %}
<div class="multiwell_cards">
{% multiwell_cards cursid observations %}
</div>
{% endif %}
</form>
{% if cursid %}
<a href="#" class="w3-bar-item w3-btn w3-hover-opacity" onclick="download_all_videos()">
<i class="fa-solid fa-file-export w3-text-red"></i> {% trans "Exporter l'ensemble des vidéos" %}
</a>
{% endif %}
{% endblock %}
{% block content %}
<div id="replay-grid" class="w3-black">
{% if image %}
<div class="w3-card-4 w3-border" style="min-width: 640px">
<img id="_replay_img" src="{{ image }}" style="width: 100%">
<div class="w3-bar w3-padding-small w3-light-grey">
<span class="w3-bar-item w3-marging-right w3-dark-xlight" >{{ uuid }}</span>
<button id="_replay_play" class="w3-bar-item w3-btn"><i class="fa-solid fa-play"></i></button>
<button id="_replay_pause" class="w3-bar-item w3-btn"><i class="fa-solid fa-pause"></i></button>
<button id="_replay_stop" class="w3-bar-item w3-btn"><i class="fa-solid fa-stop"></i></button>
<button id="_replay_snapshot" class="w3-bar-item w3-btn"><i class="fa-solid fa-image"></i></button>
<button id="_replay_videosnap" class="w3-bar-item w3-btn"><i class="fa-solid fa-video"></i></button>
<div class="replay-speed-control w3-bar-item w3-right w3-padding">
<span>x <span id="_speed_label">1</span></span>
<input id="_speed_control" type="range" min="0" max="8" step="1" class="w3-range">
</div>
</div>
<div class="w3-dark-light w3-nbsp w3-small w3-padding-small w3-margint-top w3-margin-bottom">
<div class="replay-ts-cursor ">
<span id="_replay_ts_iso" class="w3-left">2026-04-05T08:13:18.067</span>
<span id="_replay_percent" class="w3-right"></span>
</div>
<div class="replay-slider">
<input id="_replay_timeline" type="range" min="0" max="1000" step="0.1" class="replay-timeline" disabled="">
</div>
<div class="replay-sub-slider">
<span id="_replay_dt_left" class="w3-left">2026-04-05T08:13:18.067</span>
<span id="_replay_dt_right" class="w3-right">2026-02-20T17:18:44.331</span>
</div>
</div>
</div>
{% endif %}
</div>
{% endblock %}
{% block js_footer %}
{{ block.super }}
<script src="/static/scanner/js/replay.js"></script>
<script>
const ws_route = "{{ ws_route }}";
const uuid_btn = sId("btn-" + "{{ uuid }}");
const image_endpoint = "{% url 'scanner:export_api' %}";
const sid = parseInt("{{ cursid }}");
function download_all_videos() {
fetch(image_endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'export_videos',
sid: sid,
})
}).then(res => {
console.log(res);
}).catch(error => {
console.error('Erreur:', error);
});
}
function handleMultiwell(b) { b.classList.add('w3-green'); }
// ---- Point d'entrée ----
(async () => {
if (!uuid_btn) return;
const manager = new ReplayManager({
uuid: "{{ uuid }}",
dt_start: parseInt("{{ oldest }}"),
dt_stop: parseInt("{{ latest }}"),
fps: parseFloat("{{ conf.video_frame_rate }}"),
video_type: "{{ conf.opencv_video_type }}",
video_endpoint: "{% url 'scanner:download_api' %}",
img: sId("_replay_img"),
play: sId("_replay_play"),
pause: sId("_replay_pause"),
stop: sId("_replay_stop"),
ts: sId("_replay_ts"),
snapshot: sId("_replay_snapshot"),
videosnap: sId("_replay_videosnap"),
speed_control: sId("_speed_control"),
speed_label: sId("_speed_label"),
timeline: sId("_replay_timeline"),
ts_iso: sId("_replay_ts_iso"),
percent: sId("_replay_percent"),
dt_left: sId("_replay_dt_left"),
dt_right: sId("_replay_dt_right")
});
await manager.start();
const protocol = location.protocol === "https:" ? "wss" : "ws";
const wsUrl = `${protocol}://${location.host}/${ws_route}`;
const socket = new MetadataSocket(wsUrl);
socket.setManager(manager);
socket.connect();
manager.registerSocket(socket);
if (uuid_btn)
handleMultiwell(uuid_btn);
})();
</script>
{% endblock %}