not good but great

プログラミング、アート、映画・本の感想について書きます。

Content ScriptからBackground Scriptにメッセージ送り、popupに表示させる方法

何を作ったか?

以前、Youtubeの埋め込みコードに開始時間を設定する拡張を書いた。
YouTubeを途中再生できるように埋め込みコードを改変するChrome拡張をつくった - not good but great
Chrome Web Store - Embed Screen Jump Code for YouTube™

それの技術的な解説を書こうと思う。

アプリの設計

拡張の作り方、用語の解説

構成や、拡張の作り方はこのページを参考にした。
2013-09-09 - k4200’s notes and thoughts

アプリの動作手順

おおまかな流れは次のようになる。

行程1.Youtubeの視聴ページに行くと、URLバーの端にPage Actionのボタンが現れる。
行程2.ページ読み込み終了後、Content Scriptを実行し、Youtubeの動画オブジェクトを取得し、現在の再生時間を得る。
行程3.Content ScriptからBackground Scriptに再生時間のデータを送る。
行程4.Page Actionのボタンが押されると、popupが表示され、Background Scriptからデータを得て、情報を表示する。

行程1

//background.js
chrome.tabs.onUpdated.addListener(function (tabId,changeInfo,tab){
	if(tab.url.indexOf("youtube.com/watch?v=") != -1){
		chrome.pageAction.show(tabId);
	}
});

Youtubeの視聴ページのURL(youtube.com/watch?v=)がURLに含まれるなら、アイコンをアドレスバーに表示する。

行程2

Content Scriptの実行タイミングを設定

・manifest.json

"content_scripts":[
		{
			"matches":["http://www.youtube.com/watch?v=*"],
			"js":["js/jquery.js","js/contentscript.js"],
			"run_at":"document_end"
		}
	],

"run_at"にいつ実行するのかを設定する。“document_start“、“document_end“、“document_idle“の値がある。

matchesはbackground.jsでurl指定しているので、もしかしたら要らないかもしれない。

コンテント・スクリプト | Chrome Extensions API リファレンス

Youtubeの動画オブジェクトを取得

方法がわからないかったので、Youtubeを使った拡張機能をダウンロードして、ソースを読んで参考にした。参考にした拡張は繰り返し再生の機能を持たせる拡張だった。
Chrome Web Store - Auto Replay for YouTube

//contentscript.js
var ytobj = {
		startTime: 0,
		createHTML5Player: function(videoEle){
			ytobj.videoEle = videoEle;
			return{
				getCurrentTime: function(){
							return videoEle.currentTime;
						}
			}
		},

		getMoviePlayer:function(){
				       var p = $("#movie_player");
				       if(p.is(".html5-video-player")){
					       var _p = p.find("video")[0];
					       if(_p){
						       p = ytobj.createHTML5Player(_p);
						       console.log(p.getCurrentTime());
					       }
				       }else{
					       p = p[0];
				       }
				       return p;
			       }

	};

	ytobj.player = ytobj.getMoviePlayer();
	ytobj.startTime = ytobj.player.getCurrentTime();

jQueryでidを指定して、動画を囲っているdiv要素を取得する。そのあとvideoタグをfindで検索する。

疑問だったのはhtmlソースで「video」という文字列を検索しても見つからないこと。どうなっているんだろうかw

Youtubeのオブジェクトを取得して何が出来るかというのは、Youtube player APIのドキュメントを見るのが良い。
YouTube JavaScript Player API リファレンス - YouTube — Google Developers

player.getCurrentTime():Number
動画の再生を開始してからの経過時間を秒数で返します。

現在の再生時間を得たいので、getCurrentTime()を使う。

行程3

Background Scriptに再生時間のデータを送る

//contentscript.js
chrome.runtime.sendMessage({time: ytobj.startTime},
			function(response){
				console.log("message sent");
			});

再生時間をオブジェクトの値に設定して、sendMessageの引数に設定する。

メッセージの送り方のドキュメントはこちら。
Message Passing - Google Chrome

行程4

Background Scriptでデータを受け取る

chrome.runtime.onMessage.addListener(
	function(request,sender,sendResponse){
		parseItems = [];
		console.log(request);
		console.log(sender);
		console.log(sendResponse);
		startTime = request.time;
		url = sender.url;

		var res = "finish";
		sendResponse(res);
	}
);

メッセージを受け取ると、onMessageのイベントリスナが起動され、関数が実行される。

ここでは開始時間と送り主のURLを取得している。URLは後で、埋め込みコードを生成するときに必要なので取得した。

Popup.htmlにデータを渡す

・popup.html

<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/popup.js"></script>

jsファイルは外部から読み込むようにする。htmlファイルに直接scriptを書くと、クロスドメイン?に引っかかり実行できない。クロスドメインわからん。

//popup.js
var startTime = ~~chrome.extension.getBackgroundPage().startTime,
    url = chrome.extension.getBackgroundPage().url;

"chrome.extension.getBackgroundPage()"の後に変数名を書けば、backgroundが持っているデータを引き出せる。

あとはpopup.jsで受け取ったデータを処理して、埋め込みコードを生成してる。

改善したいところ

現在の時間の取得タイミング

今は最初にPageActionを押した時間しか抜き出せていない。だから少し再生して、もう一回押してもそのときの再生時間にならない。これをするやり方がわからない。

Youtubeの動画の下のメニューにある「共有」を押すと、URLに開始時間を加えることが出来る。それはリアルタイムで開始時間が変化している。それのように拡張の方も動いたらいいのになと思う。