<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
		xmlns:xhtml="http://www.w3.org/1999/xhtml"
>

<channel>
	<title>クレコ &#187; Softalk</title>
	<atom:link href="http://creco.net/tag/softalk/feed/" rel="self" type="application/rss+xml" />
	<link>http://creco.net</link>
	<description>East or west, home is best.</description>
	<lastBuildDate>Fri, 27 Nov 2009 13:26:56 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://creco.net/tag/softalk/feed/" />
		<item>
		<title>TwitterをSoftalkのゆっくりボイスでしゃべらせる 2</title>
		<link>http://creco.net/2009/07/17/softalk_twitter_to_bring_out_slowly_in_a_voice_of/</link>
		<comments>http://creco.net/2009/07/17/softalk_twitter_to_bring_out_slowly_in_a_voice_of/#comments</comments>
		<pubDate>Thu, 16 Jul 2009 22:39:31 +0000</pubDate>
		<dc:creator>inagaki</dc:creator>
				<category><![CDATA[作ってみた]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Softalk]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://creco.net/2009/07/17/softalk_twitter_to_bring_out_slowly_in_a_voice_of/</guid>
		<description><![CDATA[TwitterをSoftalkのゆっくりボイスでしゃべらせる &#124; クレコ
では、python-twitterというライブラリを使っていたわけですが、そもそもタイムライン、メンションを読むだけなら、そこまで高機能なのはいら [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://creco.net/2009/04/13/softalk_tweet_timeline_of_twitter/">TwitterをSoftalkのゆっくりボイスでしゃべらせる | クレコ</a></p>
<p>では、python-twitterというライブラリを使っていたわけですが、そもそもタイムライン、メンションを読むだけなら、そこまで高機能なのはいらない！それに、導入するのが面倒！ってわけで、簡単お気軽に導入できるようにしてみた。</p>
<p> <span id="more-714"></span><br />
<h3>ソース</h3>
<pre class="csharpcode"># -*- coding: utf-8 -*-

import feedparser, os, nkf, re, time

# config
userName = <span class="str">&quot;USERNAME&quot;</span>
passWord = <span class="str">&quot;PASSWORD&quot;</span>
softalkPath = <span class="str">&quot;C:\softalk\softalk.exe&quot;</span>
softalkSpeed = <span class="str">&quot;120&quot;</span>
lastSinceId = 1
lastGetTime = 0

# convert <span class="kwrd">string</span>
def convertString(<span class="kwrd">string</span>):
    # remove HTML entity
    <span class="kwrd">string</span> = re.sub(<span class="str">'&amp;.+;'</span>, <span class="str">' '</span>, <span class="kwrd">string</span>)
    # remove URL
    <span class="kwrd">string</span> = re.sub(<span class="str">'(https?|ftp)(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&amp;=+\$,%#]+)'</span>, u<span class="str">'ウェブ'</span>, <span class="kwrd">string</span>)

    # remove quote
    <span class="kwrd">string</span> = re.sub(<span class="str">'&quot;'</span>, <span class="str">' '</span>, <span class="kwrd">string</span>)
    <span class="kwrd">string</span> = re.sub(<span class="str">&quot;'&quot;</span>, <span class="str">' '</span>, <span class="kwrd">string</span>)
    <span class="kwrd">string</span> = re.sub(<span class="str">'\/'</span>, <span class="str">' '</span>, <span class="kwrd">string</span>)

    # remove my username
    <span class="kwrd">string</span> = re.sub(<span class="str">'@'</span> + userName , u<span class="str">'あなた'</span>, <span class="kwrd">string</span>)

    # convert unicode to sjis <span class="kwrd">using</span> nkf module
    <span class="kwrd">string</span> = nkf.nkf(<span class="str">&quot;-sX&quot;</span>, <span class="kwrd">string</span>.encode(<span class="str">&quot;utf8&quot;</span>))

    <span class="kwrd">return</span> <span class="kwrd">string</span>

# get twitter timeline
def getTimeline():
    global lastSinceId

    rss = feedparser.parse(<span class="str">'https://'</span> + userName + <span class="str">':'</span> + passWord + <span class="str">'@twitter.com/statuses/mentions.rss?since_id='</span> + str(lastSinceId) )
#    rss = feedparser.parse(<span class="str">'https://'</span> + userName + <span class="str">':'</span> + passWord + <span class="str">'@twitter.com/statuses/friends_timeline.rss?since_id='</span> + str(lastSinceId) )

    <span class="kwrd">if</span> len(rss.entries) &gt; 0:
        lastSinceId = re.search(<span class="str">'\d+$'</span>, rss.entries[0].guid).group()

    reversed(rss.entries)

    <span class="kwrd">for</span> i <span class="kwrd">in</span> rss.entries[::-1]:
        print <span class="str">&quot;%s&quot;</span> % (convertString(i.title))
        os.system(<span class="str">'&quot;'</span> + softalkPath + <span class="str">'&quot; /V:60 /S:'</span>+softalkSpeed+<span class="str">' /T:3 /W:'</span> + convertString(i.title))

<span class="kwrd">while</span> True:
    # time span of get timeline
    <span class="kwrd">if</span> time.time() &gt; lastGetTime + 60:
        lastGetTime = time.time()
        getTimeline()
    <span class="kwrd">else</span>:
        time.sleep(5)</pre>
<h3>解説</h3>
<h4>導入するもの<br />
<style type="text/css">
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</h4>
<ul>
<li>Python実行環境</li>
<li><a href="http://www.feedparser.org/">feedparser</a></li>
<li>nkf</li>
<li>SofTalk ver0151（複数起動ができるバージョン）</li>
</ul>
<h4>やっていること</h4>
<p>今回は、feedparser使ってRSSで取得をしています。since_idで最新のものだけを取得しますが、20件以上あった場合のページ処理はしていませんので注意！20件以上あると読み上げが追いつかなくなりそうですけど。</p>
<p>あとは取得した本文をフィルタかけて読み上げるだけ。前はURLとかも全部読ませていたけど、URLなんて読み上げられたところでどうしようもないので、省略して「ウェブ」とだけ読み上げるようにしました。</p>
<p>これも、適当にカスタマイズして使ってもらえればうれしいです。ではでは！</p>
]]></content:encoded>
			<wfw:commentRss>http://creco.net/2009/07/17/softalk_twitter_to_bring_out_slowly_in_a_voice_of/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://creco.net/2009/07/17/softalk_twitter_to_bring_out_slowly_in_a_voice_of/" />
	</item>
		<item>
		<title>TwitterをSoftalkのゆっくりボイスでしゃべらせる</title>
		<link>http://creco.net/2009/04/13/softalk_tweet_timeline_of_twitter/</link>
		<comments>http://creco.net/2009/04/13/softalk_tweet_timeline_of_twitter/#comments</comments>
		<pubDate>Sun, 12 Apr 2009 23:09:02 +0000</pubDate>
		<dc:creator>inagaki</dc:creator>
				<category><![CDATA[作ってみた]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Softalk]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://creco.net/2009/04/13/softalk_tweet_timeline_of_twitter/</guid>
		<description><![CDATA[




（完成動画。時々でてる音は録画用に使ったMacの音です、紛らわしくてごめん。）
2chのスレやしたらば、カキコなどの掲示板をSoftalkで読ませるフロントエンドはあるんだけど、Twitterのタイムラインを読 [...]]]></description>
			<content:encoded><![CDATA[<div id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:4dbd3db4-dda8-47ba-af4a-e900c0262666" class="wlWriterEditableSmartContent" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px">
<div id="8ef7f156-15c7-477a-bdeb-090127dbb58f" style="margin: 0px; padding: 0px; display: inline;">
<div><a href="http://www.youtube.com/watch?v=XA-KpNdgjCY&amp;hl=ja&amp;fs=1&amp;rel=0" target="_new"><img style="border-style: none" src="http://creco.net/wp-content/uploads/video814103ce00161.jpg" alt="" /></a></div>
</div>
</div>
<p>（完成動画。時々でてる音は録画用に使ったMacの音です、紛らわしくてごめん。）</p>
<p>2chのスレやしたらば、カキコなどの掲示板を<a href="http://cncc.hp.infoseek.co.jp/">Softalk</a>で読ませるフロントエンドはあるんだけど、Twitterのタイムラインを読ませるっていうのは見つからなかったので作ってみた。</p>
<p>TwitterのAPIを読むだけなので、スクラッチで書いてもそんなに難しいものではないんだけど、勉強がてらPythonのpython-twitterというライブラリを使ってみる。</p>
<h5>追記：新しくエントリーを書きました</h5>
<p><a href="../2009/07/17/softalk_twitter_to_bring_out_slowly_in_a_voice_of/">TwitterをSoftalkのゆっくりボイスでしゃべらせる  2 | クレコ</a></p>
<p><span id="more-350"></span></p>
<h4>python-twitterの導入</h4>
<p>実はこれがくそめんどいｗ</p>
<p><a href="http://d.hatena.ne.jp/ama-ch/20080514/1210757894">python-twitterまとめ ～導入まで &#8211; テックノート＠ama-ch</a><br />
を参考にして導入する。</p>
<p>simplejsonは、WindowsでCのコンパイラ環境が必要になったりする。詳しくないので、書いてある通りに実行していった。</p>
<h5>Python 2.6ではhashlibなんちゃらの警告がでます</h5>
<p>別にそのままつかっても問題ないけど毎回警告がでるので直し方。</p>
<p>@aoshimanさんに教えていただいた解決法、<br />
<a href="http://d.hatena.ne.jp/nakku/20090218#1234963425">2009-02-18 &#8211; nakkuの日記</a> [python]python2.6にtwitterのモジュールを入れる<br />
にpatchがあるので、twitter.pyを書き換えればいい。</p>
<p>具体的には、simplejsonモジュールを使っているところをjsonモジュール、md5モジュールを使っているところをhashlibモジュールを使うようにそれぞれ書き換える。</p>
<h4>TwitterのTLをSoftalkでしゃべらせるPythonスクリプト</h4>
<pre class="csharpcode">import twitter, os, nkf, re, time

# config
userName = <span class="str">"username"</span>
passWord = <span class="str">"password"</span>
softalkPath = <span class="str">"C:\hogehoge\softalk.exe"</span>
softalkSpeed = <span class="str">"120"</span>
lastSinceTime = 0
lastGetTime = 0

# convert <span class="kwrd">string</span>
def convertString(<span class="kwrd">string</span>):
    # remove HTML entity
    <span class="kwrd">string</span> = re.sub(<span class="str">'&amp;.+;'</span>, <span class="str">' '</span>, <span class="kwrd">string</span>)
    # remove quote
    <span class="kwrd">string</span> = re.sub(<span class="str">'"'</span>, <span class="str">' '</span>, <span class="kwrd">string</span>)
    <span class="kwrd">string</span> = re.sub(<span class="str">"'"</span>, <span class="str">' '</span>, <span class="kwrd">string</span>)

    # remove my username
    <span class="kwrd">string</span> = re.sub(<span class="str">'^@'</span> + userName + <span class="str">' '</span>, <span class="str">''</span>, <span class="kwrd">string</span>)

    # convert unicode to sjis <span class="kwrd">using</span> nkf module
    <span class="kwrd">string</span> = nkf.nkf(<span class="str">"-sX"</span>, <span class="kwrd">string</span>.encode(<span class="str">"utf8"</span>))

    <span class="kwrd">return</span> <span class="kwrd">string</span>

# get twitter timeline
def getTimeline():
    global lastSinceTime

    api = twitter.Api(userName, passWord)
    statuses = api.GetFriendsTimeline(userName)
    #statuses = api.GetUserTimeline(userName)
    #statuses = api.GetReplies()

    <span class="kwrd">for</span> i <span class="kwrd">in</span> statuses[::-1]:
        <span class="kwrd">if</span> i.created_at_in_seconds &gt; lastSinceTime:
            print <span class="str">"%s : %s"</span> % (convertString(i.user.name), convertString(i.text))
            os.system(<span class="str">'"'</span> + softalkPath + <span class="str">'" /V:60 /S:'</span>+softalkSpeed+<span class="str">' /T:1 /W:'</span> + convertString(i.user.name))

            # when find my name and change voice
            <span class="kwrd">if</span> re.search(userName, i.text):
                os.system(<span class="str">'"'</span> + softalkPath + <span class="str">'" /V:60 /S:'</span>+softalkSpeed+<span class="str">' /T:0 /W:'</span> + convertString(i.text))
            <span class="kwrd">else</span>:
                os.system(<span class="str">'"'</span> + softalkPath + <span class="str">'" /V:60 /S:'</span>+softalkSpeed+<span class="str">' /T:3 /W:'</span> + convertString(i.text))
            lastSinceTime = i.created_at_in_seconds

<span class="kwrd">while</span> True:
    # time span of get timeline
    <span class="kwrd">if</span> time.time() &gt; lastGetTime + 60:
        lastGetTime = time.time()
        getTimeline()
    <span class="kwrd">else</span>:
        time.sleep(5)</pre>
<p><!--.csharpcode, .csharpcode pre { 	font-size: small; 	color: black; 	font-family: consolas, "Courier New", courier, monospace; 	background-color: #ffffff; 	/*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt  { 	background-color: #f4f4f4; 	width: 100%; 	margin: 0em; } .csharpcode .lnum { color: #606060; } --></p>
<h5>twitterモジュール</h5>
<blockquote><p>api = twitter.Api(userName, passWord)</p>
<p>statuses = api.GetFriendsTimeline(userName)</p></blockquote>
<p>で、認証してタイムライン（ここではFriendTimeline）を取ってくる。</p>
<p>んで、そのリストは時系列昇順にしゃべらせるために、スライスを使って逆順にし、forで回してやる。</p>
<h5>osモジュール</h5>
<blockquote><p>os.system(<span class="str">&#8216;&#8221;&#8216;</span> + softalkPath + <span class="str">&#8216;&#8221; /V:60 /S:&#8217;</span>+softalkSpeed+<span class="str">&#8216; /T:1 /W:&#8217;</span> + convertString(i.user.name))</p></blockquote>
<p>外部コマンドでSoftalkを実行する。softalkPathにsoftalk.exeの位置を設定して、あとはパラメータ。つぶやきの中に自分のユーザー名があったら音声を変えたり。</p>
<p>/V:ボリューム、/S:スピード、/T:音声パターン、/W:しゃべらせたいテキスト</p>
<p>Softalkのソフトについては後述。</p>
<h5>nkfモジュール</h5>
<p><a href="http://city.plala.jp/moin/NkfPython">NkfPython – Ma2</a></p>
<p>Softalkにコマンド引数として値を渡すときに、UnicodeからS-JISへ変換してやる必要があるんだけど、この変換でencode()を使うとウムラウトとかが原因でエラー。</p>
<p>nkfを使えばいいらしいので、nkf使って変換。</p>
<blockquote><p><span class="kwrd">string</span> = nkf.nkf(<span class="str">&#8220;-sX&#8221;</span>, <span class="kwrd">string</span>.encode(<span class="str">&#8220;utf8&#8243;</span>))</p></blockquote>
<h5>reモジュール</h5>
<blockquote><p>string = re.sub(&#8216;&amp;.+;&#8217;, &#8216; &#8216;, string)</p></blockquote>
<p>HTMLエンティティをそのまま渡すと、コマンド引数が途切れたりしたので、HTMLエンティティはばっさり消しちゃうことにした。re.sub()は正規表現で置き換え。</p>
<p>同様に、先頭に自分のユーザー名が来てるようなreplyメッセージでのユーザー名とか、クォート符号も消す。</p>
<p>他にも何かエラー引き起こす文字があったら、深く考えないで消す。とても適当でごめんなさい。</p>
<h5>timeモジュール</h5>
<p>実行したら無限ループに入れてやり、前回の取得時間より1分以上経っていたら取得しに行く、それ以外なら5秒スリープしてループの先頭に戻る。</p>
<h4>利用するSoftalkのバージョン</h4>
<p>実行してみると、Softalkが実行するときにいちいちWindowがピョコンとでてきて、終了をしてあげないと次のつぶやきをしゃべってくれない。</p>
<p>なんか以前と違うなぁって不思議に思っていたんだけど、</p>
<p>ニコニコ動画のニコ生（生で配信）用のツール</p>
<p><a href="http://d.hatena.ne.jp/ExceptionError/20090318/1237359366">NicoRequest Ver.2.3.2 – ExceptionErrorMessage</a></p>
<p>NicoRequestのドキュメントを読んでみると、どうやらSoftalkの最新バージョンで挙動が変わったらしい。</p>
<p>ver0151に置き換えて実行してみたところ、ちゃんとうまくいって、一番はじめの動画のようにゆっくりボイスでしゃべってくれた。</p>
<h4>感想</h4>
<ul>
<li>声でタイムラインを読んでくれるっていうのは新鮮でおもしろいよ</li>
<li>Softalkは英語が不得意なので、無理にローマ字読みして何いってるかわからないことしばしば</li>
<li>移動体ライブ配信の読み上げに使おうとおもったけど、よく考えると60秒更新スパンくらいが負荷で限界なので、ものすっごくタイムラグ発生するかもね</li>
<li>PythonよりもNicoRequestみたいにJavaScriptで実現したほうがいいかも</li>
<li>SoftalkとそのライブラリAques TalkはWindows版でしか無償でつかえないので、環境を選ぶ</li>
</ul>
<p>つぶやきを送ると、ゆっくりボイスで変換してくれるBOTとか作ったら面白そう。</p>
]]></content:encoded>
			<wfw:commentRss>http://creco.net/2009/04/13/softalk_tweet_timeline_of_twitter/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://creco.net/2009/04/13/softalk_tweet_timeline_of_twitter/" />
	</item>
	</channel>
</rss>
