2008-04-30
Last.fmの英語版アプリケーションをダウンロードする方法
そもそも日本語版だと何が悲しいかというと、一番重要なラジオ機能がカットされている事。
Exciteとの提携時(もう撤退したみたいだけど→記事)からの名残か日本の著作権に配慮してか、とにかく聴くことができない。
英語版ダウンロードの方法はとても簡単で、ブラウザの設定をen-usにすればいいだけ。
その後、http://last.fmからダウンロード
前回は嵌ってlynxから海外のプロキシを通したりと無駄な苦労をしてしまった。
インストール時の設定は特に必要なく、英語版でも日本語のインターフェースになる。
インストール後アップデートのウィザードが勝手に立ち上がるが、ここからアップデートすると日本語版に変わってしまうので注意が必要。
2008-04-16
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
私が書いたスクリプトも適当にでっちあげたながらも使っていただいているようでなんだが申し訳ない気分です。
そうこうしている内にオフラインでキャッシュを利用できる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」というアクセスポイントに繋ぐと自動的に↓ページに飛ばされる。
右上の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で閉鎖という記事タイトルだと
で「マッシュ,アップ,コミュニティー,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があるのか疑問なので自分の調べ方が悪いだけかもしれない。
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だとこんな感じ↓
そのソースをコピペすれば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から使うクラスを書いているが、本家版がなかったので書いてみた。
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,山梨県

