2011年6月21日火曜日

Turntableで再生中の曲情報を取得する。その2。

まえおき
前回Turntableで再生中の曲情報をポップアップで表示するところまでやりました。
しかし、この方法だと
・ページ開いていないとポップアップが見られない
という問題があります。
そこで、他の作業をしていてもちゃんと通知が見えるようにしなくてはなりません。

この問題を解決するために今回はデスクトップ通知に対応させます。

こんな感じになります↓。


デスクトップに通知する方法
デスクトップに通知する方法として例えばGrowlがあります。
Growlは↓のようにデスクトップに通知を出してくれます。


Growlはこのようにデスクトップに通知を出してくれます。

Chrome Extensionsでもこれと同じような機能があります。
それが、Desktop Notificationsです。そのまんまですね。

これを使うと先ほどのGrowlと同じように、デスクトップに通知ができます↓。


デスクトップの通知にはこれを使えば良さそうです。
また、Desktop Notificationを使う場合にはmanifest.jsonのpermissionsに、"notifications"を加える必要があります。
"permissions": [
"tabs",
"http://*/",
"https://*/",
"notifications"
]

通知する内容を考える
Desktop Notificationで表示する中身を作る方法は二通りあります。
ひとつはSimple Text Notification 、もうひとつはHTML Notificationです。

Simple Text Notificationは
  • アイコン画像
  • タイトル
  • メッセージ
から作ります。

HTML Notificationは

  • 外部のHTML

から通知する画面を作ります。

なので、単純に画像だけを表示するものはない!のです。
Simple Text Notificationのアイコン画像は小さすぎるため、今回の用途には使えません。

そこでHTML Notificationを使うことになるのですが、問題は
「どうやって画像を表示するか」
です。
ただ、あんまりhtmlの知識がないので、画像ならimgタグだろうぐらいしか思いつきませんでした。なので、ここではimgタグを使います。
そして、解決しないといけない問題がもうひとつあります。それは
「どうやって画像を渡すか」
です。

今回の構成ではキャプチャを取るbackground.htmlと通知画面を作るるnotif.htmlの二つのファイルに分かれています。
そのため、background.htmlでキャプチャした画像をnotif.htmlに送らなければなりません。
通常のウェブページであれば、ローカルにあるファイルを読み込んだり、ウェブ上にある画像のURLをimgタグのソースに指定すれば良いのですが、今回の場合、

  • キャプチャした画像をローカルに保存できない(多分)
  • どこかにアップロードすることもできない

といった理由からこれは無理そうです。

しかし、imgタグで画像を表示するにはこれ以外にも画像のデータを直接指定する、という方法が使えます。
画像のデータには例えばBase64エンコーディグされた文字列が使えます。
なんだか、ちょっと道が見えてきました。

通知する画像データを作る
imgタグのソースに画像データを指定できることがわかりました。
そうすろt、指定するための画像データを作らなければなりません。

通知画面で表示する画像は前回(リンク)ポップアップで表示した画像をそのまま使うことにしましょう。
この画像はCanvasに描かれています。
そしてなんと、HTML5のCanvasにはtoDataURL()というまさにこの用途に使うためにあるかのようなメソッドがあります。

この関数はCanvasに描かれた内容を指定した形式でBase64エンコーディングした画像データ(URL)として出力してくれます。こんな感じです↓。
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABGcAAAJqCAIAAAAJ+7rbAAAgAElEQVR4nOzdeXxV1b03/s9aa+9zdnJOQhJCIGAYS1RSxMpQFBUHnPCRipXWscUOONxb2/pcuT/709Zbbf090p9WbWuL16utor2ldcCLCoojCAURLAY1yhhIIISQ4SRn2Guv9fyReTrMYs3n/fJVz7DO2uvsnGP353zXXlu4D20HERERERFRX/LymE9838/JyUkkElprIUQ4HHZd13Ec13WbbyilgiBIJpPOsR4tERERERHRZ00pNXjw4CFDhkgpfd9vampKJBJSSrcDKaUxJh6PMzUREREREVGfo5SSUrbFpMzMzFgs1tTU5DiOlFK1CoJAKcXUREREREREfU5zOhJCABBCWGullG3T80KhkOM4QggppdaaqYmIiIiIiPo0Y0xjY2NjY6NSyrQC0JypADA1ERERERFRn2OttdYCSKVS1dXVjY2NAEKhUCqVcl03EokIIVzXbW7M1ERERERERH2OlBJAMpncsWNHaWnp7t276+rqYrFYOBzOy8sbMWLEuHHjCgoKHMex1jI1ERERERFRn2OMCYLgww8/XPZG6VtlzsfJkVWZBTbDyfF3D6nbcUL...
次は、こいつをnotif.htmlに渡しましょう!

notif.htmlに画像データを送る
画像データを生成することができたので、次は通知するhtmlにこのデータを送らなければいけません。
他のhtmlファイルにデータを送るには

  • 画像ファイルを作る
  • WebSocketを使う
  • クエリを使う

みたいな方法があると思うのですが、今回はクエリを使って実現しています。
画像ファイルは生成する方法がわからなかった。
WebSocketはめんどくさそうだったのと、今回の用途みたいにちょこっと使うにはコストが高かいと思ったのでやめました。
(やるとしたら、サーバー側の実装も必要?)

そこで、クエリを使う方法です。
htmlを読み込むときのファイル名に、
notif.html?q1=v1&q2=v2...
というような指定をすることができます。
こう書くと実際に読み込まれるファイルはnotif.htmlとなり、"?"より後ろに書いた文字列は無視されます。
では、"?"の後ろの文字列はどうなるのか、というと、notif.html側で読み取ることができるんです!

これで、通知用のnotif.htmlを読み込むときに画像データをくっつけてあげれば、notif.htmlに画像データを送ることができそうです。
実際にはこんな感じになります↓。

var notification = webkitNotifications.createHTMLNotification(
    'notif.html?data=' + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABGcAAAJqCAIAAAAJ+7rbAAAgAElEQVR4nOzdeXxV1b03/s9aa+9zdnJOQhJCIGAYS1RSxMpQFBUHnPCRipXWscUOONxb2/pcuT/709Zbbf090p9WbWuL16utor2ldcCLCoojCAURLAY1yhhIIISQ4SRn2Guv9fyReTrMYs3n/fJVz7DO2uvsnGP353zXXlu4D20HERERERFRX/LymE9838/JyUkkElprIUQ4HHZd13Ec13WbbyilgiBIJpPOsR4tERERERHRZ00pNXjw4CFDhkgpfd9vampKJBJSSrcDKaUxJh6PMzUREREREVGfo5SSUrbFpMzMzFgs1tTU5DiOlFK1CoJAKcXUREREREREfU5zOhJCABBCWGullG3T80KhkOM4QggppdaaqYmIiIiIiPo0Y0xjY2NjY6NSyrQC0JypADA1ERERERFRn2OttdYCSKVS1dXVjY2NAEKhUCqVcl03EokIIVzXbW7M1ERERERERH2OlBJAMpncsWNHaWnp7t276+rqYrFYOBzOy8sbMWLEuHHjCgoKHMex1jI1ERERERFRn2OMCYLgww8/XPZG6VtlzsfJkVWZBTbDyfF3D6nbcUL...';
  );
  notification.show();

渡した文字列を取得する
window.location.search.substring()
を使っています。substringの中に渡した文字列が入っているので、
ここから必要な箇所(画像データ)だけを抜き出します。
抜き出した画像データをimgタグのソースに指定すれば画像が表示されます。
やったね!

次回!
次回は一定時間おきに通知するようにしてみます。

ソース
background.html
<html>
<head>
<script>

chrome.browserAction.onClicked.addListener(function(tab) {
  capture();
});

function capture() {
  chrome.windows.getCurrent(function (win) {
    chrome.tabs.captureVisibleTab(win.id,{format:"png"}, function(imgUrl) {
      createImageData(imgUrl, onImageData);
    });
  });
}

function onImageData(imgData) {
  showNotification(imgData, 3000);
}

function createImageData(imgUrl, callback) {

  var img = document.getElementById('myImg');
  img.setAttribute('src', imgUrl);

 setTimeout(function() {

      var canvas = drawToCanvas(img);

      img.setAttribute('src', 'data:image/png;base64,');

      if(callback) {
        callback(canvas.toDataURL());
      }
  }, 10);
}

function drawToCanvas(img) {
  var canvas = document.getElementById('myCanvas');
  var context = canvas.getContext('2d');
  context.fillRect(0, 0, 100, 100);
  var x = (img.width - 760) / 2 + 72;
  context.drawImage(img, x, 238, 360, 88, 0, 0, canvas.width, canvas.height);
  return canvas;
}

function showNotification(data, duration) {
  var notification = webkitNotifications.createHTMLNotification(
    'notif.html?data=' + data
  );
  notification.show();
  setTimeout(function() {
    notification.cancel();
  }, (duration ? duration : 3000));
}

</script>
</head>
<body>
<img id="myImg" src="" />
<canvas id="myCanvas" width="280" height="68" />
</body>
</html>
notif.html
<html>
<script>
  function onLoad() {
    var query = "?data=";
    var imgData = window.location.search.substring(query.length);
    var img = document.getElementById("myImg");
    img.src = imgData;
  }
</script>
<body onload="onLoad()">
<img id="myImg" src="" />
</body>
</html>
manifest.json
{
  "name": "Test",
  "version": "1.0",
  "background_page": "background.html",
  "browser_action": {
    "default_icon": "icon.png"
  },
  "permissions": [
    "tabs",
    "http://*/",
    "https://*/",
    "notifications"
  ]
}

そんじゃーね。

0 件のコメント:

コメントを投稿