‘Programming’ カテゴリーのアーカイブ
Ubiquityを使って英単語を調べる – smart.fm (iknow)経由
以前、ubiquityを使って英単語を調べるというエントリを書きましたが、mozilla labの開発スピードに負けて使えなくなっていた事を発見。新しいUbiquityのapiにアップデートしてみました。
ついでに、フォントの色も変えたら少し見やすくなった気がします。
Ubiquityのコマンドエディターに”共有”というのがあったので、クリックするとGitHubのGist(コード共有サービス)にアップロードされました。多分Firefoxの人なら http://gist.github.com/170912 に行くとインストールできると思います。楽ちんでいいですね
UbiquityのAPIについては、 Parser 2 API Conversion Tutorial に解説があるので、それに従って変更しました。関連があったのは、CmdUtilsの使い方で下記の二点。
- 2行目 – コマンドの名前の指定(以前はnameというキーに対応する文字列だったが、現在はnamesというキー対応する文字列の配列に変更された。つまりコマンド名が複数持てる。またコマンドの名前に空白が入れれるようになった。)
- 9行目,その他 – previewおよびexecuteの引数の指定(今まではtakesやmodifiersだったが、argumentsというキーで指定する。
2番目の変更はちょっとむずかしいですが、引数と動詞(コマンド)の関係を指定するSemantic Roleというのが導入されたようです。たとえば”A地点からB地点まで〜を移動させる”というようなコマンドでは、”移動させる”がコマンド(動詞) で、”〜を”は直接目的語です。ただ、この文には”A地点から”や”B地点まで”という修飾語もあり、それらがコマンドの引数として渡される場合もある訳 です。なので、Parser 2では引数が動詞に対して、どのような役割を果たすかを示すために、roleというパラメーターをargumentsに指定し、goal(目的地)や source(出発点)など引数として渡す値とコマンドの関係性を指定できるらしいです。言語間でのこうした関係性の表現の違い(日本語は”〜から”とい う後置詞、英語の場合は”from”という前置詞)を吸収するためにsemantic roleを導入しているようです。
このコマンドは引数に動詞(コマンド)の目的語(つまり検索する文字列)しかとらないので、roleは そのまま(direct) objectです。
-
CmdUtils.CreateCommand({
-
names: [‘iknow search’],
-
icon: "http://example.com/example.png",
-
homepage: "http://bitsized.wordpress.com/",
-
author: { name: "Taku Okawa", email: "xxxxx@gmail.com"},
-
license: "GPL",
-
description: "search words or pharase in iknow",
-
help: "iknow",
-
arguments: [{role: "object",nountype: noun_arb_text}],
-
preview: function( pblock, arguments ) {
-
-
var baseUrl = "http://api.iknow.co.jp/items/matching/${word}.${format}";
-
var tempUrl = {"word":arguments.object.text,"format":"json"}
-
var params = {include_sentences:"true"};
-
pblock.innerHTML = "requesting … " + CmdUtils.renderTemplate(baseUrl,tempUrl) + "<br/>";
-
-
jQuery.getJSON(CmdUtils.renderTemplate(baseUrl,tempUrl),params,function(resp){
-
pblock.innerHTML = "";
-
jQuery.each(resp,function(i){
-
pblock.innerHTML += "<span style=’color:#ff0000′>" + this.responses[0].text + "</span>" + "<br/>";
-
pblock.innerHTML += "[例文] " + "<span style=’color:#0066ff’>" + this.sentences[0].text + "</span>" + "<br/>";
-
pblock.innerHTML += "[和訳] " + this.sentences[0].translations[0].text + "<br/>";
-
});
-
});
-
-
},
-
execute: function(arguments) {
-
var baseUrl ="http://www.iknow.co.jp/items/search?keyword=${QUERY}";
-
var tempUrl = {"QUERY":arguments.object.text};
-
var urlString = CmdUtils.renderTemplate(baseUrl, tempUrl);
-
Utils.openUrlInBrowser(urlString);
-
}
-
});
Ubiquityを使って英単語を調べる
FireFoxのプラグインでUbiquityというのがあります。他のWebサイトの機能をコマンドとして登録して使用できる、User MashUpを可能にするFirefox上の環境です。将来的にはFirefoxのURLバーに実装されるかも知れません(URLをWebのドキュメントがある場所であると考えるのではなく、Web上のリソースに対するリクエストような考えると割と自然な進歩?)。
ブラウザの新境地? Ubiquityが変える衝撃のブラウザ体験 (1/2):
http://www.itmedia.co.jp/enterprise/articles/0808/31/news003.html
まあ、そういうわけでどういうものかちょっと気になって見てみて、最近APIが公開されたiknowという英語学習SNSの単語検索を呼び出すコマンドを作成してみました。
コード
CmdUtils.CreateCommand({
name: "iknow_search",
icon: "http://example.com/example.png",
homepage: "http://example.com/",
author: { name: "xxxx", email: "xxxxx@gmail.com"},
license: "GPL",
description: "search words or pharase in iknow",
help: "iknow",
takes: {"input": noun_arb_text},
preview: function( pblock, input ) {
var baseUrl = "http://api.iknow.co.jp/items/matching/${word}.${format}";
var tempUrl = {"word":input.text,"format":"json"}
var params = {include_sentences:"true"};
pblock.innerHTML = "";
jQuery.getJSON(CmdUtils.renderTemplate(baseUrl,tempUrl),params,function(resp){
jQuery.each(resp,function(i){
pblock.innerHTML += this.responses[0].text + "<br/>";
pblock.innerHTML += this.sentences[0].text + "<br/>";
pblock.innerHTML += this.sentences[0].translations[0].text + "<br/>";
});
});
},
execute: function(input) {
var baseUrl ="http://www.iknow.co.jp/items/search?keyword=${QUERY}";
var tempUrl = {"QUERY":input.text};
var urlString = CmdUtils.renderTemplate(baseUrl, tempUrl);
Utils.openUrlInBrowser(urlString);
}
});
Ubiquityコマンドの作成
Ubiquityコマンド作成の情報は、現状下記のリンクかソースを見るしかないくらい少なく、しかも上記のコマンドはまだプレビューで訳を表示しEnterキーでiKnowのサイトで該当のアイテム検索結果を表示するのみですが、行数の割には用を足しているかと思います。Ubiquity導入後、Command Editorを使用して上記のコードを貼付ければ使用できます。
Labs/Ubiquity/Ubiquity 0.1 Author Tutorial
https://wiki.mozilla.org/Labs/Ubiquity/Ubiquity_0.1_Author_Tutorial
上のチュートリアルに載っている事ですが簡単に作り方を説明したいと思います。
CmdUtils.CreateCommand({
name: "hello-world",
execute: function() {
displayMessage( "Hello, World!" );
}
})
ubiquityコマンドは、cmd_<コマンド名>というfunctionがあればそれを参照するのですが、普通はCmdUtils.CreateCommand()というユーティリティ関数を使用して作成します。上記のコードはその最も単純な例です。
CreateCommandに渡すオブジェクトのnameとexecuteというプロパティに、それぞれコマンド名の文字列と実行する関数を指定します。execute(コマンドの実行)はUbiquityのコンソールにコマンド名を入力しEnterを押した時点で実行されます。displayMessage()を実行すると、MacならGrowl,WindowsならUbiquityのコマンドの下に引数に与えた文字列が表示されます。
CmdUtilsにはコマンド作成以外にも、ユーザーがブラウザで選択中の箇所にテキストやHTMLを挿入(setSelection),IPから位置情報を取得(getGeoLocation),文字列のテンプレート処理(renderTemplate)などコマンド作成を楽にする関数が用意されており、これまたドキュメントは少ないのですが、ソースはこちらで見る事ができます。
プレビューの表示
Ubiquityではユーザーの入力に応じて出力されるプレビューウインドウがあり、こちらはCreateCommandに渡すオブジェクトのpreviewプロパティに、HTML文字列か関数を指定する事で実現できます。下記は冒頭のコマンドでのpreview部分です。
preview: function( pblock, input ) { var baseUrl = "http://api.iknow.co.jp/items/matching/${word}.${format}"; var tempUrl = {"word":input.text,"format":"json"} var params = {include_sentences:"true"}; pblock.innerHTML = ""; jQuery.getJSON(CmdUtils.renderTemplate(baseUrl,tempUrl),params,function(resp){ jQuery.each(resp,function(i){ pblock.innerHTML += this.responses[0].text + "<br/>"; pblock.innerHTML += this.sentences[0].text + "<br/>"; pblock.innerHTML += this.sentences[0].translations[0].text + "<br/>"; }); }); },.....
previewは第一引数にpreviewエリアに表示するDOM要素を、第二引数にユーザーから渡されるコマンドの引数をとっています。コマンドの引数はtakeプロパティで、どのnoun_typeで取得するか指定できます。
takes: {"input": noun_arb_text},
引数データの扱い
noun_typeは引数の制約や、コマンドの補完機能(例えば日付データが入力されたら、日付データを引数にとるコマンドをUbiquityがサジェストする)に使用され、下記のようなnoun_typeがあります。また、CmdUtilsを使用してカスタムのnoun_typeを作成する事ができます。
- noun_type_arb_text
- noun_type_date
- noun_type_language
- noun_type_people
- noun_type_place
- noun_type_tab
noun_typeのソースは下記で確認する事ができます
nountypes.js
一方、コマンドの引数としてpreviewやexecute(の第二引数)に渡されるオブジェクトは、下記のようなプロパティを持ちます。
- inputObject.text // 文字列
- inputObject.html //タグを含む整形されたHTML
- inputObject.data // 文字列以外のnoun_typeのデータ
- inputObject.summary // 長い文字列の要約版
iknow-searchのpreviewで行っているのは、コマンドの引数から(テンプレート機能を使用して)URL文字列を組み立て、JSONでリクエストを取得、preview用のDOMに結果を反映するという一連の処理ですが、uqibuityではjQueryが使用できるため簡単に実装できます。
また同様に、コマンド入力後Enterを押した時に実行されるexecuteでは、Utils.openUrlInBrowser()を使用してブラウザで該当のURL(検索結果ページ)を開くようになっています。
まだまだ発展途上(というかできたばかり)のコンセプトですが、Webの機能をお手軽にコマンドにできるのはこれから重宝しそうです。
追記:Ubiquity のアップデートに合わせて、コードも少し書き換えました
Processingでグラフ
前から少し気になっていたProcessingという言語について、ちょうど本屋におもしろそうなオライリー本が出ていたので買ってみました。
ビジュアライジング・データ ―Processingによる情報視覚化手法
簡単な例としてグラフの作成があったので、自分でも日本の人口統計を使ってグラフを書いてみました。

Population growth in Japan
-
FloatTable data;
-
PFont plotFont;
-
float plotX1,plotY1;
-
float plotX2,plotY2;
-
float labelX,labelY;
-
float dataAreaWidth;
-
float dataAreaHeight;
-
final float dataOffsetY = 30;
-
float volumnInterval = 10000;
-
float dataCeil;
-
int []years;
-
int yearMin;
-
int yearMax;
-
int yearInterval;
-
float dataMin;
-
float dataMax;
-
void setup(){
-
plotFont = createFont(“SansSerif”,20);
-
textFont(plotFont);
- //load csv file
-
data = new FloatTable(“ppl1920-1990-grs-t.csv”);
-
years = int(data.getRowNames());
-
yearMin = years[0];
-
yearMax = years[years.length -1];
-
yearInterval = 10;
-
dataMin = data.getColumnMin(0);
-
dataMax = data.getColumnMax(0);
-
println(ceil(dataMax/volumnInterval));
-
dataCeil = ceil(dataMax/volumnInterval) * volumnInterval;
-
size(600,400);
-
smooth();
-
plotX1 = 160;
-
plotY1 = 80;
-
plotX2 = width - plotX1/2;
-
plotY2 = height - plotY1;
-
labelX = plotX1 -110;
-
labelY = plotY2 +40;
-
dataAreaWidth = plotX2 - plotX1;
-
dataAreaHeight = plotY2- plotY1;
-
}
-
-
void draw(){
-
background(022); // (1)background color
-
fill(044);
-
rectMode(CORNERS);
-
noStroke();
-
rect(plotX1,plotY1,plotX2,plotY2);
-
strokeWeight(0.4);
-
stroke(254);
-
drawDataArea();
-
stroke(112);
-
strokeWeight(0.1);
-
drawLabels();
-
}
-
void drawLabels(){
-
drawTitleLabel();
-
drawAxisLabels();
-
drawYearLabels();
-
drawYearGrid();
-
drawVolumnLabels();
-
}
-
-
void drawTitleLabel( ) {
-
fill(112);
-
textSize(15);
-
textAlign(CENTER,CENTER);
-
text(“Population growth in Japan\n 1920 to 2000″,(plotX1+plotX2)/2,plotY1 - 40);
-
}
-
-
void drawAxisLabels( ) {
-
fill(112);
-
textSize(13);
-
textLeading(15);
-
textAlign(CENTER, CENTER);
-
text(“Total \npopulation\n(Thousand)”, labelX, (plotY1+plotY2)/2);
-
textAlign(CENTER);
-
text(“Year”, (plotX1+plotX2)/2, labelY);
-
}
-
void drawYearLabels(){
-
fill(112);
-
textSize(12);
-
textAlign(LEFT);
-
int rowCount = data.getRowCount();
-
for(int i=0;i < rowCount;i++){
-
if(years[i] % yearInterval ==0){
-
String yearText = data.getRowName(i);
-
float x = map(int(yearText),yearMin,yearMax,plotX1,plotX2);
-
text(yearText,x,plotY2+12);
-
}
-
}
-
}
-
void drawYearGrid(){
-
int rowCount = data.getRowCount();
-
for(int i=0;i < rowCount;i++){
-
if(years[i] % yearInterval ==0){
-
float x = float(data.getRowName(i));
-
x = map(x,yearMin,yearMax,plotX1,plotX2);
-
line(x,plotY2,x,plotY1);
-
}
-
}
-
}
-
void drawVolumnLabels(){
-
fill(112);
-
textSize(10);
-
textAlign(RIGHT);
-
float x = plotX1;
-
float y;
-
for(float v = floor(dataMin/volumnInterval)*volumnInterval;v <= dataCeil;v+= volumnInterval){
-
y = map(v,floor(dataMin/volumnInterval)*volumnInterval,dataCeil,plotY2,plotY1);
-
line(x-10,y,x,y);
-
//println(v);
-
text(floor(v),x-20,y+4);
-
}
-
}
-
void drawDataArea(){
-
beginShape();
-
int rowCount = data.getRowCount();
-
for(int i=0;i < rowCount;i++){
-
float value = data.getFloat(i,0);
-
float x = map(years[i],yearMin,yearMax,plotX1,plotX2);
-
float y = map(value,floor(dataMin/volumnInterval)*volumnInterval,dataCeil,plotY2,plotY1);
-
vertex(x,y);
-
}
-
endShape();
-
}
-
void keyPressed( ) {
-
saveFrame(“japan_pl_##.png”);
-
}
processing実行後に何かキーを押すと、連番で”japan_pl_01.png”という画像が保存されます。FloatTableというクラスは本のサンプルコードに含まれているものですが、http://benfry.com/writing/archives/3 からダウンロードできます。人口のCSVは統計局からダウンロードしたものをタブ区切りのcsvにしてます。
こんな感じで
-
Year Total
-
1920 55963
-
1921 56666
-
1922 57390
-
1923 58119
-
1924 58876
-
1925 59737
-
1926 60740.9
-
1927 61659.3
-
1928 62595.3
-
1929 63460.6
-
1930 64450
-
1931 65457
-
1932 66434
-
1933 67432
-
1934 68309
-
1935 69254
-
1936 70114
-
1937 70630
-
1938 71013
-
1939 71380
-
1940 71933
-
1941 71933
-
1942 71933
-
1943 71933
-
1944 73064
-
1945 71998
-
1946 73114
-
1947 78101
-
1948 80002
-
1949 81773
-
1950 83200
-
1951 84573
-
1952 85852
-
1953 87033
-
1954 88293
-
1955 89276
-
1956 90259
-
1957 91088
-
1958 92010
-
1959 92973
-
1960 93419
-
1961 94285
-
1962 95178
-
1963 96156
-
1964 97186
-
1965 98275
-
1966 99054
-
1967 100243
-
1968 101408
-
1969 102648
-
1970 103720
-
1971 105014
-
1972 107332
-
1973 108710
-
1974 110049
-
1975 111940
-
1976 110089
-
1977 114154
-
1978 115174
-
1979 116133
-
1980 117060
-
1981 117884
-
1982 118693
-
1983 119483
-
1984 120235
-
1985 121049
-
1986 121672
-
1987 122264
-
1988 122783
-
1989 123255
-
1990 123611
-
1991 124043
-
1992 124452
-
1993 124764
-
1994 125034
-
1995 125570
-
1996 125864
-
1997 126166
-
1998 126486
-
1999 126686
-
2000 126926
Processingを一言で説明しようとすると、Javaの描写機能を使用しやすいインタフェースで提供する言語環境(なのかな?)でしょうが、なんでProcessingに興味をもっていたかというと、これを使用した作品(っていうのがいいですね)に興味深いというか斬新なものが多かったからな訳です。
MusicBox: a truly powerful visualization of your music library:http://www.crunchgear.com/2008/12/15/musicbox-a-truly-powerful-visualization-of-your-music-library/
音楽のライブラリを可視化するソフト。ファイルのメタデータ(作者やジャンルなど)のみではなく、実際の音声データをスキャンしてマッピングする。
Aligning humans and mammals:http://benfry.com/infoseed/
人間とほ乳類の遺伝子配列をならべて描写した画像
Base26:http://toxi.co.uk/p5/base26/
英語の言葉同士の慣例性を表現した図。
仕事ではほとんどCRUDなWEBアプリケーションしか見ないのですが、こういうデータの重要性もさることながらどう見せるかでどれだけ印象や理解度が変わるかという事を考えるとおもしろい。色々遊んでみようと思います。
キーワードで検索した時のgoogleランキングを調べるrubyスクリプト
「SEO対策の有無をチェックするために、あるキーワードで検索して対象のWebサイトが何位くらいか調べる 」 という事をちょっと前仕事でやっていたのだが、数をこなさなければならないのと、対象のWebサイトが多かったのでバッチコマンドっぽく書いてみた
使い方
google_rank.rb [-l | --limit 検索数 ] 検索文字列
例えば、”bit sized”という文字列で30位までのURLを取得しようとすると
google_rank.rb -l 30 bit sized
とすればよい、結果は下記のようになる
google_rank.rb -l 30 bit sized
1,bitsized.wordpress.com/ 2,bitsized.wordpress.com/.../ 3,en.wikipedia.org/wiki/Drill_bit_sizes 4,www.madison.k12.wi.us/toki/teched/codrills.htm 5,www.imao.us/archives/000960.html 6,www.theoriginalbitfit.com/ 7,bitesizestandards.com/ 8,www.bitesizebonus.com/ 9,www.japaninc.com/article.php?articleID=521 10,www.crypto.rub.de/imperia/md/content/ 11,home-and-garden.become.com/ 12,www.springerlink.com/index/74HV57D1UH95PHHL.pdf 13,www.hardforum.com/showthread.php?t=967973 14,www.hydracore.com/drill_bit_sizes.htm 15,dic.yahoo.co.jp/dsearch?enc=UTF-8&p=bit& 16,atlaspen.com/search/?item=503438&pv=1 17,www.goodexperience.com/blog/archives/000633.php 18,www.wired.com/wired/archive/15.03/snackminifesto.html 19,search.luky.org/linux-kernel.2001/msg05005.html 20,www.modulaware.com/mdlt76.htm 21,www.patentstorm.us/patents/5501020-description.html 22,answers.yahoo.com/question/ 23,www.hechinger.com/hardware/tools/ 24,www.gfl-hand-tools.com/product-word/209/Bit-Sets.doc 25,bobmay.astronomy.net/misc/drillchart.htm 26,www.theoriginalbitfit.com/v4/go.gnf?s=bitfit& 27,thatgrrlca.blogspot.com/2007/ 28,www.dri.co.jp/auto/report/wf/wfmts340mb07.htm 29,www.ttora.com/forum/showthread.php?t=29091 30,docs.sun.com/app/docs/doc/
準備
HTMLのパースにhpricotというライブラリを使用しているため、あらかじめ準備しておく必要がある。”gem install hpricot”でインストールできる
ソースコード
google_rank.rb
require 'rubygems' require 'optparse' require 'hpricot' require 'open-uri' require 'cgi' # class definition class GoogleRank def initialize @str_query = "" @base_url = "http://www.google.co.jp/search?hl=ja&q=" @suffix_url = "&lr=" @srch_url = "" @srch_limit = 20 @current_number = 0 end def encode_query @str_query = CGI.escape(@str_query) end def cat_query if @current_number == 0 @srch_url = @base_url + @str_query + @suffix_url else @srch_url = @base_url + @str_query + @suffix_url + "&start=" + @current_number.to_s + "&sa=N" end end def get_rank doc = Hpricot(open(@srch_url)) # get the <div> that contains search result res = doc.search("//div[@id='res']") # <span class="a">hoge.com/target.html</a> spans = res.search("//span[@class='a']") spans.each_with_index{ |span,i| page_info = CGI.unescape(span.inner_html) #puts "page_info:" + page_info page_url = page_info.split(/ /) # trims html tags item_url = page_url[0].gsub(/<[\/]*[a-z]+[\/]*>/,"") puts (@current_number + i + 1).to_s + ","+ item_url } end def search_rank self.encode_query while @current_number < @srch_limit self.cat_query self.get_rank @current_number += 10 #puts "current_number=" + @current_number.to_s end end attr_accessor :str_query attr_accessor :srch_limit end # bat command process rank = GoogleRank.new opt = OptionParser.new opt.on('-l VAL','--limit VAL'){ |v| rank.srch_limit = v.to_i } opt.parse!(ARGV) ARGV.each {|i| if rank.str_query == "" rank.str_query = i.to_s else rank.str_query = rank.str_query + " " + i.to_s end } rank.search_rank
Podcast × 速聴 – Podcastを速聴してみる(新刊JP)
Podcast に登録している番組の数が増えてきたというのと、以前ちょっと興味を引かれた速聴なるものを試したいと思い、「じゃあ、Podcastを速聴してみよう」と企ててみました。
速聴については、簡単に言えば
「普通に話しているスピードの3-4倍以上で話を聞くと、普段の言語処理を行う際には使用されない脳の部分が活性化され、記憶力などの脳力向上に役立つ」
というものです。
どうやって、Podcastを3-4倍速で聞こうか?という部分ですが
- Podcast再生時にipodの再生速度を変更する機能を使用する
- Podcastに登録される前に、mp3の音声データを編集しておく(3-4倍速に変換しておく)
という2種類の方法が考えられると思いますが、1の方法では
- せいぜい20%くらいの速度変換しかできない
- オーディオブックしか再生速度を変えられない
という事で、自宅にある余っているLinux+ Apacheを使用して自分用のフィードに変換(mp3 + rssを編集)して、それをPodcastに登録する事にしました(下図)
最近個人的によく聞く、新刊JPで配信している新刊のダイジェスト(火木土更新)での例。
- rssファイルを新刊JPのサイトから取得
- 1のファイルをparseして、各エントリのmp3ファイルをダウンロードする。
- ダウンロードしたmp3を3-4倍速に変換。
- 変換済みのmp3ファイルのパスを、1のrssファイルでの各エントリの ファイルとして書き換える
- 変換済みのmp3ファイル+編集済みのrssファイルをapacheのディレクトリに配置する。
- iTuneから、5のurlを指定してpodcastを登録する
Linuxマシンの方で必要なものは下記ですが、sox以外はデフォルトで使用できるのではないでしょうか?
- ruby
- 本体
- ライブラリ
- rexml
- open-uri
- Linuxコマンド
- wget
- sox (mp3編集ツール)
処理としては、上記のツールをつなぎ合わせているだけのようなものなので、
シェルでもできとおもいますが、勉強も兼ねてRubyで書いてみました。
あとは、更新日にあわせてCronに登録しておけばよいでしょう
#!/usr/bin/ruby require 'open-uri' require 'rexml/document' # global variables $feed_org = "http://www.sinkan.jp/rss.xml" #新刊JPダイジェストのRSS $data_dir = "/var/www/xxx/xxx/" #Linuxのhttpdディレクトリ $data_dir_url = "htttp://hostname/xxx/xxx/" #↑のurl $username = "username" #新刊JPのユーザー名(メールアドレス) $password = "password" #パスワード class Feed def initialize(feed_path) @feed_path = feed_path @rss_file_name = @feed_path.split(/\//)[-1] @feed_local = $data_dir + @rss_file_name doc = REXML::Document.new(open(@feed_path).read) @rss_root = doc.root @feed_items = Array.new @rss_root.elements.to_a("/rss/channel/item").each { |i| @feed_items.push( FeedItem.new(i)) } end def comp_feed_entry(org_idx,stretch_rate) @feed_items[org_idx].stretch_rate = stretch_rate @feed_items[org_idx].download_mp3($username,$password) @feed_items[org_idx].time_stretch end def comp_all(stretch_rate) for i in 0..@feed_items.size - 1 comp_feed_entry(i,stretch_rate) end @rss_root.elements["/rss/channel/title"].text = "[" + stretch_rate.to_s + " ]" + @rss_root.elements["/rss/channel/title"].text + "_" end def save_feed local_doc = File.open(@feed_local,"w") @rss_root.write local_doc end end class FeedItem def initialize(rss_node,stretch_rate = "") @rss_node = rss_node @stretch_rate = stretch_rate # rss node mapping @title = @rss_node.elements['title'] @mp3_path = @rss_node.elements['enclosure'].attributes['url'] @mp3_name = @mp3_path.split(/\//)[-1] end def time_stretch puts @stretch_rate stretched_mp3_name = @mp3_name.sub(/(.+?)\.(.+)/) {|m| $1 + "_" + @stretch_ rate.to_s + "." + $2 } stretched_mp3_path = $data_dir + stretched_mp3_name command_line ="sox " + @mp3_path + " " +stretched_mp3_path + " stretch " + @stretch_rate.to_s puts command_line system(command_line) @title.text = "[" + @stretch_rate.to_s + "]" + @title.text @rss_node.elements['enclosure'].attributes['url'] = $data_dir_url + stretche d_mp3_name end def download_mp3(un = "",pw = "") if File.exist?($data_dir + @mp3_name) then File.unlink($data_dir + @mp3_name) end if un != "" || pw != "" then command_line = "wget -P " + $data_dir + " --user=" + un + " --password=" + pw + " " + @mp3_path else command_line = "wget -P " + $data_dir + @mp3_path end system(command_line) @mp3_path = $data_dir + @mp3_name end attr_accessor :rss_node attr_accessor :title attr_accessor :stretch_rate end fd = Feed.new($feed_org) fd.comp_all(0.3) fd.save_feed




