Diary

@ssig33

PDF を Gyazo に展開して Scrapbox の記事にして全文検索する という試みについてです。

まず PDF を Gyazo に展開して Scrapbox の記事にするということですが、これについてブラウザ上で簡単に動くツールを実装しました。

https://ssig33.github.io/pdftoscrapbox/

img

おそろしく素朴な見た目ですがとりあえず動きます。Chrome や Edge に Tamper Monkey (試してないけど Firefox と Greasemonkey でも動くんじゃないかな)を入れて、 input に Scrapbox のプロジェクト名を入れて user.js をインストールした上で赤いところに PDFをドラッグ&ドロップすると、 PDF.js で PDF でレンダリングした上で全てのページを Gyazo にアップロードして Scrapbox のページを作成します。

何故 user.js を使っているかというと、 CORS 制限を突破する目的です。

これで実際どういう記事が出来るかということなのですが、

img

こういう感じです。

ページごとに画像になっているので、特定のページへのリンクを作成できますし、また Scrapbox の機能を用いていろいろとメモを書いていくことも可能です。

ではこうやって PDF を Scrapbox に展開できたとして検索が出来なければあまり使いやすいとはいえません。ですが、 Gyazo には強力な OCR 機能があり、画像内の文字列をかなり正確に検索することができます。

img

この結果を用いて Scrapbox を検索することができると便利です。というわけでそれも作りました。こちらの user.js をインストールすると Gyazo の OCR 結果を使って Scrapbox を検索することができます。

img

こんな感じで新しいボタンが出るようになるので、これをクリックすると

img

こう。ちなみにこの機能をまともに使うには Gyazo Pro に課金する必要がありますが、画像を強力に OCR して検索できるツールが月額たったの $5 と思えば大変に安いものです、是非契約しましょう。

PDF がいろいろ集まってくるけど読めない、管理できない、読んだメモを残せない、という人は結構多いと思うのですが、個人用の Scrapbox とこれらのスクリプトを用いることで非常によい検索性とメモ環境を得られると思います。

今回つくったツールのソースコードは https://github.com/ssig33/pdftoscrapbox にあります。ソースを見れば分かる通りですが今回作られたツールはすべてブラウザ上で動作し、僕が管理するサーバーをデータを通過することがないため安全に使うことができます(ぼくがこのツールの運用に支払うコストがゼロであることも意味します)。

18 Mar 2020 Wed 15:17

コアラ

10 Mar 2020 Tue 15:07

はーだるい

10 Mar 2020 Tue 15:07

GraphQL を CDN にキャッシュさせるのってどうするのがいいの

25 Feb 2020 Tue 14:39

ゴアラについて考えている

25 Feb 2020 Tue 14:29

ゴリラについて考えている

25 Feb 2020 Tue 14:23

とてもだるい

25 Feb 2020 Tue 14:22

消費者庁のサイトが speechSynthesis を使って読み上げ機能を提供しているが壊れている

現代のブラウザには speechSynthesis という API があってそれなりの性能の読み上げをすぐ実装できて便利なのだが、あまり活用例はないという状態だった。

ところが昨日偶然消費者庁がやっている特商法の解説サイトがこれを活用しているのを発見した。しかし盛大に壊れている。どう壊れているかは以下をご確認頂きたい。

で、なんでこんなことになっているのかとソースコードを見てみた。ぶっ壊れの理由は以下のような実装になっているからである(一部省略して核心部だけ示している)。

var voiceNum = 0;       
if(navigator.userAgent.toLowerCase().indexOf('firefox') != -1) {
    voiceNum = 0;
    console.log('win firefox');
}else if(navigator.appVersion.indexOf('Edge') != -1) {
    voiceNum = 0;
    console.log('win Edge');
}else if(navigator.appVersion.indexOf('Chrome') != -1) {
    voiceNum = 11;
    voiceRate = 1.1;
    console.log('win Chrome');
}else{
    voiceNum = 0;
    console.log('win');
}

var utterance = new SpeechSynthesisUtterance();
utterance.lang = 'ja-JP';
utterance.rate = voiceRate;
utterance.voice = speechSynthesis.getVoices()[voiceNum];

このコードは、 speechSynthesis.getVoices() の値が常に一定であることに依存している。しかし MDNの解説を見る限りそれは保証されていないようだし(そもそも This is an experimental technology とある)、実際僕の環境は実装者の意図とは違う値がかえってきているようだ。

ちょっと確認した限りでは、

  • Windows 10 の Chrome と Edge ではダメ
  • Mac の Chrome は大丈夫
  • Mac の Firefox もダメ

というかんじであった。

ではどうすればよかったのか?というと以下のようにすべきである

speechSynthesis.getVoices().find(v => v.lang === 'ja-JP')

で、 Windows 10 の Chrome でこれに置き換えてみたら以下のようになった。

感想

  • experimental と書かれている機能を使う場合、継続的にちゃんと動いているかの確認が必要と思う
  • speechSynthesis は(ちゃんと使えば)想像以上によく動く。積極的に導入していく価値がある
06 Feb 2020 Thu 12:06

Fastly のログイン画面をどうにかしてほしいという話

Image from Gyazo

複数の Fastly アカウントにまたがって構築されいるシステムのメンテナンスという作業をしていて、気付いたらかなり体調が悪化してて、激しい頭痛と吐き気の襲われた。というのも、ログアウト => ログインを何度も何度も繰り返すことになるから↑の画面を何度も何度も何度も何度もみていたわけだ。

これを 30 インチのディスプレイに全画面でドカーンと出していたので、これはつまりポケモンショック同様の症状ということだと思う。

自分がそういう状態になっていると気付いてからは、以下の user.css を書いて回避した(user.css の適用にはこの拡張を使っている)。しかしまあ一度崩れた体調は今に至るまで回復していない。

section.authentication{
  background-color:darkred;
}

Image from Gyazo

Fastly は実際驚異的な CDN で、これなしに自分の仕事、生活はもはやなりたたないほどで本当に感謝しているのだが、さすがにこのログイン画面はしんどすぎる。どうにかしてほしい、、、

04 Feb 2020 Tue 15:21

かに

01 Feb 2020 Sat 22:48

next.js で作った動的なサイトを CDN で全力でキャッシュさせる

というようなことをしたくなることもあると思います。その上で動的なサイトの場合 CDN のキャッシュをリアルタイムで飛ばしたいことも多いかと思いますので、 CDN の選択肢は事実上 fastly 一つということになります。

この時、 next.js なアプリをどこにどうやってデプロイするかが問題になってきます。

1. ZEIT

next.js をつくってるところのホスティングサービスで、すごく簡単に使えていいのですが、キャッシュさせようと思うとすごくめんどくさくなります。ZEIT 標準の CDN とキャッシュ機構もありますが使いやすくないですし、 fastly でキャッシュさせるためにカスタムヘッダーを吐かせようとしても now.json とかにゴチャゴチャ書くことになってあまりよろしくない。

ZEIT 自体よく出来てる気はするのだがあと一歩という感じがする。

2. firebase

next.js のデプロイ先として定番だと思うのですが、今回はダメでした。 firebase の CDN はなぜか Cloud CDN でなく fastly であることがよく知られています。このためさらに前に fastly を置こうとすると firebase の fastly に Surrogate-Key ヘッダーを握り潰されてしまいます。

3. Netlify

これも定番なんだろうけど触ったことないので知らん

4. で、どうしたか

Docker で固めて Cloud Run において fastly => Cloud Run という構成にしました。カスタムサーバーは以下のようになっています。

const express = require("express");
const next = require("next");

const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });

const handle = app.getRequestHandler();

app.prepare().then(() => {
  const server = express();

  server.get("*", (req, res) => {
    res.setHeader("Surrogate-Key", "SOME_KEY");
    handle(req, res);
  });

  server.listen(port, err => {
    if (err) throw err;
    console.log(`> Ready on http://localhost:${port}`);
  });
});

URL ごとにキャッシュのルール変えたいときとかはここで Surrogate-Key 出し分ければよさそうですね。しかしまあ ZEIT にサクっと上げて超全力でキャッシュしてくれるとかそういうのできればそれが楽なのでどうにかできないのか、、、

01 Feb 2020 Sat 16:46

はーめんどくせ

01 Feb 2020 Sat 16:37

firebase の前に fastly おくと fastly => fastly になってしまってあんまりよくないっぽいな、、、

01 Feb 2020 Sat 16:25

フロントエンド firebase においたが 暖まってないと Cloud Run より起動遅いな

01 Feb 2020 Sat 15:22

ページ遷移わりと最速になった

31 Jan 2020 Fri 11:43

CDN おじさんになったところで 、潰しがきかないんだろうと思っていて、あまり深入りしないようにはしている

30 Jan 2020 Thu 23:53

Cloudflare がいらんことしていた

30 Jan 2020 Thu 23:52

test

30 Jan 2020 Thu 23:48

キャッシュできてるけど思ったとおりに飛んでねえな

30 Jan 2020 Thu 23:37

もうちょっといじって

Cloudflare(HTTPS化) => Fastly(キャッシュ) => Cloud Run(ここで next.js 動かす) => Cloudflare => Fastly => Cloud Run(Go で書かれた API)

という構成にした。

30 Jan 2020 Thu 23:35

CDN 沢山つかってるとキャッシュとばすのまじでめんどう

30 Jan 2020 Thu 22:58

キャッシュ

30 Jan 2020 Thu 22:34

おなかすいた、、、

30 Jan 2020 Thu 18:13

コアラ

30 Jan 2020 Thu 18:00

ゴリラ

30 Jan 2020 Thu 17:59

サイトの構成かえた

Cloudflare (HTTPS 化) => Fastly (キャッシュなど) => ZEIT (next.js の実行) => Fastly(キャッシュ) => Cloud Run (Go で書かれた API)

というような構成にした。だいぶ破滅的でやばいがいろいろいじりやすくはなった。

30 Jan 2020 Thu 17:45

ジャバ

30 Jan 2020 Thu 15:33

ねむい

30 Jan 2020 Thu 14:37

canvas を使って画像をトリミングする

const img = document.querySelector('img');
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const context = canvas.getContext("2d");
context.drawImage(img, x, y, width, height, 0, 0, width, height);

というようなコードが紹介されることが多いですが、ダメです。これはディスプレイの解像度が伝統的な 96DPI になっていることに依存したコードで、現代的な HiDPI 環境では思った通りに動きません。

こうした問題に対応するためにwindow.devicePixelRatioという値を使用することができます。

const ratio = window.devicePixelRatio;
const img = document.querySelector('img');
const canvas = document.createElement('canvas');
canvas.width = width * ratio;
canvas.height = height * ratio;
const context = canvas.getContext("2d");
context.drawImage(img, x * ratio, y * ratio, width * ratio, height * ratio, 0, 0, width * ratio, height * ratio);

というような感じで devicePixelRatio をかけてサイズを補正してあげれば大丈夫です。

14 Jan 2020 Tue 14:22

Qrio (旧モデル)から Sesami mini にかえた

転居に共ない鍵が 2 個ついてるドアになったので Sesami mini に変えてみた。セールで 1 個 1 万ちょいとかで買えた。

Pros

  • 安い
  • 取り付けしやすい
    • 高さ調整の仕組みはこっちのほうが使いやすいと思う
  • 自動開錠は Sesami のほうがまともに動くと思う
    • とはいえ家の中の移動で自動開錠誤爆されたりするので正直今一ではある
    • Qrio は開かない、こっちは開きすぎという印象
      • 自動開錠開きすぎ問題に対処するための答えがノック開錠という機能なのだと思うが、ノックのほうも誤爆多い感じなのでいまいちです

Cons

  • 開閉の認識が正直いまいち
    • 閉まってるのに開いてる(あるいは逆)と認識しがちなので、開閉の設定のところでちゃんと動くような設定を詰める必要がある
    • これがあるので完全に Sesami だけに頼って鍵は一切持ち歩かないという運用はちょっと怖い
      • 怖いけどまあ最悪どうにかなるだろの精神で鍵持ち歩いてませんが
  • 鍵の共有が鍵の近くじゃないとできない
    • 遠隔で鍵をわたすには WiFi に接続するための高いやつを買っとかないとダメみたい
    • 家にくる予定の人に「鍵渡しとくからよろしく」とかは出来ない
      • まあそんなことしたの結局 2 回ぐらいしかないんでそんな問題ではないと思う

ほかにもいろいろあるらしいが乗り換えた感想としてはこんなもん。開閉の認識がいまいちという問題があるのでちょっと怖い。そういうものだと認識して確認しながら使ってるので今のところ締め出されなどの問題は発生していないのだけど、 Qrio と比較すると安心感は低い。

とはいえ値段の差を考えればというところではある。

Qrio Lock (新モデル)のことはよく知りませんが、金があるなら Qrio Lock のほうがいいのではないかという予感はしている。しかしまあ Sesami でも別に困りはしてないです、以上です。

18 Dec 2019 Wed 17:18

Next