@velor/remote-mouse 6.4.8

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.
Files changed (316) hide show
  1. package/.artifacts/screenshots/remote-mobile-config.png +0 -0
  2. package/.artifacts/screenshots/remote-mobile-home.png +0 -0
  3. package/.artifacts/screenshots/remote-mobile-preferences.png +0 -0
  4. package/.artifacts/screenshots/remote-mobile-server-info.png +0 -0
  5. package/.artifacts/screenshots/remote-mobile-vlc.png +0 -0
  6. package/.env.example +93 -0
  7. package/README.md +370 -0
  8. package/bin/remote-mouse.js +19 -0
  9. package/client/core/dom.js +148 -0
  10. package/client/core/init-socket-io.js +117 -0
  11. package/client/core/socket-emit.js +6 -0
  12. package/client/core/window-events.js +23 -0
  13. package/client/i18n/apply-page-translations.js +18 -0
  14. package/client/i18n/constants.js +3 -0
  15. package/client/i18n/core.js +40 -0
  16. package/client/i18n/locale-registry.js +77 -0
  17. package/client/i18n/locales/de.js +227 -0
  18. package/client/i18n/locales/en.js +389 -0
  19. package/client/i18n/locales/es.js +228 -0
  20. package/client/i18n/locales/fr.js +389 -0
  21. package/client/i18n/locales/it.js +227 -0
  22. package/client/i18n/locales/ja.js +227 -0
  23. package/client/i18n/locales/pt.js +227 -0
  24. package/client/i18n/locales/ru.js +240 -0
  25. package/client/i18n/locales/zh.js +227 -0
  26. package/client/preferences/constants.js +15 -0
  27. package/client/preferences/effects.js +24 -0
  28. package/client/preferences/load.js +19 -0
  29. package/client/preferences/render.js +26 -0
  30. package/client/preferences/rows.js +78 -0
  31. package/client/preferences/state.js +29 -0
  32. package/client/preview/create-preview-frame-receiver.js +13 -0
  33. package/client/preview/draw.js +77 -0
  34. package/client/preview/parse-preview-frame.js +39 -0
  35. package/client/preview/preview-stream.js +152 -0
  36. package/client/services/app-state/appStateKeys.js +30 -0
  37. package/client/services/app-state/createAppStateService.js +216 -0
  38. package/client/services/app-state/createPersistStoreService.js +122 -0
  39. package/client/services/app-state/createStateStoreService.js +64 -0
  40. package/client/services/app-state/localStorageBinding.js +26 -0
  41. package/client/services/app-state/normalizers.js +74 -0
  42. package/client/services/app-state/resolveEffectiveStateValue.js +58 -0
  43. package/client/services/app-state/stateDefinitions.js +107 -0
  44. package/client/services/backend/createBackendService.js +55 -0
  45. package/client/services/config/ConfigView.js +45 -0
  46. package/client/services/config/createClientConfigService.js +122 -0
  47. package/client/services/config/defaultClientConfig.js +22 -0
  48. package/client/services/createServicesContainer.js +48 -0
  49. package/client/services/createServicesRegistry.js +26 -0
  50. package/client/services/i18n/createI18nService.js +86 -0
  51. package/client/services/notifications/createNotificationService.js +56 -0
  52. package/client/services/pubsub/createPubSubService.js +20 -0
  53. package/client/services/remotes/createRemotesService.js +20 -0
  54. package/client/services/transport/createSocketIoTransportService.js +50 -0
  55. package/client/touch/bindTouchPassthrough.js +94 -0
  56. package/client/touch/createTouchList.js +18 -0
  57. package/client/touch/dispatchSyntheticTouch.js +20 -0
  58. package/client/touch/gesture-zone.js +28 -0
  59. package/client/touch/throttle.js +46 -0
  60. package/client/touch/touch-handlers.js +193 -0
  61. package/client/touch/touchpad.js +231 -0
  62. package/client/ui/config/page.js +840 -0
  63. package/client/ui/main/applyRemoteVisibilityState.js +60 -0
  64. package/client/ui/main/bind-client-notifications.js +3 -0
  65. package/client/ui/main/bindings/bindAccordion.js +121 -0
  66. package/client/ui/main/bindings/bindActionButtons.js +13 -0
  67. package/client/ui/main/bindings/bindAdminDrawer.js +137 -0
  68. package/client/ui/main/bindings/bindAdminRemoteButtons.js +77 -0
  69. package/client/ui/main/bindings/bindAdminVersion.js +27 -0
  70. package/client/ui/main/bindings/bindBrowserRemoteButtons.js +119 -0
  71. package/client/ui/main/bindings/bindRemoteAccordion.js +23 -0
  72. package/client/ui/main/bindings/bindSamsungRemoteButtons.js +320 -0
  73. package/client/ui/main/bindings/bindSystemRemoteButtons.js +41 -0
  74. package/client/ui/main/bindings/bindVlcRemoteButtons.js +64 -0
  75. package/client/ui/main/canvas-ui.js +33 -0
  76. package/client/ui/main/connection-overlay.js +57 -0
  77. package/client/ui/main/init-ui.js +54 -0
  78. package/client/ui/main/keyboard-panel.js +271 -0
  79. package/client/ui/main/mouse-buttons.js +94 -0
  80. package/client/ui/main/page.js +21 -0
  81. package/client/ui/notifications/show-toast.js +48 -0
  82. package/client/ui/preferences/bindPreferenceSwitchers.js +49 -0
  83. package/client/ui/preferences/page.js +61 -0
  84. package/client/ui/preferences/switchers.js +200 -0
  85. package/index.js +9 -0
  86. package/package.json +41 -0
  87. package/public/admin-config.css +447 -0
  88. package/public/admin-config.html +63 -0
  89. package/public/apple-touch-icon.png +0 -0
  90. package/public/brave-icon.svg +13 -0
  91. package/public/favicon.svg +30 -0
  92. package/public/icon-192.png +0 -0
  93. package/public/icon-512.png +0 -0
  94. package/public/index.html +246 -0
  95. package/public/manifest.webmanifest +45 -0
  96. package/public/preferences.html +55 -0
  97. package/public/server-info.html +574 -0
  98. package/public/styles.css +1042 -0
  99. package/public/sw.js +103 -0
  100. package/scripts/codex-commit.sh +112 -0
  101. package/scripts/generate-mobile-screenshots.mjs +244 -0
  102. package/scripts/install-linux.sh +633 -0
  103. package/scripts/install-windows.ps1 +369 -0
  104. package/server/application/createApplicationLifecycle.js +15 -0
  105. package/server/application/logger.js +216 -0
  106. package/server/application/shutdown.js +81 -0
  107. package/server/application/start.js +95 -0
  108. package/server/application/state.js +19 -0
  109. package/server/connection/api/admin-actions.router.js +65 -0
  110. package/server/connection/api/admin-configs.router.js +165 -0
  111. package/server/connection/api/admin-remotes.router.js +61 -0
  112. package/server/connection/api/admin-subs.router.js +49 -0
  113. package/server/connection/api/client.router.js +15 -0
  114. package/server/connection/api/configs.js +96 -0
  115. package/server/connection/api/qr-page.handler.js +17 -0
  116. package/server/connection/api/remotes.router.js +30 -0
  117. package/server/connection/api/server-info.router.js +149 -0
  118. package/server/connection/api/session.middleware.js +93 -0
  119. package/server/connection/api/unauthorized-response.js +73 -0
  120. package/server/connection/socket/createConnectionRegistrar.js +23 -0
  121. package/server/connection/socket/createSocketSessionAuthMiddleware.js +49 -0
  122. package/server/connection/socket/socket-action-responder.js +12 -0
  123. package/server/connection/socket/socket.timestamp-middleware.js +51 -0
  124. package/server/index.js +12 -0
  125. package/server/init/bootstrapApi.js +87 -0
  126. package/server/init/bootstrapSocket.js +79 -0
  127. package/server/init/createAdminApiRouter.js +22 -0
  128. package/server/init/createAdminUiRouter.js +21 -0
  129. package/server/init/createSocketActionRegistrars.js +52 -0
  130. package/server/init/observers/startConfigObserver.js +51 -0
  131. package/server/init/observers/startDisplaySizeObserver.js +55 -0
  132. package/server/init/observers/startNotificationObserver.js +49 -0
  133. package/server/init/observers/startQrOverlayHoverObserver.js +89 -0
  134. package/server/init/observers/startQrOverlayRefreshObserver.js +53 -0
  135. package/server/os/darwin/app.js +45 -0
  136. package/server/os/darwin/applescript.js +51 -0
  137. package/server/os/darwin/cliSocket.js +53 -0
  138. package/server/os/darwin/url.js +9 -0
  139. package/server/os/darwin/window.js +10 -0
  140. package/server/os/linux/app.js +120 -0
  141. package/server/os/linux/cliSocket.js +53 -0
  142. package/server/os/linux/process.js +69 -0
  143. package/server/os/linux/screen.js +58 -0
  144. package/server/os/linux/systemd.js +139 -0
  145. package/server/os/linux/url.js +17 -0
  146. package/server/os/linux/windows.js +144 -0
  147. package/server/os/win32/app.js +66 -0
  148. package/server/os/win32/cliSocket.js +15 -0
  149. package/server/os/win32/powershell.js +70 -0
  150. package/server/os/win32/process.js +20 -0
  151. package/server/os/win32/service.js +95 -0
  152. package/server/os/win32/url.js +9 -0
  153. package/server/os/win32/window.js +10 -0
  154. package/server/remotes/admin/createAdminEventGuardMiddleware.js +29 -0
  155. package/server/remotes/admin/createForceUpdateCheckAction.js +39 -0
  156. package/server/remotes/admin/createInstallUpdateAction.js +64 -0
  157. package/server/remotes/admin/createOpenQrBrowserAction.js +63 -0
  158. package/server/remotes/admin/createOpenServerInfoBrowserAction.js +58 -0
  159. package/server/remotes/admin/createRestartServiceAction.js +20 -0
  160. package/server/remotes/admin/createRotateEntryTokenAction.js +43 -0
  161. package/server/remotes/admin/createToggleQrOverlayAction.js +38 -0
  162. package/server/remotes/admin/index.js +32 -0
  163. package/server/remotes/admin/notifyIfRestarted.js +102 -0
  164. package/server/remotes/admin/registrar.js +94 -0
  165. package/server/remotes/browser/actions/createFocusOrLaunchBrowserAction.js +22 -0
  166. package/server/remotes/browser/actions/openUrlOnHost.js +3 -0
  167. package/server/remotes/browser/browserCatalog.js +70 -0
  168. package/server/remotes/browser/index.js +15 -0
  169. package/server/remotes/browser/listBrowsersOnHost.js +23 -0
  170. package/server/remotes/browser/registrar.js +29 -0
  171. package/server/remotes/browser/spec.js +18 -0
  172. package/server/remotes/browser/state.js +5 -0
  173. package/server/remotes/input/registrar.js +39 -0
  174. package/server/remotes/preview/bgraToRgbaBuffer.js +20 -0
  175. package/server/remotes/preview/captureAroundCursor.js +19 -0
  176. package/server/remotes/preview/createPreviewStreamer.js +85 -0
  177. package/server/remotes/preview/registrar.js +34 -0
  178. package/server/remotes/samsung/createSamsungCommandService.js +203 -0
  179. package/server/remotes/samsung/createSamsungRemote.js +26 -0
  180. package/server/remotes/samsung/createSamsungRemoteGetter.js +46 -0
  181. package/server/remotes/samsung/createSamsungTvGetter.js +102 -0
  182. package/server/remotes/samsung/device-config.js +122 -0
  183. package/server/remotes/samsung/registrar.js +59 -0
  184. package/server/remotes/samsung/utils.js +56 -0
  185. package/server/remotes/vlc/index.js +39 -0
  186. package/server/remotes/vlc/registrar.js +94 -0
  187. package/server/remotes/vlc/spec.js +15 -0
  188. package/server/remotes/vlc/state.js +5 -0
  189. package/server/remotes/window/index.js +6 -0
  190. package/server/remotes/window/registrar.js +28 -0
  191. package/server/services/application/createApplicationDaemonService.js +144 -0
  192. package/server/services/application/getDaemonServiceAdapter.js +56 -0
  193. package/server/services/application/utils.js +29 -0
  194. package/server/services/config/bootstrapConfig.js +38 -0
  195. package/server/services/config/configPaths.js +42 -0
  196. package/server/services/config/configSchema.js +297 -0
  197. package/server/services/config/configService.js +89 -0
  198. package/server/services/config/defaultConfig.js +137 -0
  199. package/server/services/config/envConfig.js +49 -0
  200. package/server/services/config/index.js +9 -0
  201. package/server/services/config/logConfig.js +54 -0
  202. package/server/services/config/system-config.js +44 -0
  203. package/server/services/createServicesContainer.js +94 -0
  204. package/server/services/createServicesRegistry.js +48 -0
  205. package/server/services/input/createInputController.js +17 -0
  206. package/server/services/input/createKeyboardController.js +146 -0
  207. package/server/services/input/createMouseController.js +182 -0
  208. package/server/services/notifier/createClientNotifier.js +23 -0
  209. package/server/services/notifier/createHostNotifier.js +41 -0
  210. package/server/services/notifier/createNotifier.js +13 -0
  211. package/server/services/notifier/createNotifierComposite.js +122 -0
  212. package/server/services/notifier/handleOpenQrBrowserEvent.js +40 -0
  213. package/server/services/notifier/handleOpenServerInfoBrowserEvent.js +40 -0
  214. package/server/services/notifier/handleRestartServiceEvent.js +37 -0
  215. package/server/services/notifier/handleRotateEntryTokenEvent.js +42 -0
  216. package/server/services/notifier/handleSessionEvent.js +24 -0
  217. package/server/services/notifier/handleToggleQrOverlayEvent.js +21 -0
  218. package/server/services/notifier/host-notifier/createLinuxHostNotifier.js +23 -0
  219. package/server/services/notifier/host-notifier/createNodeNotifierHostNotifier.js +24 -0
  220. package/server/services/notifier/host-notifier/index.js +11 -0
  221. package/server/services/notifier/mapper/handleForceUpdateCheckEvent.js +24 -0
  222. package/server/services/notifier/mapper/handleInstallUpdateEvent.js +53 -0
  223. package/server/services/notifier/mapper/handleSocketEvent.js +40 -0
  224. package/server/services/notifier/mapper/handleUpdateManagerEvent.js +24 -0
  225. package/server/services/notifier/mapper/notify.js +7 -0
  226. package/server/services/os/index.js +23 -0
  227. package/server/services/os/platforms/createFallbackAdapter.js +31 -0
  228. package/server/services/os/platforms/darwin/app.js +6 -0
  229. package/server/services/os/platforms/darwin/index.js +21 -0
  230. package/server/services/os/platforms/darwin/scripts.js +4 -0
  231. package/server/services/os/platforms/darwin/url.js +1 -0
  232. package/server/services/os/platforms/darwin/window.js +4 -0
  233. package/server/services/os/platforms/linux/app.js +6 -0
  234. package/server/services/os/platforms/linux/index.js +33 -0
  235. package/server/services/os/platforms/linux/url.js +1 -0
  236. package/server/services/os/platforms/linux/windows.js +11 -0
  237. package/server/services/os/platforms/win32/app.js +6 -0
  238. package/server/services/os/platforms/win32/index.js +21 -0
  239. package/server/services/os/platforms/win32/overlay.js +6 -0
  240. package/server/services/os/platforms/win32/powershell.js +4 -0
  241. package/server/services/os/platforms/win32/url.js +1 -0
  242. package/server/services/os/platforms/win32/window.js +4 -0
  243. package/server/services/os/shared.js +2 -0
  244. package/server/services/overlay/createNoopOverlay.js +13 -0
  245. package/server/services/overlay/createQrOverlay.js +27 -0
  246. package/server/services/overlay/createQrOverlayWin32.js +158 -0
  247. package/server/services/overlay/createQrOverlayYad.js +178 -0
  248. package/server/services/overlay/renderQrPage.js +82 -0
  249. package/server/services/persistence/createConfigDao.js +106 -0
  250. package/server/services/persistence/createDatabaseProvider.js +23 -0
  251. package/server/services/persistence/createEntryTokenDao.js +140 -0
  252. package/server/services/persistence/createRestartLogDao.js +210 -0
  253. package/server/services/persistence/index.js +19 -0
  254. package/server/services/pubsub/createEventStore.js +54 -0
  255. package/server/services/pubsub/createPubSub.js +89 -0
  256. package/server/services/pubsub/createServiceEvents.js +29 -0
  257. package/server/services/pubsub/serviceEventConstants.js +39 -0
  258. package/server/services/remotes/createRemotes.js +25 -0
  259. package/server/services/server/createHttpsServer.js +12 -0
  260. package/server/services/server/createServer.js +66 -0
  261. package/server/services/sse/createSseService.js +96 -0
  262. package/server/services/sse/utils.js +7 -0
  263. package/server/services/system/createSystemService.js +170 -0
  264. package/server/services/system/getNetworkInfo.js +18 -0
  265. package/server/services/system/getScreenInfo.js +32 -0
  266. package/server/services/system/listNetworkInterfaces.js +27 -0
  267. package/server/services/task-manager/createTaskManager.js +68 -0
  268. package/server/services/task-runner/createTaskRunner.js +114 -0
  269. package/server/services/token-manager/createTokenManager.js +244 -0
  270. package/server/services/token-manager/token-format.js +7 -0
  271. package/server/services/token-manager/token-store-utils.js +8 -0
  272. package/server/services/update-manager/CommandUpdateSource.js +70 -0
  273. package/server/services/update-manager/NpmUpdateSource.js +34 -0
  274. package/server/services/update-manager/buildNpmGlobalUpdateCommand.js +15 -0
  275. package/server/services/update-manager/chooseUpdateCheckSource.js +20 -0
  276. package/server/services/update-manager/chooseUpdateInstallSource.js +5 -0
  277. package/server/services/update-manager/createUpdateManager.js +109 -0
  278. package/server/services/update-manager/resolveInstallUpdateCommand.js +42 -0
  279. package/server/term/cli/executeLocalServiceCommand.js +42 -0
  280. package/server/term/cli/getCliSocketPath.js +5 -0
  281. package/server/term/cli/parseCliArgs.js +110 -0
  282. package/server/term/cli/printCliResult.js +18 -0
  283. package/server/term/cli/runCliCmd.js +50 -0
  284. package/server/term/cli/sendCliCommand.js +76 -0
  285. package/server/term/cliSocket.js +29 -0
  286. package/server/term/srv/commands/configCommand.js +84 -0
  287. package/server/term/srv/commands/helpCommand.js +6 -0
  288. package/server/term/srv/commands/infoCommand.js +7 -0
  289. package/server/term/srv/commands/openQrCommand.js +7 -0
  290. package/server/term/srv/commands/samsungDetectCommand.js +52 -0
  291. package/server/term/srv/commands/serviceCommand.js +25 -0
  292. package/server/term/srv/commands/systemConfigCommand.js +7 -0
  293. package/server/term/srv/commands/tasksCommand.js +24 -0
  294. package/server/term/srv/commands/tokensCommand.js +15 -0
  295. package/server/term/srv/executeCliCommand.js +44 -0
  296. package/server/term/srv/executeCliRequest.js +38 -0
  297. package/server/term/srv/startCliServer.js +140 -0
  298. package/server/utils/createRandomToken.js +11 -0
  299. package/server/utils/env.js +155 -0
  300. package/server/utils/git.js +13 -0
  301. package/server/utils/http.js +7 -0
  302. package/server/utils/network.js +45 -0
  303. package/server/utils/paths.js +10 -0
  304. package/server/utils/process.js +57 -0
  305. package/server/utils/robot.js +11 -0
  306. package/server/utils/semver.js +33 -0
  307. package/server/utils/truncateText.js +7 -0
  308. package/utils/createLazy.js +13 -0
  309. package/utils/functional.js +48 -0
  310. package/utils/math.js +26 -0
  311. package/utils/notificationSettings.js +61 -0
  312. package/utils/object.utils.js +79 -0
  313. package/utils/predicates.js +17 -0
  314. package/utils/remoteCommands.js +40 -0
  315. package/utils/sync.js +3 -0
  316. package/velor-remote-mouse-6.4.8.tgz +0 -0
@@ -0,0 +1,203 @@
1
+ import {Keys} from "samsung-tv-remote";
2
+
3
+ import {
4
+ createSamsungResult,
5
+ resolveConfiguredKey,
6
+ resolveConfiguredKeysSequence,
7
+ toSamsungErrorMessage,
8
+ } from "./utils.js";
9
+
10
+ export function createSamsungCommandService({getConfig, discoverDevices, getSamsungTv, getLogger, createDisabledRemote}) {
11
+ let powerStateCache = {
12
+ value: 'unknown',
13
+ checkedAt: 0,
14
+ };
15
+ let powerStatePromise = null;
16
+
17
+ function getEnabledRemote() {
18
+ if (getConfig().enabled) {
19
+ return null;
20
+ }
21
+ return createDisabledRemote?.();
22
+ }
23
+
24
+ function invalidatePowerState() {
25
+ powerStateCache = {
26
+ value: 'unknown',
27
+ checkedAt: 0,
28
+ };
29
+ }
30
+
31
+ async function computePowerState() {
32
+ const disabledRemote = getEnabledRemote();
33
+ if (disabledRemote) {
34
+ return 'disabled';
35
+ }
36
+
37
+ try {
38
+ const samsungTv = await getSamsungTv();
39
+ return samsungTv.getPowerState();
40
+ } catch (error) {
41
+ getLogger().warn({err: error?.message || String(error)}, 'Etat Samsung indisponible');
42
+ return 'unknown';
43
+ }
44
+ }
45
+
46
+ async function getPowerState(options = {}) {
47
+ const maxAgeMs = Number(options.maxAgeMs);
48
+ const now = Date.now();
49
+ if (Number.isFinite(maxAgeMs) && maxAgeMs >= 0 && (now - powerStateCache.checkedAt) <= maxAgeMs) {
50
+ return powerStateCache.value;
51
+ }
52
+
53
+ if (!powerStatePromise) {
54
+ powerStatePromise = (async () => {
55
+ try {
56
+ const value = await computePowerState();
57
+ powerStateCache = {
58
+ value,
59
+ checkedAt: Date.now(),
60
+ };
61
+ return value;
62
+ } finally {
63
+ powerStatePromise = null;
64
+ }
65
+ })();
66
+ }
67
+
68
+ return powerStatePromise;
69
+ }
70
+
71
+ async function sendKey(key, successMessage) {
72
+ const disabledRemote = getEnabledRemote();
73
+ if (disabledRemote) {
74
+ return disabledRemote.turnOn();
75
+ }
76
+ try {
77
+ const samsungTv = await getSamsungTv();
78
+ await samsungTv.sendKey(key);
79
+ invalidatePowerState();
80
+ getLogger().info({key}, 'Commande Samsung envoyee');
81
+ return createSamsungResult(successMessage);
82
+ } catch (error) {
83
+ const message = toSamsungErrorMessage(error);
84
+ getLogger().warn({key, err: message}, 'Echec commande Samsung');
85
+ return {
86
+ ok: false,
87
+ message: `TV Samsung indisponible: ${message}`,
88
+ };
89
+ }
90
+ }
91
+
92
+ async function sendKeys(keys, successMessage) {
93
+ const disabledRemote = getEnabledRemote();
94
+ if (disabledRemote) {
95
+ return disabledRemote.turnOn();
96
+ }
97
+ try {
98
+ const samsungTv = await getSamsungTv();
99
+ await samsungTv.sendKeys(keys);
100
+ invalidatePowerState();
101
+ getLogger().info({keys}, 'Sequence Samsung envoyee');
102
+ return createSamsungResult(successMessage);
103
+ } catch (error) {
104
+ const message = toSamsungErrorMessage(error);
105
+ getLogger().warn({keys, err: message}, 'Echec sequence Samsung');
106
+ return {
107
+ ok: false,
108
+ message: `TV Samsung indisponible: ${message}`,
109
+ };
110
+ }
111
+ }
112
+
113
+ return {
114
+ isEnabled() {
115
+ return Boolean(getConfig().enabled);
116
+ },
117
+ async getPowerState(options) {
118
+ return getPowerState(options);
119
+ },
120
+ async discoverDevices() {
121
+ return discoverDevices();
122
+ },
123
+ async turnOn() {
124
+ const disabledRemote = getEnabledRemote();
125
+ if (disabledRemote) {
126
+ return disabledRemote.turnOn();
127
+ }
128
+ try {
129
+ const samsungTv = await getSamsungTv();
130
+ await samsungTv.wakeTV();
131
+ invalidatePowerState();
132
+ getLogger().info('Wake-on-LAN Samsung envoye');
133
+ return createSamsungResult("Demande d'allumage envoyee a la TV Samsung.");
134
+ } catch (error) {
135
+ const message = toSamsungErrorMessage(error);
136
+ getLogger().warn({err: message}, 'Echec allumage Samsung');
137
+ return {
138
+ ok: false,
139
+ message: `Impossible d'allumer la TV Samsung: ${message}`,
140
+ };
141
+ }
142
+ },
143
+ async turnOff() {
144
+ const disabledRemote = getEnabledRemote();
145
+ if (disabledRemote) {
146
+ return disabledRemote.turnOff();
147
+ }
148
+ const config = getConfig();
149
+ const powerOffKey = resolveConfiguredKey(config.powerOffKey);
150
+ if (!powerOffKey) {
151
+ return {
152
+ ok: false,
153
+ message: `Touche Samsung invalide pour l'extinction: ${config.powerOffKey}`,
154
+ };
155
+ }
156
+ return sendKey(powerOffKey, "Demande d'extinction envoyee a la TV Samsung.");
157
+ },
158
+ async volumeUp() {
159
+ return sendKey(Keys.KEY_VOLUP, 'Volume Samsung augmente.');
160
+ },
161
+ async volumeDown() {
162
+ return sendKey(Keys.KEY_VOLDOWN, 'Volume Samsung diminue.');
163
+ },
164
+ async mute() {
165
+ return sendKey(Keys.KEY_MUTE, 'Mute Samsung active/desactive.');
166
+ },
167
+ async switchInput() {
168
+ return sendKey(Keys.KEY_SOURCE, 'Changement de source Samsung demande.');
169
+ },
170
+ async confirm() {
171
+ return sendKey(Keys.KEY_ENTER, 'Validation Samsung envoyee.');
172
+ },
173
+ async switchToPcInput() {
174
+ const disabledRemote = getEnabledRemote();
175
+ if (disabledRemote) {
176
+ return disabledRemote.switchToPcInput();
177
+ }
178
+ const config = getConfig();
179
+ const configuredSequence = resolveConfiguredKeysSequence(config.pcInputSequence);
180
+ if (configuredSequence.length) {
181
+ if (configuredSequence.some((key) => !key)) {
182
+ return {
183
+ ok: false,
184
+ message: `Sequence Samsung invalide pour l'entree PC: ${config.pcInputSequence}`,
185
+ };
186
+ }
187
+ return sendKeys(
188
+ configuredSequence,
189
+ `Bascule Samsung vers l'entree PC via sequence ${config.pcInputSequence}.`,
190
+ );
191
+ }
192
+
193
+ const configuredKey = resolveConfiguredKey(config.pcInputKey);
194
+ if (!configuredKey) {
195
+ return {
196
+ ok: false,
197
+ message: `Touche Samsung invalide pour l'entree PC: ${config.pcInputKey}`,
198
+ };
199
+ }
200
+ return sendKey(configuredKey, `Bascule Samsung vers ${config.pcInputKey}.`);
201
+ },
202
+ };
203
+ }
@@ -0,0 +1,26 @@
1
+ import {createSamsungCommandService} from './createSamsungCommandService.js';
2
+ import {createSamsungDeviceConfigResolver, discoverSamsungDevices} from './device-config.js';
3
+ import {createSamsungTvGetter} from './createSamsungTvGetter.js';
4
+ import {createDisabledSamsungRemote} from './utils.js';
5
+ import {createLogger} from '../../application/logger.js';
6
+
7
+ let log;
8
+ function getModuleLog() {
9
+ log ??= createLogger('samsung:remote');
10
+ return log;
11
+ }
12
+
13
+ export function createSamsungRemote(services) {
14
+ const getLogger = () => getModuleLog();
15
+ const getConfig = ()=> services.getConfig().samsungTv;
16
+ const resolveDeviceConfig = createSamsungDeviceConfigResolver({getConfig, getLogger});
17
+ const discoverDevices = discoverSamsungDevices({getConfig});
18
+ const getSamsungTv = createSamsungTvGetter({getConfig, resolveDeviceConfig});
19
+ return createSamsungCommandService({
20
+ getConfig,
21
+ discoverDevices,
22
+ getSamsungTv,
23
+ getLogger,
24
+ createDisabledRemote: () => createDisabledSamsungRemote('Controle Samsung desactive. Activez SAMSUNG_TV_ENABLED.'),
25
+ });
26
+ }
@@ -0,0 +1,46 @@
1
+ import {SamsungTvRemote} from "samsung-tv-remote";
2
+
3
+ export function createSamsungRemoteGetter({
4
+ getConfig,
5
+ resolveDeviceConfig,
6
+ SamsungTvRemoteClass = SamsungTvRemote,
7
+ }) {
8
+ let remotePromise = null;
9
+ let remoteKey = '';
10
+
11
+ return async function getRemote() {
12
+ const config = getConfig();
13
+ const nextKey = JSON.stringify({
14
+ alwaysAutoResolve: config.alwaysAutoResolve,
15
+ appName: config.appName,
16
+ host: config.host,
17
+ mac: config.mac,
18
+ port: config.port,
19
+ timeoutMs: config.timeoutMs,
20
+ });
21
+
22
+ if (!remotePromise || remoteKey !== nextKey) {
23
+ remoteKey = nextKey;
24
+ remotePromise = (async () => {
25
+ try {
26
+ const device = await resolveDeviceConfig();
27
+ return new SamsungTvRemoteClass({
28
+ device: {
29
+ ip: device.ip,
30
+ mac: device.mac,
31
+ },
32
+ port: config.port,
33
+ name: config.appName,
34
+ timeout: config.timeoutMs,
35
+ });
36
+ } catch (error) {
37
+ remotePromise = null;
38
+ remoteKey = '';
39
+ throw error;
40
+ }
41
+ })();
42
+ }
43
+
44
+ return remotePromise;
45
+ };
46
+ }
@@ -0,0 +1,102 @@
1
+ import { SamsungTvRemote } from 'samsung-tv-remote';
2
+ import { pingHost } from '../../utils/network.js';
3
+
4
+ function isNoAwakeTvError(error) {
5
+ return String(error?.message || error || '').includes('aucune TV Samsung reveillee');
6
+ }
7
+
8
+ function isAmbiguousTvError(error) {
9
+ return String(error?.message || error || '').includes('plusieurs TV Samsung detectees');
10
+ }
11
+
12
+ export function createSamsungTvGetter({
13
+ getConfig,
14
+ resolveDeviceConfig,
15
+ pingHostFn = pingHost,
16
+ SamsungTvRemoteClass = SamsungTvRemote,
17
+ }) {
18
+ let tvPromise = null;
19
+ let tvKey = '';
20
+
21
+ return async function getSamsungTv() {
22
+ const config = getConfig();
23
+ const nextKey = JSON.stringify({
24
+ alwaysAutoResolve: config.alwaysAutoResolve,
25
+ appName: config.appName,
26
+ host: config.host,
27
+ mac: config.mac,
28
+ port: config.port,
29
+ timeoutMs: config.timeoutMs,
30
+ });
31
+
32
+ if (!tvPromise || tvKey !== nextKey) {
33
+ tvKey = nextKey;
34
+ tvPromise = (async () => {
35
+ try {
36
+ const device = await resolveDeviceConfig();
37
+ const remote = new SamsungTvRemoteClass({
38
+ device: {
39
+ ip: device.ip,
40
+ mac: device.mac,
41
+ },
42
+ port: config.port,
43
+ name: config.appName,
44
+ timeout: config.timeoutMs,
45
+ });
46
+
47
+ return {
48
+ device,
49
+ remote,
50
+ async getPowerState() {
51
+ if (!device?.ip) {
52
+ return 'unknown';
53
+ }
54
+ const reachable = await pingHostFn(
55
+ device.ip,
56
+ Math.max(500, Number(config.timeoutMs) || 2000),
57
+ );
58
+ return reachable ? 'on' : 'off';
59
+ },
60
+ async sendKey(key) {
61
+ await remote.sendKey(key);
62
+ },
63
+ async sendKeys(keys) {
64
+ await remote.sendKeys(keys);
65
+ },
66
+ async wakeTV() {
67
+ await remote.wakeTV();
68
+ },
69
+ };
70
+ } catch (error) {
71
+ tvPromise = null;
72
+ tvKey = '';
73
+
74
+ return {
75
+ device: null,
76
+ remote: null,
77
+ async getPowerState() {
78
+ if (isNoAwakeTvError(error)) {
79
+ return 'off';
80
+ }
81
+ if (isAmbiguousTvError(error)) {
82
+ return 'unknown';
83
+ }
84
+ return 'unknown';
85
+ },
86
+ async sendKey() {
87
+ throw error;
88
+ },
89
+ async sendKeys() {
90
+ throw error;
91
+ },
92
+ async wakeTV() {
93
+ throw error;
94
+ },
95
+ };
96
+ }
97
+ })();
98
+ }
99
+
100
+ return tvPromise;
101
+ };
102
+ }
@@ -0,0 +1,122 @@
1
+ import {
2
+ getAwakeSamsungDevices,
3
+ getLastConnectedDevice,
4
+ } from "samsung-tv-remote";
5
+
6
+ export function normalizeMac(value) {
7
+ return String(value || '')
8
+ .trim()
9
+ .toLowerCase()
10
+ .replace(/[^a-f0-9]/g, '');
11
+ }
12
+
13
+ export function getSamsungDeviceMac(candidate) {
14
+ return String(candidate?.wifiMac || candidate?.mac || '').trim();
15
+ }
16
+
17
+ export function pickSamsungDevice(candidates, config) {
18
+ const requestedHost = String(config.host || '').trim();
19
+ const requestedMac = normalizeMac(config.mac);
20
+
21
+ if (requestedHost) {
22
+ const byHost = candidates.find((candidate) => candidate.ip === requestedHost);
23
+ if (byHost) {
24
+ return byHost;
25
+ }
26
+ }
27
+
28
+ if (requestedMac) {
29
+ const byMac = candidates.find((candidate) => normalizeMac(getSamsungDeviceMac(candidate)) === requestedMac);
30
+ if (byMac) {
31
+ return byMac;
32
+ }
33
+ }
34
+
35
+ if (!requestedHost && !requestedMac && candidates.length === 1) {
36
+ return candidates[0];
37
+ }
38
+
39
+ return null;
40
+ }
41
+
42
+ function buildDeviceKey(candidate) {
43
+ const ip = String(candidate?.ip || '').trim();
44
+ const mac = normalizeMac(getSamsungDeviceMac(candidate));
45
+ return `${ip}|${mac}`;
46
+ }
47
+
48
+ export function discoverSamsungDevices({
49
+ getConfig,
50
+ getLastConnectedDeviceFn = getLastConnectedDevice,
51
+ getAwakeSamsungDevicesFn = getAwakeSamsungDevices,
52
+ }) {
53
+ return async function discoverDevices() {
54
+ const config = getConfig();
55
+ const lastDevice = getLastConnectedDeviceFn();
56
+ const discoveredDevices = await getAwakeSamsungDevicesFn(config.discoveryTimeoutMs);
57
+ const merged = lastDevice ? [lastDevice, ...discoveredDevices] : discoveredDevices;
58
+ const seen = new Set();
59
+
60
+ return merged.filter((candidate) => {
61
+ const key = buildDeviceKey(candidate);
62
+ if (!key || seen.has(key)) {
63
+ return false;
64
+ }
65
+ seen.add(key);
66
+ return true;
67
+ });
68
+ };
69
+ }
70
+
71
+ export function createSamsungDeviceConfigResolver({
72
+ getConfig,
73
+ getLogger,
74
+ getLastConnectedDeviceFn = getLastConnectedDevice,
75
+ getAwakeSamsungDevicesFn = getAwakeSamsungDevices,
76
+ }) {
77
+ const discoverDevices = discoverSamsungDevices({
78
+ getConfig,
79
+ getLastConnectedDeviceFn,
80
+ getAwakeSamsungDevicesFn,
81
+ });
82
+
83
+ return async function resolveDeviceConfig() {
84
+ const config = getConfig();
85
+ if (!config.alwaysAutoResolve && config.host && config.mac) {
86
+ return {
87
+ ip: config.host,
88
+ mac: config.mac,
89
+ };
90
+ }
91
+
92
+ const candidates = await discoverDevices();
93
+ const selectionConfig = config.alwaysAutoResolve
94
+ ? {...config, host: '', mac: ''}
95
+ : config;
96
+ const selected = pickSamsungDevice(candidates, selectionConfig);
97
+
98
+ if (!selected) {
99
+ if (!candidates.length) {
100
+ throw new Error('aucune TV Samsung reveillee detectee sur le reseau');
101
+ }
102
+
103
+ if (candidates.length > 1) {
104
+ throw new Error('plusieurs TV Samsung detectees, renseignez SAMSUNG_TV_HOST ou SAMSUNG_TV_MAC');
105
+ }
106
+
107
+ throw new Error('TV Samsung detectee mais impossible de resoudre host/mac');
108
+ }
109
+
110
+ getLogger().info({
111
+ ip: selected.ip,
112
+ name: selected.name,
113
+ model: selected.model,
114
+ wifiMac: getSamsungDeviceMac(selected),
115
+ }, 'TV Samsung detectee automatiquement');
116
+
117
+ return {
118
+ ip: selected.ip,
119
+ mac: getSamsungDeviceMac(selected) || config.mac,
120
+ };
121
+ };
122
+ }
@@ -0,0 +1,59 @@
1
+ import {createLogger} from "../../application/logger.js";
2
+ import {
3
+ REMOTE_EVENT_SAMSUNG_ENTER,
4
+ REMOTE_EVENT_SAMSUNG_INPUT,
5
+ REMOTE_EVENT_SAMSUNG_MUTE,
6
+ REMOTE_EVENT_SAMSUNG_OFF,
7
+ REMOTE_EVENT_SAMSUNG_ON,
8
+ REMOTE_EVENT_SAMSUNG_PC_INPUT,
9
+ REMOTE_EVENT_SAMSUNG_VOL_DOWN,
10
+ REMOTE_EVENT_SAMSUNG_VOL_UP,
11
+ } from '../../../utils/remoteCommands.js';
12
+
13
+ let log = createLogger('samsung:remote');
14
+
15
+ export function createSamsungRegistrar({samsung}) {
16
+ return socket => {
17
+ const client = socket.id.slice(0, 8);
18
+
19
+ socket.on(REMOTE_EVENT_SAMSUNG_ON, async () => {
20
+ log.info({client}, `Demande ${REMOTE_EVENT_SAMSUNG_ON}`);
21
+ await samsung.turnOn();
22
+ });
23
+
24
+ socket.on(REMOTE_EVENT_SAMSUNG_OFF, async () => {
25
+ log.info({client}, `Demande ${REMOTE_EVENT_SAMSUNG_OFF}`);
26
+ await samsung.turnOff();
27
+ });
28
+
29
+ socket.on(REMOTE_EVENT_SAMSUNG_VOL_UP, async () => {
30
+ log.info({client}, `Demande ${REMOTE_EVENT_SAMSUNG_VOL_UP}`);
31
+ await samsung.volumeUp();
32
+ });
33
+
34
+ socket.on(REMOTE_EVENT_SAMSUNG_VOL_DOWN, async () => {
35
+ log.info({client}, `Demande ${REMOTE_EVENT_SAMSUNG_VOL_DOWN}`);
36
+ await samsung.volumeDown();
37
+ });
38
+
39
+ socket.on(REMOTE_EVENT_SAMSUNG_MUTE, async () => {
40
+ log.info({client}, `Demande ${REMOTE_EVENT_SAMSUNG_MUTE}`);
41
+ await samsung.mute();
42
+ });
43
+
44
+ socket.on(REMOTE_EVENT_SAMSUNG_INPUT, async () => {
45
+ log.info({client}, `Demande ${REMOTE_EVENT_SAMSUNG_INPUT}`);
46
+ await samsung.switchInput();
47
+ });
48
+
49
+ socket.on(REMOTE_EVENT_SAMSUNG_ENTER, async () => {
50
+ log.info({client}, `Demande ${REMOTE_EVENT_SAMSUNG_ENTER}`);
51
+ await samsung.confirm();
52
+ });
53
+
54
+ socket.on(REMOTE_EVENT_SAMSUNG_PC_INPUT, async () => {
55
+ log.info({client}, `Demande ${REMOTE_EVENT_SAMSUNG_PC_INPUT}`);
56
+ await samsung.switchToPcInput();
57
+ });
58
+ }
59
+ }
@@ -0,0 +1,56 @@
1
+ import {Keys} from "samsung-tv-remote";
2
+
3
+ export function createDisabledSamsungRemote(reason) {
4
+ return {
5
+ isEnabled() {
6
+ return false;
7
+ },
8
+ async turnOn() {
9
+ return {ok: false, message: reason};
10
+ },
11
+ async turnOff() {
12
+ return {ok: false, message: reason};
13
+ },
14
+ async volumeUp() {
15
+ return {ok: false, message: reason};
16
+ },
17
+ async volumeDown() {
18
+ return {ok: false, message: reason};
19
+ },
20
+ async mute() {
21
+ return {ok: false, message: reason};
22
+ },
23
+ async switchInput() {
24
+ return {ok: false, message: reason};
25
+ },
26
+ async confirm() {
27
+ return {ok: false, message: reason};
28
+ },
29
+ async switchToPcInput() {
30
+ return {ok: false, message: reason};
31
+ },
32
+ };
33
+ }
34
+
35
+ export function toSamsungErrorMessage(error) {
36
+ return String(error?.message || error || 'Erreur Samsung inconnue');
37
+ }
38
+
39
+ export function createSamsungResult(message) {
40
+ return {
41
+ ok: true,
42
+ message,
43
+ };
44
+ }
45
+
46
+ export function resolveConfiguredKey(keyName) {
47
+ return Keys[String(keyName || '').trim()] || null;
48
+ }
49
+
50
+ export function resolveConfiguredKeysSequence(sequence) {
51
+ return String(sequence || '')
52
+ .split(',')
53
+ .map((entry) => String(entry || '').trim().toUpperCase())
54
+ .filter(Boolean)
55
+ .map((entry) => Keys[entry] || null);
56
+ }
@@ -0,0 +1,39 @@
1
+ import { createVlcReceiverState } from './state.js';
2
+ import { VLC_APP_SPEC } from './spec.js';
3
+
4
+ export function createVlc(services) {
5
+ const state = createVlcReceiverState();
6
+ let availabilityPromise = null;
7
+ const getOsService = () => services.getOs();
8
+
9
+ function getAvailability() {
10
+ if (!availabilityPromise) {
11
+ availabilityPromise = (async () => {
12
+ try {
13
+ const resolved = await getOsService().app.resolve(VLC_APP_SPEC);
14
+ return Boolean(resolved);
15
+ } catch (_error) {
16
+ return false;
17
+ }
18
+ })();
19
+ }
20
+ return availabilityPromise;
21
+ }
22
+
23
+ return {
24
+ async focusOrLaunch() {
25
+ if (state.inFlight) {
26
+ return false;
27
+ }
28
+ state.inFlight = true;
29
+ try {
30
+ return getOsService().app.openOrFocus(VLC_APP_SPEC, { maximize: false });
31
+ } finally {
32
+ state.inFlight = false;
33
+ }
34
+ },
35
+ toggleWindow: () => getOsService().app.toggleWindow(VLC_APP_SPEC),
36
+ closeWindow: () => getOsService().app.closeWindow(VLC_APP_SPEC),
37
+ isAvailable: getAvailability,
38
+ };
39
+ }