A new machine

Thinkcentre M71z というものを 1 万円で入手したので開発はそれで行うようにしたい。今となっては若干古めの、第 2 世代 Core i3 ではあるが、今開発に使ってるマシンよりベンチマークの数値は 5 倍くらいアップする。そんなに。

というわけで、ぼちぼち環境を整えないといけないのだけど。
めんどくさいなあ。
「」がうちに来て代わりにやってくれればいいのに。
おっぱいくらい触らせてあげるから。

ちなみにその 1 万円のうちの幾ばくかは投げ銭で頂いたお金を使わせてもらった。この場を借りて感謝したい。

Add-on SDK to WebExtensions

Firefox の拡張は本格的に WebExtensions ベースへの移行が始まっていて、一応のロードマップでは来年の 11 月には Firefox 57 において WebExtensions ベースではない旧来の拡張の読み込みをしないようになるという

拙作について考えてみると、あべアニの拡張の Firefox 版は WebExtensions で新規に書いたのだけど、既存の Addon SDK ベースの拡張は移行作業というものをしないといけない。具体的には赤福プラスと wasavi だ。あとは Webliopane だけど…これはどうかな。そもそも人様のものだし。

で、赤福プラスと wasavi に関しては SDK ベースではあるが、もともと Kosian という Chrome の拡張に近づけて書くためのラッパをかましているので、それぞれの拡張自身のコードに関しては大掛かりに書き換える必要はない。Firefox においてはただ単に動作の基盤を WebExtensions に差し替えればいい、はず、だ。たぶん。

というわけで、とりあえず赤福プラスをちまちまといじり始めたのだが。実際アプリケーションとしてのコードの修正よりむしろ WebExtensions の微妙な発展途上さに振り回されている。

  • まず content script と background の間を long-lived port で接続している。この際、background では port の onMessage イベントハンドラを

    function handlePortMessage (message, port) {
    ;
    ;
    }

    という風に定義している。最初の引数が飛んできたメッセージ、次の引数が使用された runtime.Port オブジェクトだ。このイベントハンドラの引数リストは Chrome の API ドキュメントに記述してある。

    で、それを Firefox の WebExtensions で動かすと、第 2 引数である port が渡されてこないのであった。これはきっとバグだろう

箇条書きにした割に 1 つしか書いてないが、きっと開発を進めるごとにいろいろ出てくる。

ところで web-ext ツールというものがあり、これは従来の cfx とか jpm に相当する。これで [cci]web-ext run[/cci] とすると一時的なプロファイルによって Firefox が起動する。開発中の拡張は自動的に読み込まれている。そして面白いことに、その状態でソースファイルを更新すると拡張が自動的にリロードされる。これはちょっと便利。

creating NTFS native symbolic link in cygwin #2

以前 Cygwin でシンボリックリンクを作るにはどうすればいいか調査したことがあった

月日は流れ、ついに Windows 10 では(開発者モードに限り)特権のエスカレーションを経ることなく一般ユーザのままシンボリックリンクを作れるようになるそうな。

へえ。しかし個人的にはもうどうでもいいトピックだったりする。というのも一応 Cygwin は入れているが、もはや Windows 上で何か開発するということが殆どない。

ちなみにその更新がもたらされる Windows 10 Creators Update は、2017年3月にリリースの予定だそうな。

The TV program time table #9

虹裏でアナウンスした際に Vivaldi で動かした時、お気に入りのチャンネルを定義する場合のドラッグ&ドロップが正常に動作しないという報告を受けた。

調べてみると、ドラッグ&ドロップのためにはいくつかのイベントを処理しないといけないわけだが、その中でドロップされた際の drop イベントと、ドラッグプロセスが完全に終了した際の dragend イベントの発行される順番の問題のようだ。

仕様では、常に drop -> dragend の順番であり、あべアニもそういう前提で組んであり、実際 Chrome、Opera、Firefox、Edge でテストした際もそういうふうに動作した。Vivaldi ではテストしなかったのだが、これは Vivaldi は結局 Chrome ファミリーであり、Chrome で動けばきっと多分 Vivaldi でも同様のはず…という判断なのだが、びっくりすることに Vivaldi では drop イベントが最後に発行するようなのである。

なんで…?

前述の通り drop -> dragend なのはそういう規格だし、Chrome 自体がそういうふうに動作するのに、何を意図して変更したんだろう? 分からないがとにかく、いずれの順番でも正しくドラッグ&ドロップが動作するように修正。

The TV program time table #8

Firefox 版は AMO に置くのを諦め、ここでホストすることにした。

Chrome 版のソースを Firefox の WebExtensions のシステムで動かす際、以下の点が Chrome と異なる。

  • [cci]chrome.runtime.onInstalled[/cci] がまだない。したがって、
    'onInstalled' in chrome.runtime && chrome.runtime.onInstalled.addListener(function () { });
    みたいな書き方をする必要がある。
  • content script で生成した CustomEvent にオブジェクトを含んだ detail を与え、ディスパッチする。それをページスクリプトでリスンすると、detail が正しく引き渡されない。Firefox では権限の異なるスクリプト間ではプリミティブな型以外のものを渡せないようだ。そんなわけで、Firefox で動かす際は detail には JSON.stringify() したものを与え、受け取る際も JSON.parse() しないといけない
  • ソースはほぼ Chrome 版と共有できるが、パッケージングはかなり異なる。ストアに登録する際は Chrome 同様にソースディレクトリを単に zip するだけでもよいが、web-ext ツールを用いてビルドと署名をコマンドラインから行う方法も用意されている。
  • 自前でホストする場合、更新情報も自分で管理しないといけない。そのために、manifest.json に

    "applications": {
    "gecko": {
    "id": "abeani-extension@appsweets.net",
    "strict_min_version": "42.0",
    "update_url": "https://appsweets.net/abeani/updates.json"
    }
    },

    というものを含める必要がある。このエントリは、Chrome は無視するのでこの manifest を Chrome に与えてもエラーにはならない。updates.json の内容は

    {
    "addons": {
    "abeani-extension@appsweets.net": {
    "updates": [
    {
    "version": "1.0.8",
    "update_link": "https://appsweets.net/abeani/extension/AbeaniExtension.xpi"
    }
    ]
    }
    }
    }

    こんな感じ。

    調子に乗って Edge でも動かしてみたのだが、まず Edge は chrome.alarms がないので普通のタイマーで代替しないといけないのだが、それは代替手段があるのだから別にいい。だがなんと、content script から chrome.runtime.sendMessage() でバックグラウンドにメッセージを送る機能がまだ実装されていない。これがないとどうにもならない。ひどい。というわけで Edge 版はしばらくペンディングだ。MS さん真面目にやってくださいよ。

The TV program time table #7

  • 表示できるチャンネルをアニメ以外にも拡大した: 各チャンネルを適当なカテゴリで分けたが、このカテゴリでいいの? というのは若干ある。REALITY SHOW は果たしてドキュメンタリーなのか? とか。あるいは、よくわからないチャンネルはすべてバラエティに突っ込んだがそれでいいのか? とか。これは文句が出たらその都度対応することにしよう
  • 各チャンネル群を従来は table 要素でマークアップしていたが、CSS flex を用いるようにした。これによりナウじゃないブラウザでは表示できなくなった可能性がある。しかし 21 世紀も 16 年も経って flex に対応していないブラウザが存在していたならば、それはそれが一方的に根本的に全て何もかも悪い。という方向でそろそろ行きたい。なにしろ flex 自体は Presto Opera ですら対応しているのだ(といいつつ、Presto Opera での表示確認は一切していないのだが)
  • 各番組の放映開始に併せて、虹裏では番組の実況スレというものが立つことが多い。このスレッドの本文を生成する助けになることを意図して、共有機能を実装した。共有機能というのはなんかよく意味がわからないが、生成したテキストをそのままツイートできるようにした上での命名だ。というのはこのツイート機能がないと「実況スレ本文生成」みたいな更によく分からない機能になってしまって、これを呼び出すためのボタンのラベルが冗長になってしまうからだ
  • ところで本文を生成する際、特定のマーカーは番組の情報に置換される。たとえば [cci][start-at][/cci] が 2016/12/06(火) といった具合だ。ここで、2016年12月06日 の形式がいい! といった場合にはマーカーのオプションとして書式を付加することができる。[cci][start-at{%m月%d日(%a)%p%l:%M}][/cci] などと書くと {〜} の中身を strftime(3) で評価した結果で置換される
  • 番組開始通知時のオプションとして、番組終了時に自動的にチャンネルのタブを閉じる機能を追加した
  • 特にチャンネルの拡大を虹裏 img でアナウンスした時なのだが、投げ銭してもいい的なレスをいくつか受けた。ありがたいことだが、しかし所詮は「」の言うことであって、9割方口だけである。が、人の心を失っていないまっとうな「」もいることを期待して、一応そのための窓口は設けた。はやくお酒飲みたいなあ
  • 通知機能のためのブラウザ拡張は、相変わらずその申請が降りるまでの時間が各ブラウザで違う。Chrome は機械的に 1 時間もすれば通る。Opera は人がレビューするが、大体 3 営業日くらいで通る(土日はお休みだ)。Firefox は、なんか以前 AMO 公式のブログや、あるいはニュースメールなどでいっぱい KAIZEN してレビューも早くなったよ!ほめて!的なアピールをやたら目にしたことがあったが、全然変化ないように思える。すなわち申請からだいたい 1 ヶ月はかかる見込みである。ぶっ飛ばされたいのか。wasavi と同様 Firefox 版だけはストアに置かない形式にするかもしれない

Cannot log in to wordpress!!

というわけでなんか書こうかと wordpress にログインしようとしたら、ログインページでログインボタンを押した途端に 403 Forbidden と書かれただけのページに飛ばされてログインできない。

どうもそのページは Apache 備え付けのエラーページのようだ。そこで、wp-login.php で適当にログを吐かせてみたところ、確かに GET でアクセスされた際はログが追記されるが、POST では何も書かれない。php の実行に入る前に Apache によって弾かれているようだ。

wp-login.php をバックアップして、wp-login.php の名前でもっとシンプルな、単に POST するだけのページを書き、試してみたところやはり 403 になる。どうも、Apache の静的な設定の段階で wp-login.php への POST アクセスを弾いているようだ。なんか、海外からのクラッキングを防ぐ的なアレなんだろうか。障害情報やメンテ情報の最近のエントリにはそれっぽいものは見つからなかったが…。

とりあえず .htaccess でアクセス制御を上書きすることで解決。解決…なのかどうか。いやまあ wp-login.php に対して Basic 認証くらいはかけているのだが。

The TV program time table #6: regalized program name

あべアニで番組開始の通知をする際「のんのんびより 開始1分前です」的な読み上げを行わせることができる。PhoneticNews に引き続き、この読み上げは voicetext を利用している。ただまあ仕方ないことだとは思うが、たまに正しく読み上げないことがある。忍ペンまん丸をしのぶぺんまんまるなどと読み上げたりする。これをなんとかできないだろうか。

アニメ作品のデータベースとしては animedb というプロジェクトがあり、その中で作品名のふりがなも管理されている。これを利用できるかもしれない。

ただ、

  • ドキュメントにも記載されているが若干表記の揺れが残っている。たとえば鷹の爪で grep すると

    $ grep "鷹の爪" google-ime-dict.txt
    ザフロッグマンショーヒミツケッシャタカノツメ THE FROGMAN SHOW「秘密結社鷹の爪」 固有名詞
    ヒミツケッシャタカノツメザムービーソウトウハニドシヌ 秘密結社 鷹の爪 THE MOVIE ~総統は二度死ぬ~ 固有名詞
    ヒミツケッシャタカノツメザムービーツーワタシヲアイシタクロウーロンチャ 秘密結社 鷹の爪 THE MOVIEⅡ ~私を愛した黒烏龍茶~ 固有名詞
    ヒミツケッシャタカノツメカウントダウン 秘密結社鷹の爪カウントダウン 固有名詞
    ヒミツケッシャタカノツメ 秘密結社鷹の爪 固有名詞
    ヒミツケッシャタカノツメザムービースリータカノツメジェイピーハエイエンニ 秘密結社 鷹の爪 THE MOVIE 3 http://鷹の爪.jpは永遠に 固有名詞
    ヒミツケッシャタカノツメザムービーフォーカスベルスキーヲモツオトコ 秘密結社鷹の爪 THE MOVIE 4 カスベルスキーを持つ男 固有名詞
    タカノツメネオ 鷹の爪 NEO 固有名詞
    ヒミツケッシャタカノツメジェーピー 秘密結社鷹の爪.jp 固有名詞
    タカノツメマックス 鷹の爪 MAX 固有名詞
    タカノツメゴーウツクシキエリエールショウシュウプラス 鷹の爪GO 美しきエリエール消臭プラス 固有名詞
    ヒミツケッシャタカノツメドットジェイピーブルーレイボックスジョウカンカンゼンシンサクエイゾウ 秘密結社 鷹の爪.jp Blu-ray BOX上巻[完全新作映像] 固有名詞
    シネマトラベルタカノツメタカノツメダンシネマトラベルヘイクノマキ シネマ・トラベル × 鷹の爪 鷹の爪団! シネマ・トラベルへ行くの巻! 固有名詞
    ヒミツケッシャタカノツメドゥー 秘密結社鷹の爪 DO 固有名詞

    などと「秘密結社」の有無、あるいは「秘密結社」に続いて空白が入っているかなどが揺れている。それともそれぞれの作品で正式名称の表記が揺れているのが正確な状態なんだろうか? よく知らない
  • 上記の例で Blu-ray BOX 上巻云々が含まれているものがあるがこれは作品名なのか? 製品名ではないのか?
  • タイトルに含まれる空白がよみがなでは省略されているが、これをそのまま読み上げさせると不自然なアクセントになってしまう。できればよみがなでも空白は維持してほしい。Google 日本語入力用の辞書ファイルなのであえてそうなっているのかと思ったら元データである animedb.yml でも同一なのでそういうわけでもないようだ

というわけで、作品名の正規化に用いるには若干難しいかもしれない。しかし膨大なデータなのは確かなので何かに利用したいなあ。

The TV program time table #5

設定機能及び番組開始時の通知機能を実装した。

番組枠のポップアップに「通知」というボタンが追加されており、それを押すと予約される。時間になると自動的に Abema.tv の該当チャンネルを開いたり、音声でガイドしたり、OS が持つ通知機能を通してメッセージを表示したりする。これらの組み合わせは設定パネルで好きにできる。

その他、

  • 予約したら、あべアニのページは閉じて良い
  • 該当チャンネルを開く際、すでに何らかの Abema.tv 上のチャンネルを開いていたらそのタブを再利用する

といった特徴がある。

このような機能を実装するとして、最も単純なのは当然、あべアニのページで [cci]setTimeout()[/cci] することだ。これなら何も実装上で難易度の高いものはない。しかしやはり当然ながら、この方法だとあべアニのページをずっと開きっぱなしじゃないといけないのである。もしも実際のユーザの使用状況が、いったんあべアニを開いたらずっと開きっぱなしであるならこの方法で実装してもいいが、そうではないなら別の方法を考えないといけない。

というわけでアクセス解析を見てみたところ、だいたいあべアニを開いて閉じるまでが5分以内のユーザが62.37%、1時間以内なのが17.8%とかそんな感じだった。つまり、setTimeout 作戦ではダメなのである。

そこで、今流行りの Push API という規格を検討してみた。これは setTimeout 作戦との比較で言えば、ここの Web サーバが setTimeout の役目を肩代わりする。そして通知をすべき時間になったら、Push サーバというものを通してブラウザに通知を送る…という仕組みだ。かつてはブラウザへの Push といえばブラウザ側から接続をかけて long polling という手法がとられた。この規格を実現している Google と Mozilla の Push サーバが未だそういう手法なのかは知らないが、いずれにしても単純な http ではない特殊な接続方法でブラウザと通信する必要があるようなので、Push サーバが必要になる。

しかし検討した結果、これも実装したい機能にはちょっと力不足だった。

  • 新しい規格なので、また仕様が固まっておらず、各種言語向けのライブラリなども揃いきってない。ペイロードを含んだ通知などではかなりめんどくさい暗号化を施さないといけないので一から作るのはちょっと大変。Node.js だと楽そうなのでビルドを試してみたがここのサーバの glibc のバージョンが異様に古くて動かない
  • ここの Web サーバが通知を送るタイミングを管理するということは、一定期間ごとに適当なプログラムを自動起動させないといけない。実はここのサーバでも一応 crontab は編集できるのだが、それは1時間に1回までという限度があるのだった。もっと細かい時間単位で起動させるには別のサーバを使わないといけないので面倒
  • ブラウザが通知を受け取ったあと、チャンネルを開くとして既存のタブを再利用するという芸当が多分現状の仕様ではできない。将来、API が拡充されればできるようになるかもしれないが、今はできない

というわけで、現実的な解としてブラウザの拡張機能との組み合わせで実現することにしてちょちょっと作った。

ナウいブラウザの拡張機能といえば、なんと言っても Firefox の WebExtensions である。この際なので WebExtensions で作ってみた。実際は作ってみたというほどのことではなくて、単純に Chrome 版のソースディレクトリを与えたらだいたい動いた、すごい! という程度のものだが。

それから当然ながら Chrome 版は Opera でもだいたい動くので Opera 版も作った。

だいたい動くというのは、例えば [cci]chrome.storage.sync[/cci] や [cci]chrome.runtime.onInstalled[/cci] など Firefox や Opera では微妙に実装されていないものがあるのでそういうものを使うのは避けないといけないということだ。このせいで拡張機能をインストールしたあといったんあべアニをリロードしないといけない。

ちなみに Chrome の拡張をパク…大いに参考にしたという意味では Edge でも動くはずだが、なんと Edge の場合 [cci]chrome.alarms[/cci] すら実装されていないそうな。もうちょっとがんばってくださいよ MS さん。

The TV program time table #4

abeani-gearいくつか、ユーザごとにカスタマイズできる項目を作りたい。そのためにとりあえず歯車アイコンを配置した。

ところで最近はこの手のページ全体に対する設定やらアクションやらを担当するリンクとしていわゆるハンバーガーアイコンがよく用いられるのだが、あれすごくダサいと思う。ダサいしそれを押すことで何が起きるのか連想できないという機能上の問題も抱えている。早くこの世からなくなって欲しい。

それはさておき、設定可能な項目をつらつらと挙げてみると:

  1. 各チャンネルのロゴ、番組枠及びその詳細リンクそれぞれをクリックした際のウィンドウ名: これを [cci]_blank[/cci] にすればクリックするごとに新しいタブが開く。特定の名前にすればクリックした時に既にそれが存在すれば再利用される(もちろんユーザにはウィンドウ名自体は重要ではないので、設定の際は単に「クリックした時タブを再利用するか否か」と簡略化される)
  2. 翌日の番組表へのリンクの背景として何時間分をチラ見せするか
  3. 番組枠上の詳細ポップアップの可否
  4. 表示するチャンネル、及びその並び
  5. 事前通知する場合の、通知方法

このうち 3. と 4. はどういう仕様にしたものかいろいろと考えることが必要だ。