2018/09/18 3:31 am
Attach an image from clipboard
Uncategorized, , ,

ついで、クリップボードに画像が格納されている時、コメント欄で Ctrl+V を押すとそれを直接添付ファイルにする機能を実装してみよう。

基本的にはコメント欄の paste イベントで clipboardData.files を見てその中から画像っぽいものを取り出し、それを覚えておき、投稿時に upfile 要素の内容の代わりに使用する、だけ。

のだが、いくつかめんどくさい点がある。

  • 貼り付けた画像のプレビューを生成しなければならない。これ自体は普通に upfile 要素で選択された画像をプレビューする処理と同じで何か新しくコードを書くわけではない。ただし、基本的な流れは画像を示す file インスタンスの内容を img 要素に割り当て、読み込み完了後に canvas 要素に縮小描画するというもので、特に file→img を従来は data スキーム経由で行っていた。しかしこれはけっこう重い。そんなわけでそこを createObjectURL/revokeObjectURL で行うようにした。今までそうしなかったというのはつまり Presto Opera でも動かすためだ。でももう Presto Opera のことは忘れる
  • 貼り付けられた画像のサイズが、板に貼れる上限を超えている場合。クリップボードに格納されている画像は、おそらく確実にブラウザへは image/png 形式で渡ってくる。png なのでサイズ的には常に大きめだ。それが板の上限を超えていた場合は jpeg でエンコードし直す必要がある。

    その場合は file を canvas に描画した後 toDataURL(‘image/jpeg’) で jpeg エンコードされた data スキームの URL を得て、それを XHR で読み込んで arraybuffer として取得し、そこから blob を生成…となる。途中で生成した canvas はそのままプレビュー生成にも使う。この辺、なんか回りくどい。canvas に blob を返すエンコードメソッドを設けてくれれば、それを FileReader から好きに読み込めばいいので汎用的だと思うのだけど…。

    あと、真面目に作るなら、jpeg エンコードしてもなお上限を超えている場合を考慮して、段階的に jpeg のクオリティを下げていくようなループにするべきなのだが、そこまではしなかった。

    ちなみに板に貼れる上限というのは注意書きの中で例えば「2000KBまで」とか書いてあるのをパースして覚えておくのですが。2000KB というのは 2000*1024=2048000byte のことでいいんだろうか。それとも 2000*1000=2000000byte か? 試してみた所 2000000byte 超のファイルは受け入れられるようなので前者とみなすようにした

だいたいこんな感じ。

2018/09/11 8:21 pm
Saving an image via Akahukuplus
Uncategorized, , ,

虹裏にはたまにいわゆる虹裏ブラウザを話題とするスレが立つのだが、赤福プラスが俎上に載ることはめったにない。そしてまれに載った際はたいてい、使いにくくて機能の少ないクソと烙印を押されるのがオチなのであった。不満の一つに画像の保存をローカルに対して行えないという点があるようなので、それに対応してみよう。

もちろん Chrome のエクステンションからローカルのファイルシステムを直接は操作できないのだが、拙作のLFO – ローカルファイル操作ライブラリを通すと不思議なことにファイルの読み書きは自由にできちゃうので、これを使う。すでに wasavi と kokoni が LFO を使用している。これに赤福プラスも加わることになる。

LFO 側で適宜設定を行ったあと、赤福プラスの設定でファイル保存名テンプレートをピクチャ/ふたば/$SERVER/$BOARD/$YEAR-$MONTH/$DAY-$SERIAL.$EXTなどと設定し、使用するストレージをlocalにする。で、保存リンクを押せばそのとおりの場所に保存される。これだけ。あとは画像を開いた際に自動的に保存、みたいなオプションもあればいいかな。

技術的には、任意のパスに保存するには画像本体の保存に先駆けていわゆる mkdir -p 的な動作が必要になる。現バージョンの LFO はこの機能を持っていないのでまずそこから実装する必要があった。LFO というか、Chrome Apps の FileSystem API 自体にそんな素敵な機能はない。従って、パス中の個々のディレクトリごとに一つずつ掘っていくという繰り返し処理を書くことになる。これを FileSystem API を直接呼びながら実現するとコードがものすごく汚くなりそうだったので、Promise を使うようにした。ついでなので、他の LFO のコマンドもすべて Promise ベースで動作するように書き直した。

ちなみにこの機能は Chrome 専用だ(Chrome Apps が Firefox や Opera で動くならその限りではないが)。

2018/09/05 10:03 pm
Prevent from executing an inline script
Uncategorized, , , ,

以前にも書いた気がするが、赤福プラスはふたばが返す html をまるごと変換し、上書きする。従って、元の html に記述されている画像や、スクリプトや、インラインフレームの読み込みはまったく不要で、ブロックする必要がある。ブロックした上で、変換後の html から改めて読み込まなければならない。

そんなわけで、Chrome では WebRequest API を用いてそれを実現していたのだが、ただ一つ html に直接記述された script 要素、つまりインラインスクリプトの実行は見逃していた。まあこれを見逃しても src 属性付きのスクリプトの読み込みはブロックしているので、大抵のインラインスクリプトはなんちゃらが定義されていませんエラーになって実害はないのだが、気にはなる。

しかし、Chrome のエクステンションの API を眺めてみてもインラインスクリプトの実行をブロックする機能は見つからない。いやあることはある。例えば WebRequest でレスポンスヘッダに CSP を忍ばせて、インラインスクリプトを除外するとか、あるいは ContentSettings でふたば上のみの javascript の実行を禁止するとか。が、リファレンスを読んでみるといずれも html を読み込んでから DOMContentLoaded までの短い期間だけスクリプトの実行を抑制するという要件にはちょっと合ってない。

いろいろ調べてみたところ、content script で MutationObserver を用いて script 要素が DOM ツリーに追加された瞬間をキャッチし、type を text/javascript とか application/javascript から、スクリプトとして実行されないものに書き換えるとそういう動作を実現できるようだ。で、用が済んだら、DOMContentLoaded ハンドラで disconnect() すればいい。完璧だ。

ただし Firefox ではこの type 書き換え法が効かないので、その代わり script 要素の beforescriptexecute イベントをリスンして適宜 preventDefault() する。つまり実行タイミングを start_at にした content script から

var observer = new MutationObserver(ms => {
.   function handleBeforeScriptExecute (e) {
.   .   e.target.removeEventListener(
.   .   .   'beforescriptexecute', handleBeforeScriptExecute, false);
.   .   e.preventDefault();
.   };
.   ms.forEach(m => {
.   .   m.addedNodes.forEach(node => {
.   .   .   if (node.nodeType != 1 || node.nodeName != 'SCRIPT') return;
.   .   .   node.type = 'text/plain';
.   .   .   node.addEventListener(
.   .   .   .   'beforescriptexecute', handleBeforeScriptExecute, false);
.   .   });
.   });
});
observer.observe(document.documentElement, {
.   childList: true,
.   subtree: true
});

とこんな感じのコードを走らせる。

ちなみに Presto Opera だとこんな長いコードを書かなくても、

window.opera.addEventListener('BeforeScript', function(e){e.source=''}, false);

だけで実現できる。オーパーツすぎる…。

そういえば忘れていたけど、次のリリースから赤福プラスは Presto Opera をもうサポートしない。

2017/02/02 5:24 pm
Old and New
Uncategorized,

調べものの途中でたまたま常用漢字の新字体と旧字体の なるものを見ていたのだが、この旧字体で文章を組むとどんな感じなのかしらん? とふと気になったので、ひとまず赤福プラスに組み込んでみた。


なかなか味わい深い。

当初は投稿時のコメントを旧字体に変換するようにしたのだが、「なんで旧字体なの」「うぜえ」などと、ID を出されて火炙りにされそうな勢いだったのでローカルでの表示のみを旧字体に変換するようにした。

この機能は開発バージョンでのみ有効で、オン・オフの設定もない。

2016/12/17 3:14 pm
Add-on SDK to WebExtensions #3
Uncategorized, , , ,

content script において window.Uint8Array を使おうとするとエラーになる。グローバルオブジェクトのそれを使わないといけない。両者は権限のドメインが違う、らしい。グローバルオブジェクトに Uint8Array が存在する場合はそれを、次に window に存在する場合はそれを使うようにした。

window. を前置するのをやめればいいじゃん、と思うかもしれないが、そうはいかない。赤福プラスでは window のプロパティを参照する際は必ず window を前置している。これは Presto Opera で動かすための措置で、Presto Opera の injected script では window がグローバルオブジェクトではないのである。したがって前置は必須なのだった。

それにしても、今 Presto Opera 使ってる人ってどんくらいいるのかなあ…? とはいえ赤福プラスはまだ Presto Opera もサポートしているので、動作確認のために新しい環境にも 12.16 を落としてインストール。

ところでメモやブックマークを同期しようとログインしようとしたらどうやっても弾かれるんですけど…。

Firefox の方は SDK 版から WebExtensions 版への自動更新が滞りなく行われることを確認。

さてこの SDK -> WebExtensions の作業において赤福プラスは前座でしかない。本丸は wasavi なのである。

2016/12/15 5:47 pm
Add-on SDK to WebExtensions #2
Uncategorized, , ,

一通り動くようになった。

すでに上げた Port の引数の問題の他、content script で生成した XMLHttpRequest の動きが変。

  • Referer が吐かれない
  • Cookie が送出されない
  • open() の際、相対 URL を与えるとエラーになる

同様の問題を抱えている人がいた。そのやり取りによると、

   try {
      return XPCNativeWrapper(new window.wrappedJSObject.XMLHttpRequest());
   }
   catch(evt){
      return new XMLHttpRequest();
   }

こんな感じで Firefox に限り意味の分からない書き方をすることで解決できるそうな。確かにこれでうまく行くけど…早く直してほしい。

ところでもうひとつ、ID の問題がある。Chrome のエクステンションは基本的にそれを識別する ID というものを開発者が意識する必要はない。エクステンションをローカルで crx にパッケージングした際に生成される .pem ファイルは取り扱いに気をつける必要はあるが、今日ではローカルパッケージングは zip で事足りるので .pem ファイルを生成する必要自体が基本的にない。

WebExtensions の場合は一応その流儀に倣っているが、しかしやはり Firefox の拡張らしく、ID は裏で健在だったりする。というのも署名を mozilla のサーバにつけてもらうと .web-extension-id という ID が書かれたドットファイルをもれなくプレゼントされるのである。うーんなんかイケてなくないですか。

一方で陽に ID を取り扱うこともできる。manifest.json の applications に

  "applications": {
    "gecko": {
      "id": "[email protected]",
      "strict_min_version": "42.0",
      "update_url": "https://github.com/akahuku/akahukuplus/raw/master/dist/firefox.json"
    }
  },

とこんな感じに書けばいい。ただよく分かんないことに、こう明示したとしてもやはり .web-extensions-id ファイルはプレゼントされる。いらないんですけど!

ところで上記の ID、いかにも Add on SDK 製の拡張っぽい書式だが、実際に SDK 版の赤福プラスの ID だ。というのも、おそらく流用しないと SDK 版から WebExtensions 版へのスムーズな自動更新が行えないからだ。うーんなんだかかっこ悪いなあ…。

2016/05/01 7:00 am
Optimize a loading of assets
Uncategorized, , ,

赤福プラスの話。

赤福プラス 3.x はふたばの画像掲示板を開いた時に DOMContentLoaded のタイミングで一旦ドキュメントをすべて書き換える。これはなかなかアグレッシブな動作で、3.x 未満の赤福プラスや、おそらくは他の、ブラウザ上で動作するふたば閲覧エクステンションはあくまでふたばがネイティブで送出するコンテンツに何かを「付け足す」ようになっていると思う。赤福プラス 3.x はそうではなく、完全に書き換える。元のドキュメントからメタな中間 XML ドキュメントを生成し、それを XSLT によって HTML に変換・再構築し、元のドキュメントに上書きする。

さて DOMContentLoaded というのは定義としては DOM の構造を構築し終わった段階で発火するイベントで、load イベントに比べてかなり早い段階で発生する。しかし、これはドキュメントに付随するスタイルシートやスクリプトや画像や iframe で指定されるサブフレームのドキュメントをまだ読んでいない段階というわけでは *ない*。もしかしたら並行して読んでいる途中かもしれないし、そうでないかもしれない。特に最新のブラウザほど、並行動作をしている割合が高い。

このブラウザの動作は、赤福プラスの仕様とは相容れない。もしその手のアセットを読み込むとしても、それは赤福プラスが管理する文書の下で読み込まれるべきで、その前段階でネットワークアクセスが発生するのは全て無駄になるため、好ましくない。

そういうわけで、その辺りを最適化するために以前から Presto Opera では外部の script 要素の動作をブロックしたりしていた。似たようなことは Chrome の WebRequest API でもできるわけで、やってみた。

やることは、赤福プラスがページを再構築している間、そのページから発生するふたば外へのリクエストをすべてブロックすることである。そのために、

  • バックエンドの main.js にタブ ID をキーとするハッシュ initializingTabIds を用意する
  • WebRequest API によりすべてのリクエストをリスンする
  • ふたばの画像掲示板の URL がアクセスされたら、そのタブ ID を initializingTabIds に記録する
  • その他の何かがアクセスされた場合、それが属するタブ ID が initializingTabIds に含まれていれば、リクエストをキャンセルする
  • 赤福プラスのフロントエンドがページを再構築を完了したら、バックエンドへ initialized メッセージを投げる
  • バックエンドが initialized メッセージを受け取ったら、そのタブ ID を intializingTabIds から削除する

という処理を加えた。

ところで WebRequest を使うには manifest.json の permissions に “webrequest” および対象となる URL パターンを含める必要がある。今回の場合は URL は http://*/* および https://*/*/ というかなり広範囲に及ぶ強いパーミッションを必要とする。その場合 webstore での審査もけっこう時間がかかるようだ。昨日の午後提出して今審査が通った。

ちなみに Firefox 版はそういう最適化をしていないので読み込みが一番遅い。気が向いたらがんばる。

2016/04/14 7:45 pm
Mysterious bound keyword
Uncategorized, , , , ,

Firefox 46a だったか 47a だったか忘れたが、wasavi と赤福プラスが両方動かなくなったことがあって調べてみた所、

  1. 両方が使っている extension_wrapper.js 内で、それが Firefox + Add on SDK で動いているかどうかを判断している箇所があり
  2. Firefox のその該当バージョンで判断のもとになっている箇所が変更されたため

動かなくなっているということだった。

extension_wrapper.js は Chrome でも Opera でも Firefox でも共通して動くので、それぞれのブラウザのうちどれで動いているのかを判断しないといけない。Chrome なら window.chrome が存在しており、Opera なら window.opera が存在しているのでそれが判断の助けになる。。

一方 Add on SDK の PageMod における content script かどうか、というのを判断するためのあんしんあんぜんな方法はないように思える。とりあえずのところ、self.on が存在し、それが function であり、かつその toString() の値が “function on (.*?) { [native code] }” とかそんな感じになっていればまあたぶんきっと SDK ベースの content script だろう…というような判断をしている。”[native code]” がミソなのだが、これが最適解というわけでは全然ない。

これが、今回動かなくなってしまったのである。それは、self.on の toString() の値が “function bound on (” というように、謎のキーワード bound が入るようになっていたからだ。bound……って何?

2016/03/14 1:15 am
Tegaki #2
Uncategorized, ,

akahukuplus-tegaki-in-summary2

ふたばのオリジナルの手描き機能では、手描き画像でスレを立てることはできない設定になっている。少なくとも虹裏 may ではできない。これはきっと理由があるのだと思うけど、まあブラウザのエクステンションでは特にそういう制限をかける必要はあるまいということで、立てられるようにした。

このとき、手描き画像のキャンバスサイズは 640×480 に拡大されるようになっている。これは Tegaki Draw and Tweet の画像サイズに準じた。

ちなみにオリジナルの手描き機能を送信する際の内部的なフォームデータは、baseform という hidden input 要素である。手描きの flash が逐一この要素に画像を base64 でエンコードした文字列を設定する。これとは別に、従来通りの普通にファイルを送信する要素は upfile である。すなわち可能性としてはファイルと手描き画像を両方同時に送信することが可能なのだが、試していないがたぶん upfile のほうが優先される。

赤福プラスでは baseform 要素を特に積極的に使う必要はない。というのは手描き画像を保持する canvas 要素から blob データを得て、送信フォームの構築時に upfile に割り当てればいいだけの話だからだ。そんな細かいことをブラウザだけでできるようになったんだねぇとしみじみしちゃうが、とりあえずレス画像としての手描きは baseform、スレ画像としては upfile を使うようにしてある。

ついでに 1 回限りの undo やペンサイズを変更するためのショートカットなどを追加。

2016/03/12 4:39 am
Tegaki
Uncategorized,

虹裏の中には手書き機能が付いている板もあるのだが、赤福プラスで閲覧している状態ではその機能を利用できなかった。そうこうしているうちにはよ実装しろやバーカバーカという声まで来てしまった。

なぜ延び延びになっているかといえば、ぶっちゃけて言えば赤福プラスをいじっても 1 円も儲からないからだ。

wasavi の場合は、Pledgie へのリンクをつけてあり、まあ元をとっているのかといえば全然ではあるのだけど、一応開発に対する対価は得ている。しかし赤福プラスの場合はそういうものはつけていない。じゃあつければいいじゃんということなのだが、果たして「」やとっしーが虹裏向けのブラウザなんかにお金を払うだろうか。いや払うわけがない。そして、仮に払ったとしても、そうすると調子に乗って文句たらたらになることは火を見るよりも明らかである。

実装の面から考えてみると、元の手書き機能は flash なのであまり扱いたくない。また、代替品を作るにしてもそれなりに手間がかかる。

そういうわけでなかなか腰が重い。殊勝なとっしーがポンと30万円くらい払ってくれてしかもおかしな注文もつけてこなければ一生懸命いじるのだが。

* * *

最後に 1 つ書いておくと、赤福プラス 3.1.207 からは手書き機能がついてある。

Archives