diff --git a/src/main/webapp/package-lock.json b/src/main/webapp/package-lock.json
index 67a1ffd..c8d23ff 100644
--- a/src/main/webapp/package-lock.json
+++ b/src/main/webapp/package-lock.json
@@ -18,7 +18,9 @@
"@fortawesome/react-fontawesome": "^0.2.0",
"axios": "^1.6.5",
"browser-image-compression": "^2.0.2",
+ "jszip": "^3.10.1",
"leaflet": "^1.9.4",
+ "obs-websocket-js": "^5.0.7",
"proj4": "^2.11.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -1058,6 +1060,14 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@msgpack/msgpack": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.8.0.tgz",
+ "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1845,6 +1855,11 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true
},
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+ },
"node_modules/crc-32": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
@@ -1870,6 +1885,11 @@
"node": ">= 8"
}
},
+ "node_modules/crypto-js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
+ },
"node_modules/css-color-keywords": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
@@ -2007,7 +2027,6 @@
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
"dependencies": {
"ms": "2.1.2"
},
@@ -2980,6 +2999,11 @@
"node": ">= 4"
}
},
+ "node_modules/immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
+ },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -3018,8 +3042,7 @@
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/internal-slot": {
"version": "1.0.6",
@@ -3360,6 +3383,14 @@
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true
},
+ "node_modules/isomorphic-ws": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
+ "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
+ "peerDependencies": {
+ "ws": "*"
+ }
+ },
"node_modules/iterator.prototype": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz",
@@ -3447,6 +3478,17 @@
"node": ">=4.0"
}
},
+ "node_modules/jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "dependencies": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
+ }
+ },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -3474,6 +3516,14 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "dependencies": {
+ "immediate": "~3.0.5"
+ }
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -3559,8 +3609,7 @@
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/nanoid": {
"version": "3.3.7",
@@ -3696,6 +3745,39 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/obs-websocket-js": {
+ "version": "5.0.7",
+ "resolved": "https://registry.npmjs.org/obs-websocket-js/-/obs-websocket-js-5.0.7.tgz",
+ "integrity": "sha512-SdSNSyrLVR6F0ogInKr7qcadV1tYaTUse/vbabxjkUL8hU3P3dyifxkZ7pEkDDrtCp3TkQ53Enx23kgZO0Cjcw==",
+ "dependencies": {
+ "@msgpack/msgpack": "^2.7.1",
+ "crypto-js": "^4.1.1",
+ "debug": "^4.3.2",
+ "eventemitter3": "^5.0.1",
+ "isomorphic-ws": "^5.0.0",
+ "type-fest": "^3.11.0",
+ "ws": "^8.13.0"
+ },
+ "engines": {
+ "node": ">16.0"
+ }
+ },
+ "node_modules/obs-websocket-js/node_modules/eventemitter3": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
+ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
+ },
+ "node_modules/obs-websocket-js/node_modules/type-fest": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz",
+ "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==",
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -3752,6 +3834,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -3855,6 +3942,11 @@
"node": ">=0.8"
}
},
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ },
"node_modules/proj4": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/proj4/-/proj4-2.11.0.tgz",
@@ -4055,6 +4147,25 @@
"react-dom": ">=16.6.0"
}
},
+ "node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/readable-stream/node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
+ },
"node_modules/recharts": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.1.tgz",
@@ -4256,6 +4367,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
"node_modules/safe-regex-test": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz",
@@ -4319,6 +4435,11 @@
"node": ">= 0.4"
}
},
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
+ },
"node_modules/shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
@@ -4378,6 +4499,14 @@
"node": ">=0.8"
}
},
+ "node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
"node_modules/string.prototype.matchall": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz",
@@ -4723,6 +4852,11 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ },
"node_modules/uzip": {
"version": "0.20201231.0",
"resolved": "https://registry.npmjs.org/uzip/-/uzip-0.20201231.0.tgz",
@@ -4922,6 +5056,26 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
+ "node_modules/ws": {
+ "version": "8.18.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
+ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
"node_modules/xlsx": {
"version": "0.18.5",
"resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
diff --git a/src/main/webapp/package.json b/src/main/webapp/package.json
index 0e57209..418755f 100644
--- a/src/main/webapp/package.json
+++ b/src/main/webapp/package.json
@@ -20,7 +20,9 @@
"@fortawesome/react-fontawesome": "^0.2.0",
"axios": "^1.6.5",
"browser-image-compression": "^2.0.2",
+ "jszip": "^3.10.1",
"leaflet": "^1.9.4",
+ "obs-websocket-js": "^5.0.7",
"proj4": "^2.11.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/src/main/webapp/public/obs_template.json b/src/main/webapp/public/obs_template.json
new file mode 100644
index 0000000..da724c5
--- /dev/null
+++ b/src/main/webapp/public/obs_template.json
@@ -0,0 +1,828 @@
+{
+ "current_scene": "Ovarlay",
+ "current_program_scene": "Ovarlay",
+ "scene_order": [
+ {
+ "name": "Ovarlay"
+ },
+ {
+ "name": "Scène 2"
+ }
+ ],
+ "name": "saf",
+ "groups": [],
+ "quick_transitions": [
+ {
+ "name": "Coupure",
+ "duration": 300,
+ "hotkeys": [],
+ "id": 5,
+ "fade_to_black": false
+ },
+ {
+ "name": "Fondu",
+ "duration": 300,
+ "hotkeys": [],
+ "id": 6,
+ "fade_to_black": false
+ }
+ ],
+ "transitions": [],
+ "saved_projectors": [],
+ "canvases": [],
+ "current_transition": "Fondu",
+ "transition_duration": 300,
+ "preview_locked": false,
+ "scaling_enabled": false,
+ "scaling_level": -9,
+ "scaling_off_x": 0.0,
+ "scaling_off_y": 0.0,
+ "virtual-camera": {
+ "type2": 3
+ },
+ "modules": {
+ "auto-scene-switcher": {
+ "interval": 300,
+ "non_matching_scene": "",
+ "switch_if_not_matching": false,
+ "active": false,
+ "switches": []
+ },
+ "captions": {
+ "source": "",
+ "enabled": false,
+ "lang_id": 1036,
+ "provider": "mssapi"
+ },
+ "output-timer": {
+ "streamTimerHours": 0,
+ "streamTimerMinutes": 0,
+ "streamTimerSeconds": 30,
+ "recordTimerHours": 0,
+ "recordTimerMinutes": 0,
+ "recordTimerSeconds": 30,
+ "autoStartStreamTimer": false,
+ "autoStartRecordTimer": false,
+ "pauseRecordTimer": false
+ },
+ "scripts-tool": []
+ },
+ "version": 1,
+ "sources": [
+ {
+ "prev_ver": 536870916,
+ "name": "Capture d'écran",
+ "uuid": "62b56523-7c2e-4ae2-b4e6-9ca3a36e904b",
+ "id": "monitor_capture",
+ "versioned_id": "monitor_capture",
+ "settings": {
+ "monitor_id": "\\\\?\\DISPLAY#HWP3320#5&3974db33&0&UID143619#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536870916,
+ "name": "Ovarlay",
+ "uuid": "670a1c48-dac6-405a-959a-d40662bab4d8",
+ "id": "scene",
+ "versioned_id": "scene",
+ "settings": {
+ "custom_size": false,
+ "id_counter": 21,
+ "items": [
+ {
+ "name": "sub1.img.blue",
+ "source_uuid": "0a37157d-f356-4657-a2ad-fa4193a298f8",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 19,
+ "group_item_backup": false,
+ "pos": {
+ "x": 1789.0,
+ "y": 950.0
+ },
+ "scale": {
+ "x": 0.11296296119689941,
+ "y": 0.11296296119689941
+ },
+ "bounds": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "sub1.img.rouge",
+ "source_uuid": "2dfe69bc-9b10-419d-8ee1-6cd9cc53a502",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 14,
+ "group_item_backup": false,
+ "pos": {
+ "x": 9.0,
+ "y": 950.0
+ },
+ "scale": {
+ "x": 0.11296296119689941,
+ "y": 0.11296296119689941
+ },
+ "bounds": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "sub1.comb.blue",
+ "source_uuid": "4e75e437-20ed-4834-bfac-b668f5cac960",
+ "visible": true,
+ "locked": true,
+ "rot": 0.0,
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 17,
+ "group_item_backup": false,
+ "pos": {
+ "x": 960.0,
+ "y": 945.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "sub1.comb.rouge",
+ "source_uuid": "69594be1-dfdc-4eee-893c-fb546e830a6f",
+ "visible": true,
+ "locked": true,
+ "rot": 0.0,
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 8,
+ "group_item_backup": false,
+ "pos": {
+ "x": 140.0,
+ "y": 945.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "sub1.score.blue",
+ "source_uuid": "264866ab-58e1-45ec-a32f-c440c32057cd",
+ "visible": true,
+ "locked": true,
+ "rot": 0.0,
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 20,
+ "group_item_backup": false,
+ "pos": {
+ "x": 1108.0,
+ "y": 10.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "sub1.score.rouge",
+ "source_uuid": "8a532b22-7bcd-4742-aa0e-8ea556f39a12",
+ "visible": true,
+ "locked": true,
+ "rot": 0.0,
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 16,
+ "group_item_backup": false,
+ "pos": {
+ "x": 686.0,
+ "y": 10.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "sub1.temps",
+ "source_uuid": "a961104f-2cad-4f65-9ff8-d50ff36f8418",
+ "visible": true,
+ "locked": true,
+ "rot": 0.0,
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 21,
+ "group_item_backup": false,
+ "pos": {
+ "x": 584.0,
+ "y": 0.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ }
+ ]
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "OBSBasic.SelectScene": [],
+ "libobs.show_scene_item.19": [],
+ "libobs.hide_scene_item.19": [],
+ "libobs.show_scene_item.14": [],
+ "libobs.hide_scene_item.14": [],
+ "libobs.show_scene_item.17": [],
+ "libobs.hide_scene_item.17": [],
+ "libobs.show_scene_item.8": [],
+ "libobs.hide_scene_item.8": [],
+ "libobs.show_scene_item.20": [],
+ "libobs.hide_scene_item.20": [],
+ "libobs.show_scene_item.16": [],
+ "libobs.hide_scene_item.16": [],
+ "libobs.show_scene_item.21": [],
+ "libobs.hide_scene_item.21": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e",
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536870916,
+ "name": "Scène 2",
+ "uuid": "d430fe13-0e4a-4d4b-a28e-7c833eb27bf6",
+ "id": "scene",
+ "versioned_id": "scene",
+ "settings": {
+ "custom_size": false,
+ "id_counter": 2,
+ "items": [
+ {
+ "name": "Capture d'écran",
+ "source_uuid": "62b56523-7c2e-4ae2-b4e6-9ca3a36e904b",
+ "visible": false,
+ "locked": false,
+ "rot": 0.0,
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 2,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Ovarlay",
+ "source_uuid": "670a1c48-dac6-405a-959a-d40662bab4d8",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 1,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ }
+ ]
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "OBSBasic.SelectScene": [],
+ "libobs.show_scene_item.2": [],
+ "libobs.hide_scene_item.2": [],
+ "libobs.show_scene_item.1": [],
+ "libobs.hide_scene_item.1": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e",
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536870916,
+ "name": "sub1.comb.blue",
+ "uuid": "4e75e437-20ed-4834-bfac-b668f5cac960",
+ "id": "text_gdiplus",
+ "versioned_id": "text_gdiplus_v2",
+ "settings": {
+ "chatlog": false,
+ "extents": true,
+ "gradient": false,
+ "outline": false,
+ "undo_sname": "sub1.comb_rouge",
+ "vertical": false,
+ "font": {
+ "face": "Arial",
+ "flags": 0,
+ "size": 65,
+ "style": "Normal"
+ },
+ "align": "right",
+ "valign": "bottom",
+ "color": 4294917120,
+ "extents_cx": 835,
+ "extents_cy": 120,
+ "antialiasing": true,
+ "overlay": true,
+ "text": "Xavier Login"
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536870916,
+ "name": "sub1.comb.rouge",
+ "uuid": "69594be1-dfdc-4eee-893c-fb546e830a6f",
+ "id": "text_gdiplus",
+ "versioned_id": "text_gdiplus_v2",
+ "settings": {
+ "chatlog": false,
+ "extents": true,
+ "gradient": false,
+ "outline": false,
+ "undo_sname": "sub1.comb_rouge",
+ "vertical": false,
+ "font": {
+ "face": "Arial",
+ "flags": 0,
+ "size": 65,
+ "style": "Normal"
+ },
+ "align": "left",
+ "valign": "bottom",
+ "color": 4278190335,
+ "extents_cx": 820,
+ "extents_cy": 120,
+ "antialiasing": true,
+ "overlay": true,
+ "text": "Xavier Login"
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536870916,
+ "name": "sub1.img.blue",
+ "uuid": "0a37157d-f356-4657-a2ad-fa4193a298f8",
+ "id": "slideshow",
+ "versioned_id": "slideshow",
+ "settings": {
+ "files": [],
+ "transition": "slide",
+ "slide_time": 9000,
+ "transition_speed": 1300,
+ "use_custom_size": "1:1",
+ "playback_behavior": "stop_restart",
+ "slide_mode": "mode_auto",
+ "overlay": true
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "SlideShow.PlayPause": [],
+ "SlideShow.Restart": [],
+ "SlideShow.Stop": [],
+ "SlideShow.NextSlide": [],
+ "SlideShow.PreviousSlide": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536870916,
+ "name": "sub1.img.rouge",
+ "uuid": "2dfe69bc-9b10-419d-8ee1-6cd9cc53a502",
+ "id": "slideshow",
+ "versioned_id": "slideshow",
+ "settings": {
+ "files": [],
+ "transition": "slide",
+ "slide_time": 9000,
+ "transition_speed": 1300,
+ "use_custom_size": "1:1",
+ "playback_behavior": "stop_restart",
+ "slide_mode": "mode_auto",
+ "overlay": true
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "SlideShow.PlayPause": [],
+ "SlideShow.Restart": [],
+ "SlideShow.Stop": [],
+ "SlideShow.NextSlide": [],
+ "SlideShow.PreviousSlide": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536870916,
+ "name": "sub1.score.blue",
+ "uuid": "264866ab-58e1-45ec-a32f-c440c32057cd",
+ "id": "text_gdiplus",
+ "versioned_id": "text_gdiplus_v2",
+ "settings": {
+ "chatlog": false,
+ "extents": true,
+ "gradient": false,
+ "outline": false,
+ "text": "0",
+ "undo_sname": "sub1.comb_rouge",
+ "vertical": false,
+ "font": {
+ "face": "Arial",
+ "flags": 0,
+ "size": 80,
+ "style": "Normal"
+ },
+ "align": "center",
+ "valign": "bottom",
+ "color": 4294917120,
+ "extents_wrap": true,
+ "extents_cx": 163,
+ "extents_cy": 80,
+ "antialiasing": true
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536870916,
+ "name": "sub1.score.rouge",
+ "uuid": "8a532b22-7bcd-4742-aa0e-8ea556f39a12",
+ "id": "text_gdiplus",
+ "versioned_id": "text_gdiplus_v2",
+ "settings": {
+ "chatlog": false,
+ "extents": true,
+ "gradient": false,
+ "outline": false,
+ "text": "0",
+ "undo_sname": "sub1.comb_rouge",
+ "vertical": false,
+ "font": {
+ "face": "Arial",
+ "flags": 0,
+ "size": 80,
+ "style": "Normal"
+ },
+ "align": "center",
+ "valign": "bottom",
+ "color": 4278190335,
+ "extents_wrap": true,
+ "extents_cx": 163,
+ "extents_cy": 80,
+ "antialiasing": true
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536870916,
+ "name": "sub1.temps",
+ "uuid": "a961104f-2cad-4f65-9ff8-d50ff36f8418",
+ "id": "text_gdiplus",
+ "versioned_id": "text_gdiplus_v2",
+ "settings": {
+ "extents": true,
+ "text": "00:10",
+ "font": {
+ "face": "Arial",
+ "flags": 0,
+ "size": 110,
+ "style": "Normal"
+ },
+ "align": "center",
+ "color": -16711936,
+ "extents_wrap": true,
+ "extents_cx": 800,
+ "extents_cy": 110
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/main/webapp/src/assets/SimpleIconsOBS.ts b/src/main/webapp/src/assets/SimpleIconsOBS.ts
new file mode 100644
index 0000000..2135033
--- /dev/null
+++ b/src/main/webapp/src/assets/SimpleIconsOBS.ts
@@ -0,0 +1,26 @@
+import {
+ IconDefinition,
+ IconName,
+ IconPrefix
+} from "@fortawesome/fontawesome-svg-core";
+
+export const SimpleIconsOBS: IconDefinition = {
+ icon: [
+ // SVG viewbox width (in pixels)
+ 20,
+
+ // SVG viewbox height (in pixels)
+ 20,
+
+ // Aliases (not needed)
+ [],
+
+ // Unicode as hex value (not needed)
+ "",
+
+ // SVG path data
+ "M10 0C4.486 0 0 4.486 0 10s4.486 10 10 10 10-4.485 10-10S15.515 0 10 0m8.159 14.075c.55-1.617-.057-3.491-1.551-4.448-1.75-1.12-5.196 1.14-5.196 1.14s-.763 2.815-.026 4.007a5.4 5.4 0 0 1-1.77 1.709c-2.348 1.4-5.372.848-7.054-1.209a9 9 0 0 1-.235-.346c1.139 1.423 3.219 1.831 4.855.908 1.809-1.02 1.427-5.124 1.427-5.124S6.598 8.774 5.26 8.799a5.424 5.424 0 0 1 2.993-7.76c.157-.03.317-.05.476-.072a3.76 3.76 0 1 0 4.525 5.435 5.4 5.4 0 0 1 2.794.793c2.199 1.345 3.119 4.041 2.344 6.397-.072.166-.154.324-.234.483"
+ ],
+ iconName: "simple-icons-obs" as IconName,
+ prefix: "simple-icons" as IconPrefix
+};
diff --git a/src/main/webapp/src/components/SmartLogoBackground.jsx b/src/main/webapp/src/components/SmartLogoBackground.jsx
index ca5a42a..270a532 100644
--- a/src/main/webapp/src/components/SmartLogoBackground.jsx
+++ b/src/main/webapp/src/components/SmartLogoBackground.jsx
@@ -2,44 +2,21 @@ import {useEffect, useRef, useState, memo} from 'react';
const cache = {};
-export function SmartLogoBackground({
- src,
+export function detectOptimalBackground(blob,
darkBackground = '#333333',
lightBackground = '#f0f0f0',
defaultBackground = 'transparent',
tolerance = 55,
- minPixels = 10, // Seuil minimal de pixels détectés pour appliquer un fond
- alt = 'Logo',
- style = {},
- imgClassName = '',
- }) {
- const canvasRef = useRef(null);
- const [background, setBackground] = useState(defaultBackground);
- const [load, setLoad] = useState(false)
-
- useEffect(() => {
- if (cache[src]) {
- setBackground(cache[src]);
- return;
- }
- if (!load)
- return;
-
- const canvas = canvasRef.current;
- const ctx = canvas.getContext('2d');
+ minPixels = 10) {
+ return new Promise((resolve) => {
+ const imgUrl = URL.createObjectURL(blob);
const img = new Image();
-
- img.crossOrigin = 'Anonymous';
- img.src = src;
-
- // Prevent error logging
- img.onerror = function () {
- return true;
- }
-
+ img.crossOrigin = "anonymous";
img.onload = () => {
+ const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
+ const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
@@ -69,12 +46,9 @@ export function SmartLogoBackground({
const i = Math.round(y * canvas.width + x) * 4;
if (isTransparent(i)) {
const neighbors = [
- i - 4, // Haut
- i + 4, // Bas
- i - 4 * canvas.width, // Gauche
- i + 4 * canvas.width, // Droite
+ i - 4, i + 4, // Haut/Bas
+ i - 4 * canvas.width, i + 4 * canvas.width, // Gauche/Droite
];
-
for (const neighbor of neighbors) {
if (neighbor >= 0 && neighbor < pixels.length) {
if (isLightColor(neighbor)) lightBorderCount++;
@@ -82,24 +56,64 @@ export function SmartLogoBackground({
}
}
}
-
-
- if (lightBorderCount >= 25 || darkBorderCount >= 25)
- break
- }
-
- if (lightBorderCount > darkBorderCount && lightBorderCount >= minPixels) {
- cache[src] = darkBackground;
- setBackground(darkBackground)
- } else if (darkBorderCount > lightBorderCount && darkBorderCount >= minPixels) {
- cache[src] = lightBackground;
- setBackground(lightBackground)
- } else {
- cache[src] = defaultBackground;
- setBackground(defaultBackground)
}
}
- }
+
+ URL.revokeObjectURL(imgUrl);
+ if (lightBorderCount > darkBorderCount && lightBorderCount >= minPixels) {
+ resolve(darkBackground); // Fond sombre
+ } else if (darkBorderCount > lightBorderCount && darkBorderCount >= minPixels) {
+ resolve(lightBackground); // Fond clair
+ } else {
+ resolve(defaultBackground); // Fond transparent
+ }
+ };
+ img.onerror = () => {
+ URL.revokeObjectURL(imgUrl);
+ resolve(defaultBackground); // En cas d'erreur
+ };
+ img.src = imgUrl;
+ });
+}
+
+export function SmartLogoBackground({
+ src,
+ darkBackground = '#333333',
+ lightBackground = '#f0f0f0',
+ defaultBackground = 'transparent',
+ tolerance = 55,
+ minPixels = 10, // Seuil minimal de pixels détectés pour appliquer un fond
+ alt = 'Logo',
+ style = {},
+ imgClassName = '',
+ }) {
+ const canvasRef = useRef(null);
+ const [background, setBackground] = useState(defaultBackground);
+ const [load, setLoad] = useState(false)
+
+ useEffect(() => {
+ if (!load) return;
+
+ const fetchAndDetect = async () => {
+ if (cache[src]) {
+ setBackground(cache[src]);
+ return;
+ }
+
+ try {
+ const response = await fetch(src);
+ const blob = await response.blob();
+ const detectedBackground = await detectOptimalBackground(blob, darkBackground, lightBackground, defaultBackground, tolerance, minPixels);
+ cache[src] = detectedBackground;
+ setBackground(detectedBackground);
+ } catch (error) {
+ console.error("Erreur de détection du fond:", error);
+ cache[src] = defaultBackground;
+ setBackground(defaultBackground);
+ }
+ };
+
+ fetchAndDetect();
}, [src, darkBackground, lightBackground, defaultBackground, tolerance, minPixels, load]);
return <>
diff --git a/src/main/webapp/src/hooks/useExternalWindow.jsx b/src/main/webapp/src/hooks/useExternalWindow.jsx
index 233b052..db7f53d 100644
--- a/src/main/webapp/src/hooks/useExternalWindow.jsx
+++ b/src/main/webapp/src/hooks/useExternalWindow.jsx
@@ -1,6 +1,15 @@
import {createContext, useContext, useReducer} from "react";
-const PubAffContext = createContext({next: [], c1: undefined, c2: undefined, showScore: true, timeCb: undefined, scoreRouge: 0, scoreBleu: 0});
+const PubAffContext = createContext({
+ next: [],
+ c1: undefined,
+ c2: undefined,
+ showScore: true,
+ timeCb: undefined,
+ timeCb2: undefined,
+ scoreRouge: 0,
+ scoreBleu: 0
+});
const PubAffDispatchContext = createContext(() => {
});
@@ -11,6 +20,8 @@ function reducer(state, action) {
case 'CALL_TIME':
if (state.timeCb)
state.timeCb(action.payload)
+ if (state.timeCb2)
+ state.timeCb2(action.payload)
return state
case 'CLEAR_CB_TIME':
return {...state, timeCb: undefined}
diff --git a/src/main/webapp/src/hooks/useOBS.jsx b/src/main/webapp/src/hooks/useOBS.jsx
new file mode 100644
index 0000000..6f74831
--- /dev/null
+++ b/src/main/webapp/src/hooks/useOBS.jsx
@@ -0,0 +1,183 @@
+import {createContext, useContext, useEffect, useRef, useState} from "react";
+import OBSWebSocket from "obs-websocket-js";
+import {hex2rgb} from "../utils/Tools.js";
+
+const OBSContext = createContext({connected: false, obs: null})
+
+export function OBSProvider({children}) {
+ const obs = useRef(null)
+ const obsParm = useRef(null)
+ const assets = useRef(null)
+ const [connected, setConnected] = useState(false)
+ const [doReconnect, setDoReconnect] = useState(false)
+
+ useEffect(() => {
+ if (!doReconnect)
+ return;
+
+ const timer = setInterval(() => {
+ if (obs.current && !connected && doReconnect) {
+ console.log("Reconnecting to OBS WebSocket...")
+ obs.current.connect(obsParm.current.adresse, obsParm.current.password)
+ .then(data => {
+ console.log("Reconnected to OBS WebSocket", data)
+ setDoReconnect(false)
+ })
+ }
+ }, 5000);
+ return () => clearInterval(timer);
+ }, [connected, doReconnect]);
+
+ const connect = (adresse, password = undefined, assets_dir = undefined) => {
+ if (connected && obs.current)
+ return;
+ assets.current = assets_dir;
+
+ const obs_ = new OBSWebSocket();
+ obs_.connect(adresse, password)
+ .then(data => {
+ console.log("Connected to OBS WebSocket", data)
+ })
+ .catch(err => {
+ console.error("Failed to connect to OBS WebSocket", err)
+ });
+ obs_.on('ConnectionOpened', () => {
+ setConnected(true)
+ console.log("OBS WebSocket connection opened")
+ });
+ obs_.on('ConnectionClosed', err => {
+ setConnected(false)
+ console.log("OBS WebSocket connection closed", err.code, err.message)
+ if (err.code === 1000 || err.code === 4009) // 1000 = Normal Closure, 4009 = Authentication Failure
+ return;
+ obsParm.current = {adresse, password}
+ setDoReconnect(true)
+ });
+ obs_.on('error', err => {
+ console.error("OBS WebSocket error", err)
+ });
+
+ obs.current = obs_;
+ }
+
+ const disconnect = () => {
+ if (obs.current && connected) {
+ obs.current.disconnect();
+ obs.current = null;
+ }
+ }
+
+ const ret = {connected, obs: obs.current, connect, disconnect, assets: assets.current}
+ return