MacのDesktop背景をかっちょいいGoogleMaps画像に自動更新する。

ogNYに向けての開発にクソ忙しかった1月に知人のtweetで Earth View from Google Maps っていうChromeアプリを知り、
ちょうどその時案件でVJアプリを作ってた関係でこれそのまま素材に使ったらパターン柄ぽくてかっこいいやん。と、
思いっきり脱線してEarth View from Google Mapsをローカルであれこれに使ってみる遊び(倫理的な話を思いっきり無視しつつ!)をしてた時のメモ書き。

結局最後は何故かDesktop背景に勝手に適用するという個人利用の範疇で着地。よかったよかった。のか?

GoogleMapsのChromeAppパクって1時間毎に壁紙変更してくれるアプリにしてみた週末の遊び。

you tanakaさん(@rettuce)が投稿した写真 –

こっから 2015.1.14 にタイムトリップ。

Earth View from Google MapsってChromeアプリが素敵だったんでこいう画像をパカパカ更新してそれを素材として見てるだけの
アプリが欲しいなと思ったので作ってみる。とりあえずお仕事がお忙しい時期なので短時間でサクッと!

まずは中のソースを見てみる。

てかChromeのappって何処にあるん?てことでGoogle先生に聞いてみる。
chrome Extensionの保存場所
ここに書いてあったとこと微妙には違うもののタイムスタンプから探し出す。

~/Library/Application Support/Google/Chrome/Profile 1/Extensions/bhloflhklmhfpedakmangadcdofhnnoh

ほいあった。

構成はこんな感じ。ほうほう。←Chromeアプリ作ったことない。

2015-01-14 20.10.32

とりあえず中のgoogle-places-backdrops.html叩いてみる。
背景真っ黒だけどとりあえずNewTabの時の挙動。なるほどあれ背景html表示させてるだけなのね。
確かChromeってローカルでは外部jsとか読み込めないよね、ってことでローカルのバーチャルホスト環境下で再度叩く。

2015-01-14 19.44.34

また怒られる。。(test.comがバーチャルドメイン)

えーと https://www.gstatic.com/prettyearth/ ってとこに取りに行ってアクセス権ねーよってことね、
とりあえず普通に取得はできるんかいね、ということでそのままブラウザでjson表示してみる。
https://www.gstatic.com/prettyearth/1714.json → なんかわーっと出たw

とりあえずこれをそのままファイル保存。
なるほど緯度経度とかzoom値のdata.jsonか。これをMapAPIに渡して表示って感じなのかね。
というわけで http://test.com/ 配下にぶっこむ。

えーとmain.js読むと initあたりにapi URLがあるので書き換え。

    this.apiUrl = 'https://www.gstatic.com/prettyearth/' +
      this.getImageId() +
      '.json';
      			↓↓↓
    this.apiUrl = 'http://test.com/' +
      this.getImageId() +
      '.json';

んでとりあえず1714.jsonしか取得してきてないからgetImageIdを書き換え。

  getImageId: function() {
    var imageIds = backgrounds.imageIds;
    return imageIds[Math.floor(Math.random() * imageIds.length)];
  },
      			↓↓↓
  getImageId: function() {
    return 1714;
  },

とりあえずこれでNewTabした時の挙動が再現できた。

/data/imageIds.json 内の配列(backgrounds.imageIds)からランダム取得してきてimageIdにしてるのね。
じゃあとりあえずこのjsonを元にがつっとローカルにdata.json取得したらローカルで同じ仕組みができそうね。

ということで初Python。えーとファイルダウンロードは。。
Webサーバーにあるファイルをダウンロードする

import urllib
urllib.urlretrieve('https://www.gstatic.com/prettyearth/1714.json', '~/Desktop/test.json');

ほいダウンロードできた。json内の配列を纏めて回すとかどうすんのかね。
json読み込み。

んでとりあえずdata.jsonがjsでの読み込み用の記述になってたんでpythonで読めるようにちょっと成形。

backgrounds.imageIds = [
		↓↓↓
{"backgrounds.imageIds" : [

あとはこの辺りを参考に。。(倫理的にそろそろアウト)

できた。

#coding:utf-8

import json
import urllib

api = "https://www.gstatic.com/prettyearth/"
data = "/www/test.com/1.6.6_0/data/imageIds.json"
home = "/www/test.com/1.6.6_0/data/json/"

f = open(data, 'r')
jsonData = json.load(f)
keyList = jsonData.keys()

for k in keyList:
        groupDict = jsonData[k]
        for x in groupDict:
        	href = api + x + ".json"
        	print href
        	urllib.urlretrieve( href, home+x+".json");
f.close()

てかphpでプロキシ通して毎回取得でもよかったかなー。
あと今回がっつりfor文回して取得しちゃったけどAPI回数制限とかあるし
ほんとは時間かけてちょっとずつ落とすとかしたほうがいいんだろうなきっと、、、汗

そして要するにこのjsonが欲しかっただけなので取得できちゃって後はもう飽きた。。w
そして月日が流れ2ヶ月後のミラノ。

こっから 2015.3.22 にタイムトリップ。

ミラノで全然開発できてないのでストレス発散に休日遊びでこちらを進めてみる。

んで取得したjson見てみたら緯度経度とかzoom値書いてあってこれをMapで表示ってことかなと思ったら、
なんか一番下にdataUriってbase64エンコードされた画像データもついてるね。これデコードしてあげたらそれでおkって感じぽい。
なるほど、だからjson dataが0.5MB〜1.5MBもあってダウンロードに全部で数時間もかかってたのか。全部で1GBくらいある。w

というわけで何からでも使いやすいようにphpでデコードして表示してみる。

dataUriの先頭 data:image/jpeg;base64, 部分取って$dataに突っ込むだけのimgview.phpを用意。

<?php
$duri = "";
if ($_POST) {
    $duri = $_POST['dataUri'];
}
$img64 = base64_decode($duri);
header( 'Content-Type: image/jpeg' );
print $img64 ;
?>

これ使えば画像にできる〜と思ったけど、
C++はPocoライブラん中にdecoderあってそれ使えばよかった。。ひがさんが書いてた。。orz

この辺りでVJ素材とかに使えそうって目処がたったので飽きる。
そういえばスクリーンセーバーにしようかなと思ってたけどoFでそれやるのもどうやら面倒くさそう。

そいえばひこさんがこの前Desktop背景ネタのアプリ?を紹介してたなと思い出し、(毎日 Mac の壁紙をいい感じのんにかえる)
あれってどうやってんだ?と調べたら案外簡単にコマンドライン(AppleScript)からいけるみたい。

んじゃとりあえずofImageに表示して保存、そいつのフルパスをAppleScriptで背景にってコマンド叩くだけのお手軽仕様でいけそう。ということで作ったのが以下。簡単!

#include "ofMain.h"

#include "ofxJSON.h"
#include "Poco/Base64Decoder.h"

class ofApp : public ofBaseApp
{
    ofxJSONElement datas, imgdata;
    int length;
    string base64ImageData = "";
    ofImage image;

    int count=0;
    string cmd;
    char* cmdchar;

    float updatetime = 60.0 * 60;  // 60min
    float nowtime = 0.;
    int updatecount = 0;

public:

    ofApp(){}

    void setup()
    {
        ofSetFrameRate(10);
        ofBackground(0);
        ofSetWindowPosition(5000, 0);

        if(datas.open("imageIds.json"))
        {
            length = datas["backgrounds.imageIds"].size();
            cout<< "JsonFiles -> " << length <> buffer;

        image.loadImage(buffer);
        string ip = "map"+ofToString(count)+".png"; // 同じファイル名とかだと壁紙が更新されない
        image.saveImage(ip);

        string path = ofDirectory(ip).getAbsolutePath();
        cmdline(path);

        updatecount++;
        count++;
        if(count>1) count=0;
    }

    // JsonListからランダムでMapIDを取得してきてbase64圧縮された画像データを返す
    string getimage(){
        string d = datas["backgrounds.imageIds"][int(ofRandom(length))].asString();
        d = "json/" + d + ".json";

        if(imgdata.open(d)){
            d = imgdata["dataUri"].asString();
            return split(d,',');
        }else{
            return NULL;
        }
    }

    // 初めのContentTypeとかいらないので消す
    string split(const string &s, char delim) {
        vector elems;
        stringstream ss(s);
        string item;
        while (getline(ss, item, delim)) {
            if (!item.empty()) {
                elems.push_back(item);
            }
        }
        return elems[1];
    }

    // AppleScriptたたく
    void cmdline(string path)
    {
        cmd = "osascript -e 'tell application \"System Events\" to set picture of current desktop to POSIX path of file \"" + path + "\"'";
        cmdchar = new char[cmd.length()+1];
        memcpy( cmdchar, cmd.c_str(), cmd.length()+1 );
        system( cmdchar );
    }
};

#include "ofAppGLFWWindow.h"
int main(int argc, const char** argv)
{
    ofAppGLFWWindow window;
    ofSetupOpenGL(&window, 1, 1, OF_WINDOW);
    ofRunApp(new ofApp);
    return 0;
}

おしまい。

という今回も非常に無意味な脱線遊びでした。

ま、楽しかったし休日だしいいよね。

you