makoto_kwのソロプロジェクト第2段WALKMAN.LOGというWebアプリを公開しました。といってもまだαバージョンとして認証をかけているので知り合い限定で公開というところからはじめようかと。
![]()
もともとの開発の動機はAudioscrobbler(Last.fm)にウォークマンの再生履歴をアップロードしたい。と思ったから。だってパソコンで音楽聞かないんだもん。iPodの履歴を送信するツールもあるけど、最近聞いたプレイリストを利用しているだけで純粋な履歴じゃなかったりするんですよね。
WALKMAN.LOGでは純粋なウォークマンの再生履歴をアップロードしています。これを実現するためにウォークマンの再生履歴を読み出すCOMを作りました。それをJavaScriptから呼び出して送信します。
再生履歴は直接Last.fmに投げるのではなく、いったんWALKMAN.LOGで履歴を管理して、そこから送信しています。これは同じ再生履歴を何度も送信しないためにどれが送信済みなのかを管理したかったため。あとはLast.fmに送信する・しないを公開・非公開として設定できたりもします。
しかし自分で作っておいて何だけど他にこれを使いたい人がいるのか不明。Last.fmユーザじゃなければ、再生履歴をアップロードしてもだから何なの?で終わってしまう。。。
自分としてはそれまで500曲程度だったLast.fmの履歴が一気に3000曲も追加されて、今週は毎日ウォークマンの履歴をWALKMAN.LOGにアップロードしてLast.fmに送信してます。かなり自己満足モードです。
Archive for 2月, 2008
最近またサッカー日本代表を真面目に応援するようになった。
2006年のドイツワールドカップの結果と中田の引退を受けてしばらくサッカーには興味が持てない時期が続いた。
オシムジャパンになっても、魅力的な選手が現れず、走る・走る・走るというキーワードが突然扱われよくわからない状態だった。
岡田監督が主任した時、正直なところ一瞬がっかりした。けれど不思議とがっかりは一瞬だった。
それは1998年のフランスワールドカップを思い出したからだと思う。ワールドカップ初出場は加茂監督が途中で更迭され、最終予選はぎりぎりでの達成だった。だから感動した。フランスワールドカップは一勝もできなかった。点差は一点差だったけど力の差は歴然としていた、でも日本サッカーが初めて世界へのスタート地点にたてたような気がした。
そして10年たって、日本ワールドカップ初監督の岡田監督の再就任。自分の中でなんらかのドラマ性がわき上がり、また日本代表を見ようと思った。ひょっとするとワールカップ出場をみざして応援していた当時の感情が舞い戻ったのかもしれない。
東アジア選手権は全部テレビ観戦した。3戦とも内容は良くなかったし、北朝鮮を除いて相手チームもそれほど良い状態にあるように見えなかった。それでも、中国戦は完全アウェーの中で逃げ切たし、韓国戦は早い段階でリードされたのに追いついた。就任してまだ時間がたってないし、けが人が多い中での結果なので評価できると思う。
内田や山瀬は、いろいろ否定的な意見も言われてると思うけど、時折光るプレー、それも得点の匂いがするところで感じさせてくれるので今後も使っていくべきだと個人的に思う。
今回使えそうな選手、使えなさそうな選手がわりとはっきりしたと思うのでオシムが選ばなかったけど、まだチームにフィットすればレベル的には十分代表トップクラスにある選手、例えば小笠原や小野あたりも一度試して欲しいと思う。山瀬とか見てると小笠原なんか代表でも普通に良い仕事しそうな気がするんだが。
YouTubeがダウン–原因はパキスタンでのアクセス遮断か
http://japan.cnet.com/news/media/story/0,2000056023,20368032,00.htm
YouTubeが落ちていたらしい。CNETの記事によると太平洋時間午前11時30分頃に発生し、午後12時15分に復旧とのこと。
時差が17時間くらいだったと思うので日本時間にすると朝の4:30-5:15くらい?確かにその時間にaTunesがアクセスできなくて、ログをみるとYouTubeへの接続が全部タイムアウトしていたので、YouTubeの機嫌を損ねる何かをしてしまったのか??と焦りました。
週初めのそんな時間に普通に起きてコード書いていた自分は社会人失格ですが、YouTubeに接続できないと、ページが開けないというWebサイトを作ってしまったのはエンジニア失格かも。
つながらないなら、つながらないなりにエラー表示しないと。。。
最近lightbox.jsというライブラリを使って遊んでいます。
http://www.huddletogether.com/projects/lightbox/
http://www.huddletogether.com/projects/lightbox2/
lightbox.jsは画像のポップアップ表示を可能にするjavascriptライブラリですが、javascriptを一行も書かずとも
<script type="text/javascript" src="js/lightbox.js"></script>
と入れるだけで
あとは
<a href="images/image-1.jpg" rel="lightbox" title="my caption">image #1</a>
とaタグのrel要素のlightboxと書くと利用できてしまうすぐれものです。
コードを見ればわかりますが利用者にjavascriptを書かなくて済むようにするためにonloadでinitLightboxを呼び出してごにょごにょしています。
Ajaxのページではこのonloadでごにょごにょしているというところに注意点があります。たとえばprototype.jsのAjax.Updaterなどで動的にページの一部を更新する場合に、
<a href="images/image-1.jpg" rel="lightbox" title="my caption">image #1</a>
と入れてもonloadが呼び出されたあとだと意味がありません。通常のaタグのまま動作してしまいます。
さて、どうすればいいか。initLightboxでごにょごにょしているところを追ってみます。
ごにょごにょしていますが、重要なところを抜き出すと
lightboxの場合
if (anchor.getAttribute("href") && (anchor.getAttribute("rel") == "lightbox")){
anchor.onclick = function () {showLightbox(this); return false;}
}
lightbox 2の場合(2008/12/06追記: 2.04ではmyLightboxというグローバルな変数は使わなくなっていました)
// use the string.match() method to catch 'lightbox' references in the rel attribute
if (anchor.getAttribute('href') && (relAttribute.toLowerCase().match('lightbox'))){
anchor.onclick = function () {myLightbox.start(this); return false;}
}
と。どちらもやってることはaタグを探して、ref=”lightbox”であればonclickにshowLightboxを表示しretturn falseし、ページ遷移を抑止する。ということだけです。
つまりは、onload以降にAjaxなどで動的に要素を追加する場合は、それぞれ
<!-- lightbox --> <a href="images/image-1.jpg" rel="lightbox" onclick="showLightbox(this); return false;" title="my caption">image #1</a> <!-- lightbox2 --> <a href="images/image-1.jpg" rel="lightbox" onclick="myLightbox.start(this); return false;" title="my caption">image #1</a>
と明示的にonclickに処理を書いてあげれば良いのです。
これで後から追加されたaタグでもlightboxを表示できます。(2008/12/06追記: 2.04ではmyLightbox変数を使わなくなっておりこの技が使えません)
さて、lightbox 2では複数の画像でスライドショーもどきな表示を行うことができます。
コードを見てみると、表示を開始するところで・・・・
// if image is NOT part of a set..
if((imageLink.getAttribute('rel') == 'lightbox')){
// add single image to imageArray
imageArray.push(new Array(imageLink.getAttribute('href'), imageLink.getAttribute('title')));
} else {
// if image is part of a set..
// loop through anchors, find other images in set, and add them to imageArray
for (var i=0; i<anchors.length; i++){
var anchor = anchors[i];
if (anchor.getAttribute('href') && (anchor.getAttribute('rel') == imageLink.getAttribute('rel'))){
imageArray.push(new Array(anchor.getAttribute('href'), anchor.getAttribute('title')));
}
}
imageArray.removeDuplicates();
while(imageArray[imageNum][0] != imageLink.getAttribute('href')) { imageNum++;}
}
とrel要素でスライドショーする画像を集めていることがわかります。
本家のサイトではスライドショー表示するときには
<a href="images/image-1.jpg" rel="lightbox[roadtrip]">image #1</a> <a href="images/image-2.jpg" rel="lightbox[roadtrip]">image #2</a> <a href="images/image-3.jpg" rel="lightbox[roadtrip]">image #3</a>
というhtmlを例に出しています。
ここまで見たコードをもとにlightbox2では
- rel要素に’lightbox’という文字が含まれているとonloadでonclickに処理が追加される
- 同じrel要素をもつものでスライドショーが行える
ということが理解できます。
ちなみに先ほどのAjaxの例で明示的にonclickにlightboxを表示する処理を記述した場合は、
rel要素に’lightbox’という文字列を入れる必要はなくなります。(2008/12/06追記: 2.04ではrel=’lightbox’は必須ぽいです)
ですが、rel要素に何も入れない場合には、すべてのaタグでスライドショー表示を行おうとするので注意が必要です。’lightbox’という文字列を入れる必要はありませんが、なんらかの文字列を入れておくとよいでしょう。
デブサミ2008に参加してきました
デブサミ2008
http://codezine.jp/devsumi/2008/
去年は仕事の都合でいけなかったのですが、今年は両日とも参加してきました。事前登録が必要なのですが、どうやら興味のあるセッションがない時間は何も取らないという選択をしていたらしく、ちらほら時間が空いたのでブースで説明を聞いたり、外でぶらぶらしたりしてきました。
とりあえず、つたないメモはWikiにあげました。
http://wiki.hackathon.jp/pukiwiki/?%E3%82%BB%E3%83%9F%E3%83%8A%E3%83%BC
文章をつくるのが面倒なので思ったこと箇条書き。
- RubyとRailsは言語が日本、Railsが英語圏で誕生してるので、いろいろ面倒そうだ。
- ひょっとすると某ソニー、某コネクトカンパニーの某Cチームと某Fチームの関係みたいなことになってないか?
- Rubyに協力したい気は起きたが、まだ1行もRuby書いたことがない自分に何ができるのか。
- 特に焦ってRailsを使う必要はないのかもしれない、symfonyで十分?
- Javaはいろんなフレームワークがあるもんだ。さわってみたいがわざわざjavaで何か作る気は起こらん。使うとしたらAndroidくらいだ。
- AIRでaTunesつくろうかな
- Project Zeroはすごそうだが、個人でWebアプリを作る分にはRailsなど既存のフレームワークで良い気がする。
- C#3.0に移行しよう。LINQなどを使えば生産性があがるかもしれない。
- AmazonでVS2008 Standardのアップグレードを発注
- MVPか。欲しいくないと言えば嘘になるけど、仕事の延長でできるならともかくそのためにMSの技術を学ぼうというのはやっぱり間違いだよな。
- にこ2モバイルはC#3.0で書いて.NET 2.0アプリにしよう
- もしLightning Sessionする機会があったら5分でつくるGadgetとかやりたい
- 「ユーザビリティ」という言葉を安易に使われるのは好きじゃない。ちゃんと学問として学び、実務経験もある人が言うなら説得力があるんだけど。
- 使い勝手の発言は1ユーザとしての立場で言っているのか、専門家としての意見なのか聞きわける必要があると思う。特にお偉いさんが口出すケースはほぼ前者なので、その発言を必要以上に重要視して要件に落とす必要はないと思う
- なんかコミニティに入ろうかな。。。性格上、特定の技術に入り込む気になれないんだよなぁ。「メディアアプリケーションの会」とかならやれそうだけど・・・アプリケーションドメインの開発コミニティって聞いたことない。
aTunesを少しばかり更新しました。
すっかり音楽番組も見なくなってアーティストの新曲が発見できない状態だったので、
Amazonから新譜を取得するようにしてみました。新譜といってもAmazonのWebサービスで発売日の新しい順でItemSearchしているだけです。アーティストによってはNew Releaseと言いながらずいぶん古いアルバムが並んだりしますが、まぁ・・・それはスルーしてください。
さて、備忘録的にaTunesの内部実装を少し書きます。
言語はPHP5、フレームワークとしてsymfonyを使っています。今回の更新ついでにsymfonyのバージョンも最新の1.0.11に更新しました。Ruby on Railsを使うことも検討したのですが、Rubyを勉強してる時間を惜しんで、とりあえずリリースしたかったのでPHPのRailsといえるsymfonyで実現しました。
Mashupとしては、
・動画コンテンツの再生、検索にYouTube APIを使用、実装にはPEARのServices/YouTubeを利用
・関連アーティストの取得には、Last.fmのAPIを使用、実装は自前
・アーテイスト情報は、SimpleAPI経由でWikepdiaから取得、実装は自前
・ページフッタにあるアーティストのタグクラウドはMoraのシングルランキング100のアーティストを取得、実装は自前
・アーティストのNewReleaseはAmazonから取得、実装にはPEARのService/Amazon(AmazonECS4)を利用
というようになっています。
割とさくっと作ったけどこうやって箇条書きにしてみるといろいろ使ったりしていました。
現状、ユーザ管理などが面倒なので会員登録とかログインしてユーザごと何かするとか、SNS的な機能などはありません。個人的にふらっと立ち寄って、使える気軽さが欲しいと思っているため、そういった機能も考えてもいません。個人設定はCookie&Sessionでできる範囲のことをやろうと思います。そういわけで、dbを使う操作も今のところありません。
残念ながらまだNow Loading…消えない問題が起きている。。。
blogにうまくコメントが投稿できない問題があったので修正しました。Movable Type 3.x時代に使っていたCaptchaプラグインがインストールしたままになっていたのですが、それが悪影響を及ぼしていたみたいです。
該当プラグインを削除し、MT4で搭載されたCpatcha認証を使うことにしました。とりあえず自分ではコメントできました。
してみる
blogをあまり書いていないので、それならtwitterのstatusをブログにしてしまおうと、
twitterの一日分のstatusを取得して、XMLRPCでMovable Typeにpostするということをしていました。(twitterのブログなのでtwilogと読んでます)
しかし、blogをたまに書いたときに記事がtwilogに埋もれてしまうという反面がありました。
そこで最新の記事リストからtwilogを除外しようと思いました。最初は記事のタイトルで”twilog”を含んでいたら除外・・ということを考えていたのですが、twilogをカテゴリに入れて該当カテゴリを除外、としたほうが汎用性があるかなと思いました。
残念ながら、twilogは今までカテゴリに入れていなかったので、手順としては。
・twilogカテゴリを作成する
・twilogエントリのpost時にカテゴリを指定する
・過去のtwilogエントリをtwilogに移動する
・記事リストでtwilogカテゴリを除外
というようになります。
カテゴリは普通にMTにログインして作成しました。次にtwilogのポストでカテゴリの指定する方法ですが、metaWeblog.newPostの仕様を見ても、mt/lib/XMLRPCServer.pmを見てもカテゴリの指定ができそうにありません。タグは追加できそうな雰囲気なのに・・・
結局のところmetaWeblog.newPostを呼んでから、mt.setPostCategoriesを呼ぶことにしました。
一部コード抜粋です。phpでPEARのXML/RPC.phpを使っています。
function mt_post_entry($title, $description, $categoryid, $publish)
{
$xtitle = new XML_RPC_Value($title, 'string');
$xdesc = new XML_RPC_Value($description, 'string');
$xpublish = new XML_RPC_Value($publish, 'boolean');
$xcontent = new XML_RPC_Value(array("title"=>$xtitle,"description"=>$xdesc), 'struct');
$postdata = array($this->xblogid,$this->xuser,$this->xpass,$xcontent,$xpublish);
$xmsg = new XML_RPC_Message('metaWeblog.newPost',$postdata);
$postid = $this->xclient->send($xmsg);
$fcode = $postid->faultCode();
if ($fcode==0 && $categoryid != null) {
$xcat = new XML_RPC_Value(array("categoryId"=>new XML_RPC_Value($categoryid,'string'),"isPrimary"=>new XML_RPC_Value(1,'boolean')),'struct');
$xcats = new XML_RPC_Value(array($xcat),'array');
$porstdata = array($postid->value(),$this->xuser,$this->xpass,$xcats);
$xmsg = new XML_RPC_Message('mt.setPostCategories', $porstdata);
$result = $this->xclient->send($xmsg);
}
if ($fcode==0 && $publish) {
$porstdata = array($postid->value(),$this->xuser,$this->xpass);
$xmsg = new XML_RPC_Message('mt.publishPost', $porstdata);
$result = $this->xclient->send($xmsg);
}
return ($fcode != 0);
}
もうtwilogポスト用なのでかなり割り切ったコードです。あらかじめcategoryidもわかっていることにしてます。
次に過去のtwilogエントリのカテゴリ移動ですが、70件以上あってこれを手動でやるのは面倒なのでSQLを実行。。。
insert mt_placement (placement_blog_id,placement_category_id,placement_entry_id,placement_is_primary) SELECT 1 as placement_blog_id, 16 as placement_category_id, entry_id as placement_entry_id, 1 as placement_is_primary FROM mt_entry WHERE entry_title LIKE '%twilog%' ;
これでtwilogエントリはカテゴリに入りました。あとは記事リストからこのカテゴリのエントリを除外するのみです。
MTEntriesには仕様を見る限り、カテゴリを除外するよな引数は残念ながらないようでした。それならば追加するか、とmt/lib/MT/Template/ContextHandlers.pmを眺めていたところ、、どうもNOTが使えそうな雰囲気です。
そこで試しに
<MTEntries lastn="10" category="NOT twilog">
としてみたら・・・
なんと”twilog”カテゴリが除外されました。素晴らしい。仕様書にはORのみ。って書いてあったのですがNOTも使えるようです。