Hatena::ブログ(Diary)

asotech RSSフィード

2008-04-30

Last.fmの英語版アプリケーションをダウンロードする方法

大分前にダウンロードしておいたけど忘れそうなのでメモ


そもそも日本語版だと何が悲しいかというと、一番重要ラジオ機能がカットされている事。

Exciteとの提携時(もう撤退したみたいだけど→記事)からの名残か日本の著作権に配慮してか、とにかく聴くことができない。


英語版ダウンロードの方法はとても簡単で、ブラウザの設定をen-usにすればいいだけ。

その後、http://last.fmからダウンロード


前回は嵌ってlynxから海外プロキシを通したりと無駄な苦労をしてしまった。


インストール時の設定は特に必要なく、英語版でも日本語のインターフェースになる。

インストール後アップデートのウィザードが勝手に立ち上がるが、ここからアップデートすると日本語版に変わってしまうので注意が必要。

2008-04-16

DD-WRT+Flets光で大いにはまる

FONのDD-WRTを設定変更のためファームを入れ替えした。

簡単に再度接続出来たのだが、ニコニコ動画など特定のページを読み込み出来ずに大いにはまる。

始めはDNSの設定かなぁと思い、DNSキャッシュ初期化やDNSの変更をしたが上手く繋がらない。


色々試した結果MTU値がおかしいことが判明。1452に書き換えて見事接続。


…久しぶりに大いにはまりなんとも言えない気分になった。

今回の敗因は二点。


  • 以前もはまったような気がするのにメモしておかなかった。
  • ファーム更新前に設定のバックアップを取らなかった。(後で知ったのだがDD-WRTは設定のバックアップが取れる)

うーん、馬鹿だなぁ。次からは気をつけよう。

2008-04-14

iPod touchオフラインMap.appのキャッシュ喪失と「Maps Offline」


以前書いた「iPod touch、オフラインでMap.appを使う方法」で快適に地図ライフを満喫中。なんですが、ついにキャッシュが消える現象が発生しました。原因は不明。


キャッシュ復活用スクリプト

if [ -f /private/var/root/Library/Caches/MapTiles/MapTiles.sqlitedb ]; then

rm /private/var/root/Library/Caches/MapTiles/MapTiles.sqlitedb

fi

ln -s /private/var/root/Media/MapTiles/MyMap.sqlitedb /private/var/root/Library/Caches/MapTiles/MapTiles.sqlitedb


前記事でも手順は書いたけど、実際にMedia領域内にsqlitedbを保存して本来あるべき場所にはシンボリックリンクを張っておくと復活させることが出来ました。これで万事OKなはず…だったんだけどなぜかブックマークも同時に消失。ええええ。


ちょっとショックですが、Bookmarks.plistもMedia領域内に保存してシンボリックリンクを張った方がいいと思います。

ln -s /private/var/root/Media/MapTiles/Bookmarks.plist /private/var/root/Library/Maps/Bookmarks.plist


復活用スクリプト

if [ -f /private/var/root/Library/Maps/Bookmarks.plist ]; then

rm /private/var/root/Library/Maps/Bookmarks.plist

fi

ln -s /private/var/root/Media/MapTiles/Bookmarks.plist /private/var/root/Library/Maps/Bookmarks.plist



私が書いたスクリプトも適当にでっちあげたながらも使っていただいているようでなんだが申し訳ない気分です。

MyMap-02.zip


そうこうしている内にオフラインでキャッシュを利用できるiPod touch用アプリ「Maps Offline」がiPod touchラボさんで紹介されていました。

http://ipodtouchlab.com/2008/04/iphoneipod-touchmaps-offline13.html


JailBreakは必須なものの私が紹介した手順に比べ格段に敷居が低いことは間違いないでしょう。

ただ、オフラインの地図を作成するためには一度その地点を閲覧しなければならないようなので、広範囲な地図が欲しい場合には向いてないかもしれません。

まぁ、よくあると思われる「とある駅の周りの地図さえあれば十分」という場合はMaps Offlineを使った方が楽だと思います。

2008-04-13

wifineにEee PC以外からキャンペーンに参加(含iPod touch)

東京の首都圏向けにNTTインフラで提供されているwifineという無線LANサービスが展開されている。

無料サービスも豊富で過去にはiPod touch向けの期間限定無料接続サービスも提供されていた。現在行われているのはEee PC向けのキャンペーンなのだが、割と簡単に他のPCやiPod touchから繋ぐことが出来た。これは問題。


まず登録。「wifine」というアクセスポイントに繋ぐと自動的に↓ページに飛ばされる。

http://wifine.jp/


右上のEeePCのキャンペーンから必要情報入力して参加登録をする(登録は4/30まで。サービスの利用自体は5月末まで行える)。

登録自体はEeePC以外からでも行える(iPod touchでも)。登録後アクセスキーが送られてくる。


その後、元のページに戻ってキャンペーンのバナーを再度クリックしてアクセスキーを入力する。

ユーザーエージェントでEeePCかどうか判定を行っているらしく、Safariでは認証不可。

FireFoxのUser Agent SwitcherなどでEeePCっぽくユーザーエージェントを偽装すればアクセスできる。


iPod touchの場合はSafariの設定をいじれないのでJailBreak済みのターミナルからcurlを使ってアクセスキーを入力。


curl -L -A "EeePCっぽいユーザーエージェント" -d "POSTするパラメーター" 認証フォームの投稿先


一度接続してしまえばiPod touchのSafariからもアクセス可能に。


この手順を使えば、EeePCの期間が終了してもその後のPSPキャンペーンでも恐らく対応可能。

真っ当な方法とは言えないので詳細な手順は省きます。どうしても知りたい方はコメントで…。

ある種セキュリティーホールとも言えるこのただ乗り。サービス提供中止というのはなしで他に対策方法はあるのでしょうか?

2008-03-31

Rubyでソーシャルブックマーク用自動タギング

はてなブックマークのようなソーシャルブックマーク(SBM)にはたいていタグ機能があるんだけど、いちいちタグ付けするのは面倒。

上手く人間の手でタグ付けするのが一番いいのは間違いないが、適当でもいい人ものぐさな人(自分)向けにRubyで書いてみた。


タイトルから名詞だけを抜き出してタグ付けしてやれば当たらずとも遠からずなタグが付けられるはず。

使うのはYahoo! Japanの形態素解析Web API

require "rubygems"
require "open-uri"
require "cgi"
require "rexml/document"


def tagging(sentence, appid, separator=",", max="8")
  req = "http://api.jlp.yahoo.co.jp/MAService/V1/parse?appid=#{appid}&results=ma&uniq_filter=9&filter=9&sentence=" + CGI.escape(sentence)
  doc = REXML::Document.new(open(req))

  words = []
  doc.elements.each("//ResultSet/ma_result/word_list/word/surface") do |word|
    words << word.text
  end
  
  ret = ""
  words.each_with_index do |word, index|
    break if index >= max # 多すぎると読めないことがある
    ret << word + separator
  end

  # 終端のセパレーターを削除
  ret = ret.split(//u)[0..-2].join
  return ret
end

で結果が返ってくる。


例えばマッシュアップコミュニティーのMashpedia、3/31で閉鎖という記事タイトルだと

tagging("マッシュアップコミュニティーのMashpedia、3/31で閉鎖", "APPID")

で「マッシュ,アップ,コミュニティー,Mashpedia,3,31,閉鎖」という結果が返ってくる。


結果を見ればわかるように数字もタグとして返ってくる点がYahoo!形態素解析の残念なところで、フィルタリングした方がいいかもしれない。

Mac OSXでFLVファイルの連結(Ruby)

mencoder in1.flv in2.flv -o out.flv -oac copy -ovc copy

で再エンコなしで結合。

しかし、音がずれるので音声のみエンコードなどなど色々試した結果、avi(mp4)に変換することに。

Youkuは6,7分割されていることもざらなのでRubyで適当に書いてみた。


renketu.rb(再エンコあり)

#!/usr/bin/ruby

require "fileutils"
require "find"

file_ini = ARGV[0] # ファイルの接頭語
dir = ARGV[1]

files = []

Find.find(dir) do |file|
  if file.index(file_ini) && file =~ /flv$/
    files << file
  end
end

files.each do |file|
  system("ffmpeg -i #{file} -b 4000 -ab 160 -y -s 320x180 #{file}.avi")
end

com = ""
# 結合順に並び替え
(0..files.size).each do |index|
  index = index * -1 -1
  com += "#{files[index]}.avi " if files[index]
end

system("mencoder #{com} -o #{dir}/#{file_ini}.avi -oac copy -ovc copy")

files.each do |file|
  FileUtils.rm("#{file}.avi")
end

使い方

renketu.rb 0200010 ~/Download/


で連結。ffmpeg部でサイズの指定をしているのは分割ファイルパート1は380x172なのに分割ファイルパート2は380x180

だったりして上手く結合できないので一度縦解像度を180に変更するようにした。


よくわからない仕様だが一応上手く変換結合できるようになった。

2008-03-22

CafePress Content APIを使いたい

マッシュペディアの記事を見てCafePressのAPIに興味があってちょっと探ってみた。簡単に言うと画像を送ってドロップシッピング用のオリジナルグッズが作れるというAPI(検索なども可能)。SVGにも対応しているようなので綺麗でかっこいい商品を作れるかなぁ…と思ったら、API用の認証キーが必要。


http://www.cafepressdn.com/api/content/Authentication.aspxによると

Content APIs are available only on request and acceptance by CafePress.com. To request an API key please fax a signed Alpha Content API Agreement along with your PID, and a brief outline of what you want to do with the APIs at 650 655 3008 (Attention: Manisha).

何?つまるところ、サインしてFAXしろと。

思わず吹いてしまったが、ドロップシッピングは代理店契約であって当然と言えば当然なのかも。しかし面倒だなぁ。


似たようなzazzleではすぐAPIが使えるようになったが、APIから直接商品を作ったりできない模様。手動で商品を作成して、商品IDを取ってきて…、という作業をしなければならずダイナミックに商品を作ろうと思うとめんどくさそう。それじゃぁそもそもなんでAPIがあるのか疑問なので自分の調べ方が悪いだけかもしれない。


ということでCafePressにFAXしようと思う(コンビニ海外にFAXできたっけ?)。

2008-03-04

OSXでMP4動画からAAC音声抽出

H.264+AACなMP4動画から再コンパイルなしでAAC音声のみを抽出する方法。


まずffmpegで音声抽出

ffmpeg -i foo.mp4 -vn -acodec copy foo.aac

ここで出来上がるのは生AACなのでQuickTimeでは再生できない。


MP4コンテナに入れるために

http://www.tkn.tu-berlin.de/research/evalvid/

からmp4boxをダウンロード


解凍

./MP4Box -add foo.aac foo.m4a

でQuickTimeやiTunesで再生できるm4aを抽出完了。


mp4boxのみでも出来そうな気がするが試していない。

あと、VLCのTranscoding Wizardでもmp4コンテナに格納出来る。しかし、これだとQuickTimeでシークが出来ず落ちる(原因不明)。

2008-02-20

YouTubeの埋め込みをXHTML validにするブックマークレット

YouTubeの埋め込みのHTMLはXHTML validではない。The W3C Markup Validation Serviceで怒られる。

そこで調べてみたら、解決方法は小粋空間さんの「YouTube の Embed タグを XHTML valid にする」でわかった。


しかし毎回書き換えるのが面倒なのでブックマークレットに。

javascript:(function(){function h(u){if(u.match(/^http:\/\/.*?youtube.com\/.*?v=(.+?)(\&.*$|$)/))return(RegExp.$1);else return(0)}function o(s){var d=window.open().document;y='';d.writeln('<textarea rows=15 cols=80><object data=%22http://www.youtube.com/v/'+s+'%22 type=%22application/x-shockwave-flash%22 width=%22425%22 height=%22355%22><param name=%22movie%22 value=%22http://www.youtube.com/v/'+s+'%22 /><param name=%22wmode%22 value=%22transparent%22 /></object></textarea>');d.close()}var r=h(location.href);if(r!=0)o(r);})();

使い方は、まず上のソースブックマークURLとして登録。名前は「YouTube XHTML」など適当につけてください。

次にYouTubeの動画ページでそのブックマークをクリックすると、別ウィンドウでXHTML validなYouTube埋め込みソースが表示されます。


Safariだとこんな感じ↓

f:id:ikki_j:20080220015328p:image


そのソースをコピペすればXHTML validに。

The W3C Markup Validation ServiceでチェックOK。動作確認はMacOSX 10.5 Leopard上のFireFoxとSafariで行いました。


これで楽にXHTMLなYouTube埋め込みができるはず。

2008-02-12

Rubyで楽天APIを使う

id:kajidaiさんが楽天市場非公式ウェブサービスRakuAPI*1をRubyから使うクラスを書いているが、本家版がなかったので書いてみた。


楽天商品検索APIのみ

require "rubygems"
require "rexml/document"
require "open-uri"

class RakutenItemSearch
  attr_reader :search_result

  def initialize(developer_id=nil, affiliate_id=nil)
    if developer_id
      @developer_id_query = "developerId=#{developer_id}"
    else
      puts "Developer IDをセットして下さい"
      exit(1)
    end

    @affiliate_id_query = "&affiliateId=#{affiliate_id}" if affiliate_id
    @request_url = "http://api.rakuten.co.jp/rws/1.11/rest"
  end

  def item_search(options=nil)
    # "type"としてkeyword、genreId、catalogCodeのいずれかを指定
    if ["keyword", "genreId", "catalogCode"].include?options[:type]
      options_query = "&#{options[:type]}=#{options[:query]}"
    else
      puts "keyword, genreId, catalogCodeのいずれかを\"type\"にセットして下さい"
      exit(1)
    end

    options_query += "&shopCode=#{options[:shopCode]}" if options[:shopCode]
    options_query += "&hits=#{options[:hits].to_s}" if options[:hits]
    options_query += "&page=#{options[:page].to_s}" if options[:page]
    options_query += "&minPrice=#{options[:minPrice].to_s}" if options[:minPrice]
    options_query += "&maxPrice=#{options[:maxPrice].to_s}" if options[:maxPrice]
    # 0:wide 1:narrow default:1
    options_query += "&field=#{options[:field].to_s}" if options[:field]
    # 0:PC 1:mobile default:0
    options_query += "&carrier=#{options[:carrier].to_s}" if options[:carrier]
    # イメージなしを含むか 0:含む 1:含まない default:0
    options_query += "&imageFlag=#{options[:imageFlag].to_s}" if options[:imageFlag]
    # orFlag 0:AND 1:OR default:0
    options_query += "&orFlag=#{options[:orFlag].to_s}" if options[:orFlag]
    options_query += "&NGKeyword=#{options[:NGKeyword]}" if options[:NGKeyword]
    options_query += "&genreInformationFlag=#{options[:genreInformationFlag]}" if options[:genreInformationFlag]
    # sorting type
    if options[:sort]
      if ["+affiliateRate","-affiliateRate","+reviewCount","-reviewCount",
        "+itemPrice","-itemPrice","+updateTimestamp","-updateTimestamp","random"].include?options[:sort]
        options_query += "&sort=#{options[:sort]}"
      else
        puts "ソート方式が不正"
        exit(1)
      end
    end

    options_query_encoded = URI.encode(options_query)
    @search_request = "#{@request_url}?#{@developer_id_query}#{@affiliate_id_query}#{options_query_encoded}
    &operation=ItemSearch&version=2007-10-25".gsub!("\n","").gsub!(" ","")

    xml_result = open(@search_request)
    @search_result = xml_to_array(xml_result)
    return @search_result
  end

  def xml_to_array(xml_result)
    doc = REXML::Document.new xml_result
    doc.elements.each("Response/header:Header/Status") do |status|
      unless status.text == "Success"
        puts "取得失敗"
        exit(1)
      end
    end

    result = Hash.new
    doc.elements.each("Response/Body/*") do |ele|
      result[:count] = ele.elements["count"].text.to_i
      result[:page] = ele.elements["page"].text.to_i
      result[:first] = ele.elements["first"].text.to_i
      result[:last] = ele.elements["last"].text.to_i
      result[:hits] = ele.elements["hits"].text.to_i
      result[:carrier] = ele.elements["carrier"].text.to_i
      result[:pageCount] = ele.elements["pageCount"].text.to_i

      result[:item] = Array.new
      ele.elements.each("Items/Item") do |item|
        result[:item].push({:itemName => item.elements["itemName"].text,
          :itemCode => item.elements["itemCode"].text,
          :itemPrice => item.elements["itemPrice"].text.to_i,
          :itemCaption => item.elements["itemCaption"].text,
          :itemUrl => item.elements["itemUrl"].text,
          :affiliateUrl => item.elements["affiliateUrl"].text,
          :imageFlag => item.elements["imageFlag"].text.to_i,
          :smallImageUrl => item.elements["smallImageUrl"].text,
          :mediumImageUrl => item.elements["mediumImageUrl"].text,
          :availability => item.elements["availability"].text,
          :taxFlag => item.elements["taxFlag"].text,
          :postageFlag => item.elements["postageFlag"].text.to_i,
          :creditCardFlag => item.elements["creditCardFlag"].text,
          :shopOfTheYearFlag => item.elements["shopOfTheYearFlag"].text,
          :affiliateRate => item.elements["affiliateRate"].text,
          :startTime => item.elements["startTime"].text,
          :endTime => item.elements["endTime"].text,
          :reviewCount => item.elements["reviewCount"].text,
          :reviewAverage => item.elements["reviewAverage"].text,
          :shopName => item.elements["shopName"].text,
          :shopCode => item.elements["shopCode"].text,
          :shopUrl => item.elements["shopUrl"].text,
          :genreId => item.elements["genreId"].text
          })
      end
    end
    return result
  end
end

使う

search = RakutenItemSearch.new("DEVID","AFFID")
options = {
  :type => "keyword",
  :query => "激安",
  :hits => 10,
  :sort => "-affiliateRate",
  :carrier => 1,
  :imageFlag => 1,
}

result = search.item_search(options)
result[:item].each{|item|puts item[:itemName]}

こんな感じで使う。


必須項目のみinitialize時に渡すとか、いろいろと手直ししたいけどとりあえずはこんな感じで。

2008-02-10

英語と日本語の都道府県名リスト

http://en.wikipedia.org/wiki/Prefectures_of_Japan

のリストから適当に置換して作成した。

アルファベット順

Aichi,愛知県
Akita,秋田県
Aomori,青森県
Chiba,千葉県
Ehime,愛媛県
Fukui,福井県
Fukuoka,福岡県
Fukushima,福島県
Gifu,岐阜県
Gunma,群馬県
Hiroshima,広島県
HokkaidoHokkaido,北海道
Hyogo,兵庫県
Ibaraki,茨城県
Ishikawa,石川県
Iwate,岩手県
Kagawa,香川県
Kagoshima,鹿児島県
Kanagawa,神奈川県
Kochi,高知県
Kumamoto,熊本県
Kyoto,京都府
Mie,三重県
Miyagi,宮城県
Miyazaki,宮崎県
Nagano,長野県
Nagasaki,長崎県
Nara,奈良県
Niigata,新潟県
Oita,大分県
Okayama,岡山県
Okinawa,沖縄県
Osaka,大阪府
Saga,佐賀県
Saitama,埼玉県
Shiga,滋賀県
Shimane,島根県
Shizuoka,静岡県
Tochigi,栃木県
Tokushima,徳島県
TokyoTokyo,東京都
Tottori,鳥取県
Toyama,富山県
Wakayama,和歌山県
Yamagata,山形県
Yamaguchi,山口県
Yamanashi,山梨県