Codage de la fièvre de la cabine : un didacticiel back-end Node.js

Publié: 2022-03-11

Le verrouillage du COVID-19 a bloqué beaucoup d'entre nous à la maison, espérant peut-être que la simple fièvre de la cabine est le pire type de fièvre que nous connaîtrons. Beaucoup d'entre nous consomment plus de contenu vidéo que jamais auparavant. Bien que l'exercice soit particulièrement important en ce moment, il y a parfois de la nostalgie pour le luxe d'une bonne télécommande à l'ancienne lorsque l'ordinateur portable est hors de portée.

C'est là qu'intervient ce projet : l'opportunité de transformer n'importe quel smartphone, même ancien et inutile faute de mises à jour, en une télécommande pratique pour le prochain Netflix/YouTube/Amazon Prime Video/etc. binge-watch. C'est aussi un tutoriel back-end Node.js : une chance d'apprendre les bases du JavaScript back-end en utilisant le framework Express et le moteur de template Pug (anciennement Jade).

Si cela semble intimidant, le projet Node.js complet sera présenté à la fin ; les lecteurs n'ont besoin d'apprendre qu'autant qu'ils sont intéressés à apprendre, et il y aura un bon nombre d'explications plus douces de certaines bases en cours de route que les lecteurs plus expérimentés peuvent ignorer.

Pourquoi pas juste... ?

Les lecteurs peuvent se demander : "Pourquoi se lancer dans le codage d'un back-end Node.js ?" (En dehors de l'opportunité d'apprentissage, bien sûr.) "N'y a-t-il pas déjà une application pour ça ?"

Bien sûr, beaucoup d'entre eux. Mais il y a deux raisons principales pour lesquelles cela peut ne pas être souhaitable :

  1. Pour ceux qui essaient de réutiliser un téléphone plus ancien, cela pourrait tout simplement ne plus être une option , comme c'est le cas avec l'appareil Windows Phone 8.1 que je voulais utiliser. (L'App Store a été officiellement fermé fin 2019.)
  2. Confiance (ou manque de confiance). Comme tant d'applications disponibles sur n'importe quelle plate-forme mobile, elles s'accompagnent souvent de l'obligation pour les utilisateurs d'accorder beaucoup plus d'autorisations que l'application n'en a besoin pour ce qu'elle est censée faire. Mais même si cet aspect est limité de manière appropriée, la nature d'une application de contrôle à distance signifie que les utilisateurs doivent toujours avoir confiance que les développeurs d'applications n'abusent pas de leurs privilèges sur le côté bureau de la solution en incluant des logiciels espions ou d'autres logiciels malveillants.

Ces problèmes existent depuis longtemps et ont même motivé un projet similaire de 2014 trouvé sur GitHub. nvm facilite l'installation d'anciennes versions de Node.js, et même si quelques dépendances nécessitaient une mise à niveau, Node.js avait la réputation d'être rétrocompatible.

Malheureusement, bitrot a gagné. Une approche obstinée et la compatibilité back-end de Node.js n'étaient pas à la hauteur des dépréciations sans fin et des boucles de dépendance impossibles parmi les anciennes versions de Grunt, Bower et des dizaines d'autres composants. Quelques heures plus tard, il était clair qu'il serait beaucoup plus facile de repartir de zéro, malgré les propres conseils de cet auteur contre la réinvention de la roue.

Nouveaux gadgets de l'ancien : réutiliser les téléphones comme télécommandes à l'aide d'un back-end Node.js

Tout d'abord, notez que ce projet Node.js est actuellement spécifique à Linux - développé et testé sur Linux Mint 19 et Linux Mint 19.3, en particulier - mais la prise en charge d'autres plates-formes pourrait certainement être ajoutée. Cela peut déjà fonctionner sur un Mac.

En supposant qu'une version moderne de Node.js est installée et qu'une invite de commande est ouverte dans un nouveau répertoire qui servira de racine du projet, nous sommes prêts à démarrer avec Express :

 npx express-generator --view=pug

Remarque : Ici, npx est un outil pratique fourni avec npm , le gestionnaire de packages Node.js fourni avec Node.js. Nous l'utilisons pour exécuter le générateur de squelette d'application d'Express. Au moment d'écrire ces lignes, le générateur crée un projet Express/Node.js qui, par défaut, utilise toujours un moteur de modèle appelé Jade, même si le projet Jade s'est renommé "Pug" à partir de la version 2.0. Donc, pour être à jour et utiliser Pug immédiatement - en plus, éviter les avertissements de dépréciation - nous --view=pug , une option de ligne de commande pour le script express-generator exécuté par npx .

Une fois cela fait, nous devons installer certains packages à partir de la liste de dépendances nouvellement remplie de notre projet Node.js dans package.json . La manière traditionnelle de le faire est d'exécuter npm i ( i pour "installer"). Mais certains préfèrent toujours la vitesse de Yarn, donc si vous l'avez installé, exécutez simplement yarn sans paramètres.

Dans ce cas, il devrait être prudent d'ignorer l'avertissement de dépréciation (espérons-le bientôt corrigé) de l'une des sous-dépendances de Pug, tant que l'accès est limité au besoin sur le réseau local.

Un démarrage rapide yarn start ou npm start , suivi d'une navigation vers localhost:3000 dans un navigateur, montre que notre back-end Node.js de base basé sur Express fonctionne. Nous pouvons le tuer avec Ctrl+C .

Node.js Back-end Tutorial, Étape 2 : Comment envoyer des frappes sur la machine hôte

La partie télécommande étant déjà à mi-chemin, tournons notre attention vers la partie contrôle . Nous avons besoin de quelque chose qui puisse contrôler par programmation la machine sur laquelle nous exécuterons notre back-end Node.js, en prétendant qu'il appuie sur les touches du clavier.

Pour cela, nous allons installer xdotool en utilisant ses instructions officielles. Un test rapide de leur exemple de commande dans un terminal :

 xdotool search "Mozilla Firefox" windowactivate --sync key --clearmodifiers ctrl+l

… devrait faire exactement ce qu'il dit, en supposant que Mozilla Firefox est ouvert à ce moment-là. C'est bien! Il est facile de faire en sorte que notre projet Node.js appelle des outils de ligne de commande comme xdotool , comme nous le verrons bientôt.

Tutoriel back-end Node.js, étape 3 : conception des fonctionnalités

Ce n'est peut-être pas vrai pour tout le monde, mais personnellement, je trouve que de nombreuses télécommandes physiques modernes ont environ cinq fois plus de boutons que je n'en utiliserai jamais. Donc, pour ce projet, nous envisageons une mise en page plein écran avec une grille trois par trois de jolis gros boutons faciles à cibler. La nature de ces neuf boutons dépend de vos préférences personnelles.

Il s'avère que les raccourcis clavier, même pour les fonctions les plus simples, ne sont pas identiques sur Netflix, YouTube et Amazon Prime Video. Ces services ne fonctionnent pas non plus avec des clés multimédias génériques comme le ferait probablement une application de lecteur de musique native. De plus, certaines fonctions peuvent ne pas être disponibles avec tous les services.

Nous devrons donc définir une disposition de télécommande différente pour chaque service et fournir un moyen de basculer entre eux.

Définir les dispositions de la télécommande et les mapper aux raccourcis clavier

Prenons un prototype rapide fonctionnant avec une poignée de préréglages. Nous les mettrons dans common/preset_commands.js — "common" car nous inclurons ces données à partir de plusieurs fichiers :

 module.exports = { // We could use ️ but some older phones (eg, Android 5.1.1) won't show it, hence ️ instead 'Netflix': { commands: { '-': 'Escape', '+': 'f', '': 'Up', '⇤': 'XF86Back', '️': 'Return', '': 'Down', '': 'Left', '': 'Right', '': 'm', }, }, 'YouTube': { commands: { '⇤': 'shift+p', '⇥': 'shift+n', '': 'Up', 'CC': 'c', '️': 'k', '': 'Down', '': 'j', '': 'l', '': 'm', }, }, 'Amazon Prime Video': { window_name_override: 'Prime Video', commands: { '⇤': 'Escape', '+': 'f', '': 'Up', 'CC': 'c', '️': 'space', '': 'Down', '': 'Left', '': 'Right', '': 'm', }, }, 'Generic / Music Player': { window_name_override: '', commands: { '⇤': 'XF86AudioPrev', '⇥': 'XF86AudioNext', '': 'XF86AudioRaiseVolume', '': 'r', '️': 'XF86AudioPlay', '': 'XF86AudioLowerVolume', '': 'Left', '': 'Right', '': 'XF86AudioMute', }, }, };

Les valeurs de code clé peuvent être trouvées en utilisant xev . (Pour moi, les touches "muet audio" et "lecture audio" n'étaient pas détectables avec cette méthode, j'ai donc également consulté une liste de touches multimédias.)

Les lecteurs peuvent remarquer la différence de casse entre space et le Return - quelle qu'en soit la raison, ce détail doit être respecté pour que xdotool fonctionne correctement. En rapport avec cela, nous avons quelques définitions écrites explicitement - par exemple, shift+p même si P fonctionnerait également - juste pour garder nos intentions claires.

Tutoriel back-end Node.js, étape 4 : Point de terminaison « clé » de notre API (Pardon the Pun)

Nous aurons besoin d'un point de terminaison à POST , qui simulera à son tour les frappes au clavier à l'aide xdotool . Étant donné que nous aurons différents groupes de clés que nous pourrons envoyer (un pour chaque service), nous appellerons le point de terminaison pour un group particulier. Nous allons réutiliser le point de terminaison des users générés en renommant routes/users.js en routes/group.js et en apportant les modifications correspondantes dans app.js :

 // ... var indexRouter = require('./routes/index'); var groupRouter = require('./routes/group'); // ... app.use('/', indexRouter); app.use('/group', groupRouter); // ...

La fonctionnalité clé utilise xdotool via un appel de shell système dans routes/group.js . Nous allons coder en dur YouTube comme menu de choix pour le moment, uniquement à des fins de test.

 const express = require('express'); const router = express.Router(); const debug = require('debug')('app'); const cp = require('child_process'); const preset_commands = require('../common/preset_commands'); /* POST keystroke to simulate */ router.post('/', function(req, res, next) { const keystroke_name = req.body.keystroke_name; const keystroke_code = preset_commands['YouTube'].commands[keystroke_name]; const final_command = `xdotool \ search "YouTube" \ windowactivate --sync \ key --clearmodifiers ${keystroke_code}`; debug(`Executing ${final_command}`); cp.exec(final_command, (err, stdout, stderr) => { debug(`Executed ${keystroke_name}`); return res.redirect(req.originalUrl); }); }); module.exports = router;

Ici, nous récupérons la clé demandée "name" dans le corps de la requête POST ( req.body ) sous le paramètre nommé keystroke_name . Ce sera quelque chose comme . Nous l'utilisons ensuite pour rechercher le code correspondant à partir de l'objet de commands de preset_commands['YouTube'] .

La commande finale est sur plus d'une ligne, donc le \ s à la fin de chaque ligne joint tous les morceaux en une seule commande :

  • search "YouTube" récupère la première fenêtre avec "YouTube" dans le titre.
  • windowactivate --sync active la fenêtre récupérée et attend qu'elle soit prête à recevoir une frappe.
  • key --clearmodifiers ${keystroke_code} envoie la frappe, en veillant à effacer temporairement les touches de modification comme Caps Lock qui peuvent interférer avec ce que nous envoyons.

À ce stade, le code suppose que nous lui fournissons une entrée valide, ce à quoi nous ferons plus attention plus tard.

Pour plus de simplicité, le code supposera également qu'il n'y a qu'une seule fenêtre d'application ouverte avec "YouTube" dans son titre. S'il y a plus d'une correspondance, il n'y a aucune garantie que nous enverrons des frappes à la fenêtre prévue. Si c'est un problème, il peut être utile que les titres des fenêtres puissent être modifiés simplement en changeant les onglets du navigateur sur toutes les fenêtres en plus de celle à contrôler à distance.

Avec cela prêt, nous pouvons redémarrer notre serveur, mais cette fois avec le débogage activé afin que nous puissions voir la sortie de nos appels de debug . Pour ce faire, exécutez simplement DEBUG=old-fashioned-remote:* yarn start ou DEBUG=old-fashioned-remote:* npm start . Une fois qu'il est en cours d'exécution, lisez une vidéo sur YouTube, ouvrez une autre fenêtre de terminal et essayez un appel cURL :

 curl --data "keystroke_name=️" http://localhost:3000/group

Cela envoie une requête POST avec le nom de frappe demandé dans son corps à notre machine locale sur le port 3000 , le port sur lequel notre serveur principal écoute. L'exécution de cette commande devrait générer des notes sur l' Executing et l' Executed dans la fenêtre npm et, plus important encore, afficher le navigateur et mettre sa vidéo en pause. L'exécution à nouveau de cette commande devrait donner la même sortie et la réactiver.

Tutoriel back-end Node.js, étape 5 : Dispositions de contrôle à distance multiples

Notre arrière-plan n'est pas tout à fait terminé. Nous en aurons également besoin pour pouvoir :

  1. Produisez une liste de dispositions de télécommande à partir de preset_commands .
  2. Produire une liste de "noms" de frappe à partir d'une fois que nous avons choisi une disposition de télécommande particulière. (Nous aurions également pu choisir d'utiliser common/preset_commands.js directement sur le front-end, puisqu'il s'agit déjà de JavaScript, et filtré là-bas. C'est l'un des avantages potentiels d'un back-end Node.js, nous ne l'utilisons tout simplement pas ici .)

Ces deux fonctionnalités sont là où notre didacticiel back-end Node.js croise le front-end basé sur Pug que nous allons construire.

Utilisation de modèles de carlin pour présenter une liste de télécommandes

La partie principale de l'équation consiste à modifier routes/index.js pour qu'il ressemble à ceci :

 const express = require('express'); const router = express.Router(); const preset_commands = require('../common/preset_commands'); /* GET home page. */ router.get('/', function(req, res, next) { const group_names = Object.keys(preset_commands); res.render('index', { title: 'Which Remote?', group_names, portrait_css: `.group_bar { height: calc(100%/${Math.min(4, group_names.length)}); line-height: calc(100vh/${Math.min(4, group_names.length)}); }`, landscape_css: `.group_bar { height: calc(100%/${Math.min(2, group_names.length)}); line-height: calc(100vh/${Math.min(2, group_names.length)}); }`, }); }); module.exports = router;

Ici, nous récupérons nos noms de disposition de contrôle à distance ( group_names ) en appelant Object.keys sur notre fichier preset_commands . Nous les envoyons ensuite, ainsi que d'autres données dont nous aurons besoin, au moteur de modèle Pug qui est automatiquement appelé via res.render() .

Attention à ne pas confondre la signification des keys ici avec les touches que nous envoyons : Object.keys Object.keys donne un tableau (une liste ordonnée) contenant toutes les clés des paires clé-valeur qui composent un objet en JavaScript :

 const my_object = { 'a key' : 'its corresponding value' , 'another key' : 'its separate corresponding value' , };

Si nous regardons common/preset_commands.js , nous verrons le modèle ci-dessus, et nos clés (au sens objet) sont les noms de nos groupes : 'Netflix' , 'YouTube' , etc. Leurs valeurs correspondantes ne sont pas des chaînes simples comme my_object a ci-dessus - ce sont des objets entiers eux-mêmes, avec leurs propres clés, c'est-à-dire commands et éventuellement window_name_override .

Le CSS personnalisé passé ici est, certes, un peu un hack. La raison pour laquelle nous en avons besoin au lieu d'utiliser une solution moderne basée sur flexbox est pour une meilleure compatibilité avec le monde merveilleux des navigateurs mobiles dans leurs incarnations plus anciennes encore plus merveilleuses. Dans ce cas, la principale chose à noter est qu'en mode paysage, nous gardons les boutons grands en n'affichant pas plus de deux options par écran ; en mode portrait, quatre.

Mais où cela est-il réellement transformé en HTML pour être envoyé au navigateur ? C'est là views/index.pug , que nous voudrons ressembler à ceci :

 extends layout block header_injection style(media='(orientation: portrait)') #{portrait_css} style(media='(orientation: landscape)') #{landscape_css} block content each group_name in group_names span(class="group_bar") a(href='/group/?group_name=' + group_name) #{group_name}

La toute première ligne est importante : extends layout signifie que Pug prendra ce fichier dans le contexte de views/layout.pug , qui est une sorte de modèle parent que nous réutiliserons ici et aussi dans une autre vue. Nous devrons ajouter quelques lignes après la ligne de link pour que le fichier final ressemble à ceci :

 doctype html html head title= title link(rel='stylesheet', href='/stylesheets/style.css') block header_injection meta(name='viewport', content='user-scalable=no') body block content

Nous n'entrerons pas dans les bases du HTML ici, mais pour les lecteurs qui ne les connaissent pas, ce code Pug reflète le code HTML standard que l'on trouve un peu partout. L'aspect de la modélisation commence par title= title , qui définit le titre HTML sur la valeur correspondant à la clé de title de l'objet que nous passons à Pug via res.render .

Nous pouvons voir un aspect différent de la modélisation deux lignes plus tard avec un block que nous header_injection . Les blocs comme ceux-ci sont des espaces réservés qui peuvent être remplacés par des modèles qui étendent l'actuel. (Sans rapport, la ligne meta est simplement une solution de contournement rapide pour les navigateurs mobiles, donc lorsque les utilisateurs appuient sur les commandes de volume plusieurs fois de suite, le téléphone s'abstient de zoomer ou dézoomer.)

Revenons à nos block : C'est pourquoi views/index.pug définit ses propres block avec les mêmes noms trouvés dans views/layout.pug . Dans ce cas de header_injection , cela nous permet d'utiliser des CSS spécifiques aux orientations portrait ou paysage dans lesquelles le téléphone se trouvera.

content est l'endroit où nous plaçons la principale partie visible de la page Web, qui dans ce cas :

  1. Boucle à travers le tableau group_names que nous lui passons,
  2. crée un élément <span> pour chacun avec la classe CSS group_bar qui lui est appliquée, et
  3. crée un lien dans chaque <span> basé sur le group_name .

La classe CSS group_bar que nous pouvons définir dans le fichier extrait via views/layout.pug , à savoir public/stylesheets/style.css :

 html, body, form { padding: 0; margin: 0; height: 100%; font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; } .group_bar, .group_bar a, .remote_button { box-sizing: border-box; border: 1px solid white; color: greenyellow; background-color: black; } .group_bar { width: 100%; font-size: 6vh; text-align: center; display: inline-block; } .group_bar a { text-decoration: none; display: block; }

À ce stade, si npm start est toujours en cours d'exécution, accéder à http://localhost:3000/ dans un navigateur de bureau devrait afficher deux très gros boutons pour Netflix et YouTube, le reste étant disponible en faisant défiler vers le bas.

Un test du sélecteur de disposition de la télécommande à l'aide d'un navigateur de bureau, montrant deux très gros boutons pour Netflix et YouTube.

Mais si nous cliquons dessus à ce stade, ils ne fonctionneront pas, car nous n'avons pas encore défini la route vers laquelle ils se lient (le GET ting de /group .)

Affichage de la disposition de la télécommande choisie

Pour ce faire, nous ajouterons ceci à routes/group.js juste avant la dernière ligne module.exports :

 router.get('/', function(req, res, next) { const group_name = req.query.group_name || ''; const group = preset_commands[group_name]; return res.render('group', { keystroke_names: Object.keys(group.commands), group_name, title: `${group_name.match(/([AZ])/g).join('')}-Remote` }); });

Cela obtiendra le nom du groupe envoyé au point de terminaison (par exemple, en mettant ?group_name=Netflix à la fin de /group/ ), et l'utilisera pour obtenir la valeur des commands du groupe correspondant. Cette valeur ( group.commands ) est un objet, et les clés de cet objet sont les noms ( keystroke_names ) que nous afficherons sur notre disposition de contrôle à distance.

Remarque : les développeurs inexpérimentés n'auront pas besoin d'entrer dans les détails de son fonctionnement, mais la valeur du title utilise un peu d'expressions régulières pour transformer nos noms de groupe/mise en page en acronymes. Par exemple, notre télécommande YouTube aura le titre du navigateur. YT-Remote . De cette façon, si nous déboguons sur notre machine hôte avant d'essayer des choses sur un téléphone, nous n'aurons pas xdotool saisissant la fenêtre du navigateur de contrôle à distance elle-même, au lieu de celle que nous essayons de contrôler. Pendant ce temps, sur nos téléphones, le titre sera agréable et court, si nous voulons marquer la télécommande.

Comme lors de notre précédente rencontre avec res.render , celui-ci envoie ses données pour se mêler au modèle views/group.pug . Nous allons créer ce fichier et le remplir avec ceci :

 extends layout block header_injection script(type='text/javascript', src='/javascript/group-client.js') block content form(action="/group?group_name=" + group_name, method="post") each keystroke_name in keystroke_names input(type="submit", name="keystroke_name", value=keystroke_name, class="remote_button")

Comme pour views/index.pug , nous remplaçons les deux blogs de views/layout.pug . Cette fois, ce n'est pas du CSS que nous mettons dans l'en-tête, mais du JavaScript côté client, sur lequel nous reviendrons sous peu. (Et oui, dans un moment de perspicacité, j'ai renommé les javascripts mal pluralisés...)

Le content principal ici est un formulaire HTML composé d'un ensemble de différents boutons de soumission, un pour chaque keystroke_name . Chaque bouton soumet le formulaire (en faisant une requête POST ) en utilisant le nom de frappe qu'il affiche comme valeur qu'il envoie avec le formulaire.

Nous aurons également besoin d'un peu plus de CSS dans notre fichier de feuille de style principal :

 .remote_button { float: left; width: calc(100%/3); height: calc(100%/3); font-size: 12vh; }

Plus tôt, lorsque nous avons configuré le point de terminaison, nous avons fini de traiter la demande avec :

 return res.redirect(req.originalUrl);

Cela signifie effectivement que lorsque le navigateur soumet le formulaire, le back-end Node.js répond en disant au navigateur de revenir à la page à partir de laquelle le formulaire a été soumis, c'est-à-dire la disposition principale de la télécommande. Ce serait plus élégant sans changer de page ; cependant, nous voulons une compatibilité maximale avec le monde étrange et merveilleux des navigateurs mobiles décrépits. De cette façon, même sans qu'aucun JavaScript frontal ne fonctionne, notre projet back-end Node.js devrait toujours fonctionner.

Un soupçon de JavaScript frontal

L'inconvénient d'utiliser un formulaire pour soumettre des frappes au clavier est que le navigateur doit attendre, puis exécuter un aller-retour supplémentaire : la page et ses dépendances doivent ensuite être demandées à notre back-end Node.js et livrées. Ensuite, ils doivent être rendus à nouveau par le navigateur.

Les lecteurs pourraient se demander quel effet cela pourrait avoir. Après tout, la page est minuscule, ses dépendances sont extrêmement minimes et notre projet Node.js final s'exécutera sur une connexion wifi locale. Cela devrait être une configuration à faible latence, non ?

En fin de compte, du moins lors des tests sur des smartphones plus anciens exécutant Windows Phone 8.1 et Android 4.4.2, l'effet est malheureusement assez perceptible dans le cas courant d'un appui rapide pour augmenter ou diminuer le volume de lecture de quelques crans. C'est là que JavaScript peut vous aider, sans vous priver de notre recours gracieux aux POST manuels via des formulaires HTML.

À ce stade, notre client JavaScript final (à placer dans public/javascript/group-client.js ) doit être compatible avec les anciens navigateurs mobiles qui ne sont plus pris en charge. Mais nous n'en avons pas besoin de beaucoup :

 (function () { function form_submit(event) { var request = new XMLHttpRequest(); request.open('POST', window.location.pathname + window.location.search, true); request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); request.send('keystroke_name=' + encodeURIComponent(event.target.value)); event.preventDefault(); } window.addEventListener("DOMContentLoaded", function() { var inputs = document.querySelectorAll("input"); for (var i = 0; i < inputs.length; i++) { inputs[i].addEventListener("click", form_submit); } }); })();

Ici, la fonction form_submit envoie simplement les données via un appel asynchrone, et la dernière ligne empêche le comportement d'envoi normal des navigateurs, par lequel une nouvelle page se charge en fonction de la réponse du serveur. La seconde moitié de cet extrait attend simplement que la page se charge, puis connecte chaque bouton d'envoi pour utiliser form_submit . Le tout est emballé dans un IIFE.

Touches finales

Il y a un certain nombre de modifications apportées aux extraits ci-dessus dans la version finale de notre code de didacticiel back-end Node.js, principalement dans le but d'améliorer la gestion des erreurs :

  • Le back-end Node.js vérifie maintenant les noms des groupes et les frappes qui lui sont envoyées pour s'assurer qu'ils existent. Ce code se trouve dans une fonction qui est réutilisée pour les fonctions GET et POST de routes/group.js .
  • Nous utilisons le modèle error Pug si ce n'est pas le cas.
  • Le JavaScript et le CSS frontaux créent désormais des boutons temporairement en gris en attendant une réponse du serveur, en vert dès que le signal est passé par xdotool et retour sans problème, et en rouge si quelque chose n'a pas fonctionné comme prévu .
  • Le back-end Node.js imprimera une trace de pile s'il meurt, ce qui sera moins probable compte tenu de ce qui précède.

Les lecteurs sont invités à parcourir (et/ou cloner) le projet Node.js complet sur GitHub.

Tutoriel back-end Node.js, étape 5 : un test en situation réelle

Il est temps de l'essayer sur un téléphone réel connecté au même réseau wifi que l'hôte qui exécute npm start et un lecteur de film ou de musique. Il s'agit simplement de faire pointer le navigateur Web d'un smartphone vers l'adresse IP locale de l'hôte (avec :3000 en suffixe), ce qui est probablement le plus facile à trouver en exécutant hostname -I | awk '{print $1}' hostname -I | awk '{print $1}' dans un terminal sur l'hôte.

Un problème que les utilisateurs de Windows Phone 8.1 pourraient remarquer est que tenter de naviguer vers quelque chose comme 192.168.2.5:3000 donnera une fenêtre d'erreur :

Une capture d'écran d'un message d'erreur Windows Phone intitulé "Adresse non prise en charge", indiquant "Internet Explorer Mobile ne prend pas en charge ce type d'adresse et ne peut pas afficher cette page.

Heureusement, il n'y a pas lieu de se décourager : il suffit de préfixer http:// ou d'ajouter un / à la fin pour récupérer l'adresse sans autre plainte.

L'écran de sélection de la disposition de la télécommande.

Choisir une option là-bas devrait nous amener à une télécommande fonctionnelle.

L'écran de télécommande "Generic/Music Player".

Pour plus de commodité, les utilisateurs peuvent souhaiter ajuster les paramètres DHCP de leur routeur pour toujours attribuer la même adresse IP à l'hôte et mettre en signet l'écran de sélection de disposition et/ou toutes les dispositions préférées.

Bienvenue aux demandes d'extraction

Il est probable que tout le monde n'aimera pas ce projet tel qu'il est. Voici quelques idées d'améliorations, pour ceux qui souhaitent approfondir le code :

  • Il devrait être simple de modifier les mises en page ou d'en ajouter de nouvelles pour d'autres services, comme Disney Plus.
  • Peut-être que certains préféreraient une disposition en «mode lumière» et la possibilité de basculer entre les deux.
  • Se retirer de Netflix, puisqu'il est irréversible, pourrait vraiment utiliser un "êtes-vous sûr?" confirmation en quelque sorte.
  • Le projet bénéficierait sûrement du support de Windows.
  • La documentation de xdotool mentionne OSX - ce projet (ou pourrait-il) fonctionner sur un Mac moderne?
  • Pour une détente avancée, un moyen de rechercher et de parcourir des films, au lieu d'avoir à choisir un seul film Netflix/Amazon Prime Video ou à créer une liste de lecture YouTube sur l'ordinateur.
  • Une suite de tests automatisés, au cas où l'une des modifications suggérées casserait la fonctionnalité d'origine.

J'espère que vous avez apprécié ce didacticiel back-end Node.js et une expérience multimédia améliorée en conséquence. Bonne diffusion et codage !

En relation : Création d'une API REST Node.js/TypeScript, Partie 1 : Express.js