2011/07/07

sonata 1.6.2.1のlyrics fetch bug

自分は音楽再生にmpdとクライアントのsonataを使っていた。quodlibetも使うことがあるがsonataはやっぱり使いやすい。
最近はアクティブに開発されてないみたいだけど。

sonataはLyricWiki (http://lyrics.wikia.com/)から歌詞をFetchしてくるのだが、ある時からそれがFailしまくっている事に気づいた。
歌詞が載っている曲でもFailするので、バグじゃないかという事でコードを見てみる。

まず、Wiresharkでパケットを見てみる。
Infoタブの(Search)っていう所を押すと、Artist NameとSong Titleを入力して、そこからFetchに行くっぽいが、どうもArtist NameとSong Titleを入力しても
それがGETリクエストに反映されてないっぽかった。
"http://lyricwiki.org/index.php?title=:&action=edit”
みたいになっちゃってる。本来なら、The ToastersとEast Side Beatで検索すると
"http://lyricwiki.org/index.php?title=The%20Toasters:East%20Side%20Beat&action=edit"
ってなるべきだと思われる。

sonata-1.6.2.1をダウンロードしてみると、info.pyのget_lyrics_thread()にこれを行う部分が。
try:
    lyricpage = urllib.urlopen("http://lyricwiki.org/index.php?title=%s:%s&action=edit" % (self.lyricwiki_format(search_artist), self.lyricwiki_format(search_title))).read()
    content = re.split("]*>", lyricpage)[1].split("")[0]
    if content.startswith("#REDIRECT [["):
        addr = "http://lyricwiki.org/index.php?title=%s&action=edit" % urllib.quote(content.split("[[")[1].split("]]")[0])
        content = urllib.urlopen(addr).read()
    lyrics = content.split("<lyrics>")[1].split("</lyrics>")[0]
    if lyrics.strip() != "<!-- PUT LYRICS HERE (and delete this entire line) -->":
        lyrics = misc.unescape_html(lyrics)
        lyrics = misc.wiki_to_html(lyrics)
        lyrics = lyrics.decode("utf-8")
# Save lyrics to file:
        misc.create_dir('~/.lyrics/')
        f = open(filename, 'w')
        f.write(lyrics)
        f.close()
    else:
        lyrics = _("Lyrics not found")
    gobject.idle_add(self.info_show_lyrics, lyrics, filename_artist, filename_title)

ここに渡されるsearch_artistとsearch_titleがおかしいのか。という事で呼び出し元をみるとmain.pyのon_lyrics_search()が。
ここのdialog.destroy()のタイミングがおかしかった。dialog.destroy()をしてからartist_entry.get_text()を呼んでいる。順番は逆であるべきか。
ここを直したがまだ歌詞ガFetchできん…。
ちゃんとリクエストは送れてるっぽいしレスポンスも大丈夫そうだった。結果のparseがおかしいのか。

と思ってもう一度info.pyを見た。
get_lyrics_threadにあるparseを行う部分と返されるレスポンスを見てみると、
info.pyでは
lyrics = content.split("<lyrics>")[1].split("</lyrics>")[0]
としているが、実際のレスポンスは
"<lyrics>" "</lyrics>"
となっている事に気づく。>でなく直接>が帰ってきていた。これはLyricWikiのバグ(仕様か?)と思われたがとりあえずparseできるようにsplitの中を改変。
試してみると歌詞のFetch成功。やったわ。

パッチは以下のようになった。
diff -ur sonata-1.6.2.1/sonata/info.py sonata-1.6.2.1.fix/sonata/info.py
--- sonata-1.6.2.1/sonata/info.py    2009-09-22 06:02:16.000000000 +0900
+++ sonata-1.6.2.1.fix/sonata/info.py    2011-07-07 21:40:31.063073755 +0900
@@ -393,8 +393,8 @@
                 if content.startswith("#REDIRECT [["):
                     addr = "http://lyricwiki.org/index.php?title=%s&action=edit" % urllib.quote(content.split("[[")[1].split("]]")[0])
                     content = urllib.urlopen(addr).read()
-                lyrics = content.split("<lyrics>")[1].split("</lyrics>")[0]
-                if lyrics.strip() != "<!-- PUT LYRICS HERE (and delete this entire line) -->":
+                lyrics = content.split("<lyrics>")[1].split("</lyrics>")[0]
+                if lyrics.strip() != "<!-- PUT LYRICS HERE (and delete this entire line) -->":
                     lyrics = misc.unescape_html(lyrics)
                     lyrics = misc.wiki_to_html(lyrics)
                     lyrics = lyrics.decode("utf-8")
diff -ur sonata-1.6.2.1/sonata/main.py sonata-1.6.2.1.fix/sonata/main.py
--- sonata-1.6.2.1/sonata/main.py    2009-09-22 06:02:16.000000000 +0900
+++ sonata-1.6.2.1.fix/sonata/main.py    2011-07-07 21:40:00.149073735 +0900
@@ -2132,12 +2132,12 @@
         ui.show(dialog.vbox)
         response = dialog.run()
         if response == gtk.RESPONSE_ACCEPT:
-            dialog.destroy()
             # Delete current lyrics:
             filename = self.info.target_lyrics_filename(artist, title, None, consts.LYRICS_LOCATION_HOME)
             misc.remove_file(filename)
             # Search for new lyrics:
             self.info.get_lyrics_start(artist_entry.get_text(), title_entry.get_text(), artist, title, os.path.dirname(mpdh.get(self.songinfo, 'file')))
+            dialog.destroy()
         else:
             dialog.destroy()


The Toasters - East Side Beat
http://www.youtube.com/watch?v=bLqCpPpB4rI
いつ聞いてもいいですね。

いいの思いついたわ。

思いついてalias o='xdg-open'ってしてみた。これでどんな種類のファイルでもGUIでダブルクリックするみたいに
「開く」ができるわ。
$ o hoge.jpg
$ o hoge.pdf
$ o hoge.avi
みたいな。今のところ便利に使ってます。
自分の端末では/usr/bin/xdg-openにあったから見てみたらシェルスクリプトでした。
detectDEっていう関数で
detectDE()
{
    if [ x"$KDE_FULL_SESSION" = x"true" ]; then DE=kde;
    elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then DE=gnome;
    elif `dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.gnome.SessionManager > /dev/null 2>&1` ; then DE=gnome;
    elif xprop -root _DT_SAVE_MODE 2> /dev/null | grep ' = \"xfce4\"$' >/dev/null 2>&1; then DE=xfce;
    elif [ x"$DESKTOP_SESSION" == x"LXDE" ]; then DE=lxde;
    else DE=""
    fi
}

みたいにしてDEをゲットして、例えばgnomeだったらopen_gnomeっていう関数でgvfs-openなりgnome-openなりを呼んでるのね。
なるほど。。
ほとんどターミナル上で作業するので便利。
$ eog huga.pdf
とかやってウザくなることが少なくなっていいわ。