キャビンフィーバーコーディング:Node.jsバックエンドチュートリアル

公開: 2022-03-11

COVID-19の封鎖により、私たちの多くは家に閉じ込められました。おそらく、単なるキャビン熱が私たちが経験する最悪の種類の熱であることを望んでいます。 私たちの多くは、これまで以上に多くのビデオコンテンツを消費しています。 現在、運動は特に重要ですが、ラップトップが手が届きにくいときに、古き良きリモコンの豪華さに懐かしさを感じることもあります。

そこで、このプロジェクトが登場します。更新がないために役に立たない古いスマートフォンであっても、次のNetflix / YouTube / AmazonPrimeVideoなどの便利なリモコンに変換する機会です。 一気見。 これはNode.jsバックエンドチュートリアルでもあります。ExpressフレームワークとPug(以前のJade)テンプレートエンジンを使用してバックエンドJavaScriptの基本を学ぶチャンスです。

それが気が遠くなるように聞こえる場合は、完全なNode.jsプロジェクトが最後に表示されます。 読者は、学習に興味がある分だけ学ぶ必要があり、経験豊富な読者がスキップできるように、いくつかの基本についてかなりの数の穏やかな説明があります。

なぜだけではないのですか...?

読者は、「なぜNode.jsバックエンドのコーディングに取り掛かるのか」と疑問に思うかもしれません。 (もちろん、学習の機会は別として。)「そのためのアプリはもうありませんか?」

確かに、それらはたくさんあります。 しかし、これが望ましくない可能性がある主な理由は2つあります。

  1. 古い電話を転用しようとしている人にとっては、私が使用したかったWindows Phone 8.1デバイスの場合のように、これはもはやオプションではないかもしれません。 (アプリストアは2019年後半に正式に閉鎖されました。)
  2. 信頼(またはその欠如)。 多くのモバイルプラットフォームで見られる多くのアプリと同様に、多くの場合、ユーザーは、アプリが意図することに対して必要とするよりもはるかに多くの権限を付与する必要があります。 ただし、この側面が適切に制限されている場合でも、リモートコントロールアプリの性質上、ユーザーは、アプリ開発者がスパイウェアやその他のマルウェアを含めてソリューションのデスクトップ側で特権を悪用していないことを信頼する必要があります。

これらの問題は長い間存在しており、GitHubで見つかった2014年の同様のプロジェクトの動機にもなりました。 nvmを使用すると、古いバージョンのNode.jsを簡単にインストールできます。また、いくつかの依存関係をアップグレードする必要がある場合でも、Node.jsは下位互換性があることで高い評価を得ています。

残念ながら、bitrotが勝ちました。 頑固なアプローチとNode.jsバックエンドの互換性は、Grunt、Bower、およびその他の数十のコンポーネントの古いバージョン間での無限の非推奨と不可能な依存関係ループに匹敵しませんでした。 数時間後、最初から始める方がはるかに簡単であることは明らかではありませんでした。それにもかかわらず、車輪の再発明に対するこの著者自身のアドバイスです。

古いものからの新しいギズモ:Node.jsバックエンドを使用したリモートコントロールとしての電話の転用

まず、このNode.jsプロジェクトは現在Linuxに固有であり、特にLinuxMint19とLinuxMint19.3で開発およびテストされていますが、他のプラットフォームのサポートも確実に追加される可能性があることに注意してください。 すでにMacで動作する可能性があります。

最新バージョンのNode.jsがインストールされ、プロジェクトルートとして機能する新しいディレクトリでコマンドプロンプトが開いていると仮定すると、Expressを開始する準備が整います。

 npx express-generator --view=pug

注:ここで、 npxは、Node.jsに付属するNode.jsパッケージマネージャーであるnpmに付属する便利なツールです。 Expressのアプリケーションスケルトンジェネレーターを実行するために使用しています。 この記事の執筆時点で、ジェネレーターはExpress / Node.jsプロジェクトを作成します。このプロジェクトは、バージョン2.0以降でJadeプロジェクトの名前が「Pug」に変更された場合でも、デフォルトでJadeと呼ばれるテンプレートエンジンを取り込みます。 したがって、最新の状態でPugをすぐに使用するために、さらに非推奨の警告を回避するために、 npxによって実行されるexpress-generatorスクリプトのコマンドラインオプションである--view=pugに取り組みます。

それが完了したら、 package.jsonにあるNode.jsプロジェクトの新しく入力された依存関係リストからいくつかのパッケージをインストールする必要があります。 これを行う従来の方法は、 npm i i 「インストール」を表すi)を実行することです。 ただし、Yarnの速度を好む人もいるため、Yarnをインストールしている場合は、パラメーターなしでyarnを実行するだけです。

この場合、ローカルネットワーク上で必要に応じてアクセスが維持される限り、Pugのサブ依存関係の1つからの(できれば間もなく修正される)非推奨の警告を無視しても安全です。

クイックyarn startまたはnpm startに続いて、ブラウザーでlocalhost:3000に移動すると、基本的なExpressベースのNode.jsバックエンドが機能することがわかります。 Ctrl+Cで殺すことができます。

Node.jsバックエンドチュートリアル、ステップ2:ホストマシンでキーストロークを送信する方法

リモート部分が半分終わったところで、コントロール部分に注目しましょう。 Node.jsバックエンドを実行するマシンをプログラムで制御し、キーボードのキーを押しているふりをすることができるものが必要です。

そのために、公式の手順を使用してxdotoolをインストールします。 ターミナルでのコマンド例の簡単なテスト:

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

…MozillaFirefoxがその時点で開いていると仮定すると、それが言っていることを正確に実行する必要があります。 それは良い! すぐにわかるように、Node.jsプロジェクトでxdotoolなどのコマンドラインツールを呼び出すのは簡単です。

Node.jsバックエンドチュートリアル、ステップ3:機能の設計

これはすべての人に当てはまるわけではありませんが、個人的には、最近の多くの物理的なリモコンには、これまでに使用するボタンの約5倍のボタンがあります。 そのため、このプロジェクトでは、3 x 3のグリッドがあり、大きくてターゲットが簡単なボタンを備えたフルスクリーンレイアウトを検討しています。 これらの9つのボタンが何であるかは個人の好み次第です。

最も単純な機能のキーボードショートカットでさえ、Netflix、YouTube、AmazonPrimeVideoで同じではないことがわかりました。 また、これらのサービスは、ネイティブの音楽プレーヤーアプリのように一般的なメディアキーでは機能しません。 また、一部の機能がすべてのサービスで利用できるとは限りません。

したがって、必要なのは、サービスごとに異なるリモートコントロールのレイアウトを定義し、それらを切り替える方法を提供することです。

リモートコントロールレイアウトの定義とキーボードショートカットへのマッピング

いくつかのプリセットを使用して、簡単なプロトタイプを作成してみましょう。 これらをcommon/preset_commands.js —「common」に配置します。これは、複数のファイルからのこのデータを含めるためです。

 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', }, }, };

キーコード値は、 xevを使用して見つけることができます。 (私にとって、「オーディオミュート」と「オーディオ再生」はこの方法では検出できなかったので、メディアキーのリストも調べました。)

読者は、 spaceReturnの大文字と小文字の違いに気付く場合があります。この理由に関係なく、 xdotoolが正しく機能するには、この詳細を尊重する必要があります。 これに関連して、意図を明確にするために、明示的に記述されたいくつかの定義があります。たとえば、 Pも機能しますがshift+pです。

Node.jsバックエンドチュートリアル、ステップ4:APIの「キー」エンドポイント(駄洒落を許してください)

POSTするエンドポイントが必要です。これにより、 xdotoolを使用してキーストロークがシミュレートされます。 送信できるキーのグループが異なるため(サービスごとに1つ)、特定の1つのgroupのエンドポイントを呼び出します。 生成されたusersエンドポイントを、 routes/users.jsの名前をroutes/group.jsに変更し、 app.jsに対応する変更を加えることで再利用します。

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

機能は、 routes/group.jsのシステムシェル呼び出しを介してxdotoolを使用することです。 テストの目的で、当面はYouTubeを選択メニューとしてハードコーディングします。

 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;

ここでは、keystroke_nameという名前のパラメーターの下で、 POSTリクエストの本文( req.body )からリクエストされたkeystroke_name 「name」を取得します。 それはのようなものになります。 次に、それを使用して、 preset_commands['YouTube']commandsオブジェクトから対応するコードを検索します。

最後のコマンドは複数の行にあるため、各行の最後にある\ sは、すべての部分を1つのコマンドに結合します。

  • search "YouTube" 」は、タイトルに「YouTube」が含まれる最初のウィンドウを取得します。
  • windowactivate --syncは、フェッチされたウィンドウをアクティブ化し、キーストロークを受信する準備ができるまで待機します。
  • key --clearmodifiers ${keystroke_code}はキーストロークを送信し、送信内容に干渉する可能性のあるCapsLockなどの修飾キーを一時的にクリアするようにします。

この時点で、コードは有効な入力を供給していることを前提としています。これについては後でさらに注意します。

簡単にするために、コードでは、タイトルに「YouTube」が含まれるアプリケーションウィンドウが1つだけ開いていると想定しています。一致するものが複数ある場合、目的のウィンドウにキーストロークを送信する保証はありません。 それが問題になる場合は、リモート制御するウィンドウ以外のすべてのウィンドウのブラウザタブを切り替えるだけで、ウィンドウのタイトルを変更できると便利な場合があります。

これでサーバーを再起動できますが、今回はデバッグを有効にして、 debug呼び出しの出力を確認できるようにします。 これを行うには、 DEBUG=old-fashioned-remote:* yarn startまたはDEBUG=old-fashioned-remote:* npm start実行するだけです。 実行されたら、YouTubeでビデオを再生し、別のターミナルウィンドウを開いて、cURL呼び出しを試してください。

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

これにより、要求されたキーストローク名を本体に含むPOSTリクエストが、バックエンドがリッスンしているポート3000のローカルマシンに送信されます。 そのコマンドを実行すると、 ExecutingExecutedに関するメモがnpmウィンドウに出力され、さらに重要なことに、ブラウザーが起動してビデオが一時停止します。 そのコマンドを再度実行すると、同じ出力が得られ、一時停止を解除する必要があります。

Node.jsバックエンドチュートリアル、ステップ5:複数のリモートコントロールレイアウト

私たちのバックエンドは完全には完了していません。 また、次のことができるようにする必要があります。

  1. preset_commandsからリモートコントロールレイアウトのリストを作成します。
  2. 特定のリモコンのレイアウトを選択したら、キーストロークの「名前」のリストを作成します。 (フロントエンドでcommon/preset_commands.jsを直接使用することもできます。これは、すでにJavaScriptであり、そこでフィルタリングされているためです。これは、Node.jsバックエンドの潜在的な利点の1つであり、ここでは使用しません。 。)

これらの機能は両方とも、Node.jsバックエンドチュートリアルが、構築するPugベースのフロントエンドと交差する場所です。

パグテンプレートを使用してリモコンのリストを表示する

方程式のバックエンド部分は、 routes/index.jsを次のように変更することを意味します。

 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;

ここでは、 preset_commandsファイルでObject.keysを呼び出して、リモートコントロールのレイアウト名( group_names )を取得します。 次に、それらと必要なその他のデータを、 res.render()を介して自動的に呼び出されるPugテンプレートエンジンに送信します。

ここでのkeysの意味と送信するキーストロークを混同しないように注意してくださいObject.keysは、JavaScriptでオブジェクトを構成するキーと値のペアのすべてのキーを含む配列(順序付きリスト)を提供します。

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

common/preset_commands.jsを見ると、上記のパターンがわかります。キー(オブジェクトの意味で)は、グループの名前です: 'Netflix''YouTube'など。対応する値はそうではありません。 my_objectが上に示したような単純な文字列—それらはオブジェクト全体であり、独自のキー、つまりcommandsと、場合によってwindow_name_overrideを備えています。

ここで渡されるカスタムCSSは、確かに、ちょっとしたハックです。 最新のフレックスボックスベースのソリューションを使用する代わりにそれが必要な理由は、さらに素晴らしい古い化身のモバイルブラウザの素晴らしい世界との互換性を高めるためです。 この場合、注意すべき主な点は、横向きモードでは、画面全体に2つ以下のオプションを表示することで、ボタンを大きく維持していることです。 ポートレートモードでは、4つ。

しかし、それは実際にどこでHTMLに変換され、ブラウザーに送信されるのでしょうか。 そこで、 views/index.pugが登場します。これは、次のようになります。

 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}

最初の行は重要ですextends layoutは、Pugがviews/layout.pugのコンテキストでこのファイルを取得することを意味します。これは、ここおよび別のビューで再利用する一種の親テンプレートです。 最終的なファイルが次のようになるように、 link行の後に数行追加する必要があります。

 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

ここではHTMLの基本については説明しませんが、HTMLに慣れていない読者のために、このPugコードは、ほぼすべての場所で見られる標準料金のHTMLコードを反映しています。 テンプレートの側面はtitle= titleで始まります。これは、HTMLタイトルをres.renderを介してPugに渡すオブジェクトのtitleキーに対応する値に設定します。

後でheader_injectionという名前のblockを使用して2行をテンプレート化する別の側面を見ることができます。 このようなブロックは、現在のブロックを拡張するテンプレートで置き換えることができるプレースホルダーです。 (関係なく、 metaはモバイルブラウザへの簡単な回避策であるため、ユーザーがボリュームコントロールを連続して何度もタップすると、電話はズームインまたはズームアウトを控えます。)

blockに戻る:これが、views/index.pugがviews/index.pug views/layout.pugあるのと同じ名前で独自のblockを定義する理由です。 このheader_injectionの場合、これにより、電話が置かれる縦向きまたは横向きに固有のCSSを使用できます。

contentは、Webページの主要な表示部分を配置する場所です。この場合は次のようになります。

  1. 渡すgroup_names配列をループします。
  2. CSSクラスgroup_barが適用された各要素に<span>要素を作成し、
  3. group_nameに基づいて各<span>内にリンクを作成します。

views/layout.pugを介してプルされたファイルで定義できるCSSクラスgroup_bar 、つまり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; }

この時点で、 npm startがまだ実行されている場合、デスクトップブラウザでhttp://localhost:3000/にアクセスすると、NetflixとYouTubeの2つの非常に大きなボタンが表示され、残りは下にスクロールして利用できます。

デスクトップブラウザを使用したリモコンレイアウトセレクターのテスト。NetflixとYouTubeの2つの非常に大きなボタンが表示されます。

ただし、この時点でクリックすると、リンク先のルートがまだ定義されていないため、機能しません( /groupGET設定)。

選択したリモコンのレイアウトを表示する

そのために、これを最後のmodule.exports行の直前のroutes/group.jsに追加します。

 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` }); });

これにより、エンドポイントに送信されるグループ名が取得され(たとえば、 /group/の最後に?group_name=Netflixを配置することにより)、それを使用して、対応するグループからcommandsの値を取得します。 その値( group.commands )はオブジェクトであり、そのオブジェクトのキーは、リモートコントロールレイアウトに表示する名前( keystroke_names )です。

注:経験の浅い開発者は、その仕組みの詳細を知る必要はありませんが、 titleの値は、グループ/レイアウト名を頭字語に変換するために少し正規表現を使用します。たとえば、YouTubeリモートにはブラウザタイトルがありますYT-Remote 。 そうすれば、電話で試す前にホストマシンでデバッグしている場合、 xdotoolが、制御しようとしているウィンドウではなく、リモートコントロールブラウザウィンドウ自体を取得することはありません。 一方、私たちの電話では、リモコンをブックマークしたい場合は、タイトルが短く短くなります。

以前のres.renderとの遭遇と同様に、これはデータを送信してテンプレートviews/group.pugと混合します。 そのファイルを作成し、次のように入力します。

 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")

views/index.pugと同様に、views/ views/layout.pugから2つのブログをオーバーライドしています。 今回は、ヘッダーに挿入するのはCSSではなく、クライアント側のJavaScriptであり、これについては後ほど説明します。 (そして、はい、気難しい瞬間に、私は誤って複数形にされたjavascriptsの名前を変更しました…)

ここでの主なcontentは、 keystroke_nameごとに1つずつ、さまざまな送信ボタンで構成されたHTMLフォームです。 各ボタンは、フォームで送信する値として表示されているキーストローク名を使用してフォームを送信します( POSTリクエストを行います)。

また、メインのスタイルシートファイルにはもう少しCSSが必要です。

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

以前、エンドポイントを設定したときに、次のコマンドでリクエストの処理を終了しました。

 return res.redirect(req.originalUrl);

これは事実上、ブラウザーがフォームを送信すると、Node.jsバックエンドが、フォームが送信されたページ、つまりメインのリモートコントロールレイアウトに戻るようにブラウザーに指示することで応答することを意味します。 ページを切り替えることなく、よりエレガントになります。 ただし、老朽化し​​たモバイルブラウザの奇妙で素晴らしい世界との最大限の互換性が必要です。 このように、フロントエンドJavaScriptがまったく機能していなくても、Node.jsバックエンドプロジェクトは機能するはずです。

フロントエンドJavaScriptのダッシュ

フォームを使用してキーストロークを送信することの欠点は、ブラウザが待機してから追加のラウンドトリップを実行する必要があることです。ページとその依存関係は、Node.jsバックエンドからリクエストされて配信される必要があります。 次に、ブラウザで再度レンダリングする必要があります。

読者は、これがどれほどの効果をもたらすのか疑問に思うかもしれません。 結局のところ、ページは小さく、その依存関係は非常に最小限であり、最終的なNode.jsプロジェクトはローカルwifi接続を介して実行されます。 低レイテンシーのセットアップである必要がありますよね?

結局のところ、少なくともWindows Phone8.1とAndroid4.4.2を実行している古いスマートフォンでテストした場合、残念ながら、すばやくタップして再生音量を数ノッチ上げたり下げたりする一般的なケースでは、その影響は非常に顕著です。 ここで、HTMLフォームを介した手動POSTの優雅なフォールバックを損なうことなくJavaScriptが役立ちます。

この時点で、最終的なクライアントJavaScript( public/javascript/group-client.jsに配置される)は、サポートされなくなった古いモバイルブラウザーと互換性がある必要があります。 しかし、私たちはそれの多くを必要としません:

 (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); } }); })();

ここで、 form_submit関数は非同期呼び出しを介してデータを送信するだけであり、最後の行はブラウザーの通常の送信動作を妨げます。これにより、サーバーの応答に基づいて新しいページが読み込まれます。 このスニペットの後半は、ページが読み込まれるまで待機してから、すべての送信ボタンを接続してform_submitを使用します。 すべてがIIFEに包まれています。

最後の仕上げ

Node.jsバックエンドチュートリアルコードの最終バージョンでは、主にエラー処理を改善する目的で、上記のスニペットにいくつかの変更が加えられています。

  • Node.jsバックエンドは、送信されたグループとキーストロークの名前をチェックして、それらが存在することを確認するようになりました。 このコードは、 routes/group.jsGET関数とPOST関数の両方で再利用される関数に含まれています。
  • そうでない場合は、Pug errorテンプレートを使用します。
  • フロントエンドのJavaScriptとCSSは、サーバーからの応答を待っている間、ボタンの輪郭を一時的に灰色にし、信号がxdotoolを通過して問題なく戻るとすぐに緑色になり、期待どおりに機能しなかった場合は赤色になります。 。
  • Node.jsバックエンドは、スタックトレースが停止した場合に出力します。これは、上記の場合に発生する可能性が低くなります。

読者は、GitHubで完全なNode.jsプロジェクトを熟読(および/または複製)することができます。

Node.jsバックエンドチュートリアル、ステップ5:実際のテスト

npm startを実行しているホストと同じwifiネットワークに接続された実際の電話と映画または音楽プレーヤーで試してみましょう。 スマートフォンのWebブラウザをホストのローカルIPアドレス(接尾辞:3000 )にポイントするだけです。これは、 hostname -I | awk '{print $1}'を実行することでおそらく最も簡単に見つかります。 ホストのターミナルでhostname -I | awk '{print $1}'

Windows Phone 8.1ユーザーが気付く可能性のある問題の1つは、 192.168.2.5:3000 :3000のようなものに移動しようとすると、エラーポップアップが表示されることです。

「サポートされていないアドレス」というタイトルのWindowsPhoneエラーメッセージのスクリーンショット。「InternetExplorerMobileはこのタイプのアドレスをサポートしていないため、このページを表示できません。

ありがたいことに、落胆する必要はありませんhttp://を前に付けるか、末尾に/を追加するだけで、苦情を言わずにアドレスを取得できます。

リモコンレイアウト選択画面。

そこでオプションを選択すると、動作するリモコンが表示されます。

「ジェネリック/ミュージックプレーヤー」のリモコン画面。

さらに便利なように、ユーザーはルーターのDHCP設定を調整して、常に同じIPアドレスをホストに割り当て、レイアウト選択画面やお気に入りのレイアウトをブックマークすることができます。

プルリクエストへようこそ

誰もがこのプロジェクトをそのまま好きになるとは限らないでしょう。 コードをさらに掘り下げたい人のために、改善のためのいくつかのアイデアがあります:

  • レイアウトを微調整したり、DisneyPlusなどの他のサービス用に新しいレイアウトを追加したりするのは簡単です。
  • 「ライトモード」レイアウトと切り替えオプションを好む人もいるかもしれません。
  • Netflixをバックアウトすると、元に戻せないため、実際に「よろしいですか?」を使用できます。 ある種の確認。
  • プロジェクトは確かにWindowsサポートの恩恵を受けるでしょう。
  • xdotoolのドキュメントにはOSXが記載されています—このプロジェクトは最新のMacで機能しますか?
  • 高度なくつろぎのために、Netflix / Amazonプライムビデオの映画を1つ選んだり、コンピューターでYouTubeプレイリストを作成したりする代わりに、映画を検索して閲覧する方法。
  • 提案された変更のいずれかが元の機能を壊した場合の自動テストスイート。

このNode.jsバックエンドチュートリアルと、結果として改善されたメディアエクスペリエンスを楽しんでいただけたと思います。 ハッピーストリーミング—そしてコーディング!

関連: Node.js / TypeScript REST APIの構築、パート1:Express.js