株式会社ライブキャストロゴ 株式会社ライブキャスト

flashcast:フリーで働くITエンジニア集団のブログ: google翻訳APIを使ったAIRアプリを作る!(意図しない翻訳を避ける編)の続きです。

基本機能はある程度できつつあります。

ただ、翻訳するだけのアプリではなんとなく物足りないので、何か付加価値のある機能をつけたいと思います。そこで考えたのが、翻訳結果をtwitterに投稿する機能です!

まずは、仕様を決めたいと思います。

翻訳部分の仕様は、以下のようになっています。

翻訳処理を実行する前に、ユーザの簡単なアクションを待つような仕組みにしたいと思います。

  • クリップボードの値が変わったときに、WindowsのタスクトレイやMacのドックのアイコンをアニメーションさせる。
  • アニメーションしている間にアイコンがクリック(ユーザの簡単なアクション)されたことをトリガーに翻訳処理を実行する。
  • アイコンがクリックされた後は、アイコンのアニメーションを停止する。

flashcast:フリーで働くITエンジニア集団のブログ: google翻訳APIを使ったAIRアプリを作る!(意図しない翻訳を避ける編)より引用。

これに加えて、以下のような仕様を追加したいと思います。

  • 正常に翻訳結果を得られたら、一度停止したアイコンを、再度アニメーションさせる。
  • 翻訳時と同じようにアニメーションしている間に、アイコンがクリックされたことをトリガーにtwitterに翻訳結果を投稿する。
  • アイコンがクリックされた後は、アイコンのアニメーションを停止する。

まとめると、、、
クリップボードに文字列をコピーしてから、twitterに翻訳結果が投稿されるまで、合計2回してアイコンが回転します。1回目の回転中にアイコンをクリックすると翻訳され、2回目の回転中にアイコンをクリックすると、twitterに翻訳結果が投稿されることになります。

※ ただ、アイコンをクリックしないと回転は停止しないため、twitterに翻訳結果を投稿しないと、次の翻訳はできないので不便です。その点は、今後、改善していきたいと思います。

まずは、twitterのAPI仕様を調べます。

[観] Twitter API 仕様書 (勝手に日本語訳シリーズ)が非常に参考になります。有志でこういったことをしてもらえると本当に助かります。

twitterは登録制なので、APIを利用するにあたっても、当然認証が必要になります。

public_timeline の取得等一部の API を除くほとんどの API で、認証を使用する。応答に protected なユーザに関する情報が含まれる可能性のある API は認証が必須となっている。
現在、OAuth認証とBASIC認証が使用可能。

Twitter API 仕様書 第二十版 (2009年4月16日版) より引用(2009/12/8時点の最新版です)。

どうやら、OAuth認証とBASIC認証をサポートしているようです。
とりあえずBASIC認証を使うことにします。

それから、つぶやきを投稿するAPIはupdateというもののようです。

update
自分のステータスを更新(update)する。引数 status は必須。
この API は必ず POST を使って発行すること。update が成功した場合は、format で指定した形式で応答が返る

URL: http://twitter.com/statuses/update.format
(format は xml, json のうちのいずれかを指定)

引数:
status=ステータス (必須)
ステータス(発言、投稿内容)を指定する。必ず URL エンコードすること。
ステータスは 160文字以内におさめること。ただし、140文字を超えた部分は必ずしも表示される保証はない。

in_reply_to_status_id (オプション)
返信(reply)対象のステータスIDを指定する。どのステータスに対する返信か明示するのに使用する
存在しない、あるいはアクセス制限のかかっているステータスIDを指定した場合は無視される

source=クライアント名 (オプション)
ステータスの投稿に使用しているクライアント名を指定する。「クライアント名」をWebフォームから申請し、承認を得ることで、Twitter の Webページ上に“from クライアント名”付きで発言が掲載されるようになる。
OAuth 認証による API 実行時は、本引数は無視される(OAuth アプリケーション登録時のアプリケーション名、URLが適用される)。
なお、本引数は公式のAPI仕様書には掲載されていない。

メソッド: POST
API制限: 適用対象外

訳者による注記:
2007年4月はじめごろまでは GET でも構わなかった。現在は、GET は使えなくなっている

同じくTwitter API 仕様書 第二十版 (2009年4月16日版) より引用。

なるほどです。

早速実装していきたいと思います。

ActionScriptでBASIC認証するにはどうするんだろう?
調べていたら、、、すぐに見つかりました。
ID、パスワードをBase64エンコードしたものを、HTTPヘッダーのAuthorizationフィールドに設定してあげればいいようです。

某開発者の独り言: AdobeAIRでBasic認証をする
こちらを参考に実装してみました。

package
{
	import com.adobe.serialization.json.JSON;

	import flash.net.URLVariables;

	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.HTTPService;
	import mx.utils.Base64Encoder;

	public class TwitterManager
	{
		private var service:HTTPService;

		public function TwitterManager()
		{
		}

		public function initTwitterManager():void {
			service = new HTTPService;
			service.method = "post";
			service.url = "http://twitter.com/statuses/update.json";
			service.resultFormat = "text";
			service.addEventListener(ResultEvent.RESULT, onResult);
			service.addEventListener(FaultEvent.FAULT, onFault);
		}

		public function Tweet(message:String):void {
			var forms:URLVariables = new URLVariables();
			forms.status = message;

			var encoder:Base64Encoder = new Base64Encoder();
			encoder.encode("username:password");

			service.headers["Authorization"] = "Basic " + encoder.toString();
			service.request = forms;
			service.send();
		}

		private function onResult(event:ResultEvent):void {
			var json:Object = JSON.decode(event.result.toString());
			trace(json.text);
		}

		private function onFault(event:FaultEvent):void {
			trace("投稿失敗...n" + event.fault.toString());
		}

	}
}
34行目は、とりあえずサンプルソースのため、username、passwordとしています。ご自分のtwitterのIDとパスワードに適宜変更してください。

次にアイコンを再びアニメーションさせる部分です。
翻訳結果が得られたときに、アニメーションを再開させるようにしたいと思います

flashcast:フリーで働くITエンジニア集団のブログ: google翻訳APIを使ったAIRアプリを作る!(翻訳部分の実装編)で作成したModelクラスに、翻訳結果を保存するメンバーを追加します。

package
{
	[Bindable]
	public class TranslateModel
	{
		public var _original:String;
		public var _translated:String;

		public function TranslateModel()
		{
		}

		public function set Original(original:String):void {
			_original = original;
		}

		public function get Original():String {
			return _original;
		}

		public function set Translated(translated:String):void {
			_translated = translated;
		}

		public function get Translated():String {
			return _translated;
		}

	}
}

メインのロジックでは、翻訳結果が変更されたかどうか監視するようにします。

package
{
	import flash.events.Event;

	import mx.binding.utils.ChangeWatcher;
	import mx.core.Application;
	import mx.events.PropertyChangeEvent;

	public class TranslatorSample6Base extends Application
	{
		private var imanager:IconManager;
		private var cmanager:ClipboardManager;
		private var gmanager:TranslateManager;
		private var tmanager:TwitterManager;

		private var gmodel:TranslateModel;

		private var tweet:Boolean;

		public function TranslatorSample5Base():void {
		}

		public function initApp():void {
			gmodel = new TranslateModel();

			imanager = new IconManager();
			cmanager = new ClipboardManager();
			gmanager = new TranslateManager();
			tmanager = new TwitterManager();

			imanager.initIconManager();
			cmanager.initClipboardManager(gmodel);
			gmanager.initTranslateManager(gmodel);
			tmanager.initTwitterManager();

			ChangeWatcher.watch(gmodel, '_original', onClipboardChangeHandler);
			ChangeWatcher.watch(gmodel, '_translated', onTranslatedChangeHandler);

			imanager.addEventListener(TranslatorSampleEvent.ICON_CLICK, onIconClick);
		}

		private function onClipboardChangeHandler(event:PropertyChangeEvent):void {
			if ((event.oldValue as String) != "") {
				this.addEventListener(Event.ENTER_FRAME, imanager.iconAnimate);
			}
		}

		private function onIconClick(event:TranslatorSampleEvent):void {
			this.removeEventListener(Event.ENTER_FRAME, imanager.iconAnimate);

			if (tweet) {
				tmanager.Tweet(gmodel.Translated.substr(0, 140));
				tweet = false;
			}
			else {
				gmanager.Translate("1.0", gmodel.Original, "en", "ja");
			}
		}

		private function onTranslatedChangeHandler(event:PropertyChangeEvent):void {
			this.addEventListener(Event.ENTER_FRAME, imanager.iconAnimate);
			tweet = true;
		}
	}
}

翻訳時と同じように、アニメーションしているアイコンをクリックするとつぶやくようにしています。また、twitterは140文字以内という制限があるため、140文字を超えているものは141文字目以降を削除してtwitterに投稿します。

実行時のデバックトレースです。つぶやいた翻訳結果を出力しています。

sample6

これでつぶやき機能を持つ、翻訳アプリが出来ました。twitterを翻訳結果の履歴管理に利用するのもいいかもしれませんね(followerには大迷惑かもしれませんが・・・)。

サンプルソース

サンプルソースをダウンロードできるようにしておきます。