From 3ad60d5e6998b4f912c55cf71971fa52933369b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20R=C3=A8gne?= Date: Sat, 4 Jul 2020 10:20:17 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20G=C3=A9rer=20la=20saisie=20d'une=20adre?= =?UTF-8?q?sse=20compl=C3=A8te=20de=20Kodi.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/_locales/en/messages.json | 23 ++++++---- src/_locales/fr/messages.json | 23 ++++++---- src/background/migrate.js | 84 +++++++++++++++++----------------- src/core/jsonrpc/kodi.js | 78 +++++++++++++++++++------------ src/options/img/help.svg | 6 +++ src/options/index.html | 19 +++++--- src/options/script.js | 46 ++++++++++--------- src/options/style.css | 7 ++- test/unit/core/jsonrpc/kodi.js | 15 +++--- test/unit/core/pebkac.js | 8 ++-- 10 files changed, 179 insertions(+), 130 deletions(-) create mode 100644 src/options/img/help.svg diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index c66c0b7b..2ef15cd7 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -41,14 +41,14 @@ "message": "No address" }, "notifications_unconfigured_message": { - "message": "IP address of Kodi Web server is missing in options." + "message": "Address of Kodi Web server is missing in options." }, - "notifications_badHost_title": { + "notifications_badAddress_title": { "message": "Address invalid" }, - "notifications_badHost_message": { - "message": "IP address of Kodi Web server $ADDRESS$ is invalid.", + "notifications_badAddress_message": { + "message": "Address of Kodi Web server $ADDRESS$ is invalid.", "placeholders": { "address": { "content": "$1" @@ -60,7 +60,7 @@ "message": "Kodi not found" }, "notifications_notFound_message": { - "message": "IP address of Kodi Web server $ADDRESS$ is invalid or Kodi's remote control isn't enabled.", + "message": "Address of Kodi Web server $ADDRESS$ is invalid or Kodi's remote control isn't enabled.", "placeholders": { "address": { "content": "$1" @@ -210,14 +210,17 @@ "options_serverModeSingle_textcontent": { "message": "Configure one server" }, - "options_serverHost_textcontent": { - "message": "IP address:" + "options_serverAddress_textcontent": { + "message": "Address:" + }, + "options_serverAddress_title": { + "message": "IP address or full address (for example : 192.168.0.1, ws://192.168.0.1:9090/jsonrpc, etc.)" }, "options_serverModeMulti_textcontent": { "message": "Configure many servers" }, - "options_serverHosts_textcontent": { - "message": "IP address" + "options_serverAddresses_textcontent": { + "message": "Address" }, "options_serverNames_textcontent": { "message": "Name" @@ -225,7 +228,7 @@ "options_serverAdd_textcontent": { "message": "Add server" }, - "options_serverHost_placeholder": { + "options_serverAddress_placeholder": { "message": "192.168.0.1" }, "options_serverName_placeholder": { diff --git a/src/_locales/fr/messages.json b/src/_locales/fr/messages.json index d68de0b7..4048e8f4 100644 --- a/src/_locales/fr/messages.json +++ b/src/_locales/fr/messages.json @@ -41,14 +41,14 @@ "message": "Aucune adresse" }, "notifications_unconfigured_message": { - "message": "L'adresse IP du serveur Web de Kodi n'est pas renseignée." + "message": "L'adresse du serveur Web de Kodi n'est pas renseignée." }, - "notifications_badHost_title": { + "notifications_badAddress_title": { "message": "Adresse invalide" }, - "notifications_badHost_message": { - "message": "L'adresse IP du serveur Web de Kodi $ADDRESS$ est invalide.", + "notifications_badAddress_message": { + "message": "L'adresse du serveur Web de Kodi $ADDRESS$ est invalide.", "placeholders": { "address": { "content": "$1" @@ -60,7 +60,7 @@ "message": "Kodi non trouvé" }, "notifications_notFound_message": { - "message": "L'adresse IP du serveur Web de Kodi $ADDRESS$ est invalide ; ou le contrôle à distance n'est pas activé dans Kodi.", + "message": "L'adresse du serveur Web de Kodi $ADDRESS$ est invalide ; ou le contrôle à distance n'est pas activé dans Kodi.", "placeholders": { "address": { "content": "$1" @@ -210,14 +210,17 @@ "options_serverModeSingle_textcontent": { "message": "Configurer un seul serveur" }, - "options_serverHost_textcontent": { - "message": "Adresse IP :" + "options_serverAddress_textcontent": { + "message": "Adresse :" + }, + "options_serverAddress_title": { + "message": "Adresse IP ou adresse complète (par exemple : 192.168.0.1, ws://192.168.0.1:9090/jsonrpc, etc.)" }, "options_serverModeMulti_textcontent": { "message": "Configurer plusieurs serveurs" }, - "options_serverHosts_textcontent": { - "message": "Adresse IP" + "options_serverAddresses_textcontent": { + "message": "Adresse" }, "options_serverNames_textcontent": { "message": "Nom" @@ -225,7 +228,7 @@ "options_serverAdd_textcontent": { "message": "Ajouter un serveur" }, - "options_serverHost_placeholder": { + "options_serverAddress_placeholder": { "message": "192.168.0.1" }, "options_serverName_placeholder": { diff --git a/src/background/migrate.js b/src/background/migrate.js index a11d4fcf..035d8eaa 100644 --- a/src/background/migrate.js +++ b/src/background/migrate.js @@ -2,13 +2,52 @@ * @module */ -browser.storage.local.get().then((config) => { - if (!("config-version" in config)) { +browser.storage.local.get().then((current) => { + if ("config-version" in current) { + let config = current; + if (1 === config["config-version"]) { + const actions = Object.entries(config) + .filter(([k, v]) => k.startsWith("menus-") && v) + .map(([k]) => k.slice(6)) + .reverse(); + const contexts = Object.entries(config) + .filter(([k, v]) => k.startsWith("contexts-") && v) + .map(([k]) => k.slice(9)); + + config = { + "config-version": 2, + "server-mode": "single", + "server-list": [{ + host: config["connection-host"], + name: "", + }], + "server-active": 0, + "general-history": config["general-history"], + "menu-actions": actions, + "menu-contexts": contexts, + "youtube-playlist": config["youtube-playlist"], + }; + } + if (2 === config["config-version"]) { + const servers = config["server-list"].map((server) => ({ + address: server.host, + name: server.name, + })); + + config["config-version"] = 3; + config["server-list"] = servers; + } + + // Nettoyer la configuration pour garder seulement les propriétés + // nécessaire. + browser.storage.local.clear(); + browser.storage.local.set(config); + } else { browser.storage.local.clear(); browser.storage.local.set({ - "config-version": 2, + "config-version": 3, "server-mode": "single", - "server-list": [{ host: "", name: "" }], + "server-list": [{ address: "", name: "" }], "server-active": 0, "general-history": false, "menu-actions": ["send", "insert", "add"], @@ -17,42 +56,5 @@ browser.storage.local.get().then((config) => { ], "youtube-playlist": "playlist", }); - } else if (1 === config["config-version"]) { - const actions = Object.entries(config) - .filter(([k, v]) => k.startsWith("menus-") && v) - .map(([k]) => k.slice(6)) - .reverse(); - const contexts = Object.entries(config) - .filter(([k, v]) => k.startsWith("contexts-") && v) - .map(([k]) => k.slice(9)); - - browser.storage.local.clear(); - browser.storage.local.set({ - "config-version": 2, - "server-mode": "single", - "server-list": [{ - host: config["connection-host"], - name: "", - }], - "server-active": 0, - "general-history": config["general-history"], - "menu-actions": actions, - "menu-contexts": contexts, - "youtube-playlist": config["youtube-playlist"], - }); - } else { - // Nettoyer la configuration en gardant seulement les propriétés - // nécessaire. - browser.storage.local.clear(); - browser.storage.local.set({ - "config-version": config["config-version"], - "server-mode": config["server-mode"], - "server-list": config["server-list"], - "server-active": config["server-active"], - "general-history": config["general-history"], - "menu-actions": config["menu-actions"], - "menu-contexts": config["menu-contexts"], - "youtube-playlist": config["youtube-playlist"], - }); } }); diff --git a/src/core/jsonrpc/kodi.js b/src/core/jsonrpc/kodi.js index cda86759..f9781d6f 100644 --- a/src/core/jsonrpc/kodi.js +++ b/src/core/jsonrpc/kodi.js @@ -20,28 +20,60 @@ export const Kodi = class { /** * Vérifie la connexion à Kodi. * - * @param {string} host L'adresse IP (ou le nom de domaine) du serveur - * hébergeant Kodi. + * @param {string} address L'adresse IP ou l'adresse complète du service de + * Kodi. * @returns {Promise.} Une promesse tenue si Kodi est accessible ; * sinon une promesse rompue. */ - static async check(host) { - const kodi = new Kodi(host); + static async check(address) { + const kodi = new Kodi(address); const result = await kodi.send("JSONRPC.Version"); kodi.close(); return result; } + /** + * Construit une URL vers le service de Kodi. + * + * @param {string} address L'adresse IP ou l'adresse complête du service de + * Kodi. + * @returns {Promise.} Une promesse contenant l'URL. + */ + static build(address) { + if ("" === address) { + throw new PebkacError("unconfigured"); + } + let url; + try { + url = new URL(address); + } catch { + // Si la connexion avec l'adresse complète n'a pas fonctionnée : + // essayer avec l'adresse IP (en y ajoutant le protocol, le port et + // le chemin). + try { + url = new URL("ws://" + address + ":9090/jsonrpc"); + } catch { + throw new PebkacError("badAddress", address); + } + // Si l'URL est incorrecte (car l'adresse IP a été corrigée par le + // constructeur). + if (url.hostname !== address.toLowerCase()) { + throw new PebkacError("badAddress", address); + } + } + return url; + } + /** * Crée un client JSON-RPC pour contacter Kodi. * - * @param {?string} [host=null] L'adresse IP (ou le nom de domaine) du - * serveur hébergeant Kodi ; ou - * null pour récupérer l'adresse - * dans la configuration. + * @param {?string} [address=null] L'adresse IP ou l'adresse complète du + * service de Kodi ; ou null + * pour récupérer l'adresse dans la + * configuration. */ - constructor(host = null) { - this.host = host; + constructor(address = null) { + this.address = address; this.jsonrpc = null; this.application = new Application(this); @@ -70,30 +102,18 @@ export const Kodi = class { */ async send(method, params) { if (null === this.jsonrpc) { - let host; - if (null === this.host) { + let address; + if (null === this.address) { const config = await browser.storage.local.get([ "server-list", "server-active", ]); - host = config["server-list"][config["server-active"]].host; + address = config["server-list"][config["server-active"]] + .address; } else { - host = this.host; - } - if ("" === host) { - throw new PebkacError("unconfigured"); - } - let url; - try { - url = new URL("ws://" + host + ":9090/jsonrpc"); - } catch { - throw new PebkacError("badHost", host); - } - // Si l'URL est incorrecte (car le nom de domaine a été corrigé - // par le constructeur). - if (url.hostname !== host.toLowerCase()) { - throw new PebkacError("badHost", host); + address = this.address; } + const url = Kodi.build(address); try { this.jsonrpc = await JSONRPC.open(url); @@ -106,7 +126,7 @@ export const Kodi = class { this.playlist.handleNotification(event); }); } catch { - throw new PebkacError("notFound", host); + throw new PebkacError("notFound", address); } } diff --git a/src/options/img/help.svg b/src/options/img/help.svg new file mode 100644 index 00000000..62abdcc3 --- /dev/null +++ b/src/options/img/help.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/options/index.html b/src/options/index.html index 71613612..e44bebf1 100644 --- a/src/options/index.html +++ b/src/options/index.html @@ -19,10 +19,11 @@

-
@@ -35,7 +36,10 @@

- + @@ -53,8 +57,9 @@

+ {} +