tag:crieit.net,2005:https://crieit.net/tags/Chrome/feed 「Chrome」の記事 - Crieit Crieitでタグ「Chrome」に投稿された最近の記事 2022-01-04T23:14:56+09:00 https://crieit.net/tags/Chrome/feed tag:crieit.net,2005:PublicArticle/17922 2022-01-04T23:14:56+09:00 2022-01-04T23:14:56+09:00 https://crieit.net/posts/chrome-extension-navigator-clipboard-failed-in-http-site-20220104 (Chrome拡張機能) navigator.clipboard を利用したクリップボードへの貼り付けが httpサイト では失敗する <p>先日作成した Chrome拡張機能 が <code>http</code>サイト では上手く動かないことに気付いたので修正しました。</p> <h2 id="経緯"><a href="#%E7%B5%8C%E7%B7%AF">経緯</a></h2> <p>早速作成した Chrome拡張機能 を運用し始めたのですが、一部のサイトでは次のエラーを出力して上手く動かないことが分かりました。</p> <blockquote> <p>Unchecked runtime.lastError: The message port closed before a response was received.</p> </blockquote> <h2 id="原因"><a href="#%E5%8E%9F%E5%9B%A0">原因</a></h2> <p>いくつかのサイトを試験した結果、 <code>http</code>サイト ではこのエラーが出力されることが分かりました。</p> <p>そこで調べてみると……</p> <blockquote> <p>WebExtension の場合、clipboardRead や clipboardWrite パーミッションを要求することで clipboard.readText() や clipboard.writeText() を使うことができます。HTTPサイトに適用されたコンテンツスクリプトは、Clipboard オブジェクトにアクセスすることはできません。</p> <p><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/API/Clipboard">Clipboard - Web API | MDN</a></p> </blockquote> <p>ビンゴ。 <code>http</code>サイト の Content Script では <code>navigator.clipboard</code> へアクセスできないようです。</p> <h2 id="対処"><a href="#%E5%AF%BE%E5%87%A6">対処</a></h2> <p><code>navigator.clipboard</code> へアクセスできないとなると、手っ取り早いのは <code>document.execCommand('copy')</code> によるクリップぼ度貼り付けです。</p> <p>今回は <code>http</code>サイト という基本レガシーと想定される環境への対処なので、 <code>document.execCommand('copy')</code> で妥協しておきますかね……という感じです。</p> <h3 id="chain.js"><a href="#chain.js">chain.js</a></h3> <pre><code class="js">- chrome.tabs.sendMessage(tab.id, clipText, function(response) { - console.log(response.value); + chrome.tabs.sendMessage( + tab.id, + { + text: clipText, + url: tab.url, + }, + function(response) { + console.log(response.value); </code></pre> <p><code>chrome.tabs.sendMessage()</code> の第二引数は元はシンプルにクリップボードに貼り付けたいテキストを投げていましたが、今回は <code>http://</code> か <code>https://</code> かの判定をしたかったのでURLのみのシンプルなテキストも送ることにしました。そこで、Stringだった引数をObjectに変更。</p> <h3 id="smith.js"><a href="#smith.js">smith.js</a></h3> <pre><code class="js"> chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { // メッセージとして送信されたクリップボードに貼り付けたいテキストをそのままレスポンスに設定して返却 - navigator.clipboard.writeText(request); + if(request.url.toLowerCase().startsWith('https://')) { + navigator.clipboard.writeText(request.text); + } + else { + const inputID = 'chromeExtension-emeraldIsle-clipText'; + console.log(document.querySelector(`#${inputID}`)) + if(document.querySelector(`#${inputID}`) === null) { + const $input = document.createElement('input'); + $input.setAttribute('type', 'text'); + $input.setAttribute('id', inputID); + $input.setAttribute('style', 'position: absolute; left: -100vw; top: 0'); + document.body.appendChild($input); + } + const $inputDom = document.querySelector(`#${inputID}`); + $inputDom.value = request.text; + $inputDom.select(); + document.execCommand('copy'); + } sendResponse({ - value: request, + value: request.text, }); + return true; }); </code></pre> <p>content Scripts 側を大改造。元々は <code>navigator.clipboard.writeText(request);</code> のみのシンプルな内容でしたが、次のように処理を変更。</p> <ol> <li>URLに <code>https://</code> (大文字小文字区別せず) で始まるかどうかを判定</li> <li>始まるならば今まで通りの <code>navigator.clipboard.writeText(request.text);</code> で貼り付け</li> <li>始まらないならば次の処理を実行 <ul> <li>もし指定したIDの要素が存在しないならば <ul> <li>ID付与、画面外領域に <code>input</code>要素 を追加</li> </ul></li> <li>再度指定したIDの <code>input</code>要素 を取得、値にクリップボードに貼り付けたいリンク文字列をセット</li> <li><code>document.execCommand('copy')</code> でクリップボードにコピー</li> </ul></li> </ol> <p>これで <code>http</code>サイト でもリンク文字列をクリップボードに貼り付けられるようになりました。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <h3 id="Unchecked runtime.lastError: The message port closed before a response was received."><a href="#Unchecked+runtime.lastError%3A+The+message+port+closed+before+a+response+was+received.">Unchecked runtime.lastError: The message port closed before a response was received.</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://onoredekaiketsu.com/unchecked-runtime-lasterror-with-chrome/">Chromeのデベロッパーツールで「Unchecked runtime.lastError:」 | 己で解決!泣かぬなら己で鳴こうホトトギス</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/noenture/items/3978f638f2ffb8ff0995">Unchecked runtime.lastError: The message port closed before a response was received. を回避した一例 - Qiita</a></li> </ul> <h3 id="navigator.clipboard へのアクセス"><a href="#navigator.clipboard+%E3%81%B8%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9">navigator.clipboard へのアクセス</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/API/Clipboard">Clipboard - Web API | MDN</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://note.affi-sapo-sv.com/js-clipbord-copy.php">【JavaScript】 クリップボードへのコピー</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://propg.ee-mall.info/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0/javascript/js-http%E7%92%B0%E5%A2%83%E3%81%A7%E3%81%AFnavigator-clipboard-writetext%E3%81%8C%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AB%E3%81%AA%E3%82%8B/">[JS] http環境ではnavigator.clipboard.writeTextがエラーになる | プロプログラマ -Flex,Air,C#,Oracle,HTML5+JS-</a></li> </ul> <h3 id="document.execCommand"><a href="#document.execCommand">document.execCommand</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions/Interact_with_the_clipboard#reading_from_the_clipboard">クリップボードとのやりとり - Mozilla | MDN</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/API/Document/execCommand#commands">Document.execCommand() - Web API | MDN</a></li> </ul> <h3 id="JavaScript"><a href="#JavaScript">JavaScript</a></h3> <h4 id="DOM要素の有無"><a href="#DOM%E8%A6%81%E7%B4%A0%E3%81%AE%E6%9C%89%E7%84%A1">DOM要素の有無</a></h4> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/mitsuhiro_K/items/7d5cef1f4316c2080fa7">JavaScriptで要素が存在するかtrue\/falseで知りたい時どうするか? - Qiita</a></li> </ul> <h4 id="テキストボックスに値をセット"><a href="#%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%83%9C%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AB%E5%80%A4%E3%82%92%E3%82%BB%E3%83%83%E3%83%88">テキストボックスに値をセット</a></h4> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/mitsuhiro_K/items/7d5cef1f4316c2080fa7">JavaScriptで要素が存在するかtrue\/falseで知りたい時どうするか? - Qiita</a></li> </ul> <h4 id="要素に属性をセット"><a href="#%E8%A6%81%E7%B4%A0%E3%81%AB%E5%B1%9E%E6%80%A7%E3%82%92%E3%82%BB%E3%83%83%E3%83%88">要素に属性をセット</a></h4> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/API/Element/setAttribute">element.setAttribute - Web API | MDN</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/API/Document_Object_Model/Traversing_an_HTML_table_with_JavaScript_and_DOM_Interfaces">JavaScript と DOM インターフェイスによる HTML の表の操作 - Web API | MDN</a></li> </ul> <h4 id="body の末尾に DOM を挿入"><a href="#body+%E3%81%AE%E6%9C%AB%E5%B0%BE%E3%81%AB+DOM+%E3%82%92%E6%8C%BF%E5%85%A5">body の末尾に DOM を挿入</a></h4> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://www.task-notes.com/entry/20161020/1476974565">【JavaScript】要素を追加するinsertBeforeとappendChildについて - TASK NOTES</a></li> </ul> <h4 id="startWith()"><a href="#startWith%28%29">startWith()</a></h4> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith">String.prototype.startsWith() - JavaScript | MDN</a></li> </ul> <h4 id="toLowerCase()"><a href="#toLowerCase%28%29">toLowerCase()</a></h4> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase">String.prototype.toLowerCase() - JavaScript | MDN</a></li> </ul> <h3 id="chrome.tabs.sendMessage, 第二引数 message の型"><a href="#chrome.tabs.sendMessage%2C+%E7%AC%AC%E4%BA%8C%E5%BC%95%E6%95%B0+message+%E3%81%AE%E5%9E%8B">chrome.tabs.sendMessage, 第二引数 message の型</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.chrome.com/docs/extensions/reference/tabs/">chrome.tabs - Chrome Developers</a></li> </ul> <p><code>any</code> だった。</p> <h3 id="(未使用) html-loader"><a href="#%28%E6%9C%AA%E4%BD%BF%E7%94%A8%29+html-loader">(未使用) html-loader</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://chocolat5.com/tips/webpack-html-template/">Webpackを使用してhtmlの共通部分をテンプレート化 | chocolat | Freelance Frontend Engineer</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.memory-lovers.blog/entry/2018/12/10/003219">【小ネタ】webpackでhtmlも扱う - くらげになりたい。</a></li> </ul> <p>一瞬 Background Page を作ってそのテキストボックスにいったん貼り付けて、その値を取得する方法を考えました。</p> <p>今回 Webpack 使用だったので <code>html-loader</code> 案件か、と思いましたが、回避しました。</p> arm-band tag:crieit.net,2005:PublicArticle/17915 2022-01-03T23:28:12+09:00 2022-01-03T23:29:08+09:00 https://crieit.net/posts/chrome-extension-copy-title-and-url-to-clipboard-20220103 (Chrome拡張機能) 右クリックのメニューから現在開いているタブのタイトルとURLをクリップボードに貼り付ける <p>よんどころなき事情により、新年早々に Chrome拡張機能を作成してみました。</p> <h2 id="経緯"><a href="#%E7%B5%8C%E7%B7%AF">経緯</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://labor.ewigleere.net/2021/12/31/create-link-note/">(Chrome拡張機能) Create Link の挙動が不安定</a>の記事に書いた通り、 Chrome拡張機能 の <a target="_blank" rel="nofollow noopener" href="https://chrome.google.com/webstore/detail/create-link/gcmghdmnkfdbncmnmlkkglmnnhagajbm">Create Link - Chromeウェブストア</a> が挙動不安定になってしまいました。</p> <p>ブログを書く際に参考記事をリストアップしたり、自分の活動にはこの機能はなくてはならないのでそれがままならないというのは不便極まりない。</p> <p>そこで、代替となる Chrome拡張機能 を自作してみることにしました。</p> <h2 id="成果物"><a href="#%E6%88%90%E6%9E%9C%E7%89%A9">成果物</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/arm-band/chrome-extension-emerald-isle">arm-band\/chrome-extension-emerald-isle</a></li> </ul> <p><a href="https://crieit.now.sh/upload_images/f56b0d4a5b2945b8216bad8d6a0cf15e61d306f64f80a.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f56b0d4a5b2945b8216bad8d6a0cf15e61d306f64f80a.jpg?mw=700" alt="自作の拡張機能を入れてコンテキストメニューを開いたときのキャプチャ画像" /></a></p> <h2 id="機能"><a href="#%E6%A9%9F%E8%83%BD">機能</a></h2> <p>Create Link の代替を想定したため、機能はこれに準じます。</p> <p>ただし、貼り付けるコードのカスタマイズの必要はない (プレーン、HTML、Markdown の3種があれば充分) ので設定画面等の自前でカスタマイズできる機能は全てオミット。</p> <p>ページを開いている状態で右クリックして、コンテキストメニューから上述3種の形式でリンクをクリップボードに貼り付けられれば良いです。</p> <h2 id="コード(要点)"><a href="#%E3%82%B3%E3%83%BC%E3%83%89%28%E8%A6%81%E7%82%B9%29">コード(要点)</a></h2> <h3 id="manifest.json"><a href="#manifest.json">manifest.json</a></h3> <pre><code class="json">{ "manifest_version": 2, "name": "emerald-isle", "description": "Make link text of open page.", "version": "0.0.1", "background": { "scripts": [ "dist/chain.js" ], "persistent": false }, "content_scripts": [ { "matches": [ "*://*/*" ], "js": [ "dist/smith.js" ] } ], "permissions": [ "tabs", "activeTab", "clipboardWrite", "contextMenus" ], "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'", "icons": { "48": "assets/icon_48.png", "128": "assets/icon_128.png" } } </code></pre> <p>特筆すべき事項はあまりないですが</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://labor.ewigleere.net/2021/04/11/open-ie-from-chrome-extension/">Chrome拡張機能 から IE を開く</a>等の実績から、幾分か触り慣れているバージョンの<code>2</code>を選択</li> <li><code>permissions</code> はタブ、クリップボードへの書き込み、右クリックメニュー(コンテキストメニュー)等</li> <li>後述しますが、クリップボードへの貼り付けは Background Scripts(Event Scripts) からアクセスはできずに Content Scripts に持ち込む必要があったため、2つのスクリプトに分かれています (結果、 <code>background</code>, <code>content_scripts</code> の2つのフィールドが存在) <ul> <li><code>content_scripts</code> を実行させるURLは全てのURLで良いので <code>*://*/*</code> 指定 (<code>matches</code> フィールド)</li> </ul></li> </ul> <p>といったところでしょうか。</p> <h3 id="chain.js (Background / Event Scripts)"><a href="#chain.js+%28Background+%2F+Event+Scripts%29">chain.js (Background / Event Scripts)</a></h3> <pre><code class="js">import { mdLink } from "markdown-function" /** * grace_O_Malley : Grace O'Malley / titleタグ 文字列のエスケープ * * @param {string} text : 開いているタブの titleタグ の中身の文字列 * @param {string} url : 開いているタブの URL の文字列 * * @returns {string} : Markdown 記法をエスケープした Markdown 形式のリンク */ const grace_O_Malley = (text, url) => { return mdLink({ text: text, url: url, }); }; /** * brianBoru_s_March : Brian Boru's March / メイン処理 * * @returns {void} */ const brianBoru_s_March = () => { chrome.runtime.onInstalled.addListener(() => { chrome.contextMenus.create({ type: 'normal', id: 'CahirCastle', title: 'Emerald Isle', contexts: [ 'all' ], }); chrome.contextMenus.create({ type: 'normal', id: 'plain', parentId: 'CahirCastle', title: 'Plain Text', contexts: [ 'all' ], }); chrome.contextMenus.create({ type: 'normal', id: 'html', parentId: 'CahirCastle', title: 'HTML', contexts: [ 'all' ], }); chrome.contextMenus.create({ type: 'normal', id: 'md', parentId: 'CahirCastle', title: 'Markdown', contexts: [ 'all' ], }); }); chrome.contextMenus.onClicked.addListener(function(item){ chrome.tabs.getSelected((tab) => { // 現在のタブ let clipText = ''; // クリックされたメニューに応じてテキストを組み立て switch (item.menuItemId) { case 'plain': clipText = `${tab.title} - ${tab.url}`; break; case 'html': clipText = `<a href="${tab.url}" target="_blank" rel="noopener noreferrer">${tab.title}</a>`; break; case 'md': clipText = grace_O_Malley(tab.title, tab.url); break; default: break; } chrome.tabs.sendMessage(tab.id, clipText, function(response) { console.log(response.value); }); }); }); }; document.addEventListener('DOMContentLoaded', brianBoru_s_March()); </code></pre> <ul> <li><code>chrome.contextMenus.create()</code> でコンテキストメニューの中身を作成</li> <li><code>chrome.contextMenus.onClicked.addListener()</code> にコンテキストメニューがクリックされた場合の処理を記述 <ul> <li>コンテキストメニューの各項目に記述した <code>id</code> の値で条件分岐してプレーン,HTML,Markdownの3種のリンクのテキストを生成</li> <li>Markdown 形式に関してはブラケットや括弧をエスケープ処理したかったので、<a target="_blank" rel="nofollow noopener" href="https://www.npmjs.com/package/markdown-function">markdown-function</a>を利用させていただきました</li> </ul></li> <li>軽く先述した通り、 Background Scripts (Event Scripts) からはクリップボードへのアクセス権限がないため、このスクリプトの中で <code>navigator.clipboard.writeText()</code> を発動させようとしても失敗してしまいます (<code>Uncaught (in promise) DOMException: Document is not focused.</code> というエラー文が出力される) <ul> <li>かといってクリップボードへ貼り付ける系の記事で散見された <code>Document.execCommand</code> はDOMの指定が必要でこれも Content Scripts 側の動作と思われる上、<a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/API/Document/execCommand">Document.execCommand() - Web API | MDN</a>に <code>非推奨: この機能は非推奨になりました。</code> と記載されているため、今からこの方法を採用するのは得策ではないと判断しました <ul> <li>しかも開いているタブにフォーカスが当たっている必要がありますが、<code>document.querySelector('document').focus();</code> 等としても Background Scripts からDOM指定をすると Background Scripts に紐付けられた Background Page を拾ってしまうので実際に開いているタブのDOMは拾えずにエラーとなる</li> </ul></li> <li>Clipboard.js もインスタンス化の際にDOM指定が必要なのでこれも没</li> <li>色々調べた結果、 Content Scripts へ経由させる必要がありそうなことが分かったため <code>chrome.tabs.sendMessage()</code> でクリップボードへ貼り付けたいテキストを <code>request</code> としてメッセージ送信で投げることにしました</li> </ul></li> </ul> <p>ちなみに markdown-function 使用のため Webpack を使用しました。</p> <h3 id="smith.js"><a href="#smith.js">smith.js</a></h3> <pre><code class="js">chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { // メッセージとして送信されたクリップボードに貼り付けたいテキストをそのままレスポンスに設定して返却 navigator.clipboard.writeText(request); sendResponse({ value: request, }); }); </code></pre> <p>ということで、上述した通り Background Scripts (Event Scripts) から投げられたメッセージを受け取って <code>navigator.clipboard.writeText()</code> でクリップボードに貼り付ける側のコード。こちらは述べた通りの役割のみなのでシンプルです。</p> <p>お作法として元の Background Scripts (Event Scripts) にレスポンスを返す形になるので、 <code>request</code> で投げられたものをそのまま返しています (返却後も <code>console.log()</code> しているだけですが)。</p> <p>これで望む動作の Chrome拡張機能 を作ることができました。</p> <p>一度 Background Scripts (Event Scripts) と Content Scripts の違いや権限周りを履修していたのでそこそこスムーズに進めることができたと思います。</p> <h2 id="(余談) 名前の由来"><a href="#%28%E4%BD%99%E8%AB%87%29+%E5%90%8D%E5%89%8D%E3%81%AE%E7%94%B1%E6%9D%A5">(余談) 名前の由来</a></h2> <p>毎度恒例の名前について。</p> <p>今回はリンクを生成するということで鎖を連想しました。</p> <p>で、色々調べたところ</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://www.youtube.com/watch?v=-GvacwBftIs">伝説のアイルランド : Ireland Of Legend and Lore ~ 陸上自衛隊中央音楽隊 - YouTube</a></li> </ul> <p>鎖を楽器として使用する吹奏楽の楽曲があることを知りました。冒頭部で本当に鎖を落として音を出していますね……。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="http://www.worldfolksong.com/classical/wind-band/ireland-legend.htm">伝説のアイルランド 吹奏楽曲 - 世界の民謡・童謡</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://en.wikipedia.org/wiki/Siege_of_Cahir_Castle">Siege of Cahir Castle - Wikipedia</a></li> </ul> <p>この楽曲に着想を得てアイルランドの俗称である「エメラルドの島 (Emerald Isle)」としました。</p> <p>各種関数やファイル名もこれに関連したものからチョイス。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <h3 id="Content Scirpts, Background Script (Event Scripts)"><a href="#Content+Scirpts%2C+Background+Script+%28Event+Scripts%29">Content Scirpts, Background Script (Event Scripts)</a></h3> <ul> <li>過去記事: <a target="_blank" rel="nofollow noopener" href="https://labor.ewigleere.net/2021/04/11/open-ie-from-chrome-extension/">Chrome拡張機能 から IE を開く</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.sukerou.com/2020/11/chrome_26.html">Chrome拡張機能!コンテキストメニューでクリックされた要素を取得する方法-スケ郎のお話</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sakaimo/items/5e41d6b2ad8d7ee04b12">Chrome Extension の作り方 (最終話: メッセージパッシング) - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://yaraneba.com/extensions-key-binding/">キー割り当てをカスタマイズする拡張機能を自作してみる - やらねば.com</a></li> </ul> <h3 id="Content Scripts"><a href="#Content+Scripts">Content Scripts</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts">content_scripts - Mozilla | MDN</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions/Match_patterns">マッチパターン - Mozilla | MDN</a></li> </ul> <h3 id="chrome.tabs"><a href="#chrome.tabs">chrome.tabs</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.chrome.com/docs/extensions/reference/tabs/">chrome.tabs - Chrome Developers</a></li> </ul> <h3 id="clipboard API"><a href="#clipboard+API">clipboard API</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/en-US/docs/Web/API/Clipboard">Clipboard - Web APIs | MDN</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText">Clipboard.writeText() - Web APIs | MDN</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/eyuta/items/859d1e8952eef4d8f061">【Javascript】Markdown形式のウェブページのリンクを、ブックマークレットで取得する - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/54386279/how-can-i-use-navigator-clipboard-readtext-in-a-chrome-extension">firefox - How can I use navigator.clipboard.readText() in a Chrome extension? - Stack Overflow</a></li> </ul> <h3 id="権限"><a href="#%E6%A8%A9%E9%99%90">権限</a></h3> <ul> <li>v2: <a target="_blank" rel="nofollow noopener" href="https://developer.chrome.com/docs/extensions/mv2/declare_permissions/">Declare permissions - Chrome Developers</a> <ul> <li>v3: <a target="_blank" rel="nofollow noopener" href="https://developer.chrome.com/docs/extensions/mv3/declare_permissions/">Declare permissions - Chrome Developers</a></li> </ul></li> </ul> <h3 id="右クリックメニュー (Context Menu)"><a href="#%E5%8F%B3%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC+%28Context+Menu%29">右クリックメニュー (Context Menu)</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.chrome.com/docs/extensions/reference/contextMenus/">chrome.contextMenus - Chrome Developers</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/plumfield56/items/e98c247888d82a79c7ea">Chrome拡張機能で右クリックメニューを作る方法 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/apps/samples/context-menu">chrome-extensions-samples\/apps\/samples\/context-menu at main · GoogleChrome\/chrome-extensions-samples</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/GoogleChrome/chrome-extensions-samples/blob/main/apps/samples/context-menu/main.js">chrome-extensions-samples\/main.js at main · GoogleChrome\/chrome-extensions-samples</a></li> </ul> <h3 id="Markdown のリンク生成・エスケープ"><a href="#Markdown+%E3%81%AE%E3%83%AA%E3%83%B3%E3%82%AF%E7%94%9F%E6%88%90%E3%83%BB%E3%82%A8%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%97">Markdown のリンク生成・エスケープ</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://www.npmjs.com/package/markdown-function">markdown-function - npm</a></li> </ul> <h3 id="(未使用) Clipboard.js"><a href="#%28%E6%9C%AA%E4%BD%BF%E7%94%A8%29+Clipboard.js">(未使用) Clipboard.js</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/eyuta/items/859d1e8952eef4d8f061">【Javascript】Markdown形式のウェブページのリンクを、ブックマークレットで取得する - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.npmjs.com/package/clipboard">clipboard - npm</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/Cesaroshun/items/776c44ac25f21c37b67e">Clipboard.jsの使い方 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/R_TES_/items/194bc78ad73a29daef5f">Google Chrome 拡張機能の開発 - 2 - 早速自作したものに機能追加していく - Qiita</a></li> </ul> <h3 id="(未使用) chrome.clipboard"><a href="#%28%E6%9C%AA%E4%BD%BF%E7%94%A8%29+chrome.clipboard">(未使用) chrome.clipboard</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.chrome.com/docs/extensions/reference/clipboard/">chrome.clipboard - Chrome Developers</a></li> </ul> <h3 id="(未使用) Document.execCommand()"><a href="#%28%E6%9C%AA%E4%BD%BF%E7%94%A8%29+Document.execCommand%28%29">(未使用) Document.execCommand()</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/API/Document/execCommand">Document.execCommand() - Web API | MDN</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions/Interact_with_the_clipboard#reading_from_the_clipboard">クリップボードとのやりとり - Mozilla | MDN</a></li> </ul> <h3 id="(未使用) その他の clipboard"><a href="#%28%E6%9C%AA%E4%BD%BF%E7%94%A8%29+%E3%81%9D%E3%81%AE%E4%BB%96%E3%81%AE+clipboard">(未使用) その他の clipboard</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/GoogleChrome/chrome-extensions-samples/blob/e716678b67fd30a5876a552b9665e9f847d6d84b/apps/samples/text-editor/lib/ace/keyboard/textinput.js">chrome-extensions-samples\/textinput.js at e716678b67fd30a5876a552b9665e9f847d6d84b · GoogleChrome\/chrome-extensions-samples</a></li> </ul> <h3 id="(未使用) HTMLElement.focus()"><a href="#%28%E6%9C%AA%E4%BD%BF%E7%94%A8%29+HTMLElement.focus%28%29">(未使用) HTMLElement.focus()</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/focus">HTMLElement.focus() - Web API | MDN</a></li> </ul> <h3 id="(未使用) Markdown のエスケープ"><a href="#%28%E6%9C%AA%E4%BD%BF%E7%94%A8%29+Markdown+%E3%81%AE%E3%82%A8%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%97">(未使用) Markdown のエスケープ</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://note.crohaco.net/2018/markdown-xss/">Markdownのクロスサイトスクリプティングに気をつけろ! - くろのて</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qumeru.com/magazine/108">JavaScriptの正規表現でエスケープが必要な文字列の一覧を紹介! | Qumeruマガジン</a></li> </ul> arm-band tag:crieit.net,2005:PublicArticle/17746 2021-11-10T13:33:47+09:00 2022-05-12T19:10:56+09:00 https://crieit.net/posts/Web-Google-Chrome-Notta-Audio-Clipper 入れるとすぐWebページの音声コンテンツをテキスト化?おすすめGoogle Chrome拡張機能「Notta Audio Clipper」の活用方 <p>元記事:<a target="_blank" rel="nofollow noopener" href="https://www.notta.ai/blog/notta-audio-clipper-extension-guide">https://www.notta.ai/blog/notta-audio-clipper-extension-guide</a></p> <p><a href="https://crieit.now.sh/upload_images/9cfa78fc38e210e99b3e292ce59df382618b4b51cf780.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/9cfa78fc38e210e99b3e292ce59df382618b4b51cf780.png?mw=700" alt="image" /></a></p> <h1 id="Notta Audio Clipperとは?"><a href="#Notta+Audio+Clipper%E3%81%A8%E3%81%AF%EF%BC%9F">Notta Audio Clipperとは?</a></h1> <p>AI音声認識文字起こしサービス「Notta」の新しいChrome拡張機能は、Webページの音声をリアルタイムで録音し、文字起こしすることができます。文字起こし結果はNottaアカウントに保存し、どの端末でも確認できます。Web会議(Zoom、Google Meetなど)やYouTube動画の字幕起こし、在宅テープ起こし、お気に入りのポッドキャストの保存など、手作業による文字起こしの手間が省け、作業効率が大幅UP!</p> <p>‍</p> <h2 id="前提条件"><a href="#%E5%89%8D%E6%8F%90%E6%9D%A1%E4%BB%B6">前提条件</a></h2> <p>Google Chromeブラウザ<br /> Notta Audio Clipper拡張機能 <a target="_blank" rel="nofollow noopener" href="https://bit.ly/3jvP5O0">Chromeウェブストア>></a><br /> Notta アカウント 新規登録は<a target="_blank" rel="nofollow noopener" href="https://app.notta.ai/signup?language=ja">こちら</a><br /> ‍</p> <h1 id="Notta拡張機能をchromeに追加"><a href="#Notta%E6%8B%A1%E5%BC%B5%E6%A9%9F%E8%83%BD%E3%82%92chrome%E3%81%AB%E8%BF%BD%E5%8A%A0">Notta拡張機能をchromeに追加</a></h1> <p>‍</p> <p>Chromeのウェブストアの画面上部にある検索窓に「Notta」を入力して検索ください。画面の右上にある「Chromeに追加」ボタンをクリックして、拡張機能ブラウザに追加します。</p> <p>‍<a href="https://crieit.now.sh/upload_images/c902ef805427ce6191b927e17ab3e93f618b4b5b803cb.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/c902ef805427ce6191b927e17ab3e93f618b4b5b803cb.png?mw=700" alt="image" /></a><br /> <a href="https://crieit.now.sh/upload_images/992bbbcbf1953425eaa50e362f8975d3618b4b61a7b05.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/992bbbcbf1953425eaa50e362f8975d3618b4b61a7b05.png?mw=700" alt="image" /></a><br /> ‍</p> <p>追加した後、Chrome アドレスバーの横にある「拡張機能アイコン」をクリックください。「画びょう」アイコンをクリックと、ブラウザのツールバーに拡張機能が固定されます。</p> <p><a href="https://crieit.now.sh/upload_images/88fb27b04be9b95c1e859642aad965eb618b4b69c8abb.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/88fb27b04be9b95c1e859642aad965eb618b4b69c8abb.png?mw=700" alt="image" /></a><br /> <a href="https://crieit.now.sh/upload_images/22fb35cf5b0daed269bba45b45a286bc618b4b711e644.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/22fb35cf5b0daed269bba45b45a286bc618b4b711e644.png?mw=700" alt="image" /></a></p> <p>シークレットモードでも拡張機能を有効にしたいの場合、設定方法は簡単です。設定メニューを開く、「拡張機能」を選択したら、インストールされている拡張機能の一覧が表示されます。Notta拡張機能の「詳細」をクリックください。</p> <p>‍<a href="https://crieit.now.sh/upload_images/3dcdd87eba7f5d10dc4c09179a6cec4d618b4b77f2c96.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/3dcdd87eba7f5d10dc4c09179a6cec4d618b4b77f2c96.png?mw=700" alt="image" /></a><br /> <a href="https://crieit.now.sh/upload_images/b779cdd2eefdbe7c9b161bec4734c447618b4b7d924ad.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b779cdd2eefdbe7c9b161bec4734c447618b4b7d924ad.png?mw=700" alt="image" /></a></p> <p>詳細場面で「シークレットモードでの実行を許可する」をONにします。</p> <p>‍<a href="https://crieit.now.sh/upload_images/15b8eaefd4792214aa4d4fabc52e8ea2618b4b8431724.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/15b8eaefd4792214aa4d4fabc52e8ea2618b4b8431724.png?mw=700" alt="image" /></a></p> <p>再び読み込みすると、Notta Audio Clipper拡張機能がシークレットモードでも有効になります。</p> <p><a href="https://crieit.now.sh/upload_images/87134956358479b9a4253a6bcf03dbab618b4b8a0521d.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/87134956358479b9a4253a6bcf03dbab618b4b8a0521d.png?mw=700" alt="image" /></a></p> <h1 id="準備完了!YouTube動画を文字起こししましょう"><a href="#%E6%BA%96%E5%82%99%E5%AE%8C%E4%BA%86%EF%BC%81YouTube%E5%8B%95%E7%94%BB%E3%82%92%E6%96%87%E5%AD%97%E8%B5%B7%E3%81%93%E3%81%97%E3%81%97%E3%81%BE%E3%81%97%E3%82%87%E3%81%86">準備完了!YouTube動画を文字起こししましょう</a></h1> <p>‍</p> <p>音声コンテンツを文字変換したいウェブページを開き、Nottaのロゴマークをクリックします。</p> <p>「このページの録音を開始します」ボタンをクリックすれば、流れている音声をレコードしはじめます。<strong>一度に5新規タブ</strong>まで同時に録音することが可能です。</p> <p>‍<a href="https://crieit.now.sh/upload_images/9d4cd53458032a67da75848f99a2cfb9618b4b9177238.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/9d4cd53458032a67da75848f99a2cfb9618b4b9177238.png?mw=700" alt="image" /></a><br /> <a href="https://crieit.now.sh/upload_images/cb8d43a804853ea4374032e2da5cbc9b618b4b97b7ad8.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/cb8d43a804853ea4374032e2da5cbc9b618b4b97b7ad8.png?mw=700" alt="image" /></a></p> <p>録音が終了後、「終了」ボタンをクリックします。</p> <p><a href="https://crieit.now.sh/upload_images/9998eb3de1bfeb10e90d99dbf1ba636d618b4b9e0c8e8.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/9998eb3de1bfeb10e90d99dbf1ba636d618b4b9e0c8e8.png?mw=700" alt="image" /></a></p> <h1 id="Notta Web版で文字起こし結果をチェック・編集"><a href="#Notta+Web%E7%89%88%E3%81%A7%E6%96%87%E5%AD%97%E8%B5%B7%E3%81%93%E3%81%97%E7%B5%90%E6%9E%9C%E3%82%92%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%83%BB%E7%B7%A8%E9%9B%86">Notta Web版で文字起こし結果をチェック・編集</a></h1> <p>‍</p> <p>データはNottaアカウントに保存されます。 <a target="_blank" rel="nofollow noopener" href="https://app.notta.ai/signup?language=ja">Notta Web版</a>に登録すると、録音を確認したり、文字起こし結果を編集したり、メモ・画像を挿入したりすることができます。</p> <p>音声、テキストデータそれぞれの導出も可能です。また、データは複数デバイスにも同期するため、携帯やほかの端末にて随時振り返れます。</p> <p><a href="https://crieit.now.sh/upload_images/1af77b84f6b95d1c8b6678f778f0aea0618b4ba3cd340.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/1af77b84f6b95d1c8b6678f778f0aea0618b4ba3cd340.png?mw=700" alt="image" /></a></p> <hr /> <p>Nottaは無料体験できますので、試してみましょう。<br /> ‍<br /> ‍Web版<br /> ‍Google ChromeやMicrosoft Edgeブラウザから<a target="_blank" rel="nofollow noopener" href="http://www.notta.ai/">Web版</a>をアクセス<br /> ‍<br /> ‍Chrome拡張機能<br /> ‍Chrome web storeから<a target="_blank" rel="nofollow noopener" href="https://chrome.google.com/webstore/detail/notta-speech-to-text-tran/kdelkaogljjcbjffjmahedaobfjineig?hl=ja">Notta拡張機能</a>を追加<br /> ‍<br /> ‍アプリ版‍<br /> iOSアプリは<a target="_blank" rel="nofollow noopener" href="https://apps.apple.com/jp/app/notta-%E9%9F%B3%E5%A3%B0%E3%81%AE%E9%8C%B2%E9%9F%B3%E3%81%A8%E6%96%87%E5%AD%97%E8%B5%B7%E3%81%93%E3%81%97-ai%E9%9F%B3%E5%A3%B0%E8%AA%8D%E8%AD%98%E3%82%A2%E3%83%97%E3%83%AA/id1480649572">App Store</a>からダウンロード<br /> Androidアプリは<a target="_blank" rel="nofollow noopener" href="https://play.google.com/store/apps/details?id=com.langogo.transcribe&hl=ja&gl=US">Google Play</a>からダウンロード</p> Notta | 文字起こしサービス | AI音声認識 tag:crieit.net,2005:PublicArticle/17419 2021-06-19T19:16:24+09:00 2021-06-19T19:16:24+09:00 https://crieit.net/posts/10-Firefox-3 10年ぶりにFirefoxを3ヶ月ほどメインにした所感 <p>ここ10年ほど、僕はずっとGoogle Chromeを使っていた。正直Chrome最強だと思う。Chrome最強だと思うんだが、どういうわけなのか、僕のMacではやたらとCPUを使ってくれて、ただでさえ爆熱のMac mini 2018を目玉焼きでも焼けそうなほどに熱してくれる。MacBook Pro 2019でも同様だ。Windowsのマシンではそういうことはなかったので、Macとの相性問題もあったりするんだろうか。それとも何かエクステンションが悪さしているのか。</p> <h2 id="Firefoxを使い始める"><a href="#Firefox%E3%82%92%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B">Firefoxを使い始める</a></h2> <p>わからないが、もうずっと爆熱が続いて全然なおらないので、ついに僕はChromeをメインにすることをやめて、Firefoxを使い始めた。それが今年の3月のことだ。</p> <p>Firefoxをメインにするのは、10年ぶりくらいだろうか。僕の中ではFirefoxは今なお3.5だったのだが、もうバージョン90になっている。おかげで軽くタイムスリップしたような気分になれた。</p> <p>さて、久方ぶりのFirefoxだが、けっこうすんなりと移行することができた。まぁもともと使っていたしね。</p> <p>以下に、Firefox移行後の所感について書く。</p> <h2 id="爆熱は微妙におさまった"><a href="#%E7%88%86%E7%86%B1%E3%81%AF%E5%BE%AE%E5%A6%99%E3%81%AB%E3%81%8A%E3%81%95%E3%81%BE%E3%81%A3%E3%81%9F">爆熱は微妙におさまった</a></h2> <p>まずChromeからの移行のきっかけとなった爆熱についてだが、これは微妙におさまった。微妙にというのは、Firefoxも立ち上げてしばらくすると、やはりCPUをぶん回し始める現象が起きたからだ。</p> <p>しかし、ウィンドウを閉じるとおさまるので、プロセスを終了しないと暴走がおさまらなかったChromeに比べるとマシだ。また、Chromeは起動してすぐくらいの勢いで暴走を初めていたが、Firefoxについては長時間起動していると、という感じなので、まぁいいかなという感じ。</p> <h2 id="ブックマーク、パスワードの同期"><a href="#%E3%83%96%E3%83%83%E3%82%AF%E3%83%9E%E3%83%BC%E3%82%AF%E3%80%81%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E3%81%AE%E5%90%8C%E6%9C%9F">ブックマーク、パスワードの同期</a></h2> <p>次に同期の問題。</p> <p>まず、パスワード同期については僕はBitwardenを利用しており、BitwardenはFirefox用のエクステンションも提供しているから、その点は問題ない。</p> <p>ただ、Android用のFirefoxブラウザにおいては、パスワード欄をタップした時のBitwarden連携が不安定で、出たり出なかったり、出たとしても一瞬で消えたり、ということが頻発してちょっと苛々する。iOS用Firefoxではそういう問題は起きない(まぁキーボードにパスワードマネージャの立ち上げがくっついてる形なので)。</p> <p>ブックマーク同期については、昔はそれ用のソフトを使っていた(具体的には確かXmarksだ、もうサービス終了している)が、今はブラウザの同期機能を利用しているため、Firefox Syncの世話になった。これは普通に使えたのだが、職場ではproxy経由の時に問題があるのか、使えなかった。うーん?まぁいいけど。</p> <p>それにしても、今ってクロスブラウザを前提にしたブックマーク同期アプリってあるのかな。ここしばらくChrome一強時代が続いているから、ちょっと厳しいよね。</p> <h2 id="パフォーマンス"><a href="#%E3%83%91%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%B3%E3%82%B9">パフォーマンス</a></h2> <p>パフォーマンスについては、正直体感ではあまり差がない。その昔は明らかにChromeのほうが快適で、まぁそのためにChromeは天下を取ったとも言えるのだが、今はそんなこともないようだ。</p> <h2 id="画面の崩れ"><a href="#%E7%94%BB%E9%9D%A2%E3%81%AE%E5%B4%A9%E3%82%8C">画面の崩れ</a></h2> <p>ほとんどない。今どきのモダンブラウザで表示が問題になることはないようだ。IEを使っている人は税金払ってほしい。</p> <p>あ、そういえば職場のクソアプリが、Chromeだといつもレイアウトが崩れていたんだけれど、Firefoxだと崩れなくなった。</p> <h2 id="エクステンション"><a href="#%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%86%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%B3">エクステンション</a></h2> <p>PCでWebブラウジングする魅力は、なんといってもフルブラウザ、というか豊富なエクステンションだろう。Amazonの商品の金額遷移を表示するKeepa、タイトルとURLをコピーするシンプルながら使い勝手の良いCreateLink、複数リンクを同時に開くLinkclump、Google検索からゴミサイトを排除するゴシップブロッカーなど、愛用しているエクステンションはいくつかある。</p> <p>で、調べてみるとだいたいFirefoxに対応しているか、あるいはFirefoxで使える代替えとなるエクステンションがあったので、これも問題がなかった。ただもちろん、人によっては諦めなければならない機能はあるだろう。</p> <p>とはいえ、大昔野良エクステンションが跋扈していた時代に比べると、随分と環境が整備されたのだなぁと思う。</p> <h2 id="スマホの検索窓など画面下部に"><a href="#%E3%82%B9%E3%83%9E%E3%83%9B%E3%81%AE%E6%A4%9C%E7%B4%A2%E7%AA%93%E3%81%AA%E3%81%A9%E7%94%BB%E9%9D%A2%E4%B8%8B%E9%83%A8%E3%81%AB">スマホの検索窓など画面下部に</a></h2> <p>細かいのだが、いいなぁと思ったのはスマホのFirefoxだと検索窓を画面下部にすることができるところだった。</p> <p><img src="https://hack-le.com/wp-content/uploads/2021/06/2021-06-19-18.19.33.png" alt="" /></p> <p>これは楽天Bigのスクリーンショットだ。楽天Bigはクソデカイので、検索するには少しばかり親指をダルシムのごとく伸ばす必要があるのだが、画面下部にあればホビット族の血を受け継ぐ僕も楽々検索することが可能だ。これは地味ながら嬉しいユーザー体験だった。</p> <p>既に開いているタブ一覧なども、Chromeがやたらと親指の限界を試すのに比べて、Firefoxは軽く伸ばせば届くところがタップ範囲で、非常に好ましく思えた。</p> <h2 id="タブをウィンドウから移動させた時の挙動が不満"><a href="#%E3%82%BF%E3%83%96%E3%82%92%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6%E3%81%8B%E3%82%89%E7%A7%BB%E5%8B%95%E3%81%95%E3%81%9B%E3%81%9F%E6%99%82%E3%81%AE%E6%8C%99%E5%8B%95%E3%81%8C%E4%B8%8D%E6%BA%80">タブをウィンドウから移動させた時の挙動が不満</a></h2> <p>これまた地味だが、PCでタブを別ウィンドウに移動させた時、期待する動作はマウスポインタの場所あたりに新たなウィンドウを開いてタブが移動することだが、どうもそうならない。これがMac版故なのかどうかはわからないが、あまり直感的ではない。まぁ大した問題ではないのだが、ちょっとイラッとする。</p> <h2 id="マルチユーザーだとちょっと使いづらかった"><a href="#%E3%83%9E%E3%83%AB%E3%83%81%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%A0%E3%81%A8%E3%81%A1%E3%82%87%E3%81%A3%E3%81%A8%E4%BD%BF%E3%81%84%E3%81%A5%E3%82%89%E3%81%8B%E3%81%A3%E3%81%9F">マルチユーザーだとちょっと使いづらかった</a></h2> <p>Firefoxでマルチユーザーっぽく使おうと思ったら、ユーザーごとにprofileを作成し、都度切り替えていくことになると思うが、どうも使いづらい。</p> <p>たとえば他アプリからURLをクリックしてFirefoxに飛ぶ時、Chromeだと最後に開いていたユーザーのウィンドウで開くが、Firefoxだと必ずデフォルトのprofileで開かれてしまう。</p> <p>また、Firefoxを起動した時に最初に開かれるのがデフォルトユーザーではなくなることもちょくちょくあり、まぁOS再起動などすればなおるのだが、どうにもprofile周りは挙動が若干不安定に思えた。</p> <p>そもそもabout:profilesを毎度入力するのがイケてないように思うが、他にいいやり方があるんだろうか……。</p> <p>まぁでも、少し特殊な使い方だとは思う。</p> <h2 id="総評"><a href="#%E7%B7%8F%E8%A9%95">総評</a></h2> <p>ということで、Firefoxを3ヶ月ほどメインにした結果、十分に使えるものだということがわかった。</p> <p>わかったが、しかしFirefoxでなければならない積極的な理由も特にはなく、恐らく多くの人にとってFirefoxを使う一番のモチベーションは「Chromeを使いたくない」になってしまうのではないだろうか。</p> <p>まぁでも、それは案外バカにできない理由かもしれない。僕のChrome熱暴走問題は恐らくおまかんなのだが、おまかんと言われても僕の環境で起きている以上僕にとっては大きな問題であって、ブラウザを変えるだけで解決できるならそうしてしまいたいし、事象が異なるだけでブラウザを変えたい気持ちになっている人は、何も宗教上の理由がなくてもけっこういるであろう。</p> <p>まぁもちろんChrome以外というだけなら他にも選択肢があるんだが、「結局WebKitじゃねぇか」みたいなものが多い中で、Firefoxの「Geckoですけど?」はひときわ輝いてみえる(個人の感想です)し、昔からクロスOSでやってきている信頼感もある。</p> <p>ということで、Firefox悪くないんじゃないの、と言いながら、実はこの記事はBrave上で書いてます。結局WebKitじゃねぇか。いやBlinkです。使えればなんでもいいよ。はい。</p> tama tag:crieit.net,2005:PublicArticle/17357 2021-06-03T20:00:44+09:00 2021-06-03T20:00:44+09:00 https://crieit.net/posts/chrome-unsafe-port-10080-20210603 Chrome 91 で 10080ポート がブロックされる (ERR_UNSAFE_PORT) <p>Chrome でとあるサイトを開こうとしたら ERR_UNSAFE_PORT のエラーでブロックされてしまったので対処。</p> <h2 id="経緯"><a href="#%E7%B5%8C%E7%B7%AF">経緯</a></h2> <p>Chrome でとあるサイトを開こうとしたら以下の画面が表示されました。</p> <p><a href="https://crieit.now.sh/upload_images/3877447a1747b5933833f801ebcd136060b8b5e482a5c.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/3877447a1747b5933833f801ebcd136060b8b5e482a5c.jpg?mw=700" alt="このサイトにアクセスできません http://example.jp:10080/ のウェブページは一時的に停止しているか、新しいウェブアドレスに移動した可能性があります。" /></a></p> <blockquote> <p>このサイトにアクセスできません http://example.jp:10080/ のウェブページは一時的に停止しているか、新しいウェブアドレスに移動した可能性があります。</p> <p>ERR_UNSAFE_PORT</p> </blockquote> <p>先週は開けたのに……。</p> <p>ちなみに Chrome のバージョンは <code>91.0.4472.77</code> 。アップデートして現状最新版です。</p> <h2 id="仮対処 (没)"><a href="#%E4%BB%AE%E5%AF%BE%E5%87%A6+%28%E6%B2%A1%29">仮対処 (没)</a></h2> <p>対処として該当サイトを許可リストに加えます。</p> <p><a href="https://crieit.now.sh/upload_images/ffacc6e323a691b69f04da96bd2559f160b8b5ef2f7e6.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/ffacc6e323a691b69f04da96bd2559f160b8b5ef2f7e6.jpg?mw=700" alt="「プライバシーとセキュリティ」→「サイトの設定」" /></a></p> <p>「プライバシーとセキュリティ」→「サイトの設定」</p> <p><a href="https://crieit.now.sh/upload_images/6ac1d602a924511072ae906ea5afdb1860b8b5faa7394.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6ac1d602a924511072ae906ea5afdb1860b8b5faa7394.jpg?mw=700" alt="「その他のコンテンツの設定」" /></a></p> <p>「その他のコンテンツの設定」</p> <p><a href="https://crieit.now.sh/upload_images/dfa8f88c3be8723965cecefdc000d03160b8b60287983.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/dfa8f88c3be8723965cecefdc000d03160b8b60287983.jpg?mw=700" alt="「安全でないコンテンツ」" /></a></p> <p>「安全でないコンテンツ」</p> <p><a href="https://crieit.now.sh/upload_images/fd735179b5d692add189ce4c65e4d8dc60b8b609f2477.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/fd735179b5d692add189ce4c65e4d8dc60b8b609f2477.jpg?mw=700" alt="「許可」リストに「追加」" /></a></p> <p>「許可」リストに「追加」</p> <p><a href="https://crieit.now.sh/upload_images/f1225da8598d6f101e0cf6f70e37d9e560b8b6118285b.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f1225da8598d6f101e0cf6f70e37d9e560b8b6118285b.jpg?mw=700" alt="ドメインとポートを入力" /></a></p> <p>「サイトの追加」で該当サイトのドメインとポート (例: <code>example.jp:10080/</code> ) を入力し、追加します。</p> <p>これで Chrome を再起動すると、閲覧できるようになりました。</p> <h2 id="仮対処2 (没・失敗)"><a href="#%E4%BB%AE%E5%AF%BE%E5%87%A62+%28%E6%B2%A1%E3%83%BB%E5%A4%B1%E6%95%97%29">仮対処2 (没・失敗)</a></h2> <p>Chrome が怒られたということは、 Edge も怒られるということになります。</p> <p>バージョン <code>91.0.864.37</code> で同様にアクセスしたところ、以下の表示になりやはり接続できませんでした。</p> <blockquote> <p>申し訳ございません。このページに到達できません http://example.jp:10080/ の Web ページに問題が発生しているか、新しい Web アドレスに完全に移動された可能性があります。</p> <p>ERR_UNSAFE_PORT</p> </blockquote> <p>文言が多少変わっていますが、エラーの内容としては同じです。</p> <p><a href="https://crieit.now.sh/upload_images/02368a343e61fece82ef14d3e731d87560b8b61cde4f5.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/02368a343e61fece82ef14d3e731d87560b8b61cde4f5.jpg?mw=700" alt="「Cookie とサイトのアクセス許可」→「セキュリティで保護されていないコンテンツ」" /></a></p> <p>「Cookie とサイトのアクセス許可」→「セキュリティで保護されていないコンテンツ」</p> <p><a href="https://crieit.now.sh/upload_images/6037baf028b358c5a33624ac5120eee960b8b62f78834.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6037baf028b358c5a33624ac5120eee960b8b62f78834.jpg?mw=700" alt="「許可」リストにサイトを追加" /></a></p> <p>「許可」リストにサイトを追加</p> <p>これで Edge も再起動してアクセスしてみましたが……改善されませんでした。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://answers.microsoft.com/en-us/microsoftedge/forum/all/cannot-open-local-link-in-edge-after-last-windows/1f25d29e-65b1-4788-9d3c-36de25e27315">cannot open local link in edge after last windows update - Microsoft Community</a></li> </ul> <p>一応、アプリ起動時のショートカットアイコン等でパラメータに <code>--explicitly-allowed-ports=10080</code> のような形で追記してあげると回避できるようですが、これを行うとショートカットを誤って消したときなどに今回の対処を忘れて嵌まりそうなので没。</p> <h2 id="調査・対処"><a href="#%E8%AA%BF%E6%9F%BB%E3%83%BB%E5%AF%BE%E5%87%A6">調査・対処</a></h2> <p>以前 <a target="_blank" rel="nofollow noopener" href="https://labor.ewigleere.net/2021/01/29/firefox_restrict_non_well_known_port/">Firefox でも同じ現象が発生した</a> ことを思い出し、調べてみました。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://zenn.dev/ota42y/articles/127fee3353bafe">Web Application開発に10080番ポートは使ってはいけない</a> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://asnokaze.hatenablog.com/entry/2020/11/08/003731">NAT Slipstreaming攻撃とブラウザ側の対策 - ASnoKaze blog</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://asnokaze.hatenablog.com/entry/2021/01/29/014759">NAT Slipstreaming v2 攻撃とブラウザ側の対策 - ASnoKaze blog</a></li> </ul></li> </ul> <p>今回の対処は NAT Slipstreaming v2 と呼ばれる攻撃で <code>10080</code>ポート が使用されるため、ブラウザ側で攻撃を防ぐためにブロックした、という流れのようです。</p> <p>そうであれば、「ブラウザにアクセスを許可するように登録」するよりも、サーバのポート番号を変更した方が良さそうです。</p> <p>そこで、最終的には上述の仮対処はやめて、サーバの Listenポート を変更する方向で対処しました。</p> <p>以前の記事の Firefox の <code>network.security.ports.banned.override</code> の設定も削除しました。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://answers.microsoft.com/en-us/microsoftedge/forum/all/cannot-open-local-link-in-edge-after-last-windows/1f25d29e-65b1-4788-9d3c-36de25e27315">cannot open local link in edge after last windows update - Microsoft Community</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://zenn.dev/ota42y/articles/127fee3353bafe">Web Application開発に10080番ポートは使ってはいけない</a> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://asnokaze.hatenablog.com/entry/2020/11/08/003731">NAT Slipstreaming攻撃とブラウザ側の対策 - ASnoKaze blog</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://asnokaze.hatenablog.com/entry/2021/01/29/014759">NAT Slipstreaming v2 攻撃とブラウザ側の対策 - ASnoKaze blog</a></li> </ul></li> </ul> arm-band tag:crieit.net,2005:PublicArticle/16550 2021-01-06T23:45:20+09:00 2021-01-06T23:55:33+09:00 https://crieit.net/posts/badge-of-github-actions-with-chrome-extension-20210106 Github Actions のバッジを付ける (+バッジに Github Actions ページへのリンクを付与するChrome拡張機能を作成) <p><a href="https://crieit.net/posts/run-phpunit-on-github-actions-20210105">前回記事</a>の続き。 Github Actions で PHPUnit が走ることが確認できたところで、今度は「そういえば Github Actions のバッジはあるのだろうか?」と気になって調べてみました。</p> <h2 id="バッジの所在"><a href="#%E3%83%90%E3%83%83%E3%82%B8%E3%81%AE%E6%89%80%E5%9C%A8">バッジの所在</a></h2> <p>バッジについては Github Actions のページにありました。</p> <ol> <li>リポジトリの対象アクション ( <code>https://github.com/<user>/<repo>/actions?<workflow></code> ) に遷移</li> <li>上のハンバーガー( <code>…</code> ) からメニューを開く</li> <li><code>Create status badge</code> をクリック</li> </ol> <p>以上の手順で発行できます。</p> <p><a href="https://crieit.now.sh/upload_images/30fd56cee47ae62946d6c90ff72122da5ff5cbafc5560.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/30fd56cee47ae62946d6c90ff72122da5ff5cbafc5560.jpg?mw=700" alt="バッジ発行のメニューを展開した画面" /></a></p> <p>メニュー展開時。</p> <p><a href="https://crieit.now.sh/upload_images/8ae1b6cc9da667dd3e02d32105a009505ff5cbba9ec66.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/8ae1b6cc9da667dd3e02d32105a009505ff5cbba9ec66.jpg?mw=700" alt="バッジの Markdownコード をコピペできるダイアログ" /></a></p> <p>ダイアログ表示。</p> <p><a href="https://crieit.now.sh/upload_images/141188e82ee2e92f15b7ec06bc7286ef5ff5cbc8c6e40.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/141188e82ee2e92f15b7ec06bc7286ef5ff5cbc8c6e40.jpg?mw=700" alt="バッジを readme.md に貼り付け" /></a></p> <p>バッジを readme.md に貼り付けてみました。</p> <h2 id="バッジのリンクを変更する Chrome拡張機能"><a href="#%E3%83%90%E3%83%83%E3%82%B8%E3%81%AE%E3%83%AA%E3%83%B3%E3%82%AF%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B+Chrome%E6%8B%A1%E5%BC%B5%E6%A9%9F%E8%83%BD">バッジのリンクを変更する Chrome拡張機能</a></h2> <p>ところで、</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/akameco/items/e474691964703033e18d">GitHub Actionsのバッジをリンク付きでREADMEに追加する - Qiita</a></li> </ul> <p>こちらの記事で「デフォルトのバッジ画像の Markdownコード は画像のみとなっていて対象の Github Actions へのリンクにはなっていないのが不便」とありました。確かに……。</p> <p>上記の記事では UserScript で該当の Markdownコード を書き換える方法を紹介していましたが、個人的には Chrome拡張機能 で充分な気がしたのでざっくり自前で作ってみました。</p> <h3 id="リポジトリ"><a href="#%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA">リポジトリ</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/arm-band/chrome_extensions_cambadge">arm-band/chrome_extensions_cambadge</a></li> </ul> <h3 id="manifest.json"><a href="#manifest.json">manifest.json</a></h3> <pre><code class="json">{ "manifest_version": 2, "name": "cambadge", "description": "Github Actions のバッジのURLを変更する拡張機能です。", "version": "0.0.1", "browser_action": { "default_icon": { "19": "icon_19.png", "38": "icon_38.png" }, "default_title": "cambadge" }, "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'", "content_scripts": [ { "matches": [ "https://github.com/*" ], "js": [ "main.js" ] } ] } </code></pre> <h3 id="main.js"><a href="#main.js">main.js</a></h3> <pre><code class="javascript">/** * cambadgeCampaign: rewrite markdown code in textarea * * @param {object} DOMBadgeMd */ const cambadgeCampaign = (DOMBadgeMd) => { if (/^\!\[(.*)\]\((.*)\)$/gi.test(DOMBadgeMd.textContent)) { DOMBadgeMd.textContent = `[${DOMBadgeMd.textContent}](${location.href})`; } }; window.addEventListener('load', (e) => { // triggered load if (/https:\/\/github\.com\/(.*)actions(.*)/gi.test(location.href)) { // only github actions page const clickItem = document.querySelector('summary[data-test-selector="badge-builder-button"]'); clickItem.addEventListener('click', (ev) => { // triggered click of element:summary[data-test-selector="badge-builder-button"] let setIntervalId; let DOMBadgeMd; function findTargetElement () { // watch until find element:#badge-markdown DOMBadgeMd = document.querySelector('#badge-markdown'); if (DOMBadgeMd !== null && DOMBadgeMd !== undefined) { // found clearInterval(setIntervalId); // call function cambadgeCampaign(DOMBadgeMd); } }; setIntervalId = setInterval(findTargetElement, 100); }); } }); </code></pre> <p>ダイアログ中の <code>#badge-markdown</code> を含むバッジ生成の要素は <code>Create status badge</code> をクリックした際に生成されるようなので、 <code>Create status badge</code> をクリックした後、 <code>#badge-markdown</code> が見付かるまで書き換えの処理を待つようにしました。</p> <p><a href="https://crieit.now.sh/upload_images/fdaadb5b62dc4f103757d48bb84e12645ff5ccc3a2263.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/fdaadb5b62dc4f103757d48bb84e12645ff5ccc3a2263.jpg?mw=700" alt="バッジの Markdownコード (Chrome拡張機能 で書き換え実施後の表示)" /></a></p> <p>Chrome拡張機能 で書き換えられたダイアログ。これで該当の Github Actions ページへのリンクに繋がるようになりました。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <h3 id="バッジ"><a href="#%E3%83%90%E3%83%83%E3%82%B8">バッジ</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/SnowCait/items/487d70b342ffbe2f33d8#fn1">GitHub Actions でステータスバッジを表示する - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://docs.github.com/ja/free-pro-team@latest/actions/managing-workflow-runs/adding-a-workflow-status-badge">ワークフローステータスバッジを追加する - GitHub Docs</a></li> </ul> <h3 id="バッジのリンクを変更する"><a href="#%E3%83%90%E3%83%83%E3%82%B8%E3%81%AE%E3%83%AA%E3%83%B3%E3%82%AF%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B">バッジのリンクを変更する</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/akameco/items/e474691964703033e18d">GitHub Actionsのバッジをリンク付きでREADMEに追加する - Qiita</a></li> </ul> <h3 id="UserScript"><a href="#UserScript">UserScript</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://kenchan0130.github.io/post/2018-05-21-1">UserScriptで業務改善</a></li> </ul> arm-band tag:crieit.net,2005:PublicArticle/16007 2020-07-15T21:42:59+09:00 2020-07-15T21:47:11+09:00 https://crieit.net/posts/chrome-UTF-8-5f0ef9d3db43f 続・ブラウザ(chrome)のデフォルトエンコードってUTF-8じゃないの? <p><strong>かなり雑な考察ですのでご注意ください。</strong></p> <h2 id="今は昔"><a href="#%E4%BB%8A%E3%81%AF%E6%98%94">今は昔</a></h2> <p>かつて<a href="https://crieit.net/posts/chrome-UTF-8">ブラウザ(chrome)のデフォルトエンコードってUTF-8じゃないの?</a>という記事を書いたのですが。<br /> こちら、タイトルが疑問文であることからもわかる通り、単なる疑問を書き殴った記事で、解決していません。<br /> ですが、私が書いた他の記事の3倍、4倍ものアクセスがあり、心苦しいというか、「なんだよ、結局わからなかったじゃねえかよ、XXX」みたいに思われてるんだろうなあ、みたいな被害妄想をする日々でして。<br /> なので、もう少しだけ頑張ってみようと思います。</p> <h2 id="先に結論(推測)"><a href="#%E5%85%88%E3%81%AB%E7%B5%90%E8%AB%96%EF%BC%88%E6%8E%A8%E6%B8%AC%EF%BC%89">先に結論(推測)</a></h2> <ul> <li>もはやchromeにデフォルトエンコードというものはない。(たぶん)</li> <li>何もエンコードに関する指定がない場合に採用されるのは、自動判別の結果(の内のどれか)である。判別できなかったらデフォルトエンコードになる、みたいな挙動ではない。(おそらく)</li> <li>ぶっちゃけ、ちゃんとWEBサイトを作っていれば直面しない問題なので、わかってもあまり意味はない</li> </ul> <h2 id="とりあえず"><a href="#%E3%81%A8%E3%82%8A%E3%81%82%E3%81%88%E3%81%9A">とりあえず</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://chromium.googlesource.com/chromium/blink.git/+/master/Source">もぎゃさんの提示してくれたソース</a>を読もうと思ったんですけど……。<br /> なんだろう、これ。C++かな? 僕、C++やったことないんだよねえ……。<br /> これを機に覚えるというのも手ですが、正直そこまでの気力も時間もないし、機というほどのものでもないし、いきなりこのコードを読むのは辛いので、<strong>エンジニアらしからぬ感じで</strong>調べていこうと思います。</p> <p>とりあえず、ソースを落としてきます。<br /> で、調べます。<br /> 状況としては、「UTF-8になって欲しいものがShift_JISになってしまっている」ということなので、<strong>Shift_JISでgrepかけます。</strong><br /> 馬鹿みたいで、期待薄ですが、とりあえずかけます。<br /> VSCodeとか駆使しても良いですが、C++の拡張とかよくわからないので原始的にいきます。</p> <pre><code class="sh">$ grep -Ir Shift_JIS . ./platform/text/TextEncodingDetector.cpp: // a child frame in Shift_JIS and both frames do NOT specify the encoding ./wtf/text/TextCodecICU.cpp: registrar("shift-jis", "Shift_JIS"); </code></pre> <p>……お?<br /> 下のはshift-jisを正しくShift_JISにしている感じ? ちょっと関係なさそう。<br /> では、上のを見てみますか。TextEncodingDetectorなんて、いかにもそれっぽいじゃないですか。見るとなんか、コメントっぽいですね。</p> <pre><code class="c"> // If no match is found so far, just pick the top match. // This can happen, say, when a parent frame in EUC-JP refers to // a child frame in Shift_JIS and both frames do NOT specify the encoding // making us resort to auto-detection (when it IS turned on). if (!encoding && matchesCount > 0) encoding = ucsdet_getName(matches[0], &status); </code></pre> <p>とりあえずGoogle翻訳にかけます。<br /> <em>これまでに一致するものが見つからない場合は、一番上の一致を選択します。<br /> これは、たとえばEUC-JPの親フレームが<br /> Shift_JISの子フレームで、両方のフレームでエンコードが指定されていない<br /> 自動検出機能がオンになっている場合。</em><br /> ふむふむ。たぶん、「一番上」ってのは</p> <pre><code class="c">matches[0] </code></pre> <p>のことでしょう。では、matchesを入れてるのはというと、ちょい上に</p> <pre><code class="c">const UCharsetMatch** matches = ucsdet_detectAll(detector, &matchesCount, &status); </code></pre> <p>おー。……なんでしょうucsdet_detectAllって?<br /> grepかけても出てこないので、何かのライブラリかな?<br /> ということでググります。</p> <p>どうやら<a target="_blank" rel="nofollow noopener" href="https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/ucsdet_8h.html">ICU</a>というもので、<a target="_blank" rel="nofollow noopener" href="http://ykot.hateblo.jp/entry/20110112/1294821848">文字コード判定ができるもの</a>のようです。<br /> なんかそれっぽい。<br /> ただ、100%の精度ではないようで、複数の結果が返ってきたりすると。つまり、UTF-8だとかShift_JISだとかが配列になって返ってくるのかな。</p> <p>で、</p> <pre><code class="c">WTF::TextEncoding hintEncoding(hintEncodingName); // (中略) const char* matchEncoding = ucsdet_getName(matches[i], &status); //(中略) if (WTF::TextEncoding(matchEncoding) == hintEncoding) { encoding = hintEncodingName; break; } </code></pre> <p>んー、hintEncodingは引数で受け取ったhintEncodingNameからゴニョゴニョした感じっぽい。<br /> こいつ自身は/core/html/parser/TextResourceDecoder.cppから呼ばれてるっぽいな。</p> <pre><code class="c">if (detectTextEncoding(data, len, m_hintEncoding, &detectedEncoding)) setEncoding(detectedEncoding, EncodingFromContentSniffing); </code></pre> <p>それっぽい。</p> <h2 id="そろそろ限界"><a href="#%E3%81%9D%E3%82%8D%E3%81%9D%E3%82%8D%E9%99%90%E7%95%8C">そろそろ限界</a></h2> <p>そろそろ雰囲気だけで読むのは限界です……。<br /> 何となく、metaタグやwebサーバーのレスポンスヘッダなどで指定されたエンコードと、ICUの判定結果を突合して一致したものをエンコードとしてるような気がする。<br /> で、一致しなかった場合、ICUの判定結果の0番目を採用する感じかな。<br /> これ以上は限界。</p> <h2 id="遊んでみる"><a href="#%E9%81%8A%E3%82%93%E3%81%A7%E3%81%BF%E3%82%8B">遊んでみる</a></h2> <p>こんなコードを書いてみます。で、いろんなエンコードで保存します。</p> <pre><code class="html"><html> <head> </head> <body> てすと <p id="charset"></p> </body> <script type="text/javascript"> document.getElementById('charset').innerText = document.characterSet </script> </html> </code></pre> <h3 id="UTF-8"><a href="#UTF-8">UTF-8</a></h3> <p><a href="https://crieit.now.sh/upload_images/b4e7ccc0fa53a881f6b3b0f9843f0ac25efc2f0c6b0c3.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b4e7ccc0fa53a881f6b3b0f9843f0ac25efc2f0c6b0c3.png?mw=700" alt="image" /></a><br /> たぶん、UTF-8もShift_JISも検出してるけど、Shift_JISの方が先って感じなのかな? アルファベット順かな?</p> <h3 id="Shift_JIS"><a href="#Shift_JIS">Shift_JIS</a></h3> <p><a href="https://crieit.now.sh/upload_images/1d242b199842e3f464b872ff003bdce95efc2f390b029.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/1d242b199842e3f464b872ff003bdce95efc2f390b029.png?mw=700" alt="image" /></a><br /> なるほどそうなるよね</p> <h3 id="EUC"><a href="#EUC">EUC</a></h3> <p><a href="https://crieit.now.sh/upload_images/a10d542dd8e60570fefae9a2252b6bb25efc2f48bb917.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/a10d542dd8e60570fefae9a2252b6bb25efc2f48bb917.png?mw=700" alt="image" /></a><br /> おっと? 一応表示されたけどGBKって何?<br /> と思ったら簡体字用のエンコードなのね。まさかの中国語判定。</p> <h3 id="ちなみにutf-8のファイルをwebサーバー通さずにファイル表示すると"><a href="#%E3%81%A1%E3%81%AA%E3%81%BF%E3%81%AButf-8%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92web%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E9%80%9A%E3%81%95%E3%81%9A%E3%81%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E3%81%A8">ちなみにutf-8のファイルをwebサーバー通さずにファイル表示すると</a></h3> <p><a href="https://crieit.now.sh/upload_images/0a6dd05da4378d2541e95beca5646ad15efc2f646522d.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/0a6dd05da4378d2541e95beca5646ad15efc2f646522d.png?mw=700" alt="image" /></a><br /> なんで?<br /> きっとhintEncodingに何か入ってるんだろうけど……。確かに、ファイルを直で見れるので、Webサーバー通すより何かしらの情報はありそう。ただ、調べるにはちょっと力量の限界。</p> <h2 id="その他"><a href="#%E3%81%9D%E3%81%AE%E4%BB%96">その他</a></h2> <p>前の記事のコメントで、apacheでは文字化けしてIISでは文字化けしなかったみたいなこと言いましたけど、改めて検証したらIISでもちゃんと?文字化けしました。(この調査結果だとそりゃそうなんですが)<br /> たぶん、何か環境構築とか検証方法を間違えてたんだと思いますが……。<br /> もちろん、nginxでも文字化けします。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <ul> <li>結論としては最初に言った通り</li> <li>雑な考察なので信用に足るかは怪しい</li> <li>わかる人は優しく教えてください</li> <li>metaタグ等でエンコードはちゃんと設定しよう</li> </ul> hammhiko tag:crieit.net,2005:PublicArticle/14890 2019-03-28T19:12:26+09:00 2019-03-28T19:12:26+09:00 https://crieit.net/posts/chrome-UTF-8 ブラウザ(chrome)のデフォルトエンコードってUTF-8じゃないの? <p>まー、困ることはないんだけど、気になって気になって</p> <h1 id="発端"><a href="#%E7%99%BA%E7%AB%AF">発端</a></h1> <p>よく、jsとかの挙動で「あれ、どうだっけ?」ってなった時、</p> <pre><code><html> <head> </head> <body> <button onclick="test()"> test </button> <script src="index.js"> </body> </html> </code></pre> <p>とかで、</p> <pre><code>docker run -d -p 8888:80 -v `pwd`:/usr/local/apache2/htdocs httpd </code></pre> <p>で、さくっと試したりする。(果たしてこれがさくっとなのか)<br /> まー、見てわかる通り、htmlはあまりにも手抜きすぎるんだけど。<br /> 動くし、すぐ使い終わるから。</p> <p>んで、ある時、</p> <pre><code><html> <head> </head> <body> <button onclick="test()"> てすと </button> <script src="index.js"> </body> </html> </code></pre> <p>ってやったら、見事に文字化けした。<br /> (macのchrome)</p> <h1 id="対処はわかる。わかるんだけど…"><a href="#%E5%AF%BE%E5%87%A6%E3%81%AF%E3%82%8F%E3%81%8B%E3%82%8B%E3%80%82%E3%82%8F%E3%81%8B%E3%82%8B%E3%82%93%E3%81%A0%E3%81%91%E3%81%A9%E2%80%A6">対処はわかる。わかるんだけど…</a></h1> <p>対処としては簡単で、</p> <pre><code><html> <head> <meta charset="utf-8"></meta> </head> <body> <button onclick="test()"> てすと </button> <script src="index.js"> </body> </html> </code></pre> <p>metaタグでcharset指定するだけなんだけど。</p> <p>ファイル自体はUTF-8で作成していたし、UTF-8なら大丈夫だろ、とか思ってたからちょっとびっくりした。<br /> デフォルトでUTF-8じゃないのか。<br /> 気になったので調べようと思った。</p> <h1 id="調べた"><a href="#%E8%AA%BF%E3%81%B9%E3%81%9F">調べた</a></h1> <h1 id="わかんなかった"><a href="#%E3%82%8F%E3%81%8B%E3%82%93%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F">わかんなかった</a></h1> <p>「指定しないと文字化けする可能性があるので、ちゃんと指定しましょう」<br /> そんなことはわかってるんだ。<br /> わかった上で、指定しなかったらどうなるか知りたいんだ。<br /> 指定しなかったら文字化けする? 違う、そうじゃない。いや、そうなんだけど、そうじゃない。知りたいのはそこじゃない。どのエンコーディングが採用されるのか、だ。</p> <p>apacheにAddDefaultCharsetとかなかったし、ブラウザ側だと思うんだけどなー。</p> <p>それっぽいこと書いてある<a target="_blank" rel="nofollow noopener" href="http://www.ic.daito.ac.jp/~mizutani/html/default_encode.html">サイト</a>もあったが、ちょっと古い。<br /> chrome ver.35って。俺のchrome、ver.73だぞ。そんな項目ねーよ。<br /> というか、chromeは<a target="_blank" rel="nofollow noopener" href="https://www.beginnerweb.net/chrome.html">もうエンコード指定できない</a>。<br /> まー、大半のユーザーは「エンコードとは何ぞ」って感じだから、意識させないってのは、わからなくもない。charset指定しないサイトなんて今時ないだろうし。でも、だからこそ、なおのこと指定しなかった場合の挙動がよくわからん。</p> <p>普段、ちゃんと作る時は、まず間違いなく指定するmetaタグだし、わからなくても困らないっちゃ困らないし、不毛なので調べるのをやめた。</p> <h1 id="結論"><a href="#%E7%B5%90%E8%AB%96">結論</a></h1> <ul> <li>エンコードはちゃんと指定しよう</li> <li>どなたか、ご存知でしたら優しく教えてください。</li> </ul> hammhiko tag:crieit.net,2005:PublicArticle/14879 2019-03-25T19:00:00+09:00 2019-03-25T19:00:00+09:00 https://crieit.net/posts/windows10-elementary-os windows10からelementary os へリモートデスクトップ接続する <p>めちゃくちゃハマった。<br /> 祝日が溶けた。</p> <h1 id="結論"><a href="#%E7%B5%90%E8%AB%96">結論</a></h1> <p>chromeリモートデスクトップ<br /> ただし、それすらもハマる</p> <h1 id="発端"><a href="#%E7%99%BA%E7%AB%AF">発端</a></h1> <p>古いwindows PCが余ってたので、Linuxでも入れて遊ぼうかと。<br /> 古いPCって言ってるのに(スペック要求の高い)elementary os かよって話はあるけども。</p> <p>入れたは良いけども、PC2台をデスクに並べて別々にキーボードとマウス操作するのはだるいので、windowsからリモート接続しようと試みた。</p> <p>windowsならリモートデスクトップ接続(mstsc.exe)で簡単という認識だったのだけれど、windows→Linuxはどうなんだろ?<br /> と、軽くググってみたところ、どうもxrdpというのでいけるらしい。</p> <h1 id="xrdpで詰まる"><a href="#xrdp%E3%81%A7%E8%A9%B0%E3%81%BE%E3%82%8B">xrdpで詰まる</a></h1> <p>……繋がんねー</p> <pre><code>sudo apt install xrdp </code></pre> <p>でとりあえず使える、みたいなこといろんなとこに書いてあるのに、繋がんねー。<br /> ログみても</p> <pre><code>some problem </code></pre> <p>とか書いてあってさっぱりわかんねー。</p> <p>で、いろいろ試行錯誤しすぎて、どのページ見たのかわからなくなったのだけど、たぶん<a target="_blank" rel="nofollow noopener" href="https://www.hiroom2.com/2018/05/07/ubuntu-1804-xrdp-xfce-ja/">このへん</a>あたり見て設定したらとりあえず繋がった。<br /> のだけれど。</p> <p>見た目が全然違う。</p> <p>なんか、青くてDebianとか書いてある(あった気がする)。<br /> (スクショは撮ってない)<br /> 僕の気に入った綺麗なelementary os のデスクトップはどこに行ったの?</p> <h1 id="デスクトップ環境云々"><a href="#%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E7%92%B0%E5%A2%83%E4%BA%91%E3%80%85">デスクトップ環境云々</a></h1> <p>普段はwindows使って、Linuxはサーバー用途でCUIのみ、とかやってると馴染みがないけど、Linuxにはデスクトップ環境がたくさんある。<br /> windowsはOSとデスクトップが密になっているけど、Linuxはそうじゃない(気がする)<br /> windowsだと、いつも見ているあの画面がそのままリモートでって感じになるけど、Linux(というかxrdp?)だと、「指定したデスクトップ環境の見た目をエミュレートした結果をmstsc.exeに見せている」って感じなのかな。自信はない。<br /> で、上のリンク見て僕はxfceのデスクトップ環境を指定していた。</p> <p>つまり例えるなら、firefoxを立ち上げて、「chromeの見た目じゃない!」って騒いでいるようなもの。バカじゃん、俺。</p> <p>正直なところ、elementary os を使う理由ってあのデスクトップ環境なところが大部分占めてるので(でなきゃUbuntu使ってるなー)、別のデスクトップじゃ意味がない。</p> <p>じゃあつまり、elementary os のデスクトップ環境と同じのを指定すれば良いんだなと。elementary os のデスクトップ環境はPantheonっていうらしい。教えてgoogle先生!</p> <p>……なさそう。</p> <p>調べ方が悪いのか、調べても出てこないし、適当に.xsession書き換えてみたけどダメだった。<br /> 代わりに見つけたのが<a target="_blank" rel="nofollow noopener" href="https://www.reddit.com/r/elementaryos/comments/8iorv5/connect_to_remote_desktop/">これ</a></p> <p>英語苦手なんだけど、雰囲気で読んでみたら、たぶんこんなこと言ってる。</p> <p><em>「elementary os でxrdpリモートデスクトップしたいけどできないんだけど」<br /> 「xfceデスクトップ環境をインストールしてxrdpで指定すれば繋がるけど、見た目変わっちゃうよ。見た目変えたくないなら諦めてchromeリモートデスクトップ使えば?」</em></p> <p>まじか。</p> <h1 id="chromeリモートデスクトップでも詰まる"><a href="#chrome%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%81%A7%E3%82%82%E8%A9%B0%E3%81%BE%E3%82%8B">chromeリモートデスクトップでも詰まる</a></h1> <p>chromeリモートデスクトップなら使ったことあるし、<a target="_blank" rel="nofollow noopener" href="https://support.google.com/chrome/answer/1649523">公式のヘルプ</a>見ればすぐできるだろとか思ったら、そうは問屋が卸さなかった。(問屋なら卸せよ)</p> <p>ヘルプの通り設定したら、繋がった。<br /> 繋がった、けど。<br /> 壁紙だけ出て、何も操作できない。<br /> 何か設定ミスったかと思って見返してみても問題なさそう。<br /> お決まりの再起動とかしてみても変わらず。</p> <p>調べて見たら<a target="_blank" rel="nofollow noopener" href="https://qiita.com/minecraft/items/452671c93822ba06a1c4">同じような現象があった</a>のでその通りやってみたら、今度は繋がりすらしない。</p> <p>さらに調べた結果、<a target="_blank" rel="nofollow noopener" href="https://webnetforce.net/ubuntu-chrome-remote-trouble/">見つけた</a>。<br /> 内容の説明もちゃんとあって、わかりやすかった。</p> <p>繋がった。<br /> 歓喜。</p> <h1 id="レスポンスは?"><a href="#%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%81%AF%EF%BC%9F">レスポンスは?</a></h1> <p>以前、chromeリモートデスクトップ使った時は、結構動作がもっさりしてて、だから最初の選択肢になかったのだけれど、使ってみたらあまりストレス感じなかった。</p> <p>前使った時は、windows→windowsで、ネットワークもグローバル越しだったので負荷が高かったのかも。何年か前だしアプリも改良されているのかも。</p> <h1 id="教訓"><a href="#%E6%95%99%E8%A8%93">教訓</a></h1> <ul> <li>あまり情報のなさそうなやつは修羅の道と心得よ<br /> (Ubuntuだったらここまでハマらなかった気がする)</li> <li>英語の情報もちゃんと読もう<br /> (みんな言ってることだけど、改めて)</li> <li>自分がやっていることをちゃんと理解すること<br /> (あまり説明のないものをコピペ、とかやると動かなくなるし、何が悪いかもわからない)</li> </ul> hammhiko tag:crieit.net,2005:PublicArticle/14792 2019-02-12T07:22:09+09:00 2019-09-17T09:53:37+09:00 https://crieit.net/posts/Node-Chrome-Twitter NodeでChromeを操作してTwitterシェア用画像を生成するサーバー作った <p>Node.jsにはPuppeteerという画面を表示せずにChromeを扱えるライブラリがあります。それを利用し、URLをパラメータとして与えるだけでスクリーンショットを画像としてブラウザで表示させることができるサーバーアプリケーションを作成しました。</p> <p>実際にこのような画像が作成できます。例として下記はボード内投稿にコードを入れた場合に表示される画像です。</p> <p><a href="https://crieit.now.sh/upload_images/4360e4d36fd52f45541d0f4dd80cac245c56eb8b322a6.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/4360e4d36fd52f45541d0f4dd80cac245c56eb8b322a6.png?mw=700" alt="コードを表示したOGP例" /></a></p> <p>下記は記事の画像です。</p> <p><a href="https://crieit.now.sh/upload_images/597a7f2e06da1377ad7cbc486bd0f4cf5c61706d22563.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/597a7f2e06da1377ad7cbc486bd0f4cf5c61706d22563.png?mw=700" alt="記事のOGP例" /></a></p> <p>HTML, CSSから生成しているためドロップシャドウとかもこんな感じで簡単に効かせる事ができています。</p> <p>GitHubで公開していますので、とりあえず使って見たいという方は記事を読み飛ばして最後の方にあるリンクをご利用ください(こらえきれぬ涙で頬を濡らしながら)</p> <h2 id="何が便利なのか"><a href="#%E4%BD%95%E3%81%8C%E4%BE%BF%E5%88%A9%E3%81%AA%E3%81%AE%E3%81%8B">何が便利なのか</a></h2> <p>WebサービスのURLをTwitter等でシェアするだけで、URLだけでなくツイートに画像も表示されるのをよく見ると思います。</p> <p>これは画像をアップしているわけではなく、そのページ内のHTMLに書かれているメタタグで指定されている画像を勝手にSNS側で表示してくれるという便利な、いわゆるOGPというものです。</p> <h3 id="Webサービスでの困りごと"><a href="#Web%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%A7%E3%81%AE%E5%9B%B0%E3%82%8A%E3%81%94%E3%81%A8">Webサービスでの困りごと</a></h3> <p>普通のサイトであれば画像を指定するだけですが、Webサービスの場合は投稿された内容をもとにしたOGPを動的に作りたいという場合があります。</p> <p>この場合画像を動的に作成しなければならないのですが、これがなかなか面倒です。</p> <p>サーバーサイドでやると、負荷がかかったりそもそも描画がプログラムによる命令で構築されることが多く、メンテナンスが非常に面倒です。フロントでやることもできますが、ブラウザの閲覧環境によって表示に違いが出てしまったりします。</p> <h3 id="解決策"><a href="#%E8%A7%A3%E6%B1%BA%E7%AD%96">解決策</a></h3> <p>そのため、専用のPuppeteerを用いたOGP生成サーバーを用意することで前述の全ての問題を解決することができます。</p> <p>OGPはURLを指定するだけのため、サーバーを別にすることもできますので、分けておけばアプリケーションサーバー側に負荷は一切ありません。また、OGPサーバーのブラウザで表示を行いスクリーンショットをとるため、ユーザーの環境にも依存しません。</p> <h2 id="具体的な仕組み"><a href="#%E5%85%B7%E4%BD%93%E7%9A%84%E3%81%AA%E4%BB%95%E7%B5%84%E3%81%BF">具体的な仕組み</a></h2> <p>今回作成したものは、URLを指定するとそのURLのスクリーンショットを撮って画像として表示してくれる、というだけの非常にシンプルなものです。</p> <p>例えば最初の記事の画像であれば、実際の <a href="https://crieit.net/posts/Crieit-5b91bd1569dbd">なぜCrieitを作ろうと思ったか</a> のページにアクセスし、ソースを見るとわかりますが、下記のようなメタタグがあります。</p> <pre><code class="html"> <meta property="og:image" content="https://ogp.crieit.net/posts/Crieit-5b91bd1569dbd/ogp.png"> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:image" content="https://ogp.crieit.net/posts/Crieit-5b91bd1569dbd/ogp.png"> </code></pre> <p>この<code>og:image</code>と<code>twitter:image</code>に指定されている画像が今回紹介する仕組みで作成されている画像です。</p> <p>具体的には、crieit.netの全く同じパスのスクリーンショットを撮る仕組みになっています。つまり、上記であれば下記のURLのスクリーンショットを撮っています。実際に見ていただくことも可能です。(拡張子はつけれるようにしています。理由は後述します)</p> <p><a href="https://crieit.net/posts/Crieit-5b91bd1569dbd/ogp">https://crieit.net/posts/Crieit-5b91bd1569dbd/ogp</a></p> <p>アクセスしていただくとわかりますが、OGP画像をそのまま単なるHTMLとCSSで作っているだけになります。単にそのページのスクリーンショットを撮っているだけです。この例ですとフォントが違うと思いますが、それはOGPサーバー内にインストールしているのでOGPサーバー内のChromeでは正しいフォントで表示されます。</p> <p>ちなみにブラウザでのレンダリングのため、JavaScriptも動きます。今回のコード表示の例もhighlight.jsを動かしています。</p> <h3 id="URLに拡張子"><a href="#URL%E3%81%AB%E6%8B%A1%E5%BC%B5%E5%AD%90">URLに拡張子</a></h3> <p>前述の例のように、OGPサーバー側のURLには拡張子をつけることができます。これにより、CloudflareのようなCDNを介する場合、ちゃんとキャッシュしてくれるようになります。</p> <p>つまり、そのURLに一度誰かがアクセスしていればその後はCDNで配信されるようになるため、OGPサーバー側にはアクセスが来なくなります。</p> <p>実際に前述の画像を開いてリロードするとめちゃくちゃ速いのがわかると思います。たいした処理ではないにしろ、本来はブラウザでページを開くだけの時間がかかりますので全然変わってきます。</p> <p>とはいえそもそもOGPはだいたいSNS側でキャッシュされるためあまりメリットは大きくないのですが、改造すれば他の用途にも使用することができますので、この仕組みを覚えておけば色々と便利ではあると思います。</p> <h3 id="構成要素"><a href="#%E6%A7%8B%E6%88%90%E8%A6%81%E7%B4%A0">構成要素</a></h3> <p>Puppeteerを使うのでNode.jsのサーバーとなります。</p> <p>サーバーはExpressで、expressコマンドで作成したソースのほとんどそのままです。複雑なことはしていないので数十行書いたくらいで完成しました。(そのため不要な処理もたくさん残っていて作り自体は雑です…)</p> <h3 id="functions系の利用は断念"><a href="#functions%E7%B3%BB%E3%81%AE%E5%88%A9%E7%94%A8%E3%81%AF%E6%96%AD%E5%BF%B5">functions系の利用は断念</a></h3> <p>現在色々なPaasやfunctionsサービスがありますが、色々調べたり試した結果利用は断念し、最終的にシンプルにExpressによるNode.jsのサーバーで作ることにしました。</p> <p>断念した理由は下記等です。</p> <ul> <li>リクエスト毎にブラウザを起動しなければならないため、画像生成にかなり時間がかかりそう。Expressであれば最初に一度起動しておくだけでよい</li> <li>サービスによってはそもそも使えない</li> <li>サービス上では特殊な実装にしなければならない場合があるので、ローカルで試しづらく開発に時間がかかって面倒な場合がある</li> <li>サービスによってはプロセスの実行時間制限があったりする</li> </ul> <p>…等です。もしうまく簡単に動かせるサービスがあったらぜひ教えてください。</p> <h2 id="サーバー"><a href="#%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC">サーバー</a></h2> <p>実際のサーバーの作り方を解説していきます。</p> <h3 id="Chromeをインストール"><a href="#Chrome%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">Chromeをインストール</a></h3> <p>一番重要な仕事をしてくれるものです。</p> <p>ChromeDriverを試していた時の名残で一部不要なものが混じってるかもしれません。これはDockerfileの中身そのままです。</p> <pre><code class="sh">apt-get update apt-get install -y libappindicator1 fonts-liberation unzip curl -O https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb dpkg -i google-chrome*.deb || apt update && apt-get install -f -y </code></pre> <h3 id="フォントをインストール"><a href="#%E3%83%95%E3%82%A9%E3%83%B3%E3%83%88%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">フォントをインストール</a></h3> <p>Webフォントだけでページを作れば不要ですが、そうでない場合や不足のフォントがありそうな場合にはインストールしておきます。</p> <pre><code class="sh">apt-get install fonts-ipafont-gothic fonts-ipafont-mincho </code></pre> <h3 id="Node.jsをインストール"><a href="#Node.js%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">Node.jsをインストール</a></h3> <p>とりあえずnpmとyarnを入れておきます。公式サイトに書かれている手順で入れておけば問題ないと思います。</p> <h3 id="npmのモジュールーインストール"><a href="#npm%E3%81%AE%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%83%BC%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">npmのモジュールーインストール</a></h3> <p>Chromeはすでにインストールしているため、それをスキップする形でインストールします。違うパターンでインストールしたい場合は適宜変更してください。</p> <pre><code class="sh">PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true yarn </code></pre> <h3 id="Nginxをインストール"><a href="#Nginx%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">Nginxをインストール</a></h3> <p>これは必須ではないのですが、ポート3000で動いているNode.jsサーバーを80にプロキシしたかったのと、SSLに対応したかったため同じくLet's Encryptのcertbotが使用するURLもプロキシして放置で証明書が更新されるようにしたかったためNginxで動かすようにしています。(ここもわりと適当なため適宜変更してください)</p> <pre><code> listen 443 ssl default_server; ssl_certificate /etc/letsencrypt/live/ogp.example.net/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/ogp.example.net/privkey.pem; server_name ogp.example.net; proxy_redirect off; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; location ^~ /.well-known/ { root /var/www/html; } location / { proxy_pass http://localhost:3000/; } </code></pre> <h3 id="Systemdでサービス化"><a href="#Systemd%E3%81%A7%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E5%8C%96">Systemdでサービス化</a></h3> <p>下記のように設定しました。</p> <pre><code class="ini">[Unit] Description=ogp server After=syslog.target network.target [Service] Type=simple ExecStart=/usr/bin/npm start WorkingDirectory=/path/to/puppeteer-ogp KillMode=mixed Restart=always User=yourname Group=yourgroup [Install] WantedBy=multi-user.target </code></pre> <p>だと、理由はまだよく分かりませんがうまくアプリケーションやChromeのプロセスが終了してくれないため、<code>KillMode=mixed</code>にして丸々強制終了するようにしています。</p> <p>サービスの有効化は下記です。</p> <pre><code class="sh">sudo systemctl enable ogp </code></pre> <p>あとは下記で起動すれば完全放置できます。</p> <pre><code class="sh">sudo service ogp start </code></pre> <p>ちなみに僕は無料枠で動かせるGCE(Google Compute Engine)のf1-microを使っています。</p> <h2 id="公開しました"><a href="#%E5%85%AC%E9%96%8B%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F">公開しました</a></h2> <p>かなり何もやってないレベルの製作物だったので、作成したものをGitHubで公開しています。是非適当に試してみたり、改造して遊んでみたりしてみてください。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/dala00/puppeteer-ogp">dala00/puppeteer-ogp</a></p> <p>下記に重要な注意点を書きます。そのあとローカルでの開発方法もざっと書いておきます</p> <h2 id="注意点"><a href="#%E6%B3%A8%E6%84%8F%E7%82%B9">注意点</a></h2> <p>まだ動かしてからさほど経っていないため、どれくらい安定稼働してくれるかは謎です。というのも、アプリケーションとは別にChromeが動いているので、そのあたりで安定性がどうなのかという部分が全く想像できません。一応最後に調整をしてからは問題ないようなのですが、稼働初期はクラッシュしまくっていました。</p> <p>ですので利用される場合は自己責任でよろしくお願いします。一応どういう対策を入れたかと、どういう問題がありそうかをメモしておきます。</p> <h3 id="エラー処理を入れる"><a href="#%E3%82%A8%E3%83%A9%E3%83%BC%E5%87%A6%E7%90%86%E3%82%92%E5%85%A5%E3%82%8C%E3%82%8B">エラー処理を入れる</a></h3> <p>ブラウザがクラッシュする前提で、ページを開くときとかにエラーをcatchするようにし、問題があれば再起動するようにします。ただ、確認が不十分のため現在のエラー処理自体が正しくない可能性があります。実際にクラッシュするとプロセスがどんどん増えていく問題を確認済みです。</p> <p>おそらくですが、デーモン化して確実に再起動される状態であれば、問題が出たらそのままアプリケーションを落としてしまう方が安心では、という気がしています。(そうなると安定性と高頻度アクセスを保証すべきようなアプリケーションでは難しいかもしれませんが)</p> <h3 id="URLのフィルタを入れる"><a href="#URL%E3%81%AE%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%82%92%E5%85%A5%E3%82%8C%E3%82%8B">URLのフィルタを入れる</a></h3> <p>これが今のところ一番の改善になりました。というのも、サーバーを公開していると.gitフォルダやphpMyAdminを無差別に探してデータを盗もうとする不審なアクセスがあります。これが一瞬のあいだに高頻度で行われるのでChromeへの負荷が高まりクラッシュしていました。</p> <p>そのため下記のような感じで環境変数にて必要なURLだけをフィルタできるようにし、それ以外のURLの場合はChromeを使わないようにしました。これだけでクラッシュが発生しなくなりました。</p> <pre><code>URL_FILTER=/articles,/posts </code></pre> <p>とにかく、いかにChromeを使用しないか、というところが重要になってくる気がします。アクセスが多い場合、待機させるようにして同時にたくさんのページを開かないような形にすると安定性が上る可能性もありそうです。(ただしレスポンスが悪くなるとSNSがOGPを認識してくれない可能性も出てきそうですが)</p> <h3 id="キューで処理する(追記)"><a href="#%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%A7%E5%87%A6%E7%90%86%E3%81%99%E3%82%8B%EF%BC%88%E8%BF%BD%E8%A8%98%EF%BC%89">キューで処理する(追記)</a></h3> <p>来たリクエストをすぐ処理せず、キューで処理する形式にしてサーバー全体で一度に1ページしか開かないようにしたところ安定している気がします。GitHubのプログラムもそのように更新済みです。</p> <h3 id="多分結構スペックが高いサーバーの方が良さそう"><a href="#%E5%A4%9A%E5%88%86%E7%B5%90%E6%A7%8B%E3%82%B9%E3%83%9A%E3%83%83%E3%82%AF%E3%81%8C%E9%AB%98%E3%81%84%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AE%E6%96%B9%E3%81%8C%E8%89%AF%E3%81%95%E3%81%9D%E3%81%86">多分結構スペックが高いサーバーの方が良さそう</a></h3> <p>Chrome自体が低スペック環境でガンガン快適に動くようなものではないので、サーバーもスペックが高いほうが良さそうな気がします。実際に現在使っているGoogle Compute Engineのf1-microインスタンスでは、マシンタイプをグレードアップしたほうが良い、というアラートがずっと出っぱなしになっています。</p> <p>また、おそらくスペックが高いほうがクラッシュする可能性も低くなるのでは…と想像しています。</p> <h3 id="参考にした情報"><a href="#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E6%83%85%E5%A0%B1">参考にした情報</a></h3> <p>たしか下記あたりを参考にしました。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://uyamazak.hatenablog.com/entry/2019/01/30/150910">Headless Chromeを使ったPDF変換サーバーが落ちないようにした対策まとめ - GAミント至上主義</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/go_sagawa/items/4a368040fac6f7264e2c">puppeteerを永続化したNode.jsアプリ内で安定稼働させる方法 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/windyakin/items/00b085902547570eebc6">Docker上のpuppeteerがPage crashしてしまうときはshmサイズを疑う - Qiita</a></li> </ul> <h2 id="ローカルでの開発方法"><a href="#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%A7%E3%81%AE%E9%96%8B%E7%99%BA%E6%96%B9%E6%B3%95">ローカルでの開発方法</a></h2> <p>基本的にはGitHubにあげているREADMEそのままですが、Dockerとdocker-composeさえ入っていれば誰でもすぐ試せるようになっています。Getting StartedとDevelopmentのところをそのまま行うだけで動きます。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>ちょっと改造すればひとつのサーバーで複数のサービスのURLに対応することも可能ですし、特に個人開発している人はひとり一OGPサーバーを持っておくとなにかと便利な気がします。</p> <p>コードのOGPはよろしければ下記で色々投稿して試してみてください!</p> <p><a href="https://crieit.net/boards/try-code-ogp">コードのOGPを試してみるボード</a></p> <p>もし問題やプルリクエストがある場合はお気軽にGitHubに立ててください。(余裕のあるときしか見れないかもしれませんが…)</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14758 2019-01-29T19:30:29+09:00 2019-01-29T19:35:30+09:00 https://crieit.net/posts/chromedp-Node-HTML chromedpで検索したNodeのHTMLを取得する <p>Go言語でヘッドレスChromeを利用できるライブラリであるchromedpにて、検索した要素のHTMLを取得するサンプルが全く見つからなかったのでメモ。</p> <p>まずはクエリセレクタで要素リストを取得する。</p> <pre><code class="go"> err := c.Run(ctxt, chromedp.Tasks{ chromedp.Nodes(".some-class a", &nodes, chromedp.ByQueryAll), }) </code></pre> <p>このnodesの下にある要素のHTMLを取得したかったのだが、<code>cdp.Node</code>にはinnerHTML的なプロパティもメソッドもない。よくわからないがいろいろ調べたところ下記のような方法で取れた。</p> <pre><code class="go"> var result string err := c.Run(ctxt, chromedp.Tasks{ chromedp.ActionFunc(func(ctxt context.Context, h cdp.Executor) error { html, err := dom.GetOuterHTML().WithNodeID(node.NodeID).Do(ctxt, h) if err == nil { result = html } return err }), }) </code></pre> <p>十分なリファレンスがほしい…。やっぱりquerySelector等がそのまま使えるNode.jsでのpuppeteer利用が最強っぽい気がする。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14726 2019-01-18T09:29:07+09:00 2019-01-18T12:23:31+09:00 https://crieit.net/posts/UI-HTML UIを整えるためにHTMLをデバッグするする方法 <p>HTMLを書いてブラウザで確認している時にどうしても上手く思った通りにならない場合があったりします。配置がうまくいかなかったり、marginやpaddingが思い通りにならなかったりなど。その時の確認方法などをまとめてみました。</p> <p>昔はtableやfloat等が主なレイアウト方法だったのでシンプルでわかりやすかったのですが、CSS3も一般的になり色々と便利になる一方、惑わされる要素も増えてきたような気がします。</p> <p>※ <a href="https://crieit.net/boards/post-request/2e7d073b46d856eccb4e591fa599cb88">記事投稿リクエストボード</a> に投稿していただいた件に対する記事となります。</p> <h2 id="基本的な確認方法"><a href="#%E5%9F%BA%E6%9C%AC%E7%9A%84%E3%81%AA%E7%A2%BA%E8%AA%8D%E6%96%B9%E6%B3%95">基本的な確認方法</a></h2> <p>具体的な話の前にひとまず念の為基本的な確認方法を書いておきます。ご存知の方も多いと思うので適宜読み飛ばしてください。Chromeでの話です。</p> <p>調べたい要素の上で右クリックをするとこのようなメニューが出てきますので、「検証」を選択します。これでその要素が選択された状態でChrome DevToolsが開きます。もしくはF12キーを押して直接Developer Toolsを開いても構いません。</p> <p><a href="https://crieit.now.sh/upload_images/f445e18b21a560b6a255b19346aa348d5c3fca15d4d75.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/f445e18b21a560b6a255b19346aa348d5c3fca15d4d75.png?mw=700" alt="rightmenu.png" /></a></p> <p>するとこのような画面が開きます。</p> <p><a href="https://crieit.now.sh/upload_images/08b1043105d7bcfeebbf2a55d16812c85c3fcb664c73c.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/08b1043105d7bcfeebbf2a55d16812c85c3fcb664c73c.png?mw=700" alt="devtool.png" /></a></p> <p>右上はElementsタブを開いている状態です。右クリックしたあたりが表示されています。マウスカーソルを合わせると、左の画面のようにその箇所がハイライトされます。</p> <p>また、Elementsの要素をクリックすると、その下にCSSの一覧(左)、最終的なサイズやCSSの情報(右)が表示されています。これはDevToolsをウィンドウの右側にドッキングしている状態ですので、実際にどのような使い方をしているかによってこのあたりは変わってきます。適宜使いやすい方法にしてください。</p> <p>謎の挙動がなければ、だいたいはこれでほとんど問題があれば原因は分かると思います。</p> <p>また、CSSの一覧の一番上に<code>element.style</code>という空のスタイルがあると思います。これはその場で自由にスタイルを指定できますので、「このスタイルのせいで動きがおかしくなっているんじゃないか」みたいなものに気づいたらとりあえずここでそれを上書きして試すことで、それが原因か、そうでなく他に原因があるか、というのをすぐ確認することができます。</p> <h2 id="謎の挙動"><a href="#%E8%AC%8E%E3%81%AE%E6%8C%99%E5%8B%95">謎の挙動</a></h2> <p>とはいえ謎の挙動も増えている感じがするので、思いつく限り書いてみます。</p> <h3 id="要素のサイズが思ったとおりにならない"><a href="#%E8%A6%81%E7%B4%A0%E3%81%AE%E3%82%B5%E3%82%A4%E3%82%BA%E3%81%8C%E6%80%9D%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%8A%E3%82%8A%E3%81%AB%E3%81%AA%E3%82%89%E3%81%AA%E3%81%84">要素のサイズが思ったとおりにならない</a></h3> <p>横幅を指定したのに思ったとおりのサイズにならなかったりすると思います。これはわりとCSSのdisplayの設定であることが多いので、displayに指定した値によってどう変わるのかは一通りある程度把握しておいたほうが良いと思います。</p> <h4 id="inline"><a href="#inline">inline</a></h4> <p>これはspanタグやaタグのように、文章中にそのまま含めるようなタグのデフォルトのdisplayとして使われています。下記のような特徴があります。</p> <ul> <li>要素のサイズを指定しても無視される</li> <li>marginやpaddingも指定しても無視される</li> </ul> <p>しかしこれらを変えたい、という場合もあると思います。その場合は下記を使います。</p> <h4 id="inline-block"><a href="#inline-block">inline-block</a></h4> <p>これを指定すると、inline要素として文章中に並べながら要素のサイズやmargin, paddingのようなスペースを設定することができます。</p> <h4 id="block"><a href="#block">block</a></h4> <p>これは文章中などには含まず、ページ上のレイアウトを構成するための基本的な枠になります。何も指定しなければ基本的には横幅100%の要素となります。これも要素のサイズやpadding, marginは自由に設定することができます。</p> <h4 id="その他"><a href="#%E3%81%9D%E3%81%AE%E4%BB%96">その他</a></h4> <p>とりあえず基本的には上記のdisplayがベースになっています。ただ、最近は色々増えていたりするので後述します。その他、このあたりはどんどん増えていっているのでだんだんと新しいものを覚えていく必要があります。しっかり覚える必要はないと思いますが、何かあった時の問題解決のために「そういえばこういうのもあったな」くらいのフォローはしていったほうが良さそうです。</p> <h3 id="heightが0になる"><a href="#height%E3%81%8C0%E3%81%AB%E3%81%AA%E3%82%8B">heightが0になる</a></h3> <p>要素内にfloatスタイルの要素のみがある場合、親要素のサイズは連動しないためheightが0になります。</p> <p><a href="https://crieit.now.sh/upload_images/ccc543ce9d27c586c2b2b08f8dc757175c411798ada33.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/ccc543ce9d27c586c2b2b08f8dc757175c411798ada33.png?mw=700" alt="" /></a></p> <p>問題がある場合はclearfixを入れたり、あとはoverflowスタイルを入れることでも対処できるようです。もしくはflexbox等に変更するなどで対応しましょう。</p> <h3 id="位置調整をしても無視される"><a href="#%E4%BD%8D%E7%BD%AE%E8%AA%BF%E6%95%B4%E3%82%92%E3%81%97%E3%81%A6%E3%82%82%E7%84%A1%E8%A6%96%E3%81%95%E3%82%8C%E3%82%8B">位置調整をしても無視される</a></h3> <p>左に1つ目の要素を起き、そのすぐ右隣に2つ目の要素を起きたいのになぜか2つ目の要素が想定した位置に行かない、という場合。</p> <p>全て自分で作っているCSSなどの場合には気づかないといったことは少ないかもしれませんが、よく使われているCSSフレームワーク等ですと最近はFlexboxがよく使われているため、それによって位置が決まってしまったりします。下記のまとめ等を見るとわかりやすいと思います。</p> <p><a target="_blank" rel="nofollow noopener" href="https://coliss.com/articles/build-websites/operation/css/css3-flexbox-properties-by-scotch.html">CSS Flexbox の各プロパティの使い方を詳しく解説 | コリス</a></p> <h3 id="横幅を指定しても無視される"><a href="#%E6%A8%AA%E5%B9%85%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%A6%E3%82%82%E7%84%A1%E8%A6%96%E3%81%95%E3%82%8C%E3%82%8B">横幅を指定しても無視される</a></h3> <p>前述のFlexboxのページにも解説がありますが、<code>flex-grow</code>を指定すると要素のサイズも固定されてしまいます。</p> <p><a href="https://crieit.now.sh/upload_images/6104d656841f5bdd41de12c15ecba1d85c411b1a28eaf.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6104d656841f5bdd41de12c15ecba1d85c411b1a28eaf.png?mw=700" alt="flexglow.png" /></a></p> <p>この場合むりやり横幅を指定したりしても正常には動作しません。</p> <h3 id="beforeやafter"><a href="#before%E3%82%84after">beforeやafter</a></h3> <p>現在はbeforeやafterを使うこともできるため、実際の要素でなくそのあたりの設定でズレが生じてしまうこともあります。これもDeveloper Toolsで見ることができるため、確認するようにしてみてください。</p> <p><a href="https://crieit.now.sh/upload_images/c63ae1144a6799ccaf1bea54929e49f75c411ce8d0fbb.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/c63ae1144a6799ccaf1bea54929e49f75c411ce8d0fbb.png?mw=700" alt="after.png" /></a></p> <h3 id="iframeが使われている"><a href="#iframe%E3%81%8C%E4%BD%BF%E3%82%8F%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B">iframeが使われている</a></h3> <p>iframeがあっても一応要素のサイズを見ることはできるのですが、どうも状態によっては正しくDeveloper Toolsでもちゃんとサイズが見れなかったりする場合があるような気がします。この場合はiframe内の謎挙動を無視できるようにCSSを整えていくしかないかもしれません。</p> <h2 id="動きのあるコンテンツを調べたい場合"><a href="#%E5%8B%95%E3%81%8D%E3%81%AE%E3%81%82%E3%82%8B%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84%E3%82%92%E8%AA%BF%E3%81%B9%E3%81%9F%E3%81%84%E5%A0%B4%E5%90%88">動きのあるコンテンツを調べたい場合</a></h2> <p>一瞬だけ出てくるアニメーション等を調べたい場合、F8で一時停止することができます。これで時を止めて要素を調べることで解決できます。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>今のところこれくらいしか思いつかなかったので、もし何か思いついたら追記します。他にも追記すべき情報があればコメントいただければ追記させていただきます。(もしくは詳しい方が記事を書いていただけると助かります)</p> <p>昔は本当にDeveloper Toolsでひたすら調べればなんとかなったのですが、FlexboxやGrid等、新しい機能が追加される度に、デバッグするためにはだんだんと頑張るだけではなく、知識も必要になってきています。可能な範囲でHTML、CSSの新しい情報は追っていくといざデバッグする時に役に立つと思われます。</p> だら@Crieit開発者