2018年3月18日日曜日

Google Driveにあるファイルサイズの合計を求める

Googleドライブのストレージ消費量はここ(新しいウインドウで開きます)で確認できます。しかし、確認できるのはストレージ容量を消費している容量です。
基本的にはそれでも困らないのですが、高画質設定のGoogleフォトにバックアップした画像などの容量を消費しないファイルサイズの合計を知りたいときもある?。

ということで、Googleドライブに保存されているファイルの総容量を数えてみようと思います。ですが今回はチョット応用して画像(静止画と動画)の総容量を求めてみます。

手順
  1. GoogleドライブにGoogle Apps Scriptをインストールし、新規のスクリプトを作成する。Google Apps Scriptを使ったことがない人はここ(新しいウインドウで開きます)を参照。
  2. 下記のスクリプトを張り付ける。
  3. スクリプト内のMain関数を実行する。(メニュー>実行>関数を実行>Main)
  4. 実行結果はメールで受け取ります。しかし、ファイル数が多い場合には複数回に分けで処理を実行します。そのため5分に1回程度途中経過を通知する集計中メールを飛ばすようにしています。完了メールが来るまで待ってください。

スクリプト
// メニュー>実行>関数を実行>Main を選択して実行してください
function Main(){
  PropertiesService.getUserProperties().deleteAllProperties();
  CountFileSize();
}
  
function CountFileSize(){
  var StartTime   = new Date();

  var triggers = ScriptApp.getProjectTriggers();
  for (var i = 0; i < triggers.length; i++) {
    ScriptApp.deleteTrigger(triggers[i]);
  }

  trigger = ScriptApp.newTrigger("CountFileSize")
  .timeBased()
  .everyMinutes(5)
  .create();
  
  var UserProperties = PropertiesService.getUserProperties();
  var ContinuationToken = UserProperties.getProperty("ContinuationToken");

  if(ContinuationToken) {
    var images = DriveApp.continueFileIterator(ContinuationToken);
    var TotalFileSize = parseFloat(UserProperties.getProperty("TotalFileSize"));
  } else {
    // カウントしたい条件に応じてコメントアウトする行を変更してください。

    // ドライブのすべてのファイルをカウントする場合
    // var images = DriveApp.getFiles();

    // 自分がオーナーのファイルだけをカウントする場合
    // var images = DriveApp.searchFiles('"me" in owners');

    // 画像だけをカウントする場合
    var images = DriveApp.searchFiles('mimeType contains "image/" or mimeType contains "video/"');

    // 自分がオーナーの画像だけをカウントする場合
    // var images = DriveApp.searchFiles('(mimeType contains "image/" or mimeType contains "video/") and "me" in owners');

    var TotalFileSize = 0;
  }
  
  while(images.hasNext()) {
    var CurrentTime = new Date();
    if( (CurrentTime - StartTime) > 4*60*1000 ){
      UserProperties.setProperty("ContinuationToken", images.getContinuationToken());
      UserProperties.setProperty("TotalFileSize", TotalFileSize);
      // 集計中メールがうるさい場合は以下の一行をコメントアウトしてください。
      SendResult("集計中\n" + TotalFileSize + " Byte\n" + TotalFileSize/1024 + " KByte\n" + TotalFileSize/1024/1024 + " MByte\n" + TotalFileSize/1024/1024/1024 + " GByte\n" );
      return;
    }

    var file = images.next();
    TotalFileSize += file.getSize();
  }

  SendResult("完了\n" + TotalFileSize + " Byte\n" + TotalFileSize/1024 + " KByte\n" + TotalFileSize/1024/1024 + " MByte\n" + TotalFileSize/1024/1024/1024 + " GByte\n" );
  ScriptApp.deleteTrigger(trigger);
  UserProperties.deleteAllProperties();
}

function SendResult(MailBody){
  var address = Session.getActiveUser().getEmail();
  GmailApp.sendEmail(Session.getActiveUser().getEmail(), "Googleドライブのファイルサイズの合計を求める", MailBody);
}

スクリプトの説明

要点だけ書きます、なんとなく処理の順に記載しますが、厳密には処理順ではありません。難しいコードではないのでコードを見てください。
  1. 起動はMain関数、実処理はCountFileSize関数
  2. Main関数では後述するトリガを削除する。
  3. 6分制限対策としてスクリプト起動に5分のタイマー起動のトリガーを設定、トリガではCountFileSize関数を呼び出す。(処理が完了したときにトリガを削除する。)
  4. カウントするファイルリストを取得する。
    ここでカウントしたいファイルを検索する。
    • ドライブ内のすべてのファイルをカウントしたい場合
      var images = DriveApp.getFiles();
    • 自分がオーナーのファイルだけをカウントする場合
      var images = DriveApp.searchFiles('"me" in owners');
    • 画像だけをカウントする場合
      var images = DriveApp.searchFiles('mimeType contains "image/" or mimeType contains "video/"');
    • 自分がオーナーの画像だけをカウントする場合var images = DriveApp.searchFiles('(mimeType contains "image/" or mimeType contains "video/") and "me" in owners');
    • 特定のオーナーのファイルをカウントする場合
      var images = DriveApp.searchFiles('"XXXX@google.com" in owners');
  5. スクリプト実行開始から4分経ったらユーザプロパティに必要な情報を保存して処理を中断する。すでにトリガ設定が終わっているのでここではトリガ設定の処理は行わなくてもよい。
  6. ユーザープロパティには「どこまで処理が完了したか」と「集計中のトータルファイルサイズ」を保存する。
  7. ファイルサイズをTotalFileSizeにどんどん加算していきます。
  8. 正常に終了したらトリガを削除し、本文に集計結果を含めて完了メールを送信する。
スクリプトの応用
高画質設定のGoogleフォトにアップロードした画像の総容量を調べたい場合
  1. Googleフォトを使用していない別ユーザにパートナー共有する。
  2. 別ユーザーはすべてのファイルをライブラリに保存する設定にする。
  3. 別ユーザーのGoogleドライブ設定で「Google フォト」フォルダを作成するをオンにする
  4. 別ユーザーで本スクリプトを実行する。もしくはGoogleフォトフォルダをオリジナルユーザーに共有し、オリジナルユーザー側でOwner指定で本スクリプトを実行する。

    2018年3月11日日曜日

    iPhoneのGoogleフォトアプリ利用時にカメラロールから安全に写真を削除する方法

    この記事は古いのでこちらの記事を参照してください。

    Googleフォトにアップロードされた画像をiPhoneのカメラロールから削除したい時があります。その方法について説明します。

    ×絶対やってはいけないこと
    Googleフォトアプリで画像を選択し「ゴミ箱」アイコンをタップして画像を削除。
    これを行うとGoogleフォトからもカメラロール(もしくはすべての写真)からも画像が削除されてしまいます。

    △お勧めしない方法
    写真アプリカメラロール(もしくはすべての写真)で画像を選択し「ゴミ箱」アイコンをタップして画像を削除。
    この操作を行う前には削除する画像がGoogleフォトにアップロードされていることを確認する必要があります。確認は https://photos.google.com/login にアクセスして行ってください。

    ◎おすすめの方法
    Googleフォトアプリで削除したい画像を選択して、「・・・」メニューから「デバイスから削除」「元のファイルn個をデバイスから削除」を行う。もしくは下から表示されたメニューを横スクロースして「元のファイルをデバイスから削除」を実施する。※デバイスやアプリのバージョンによって操作性が変わるようです。

    おすすめの理由は、アップロードできていない画像を選択してこの操作を行って実施すると”一部のファイルはGoogleフォトにバックアップされていないため、この操作を行うと完全に削除されます”と言った警告が出ることです。この警告が出た場合には一度キャンセルし選択された画像をアップロードしてから再度実施してください。

    [番外編]カメラロールの写真をすべて削除する方法
    Googleフォトアプリで画面右上「アカウントアイコン」をタップし「フォトの設定」>「デバイスの空き容量の管理」と遷移し「空き容量を増やす」を選択します。アップロード済みの画像すべてをカメラロールから削除します。この操作を行った後に残った画像はアップロードできていない画像の可能性が高いです。
    たまにアップロードされている画像も残ることがある気がしますが、未検証です。

    Google Apps Scriptの始め方

    手順



    1. ブラウザでGoogle Driveにログインする。
    2. ”新規” > "その他” > ”+アプリを追加” を選択する。

    3. 検索入力ボックスに”Google Apps Script”と入力しEnterキーを押して検索を行い、Google Apps Scriptを”+接続”する。
    4. ”新規” > "その他” > ”Google Apps Script” を選択する。
    5. コードを入力し、実行したい関数を指定して、実行を押す。(いきなり説明がいい加減、、、)

      今回は以下のスクリプトにした。
      function myFunction() {
        Logger.log("こんにちは");
      }
      
    6. すぐに実行できるかと思いきや、いろいろと許可しないといけない。ただし、こう言ったものはちょくちょく変化していくので細かい説明は省略。現時点での画面を貼っておくので、参考にしてほしい。
    参考になるかもしれない情報

    Googleドライブでフォルダに属していないファイルを集める

    Googleドライブを使用していると、どのフォルダにも属していないファイルが見つかることがある。 ドライブ内を検索したり、ストレージ容量消費が多い順にファイルを並べたりしたとき目にすることがある。
    • フォルダに属しているファイルの情報には”パス”という項目がある。


    • フォルダに属していないファイルの情報には本来あるべき”パス”という項目がない。
    見えないファイルがあるのは気持ち悪いので、行方不明ファイルを一か所のフォルダに集めちゃおうというのが今回の内容。

    手順
    1. GoogleドライブにGoogle Apps Scriptをインストールし、新規のスクリプトを作成する。詳細はここを参照。
    2. 下記のスクリプトを張り付ける。
    3. スクリプト内のMain関数を実行する。(メニュー>実行>関数を実行>Main)
    4. ドライブで管理しているファイル数が少ないときは一回の実行で完了するが、ファイル数が多くなると時間がかかり、Google Apps Scriptの制限の一つである6分以内という制限に引っかかってしまうため、繰り返し実行することですべてのファイルをスキャンする。処理が完了したらメールで通知を行う。
    スクリプト

    • 本スクリプトはフォルダに属していないファイルをマイドライブ直下のLostFilesフォルダにまとめる。
    • Main関数を一回実行すると処理が終了するまで定期的にスクリプトが実行される。
    • 処理が完了するとメールが送られてくる。

    // http://blog.hikozaru.com/2018/03/google.html
    // メニュー>実行>関数を実行>Main を選択して実行してください
    function Main(){
      PropertiesService.getUserProperties().deleteAllProperties();
      FindLostFiles();
    }
    
    function FindLostFiles(){
      var StartTime   = new Date();
    
      var triggers = ScriptApp.getProjectTriggers();
      for (var i = 0; i < triggers.length; i++) {
        ScriptApp.deleteTrigger(triggers[i]);
      }
    
      trigger = ScriptApp.newTrigger("FindLostFiles")
      .timeBased()
      .everyMinutes(5)
      .create();
        
      var UserProperties = PropertiesService.getUserProperties();
      var ContinuationToken = UserProperties.getProperty("ContinuationToken");
    
      if(ContinuationToken) {
        var files = DriveApp.continueFileIterator(ContinuationToken);
      } else {
        var files = DriveApp.getFiles();
      }
      
      var Folder = getSubFolder( DriveApp.getRootFolder(),'LostFiles');
      while(files.hasNext()) {
        var CurrentTime = new Date();
        if( (CurrentTime - StartTime) > 4*60*1000 ){
          UserProperties.setProperty("ContinuationToken", files.getContinuationToken());
          return;
        }
        
        var file = files.next();
        if( !file.getParents().hasNext() )
        {
          Folder.addFile(file);
        }
      }
      // トークンを削除
      ScriptApp.deleteTrigger(trigger);
      UserProperties.deleteAllProperties();
      SendResult("処理終了\n" + Folder.getUrl());
    }
    
    function getSubFolder( baseFolder, subFolderName ) {
      var subFolders = baseFolder.getFoldersByName(subFolderName);
      if( subFolders.hasNext() )
      {
        return subFolders.next();
      }
      return baseFolder.createFolder(subFolderName);
    }
    
    function SendResult(MailBody){
      var address = Session.getActiveUser().getEmail();
      GmailApp.sendEmail(Session.getActiveUser().getEmail(), "フォルダに属していないファイルを探す", MailBody);
    }
    

    スクリプトの説明

    • Main関数はスタート用の関数。
    • FindLostFilesが時間主導トリガとして実行される。
    • スクリプト起動から4分程度でスクリプトを中断する。
    • 再開用のトリガはスクリプト起動時に設定するので中断時には設定不要。
    • 終了時にはファイルを集めたフォルダのURIと主にスクリプトの終了をメールで通知する。

    参考にした情報




    2015年1月17日土曜日

    Google Apps Scriptのファイル/フォルダ操作(2)

    同じパスのフォルダやファイルが複数存在可能なGoogleDriveで階層が深いフォルダを一発で指定したり、階層が深いフォルダを一回で作成するための関数を検討してみた。簡単な動作確認では思ったとおりに動作しているようだ。まったくオブジェクト志向ではないコードになってしまいました。
    /**
    * フォルダパスを指定してフォルダを生成する。
    *
    * @param {String} path フォルダパス
    * @param {Folder} base ベースフォルダ(省略時はルート)
    * @return {Folder} 生成したフォルダ。失敗時はnull。
    */
    function createFolder(path,base)
    {
    if(typeof base === 'undefined'){
    base = DriveApp.getRootFolder();
    }
    var splitpath = path.split("/");
    if( splitpath[0] == "" ){
    splitpath.splice(0,1);
    }
    if( splitpath[0] == "" ){
    base = DriveApp.getRootFolder();
    splitpath.splice(0,1);
    }
    var parent= new Array();
    var child=new Array();
    parent[0] = base;

    for( var level=0; level < splitpath.length && splitpath[level]!=""; level++ ){
    for( var i = 0; i<parent.length ; i++ ){
    var folders = parent[i].getFoldersByName(splitpath[level]);
    while( folders.hasNext() ){
    child.push( folders.next() );
    }
    }
    if( child.length == 0 ){
    child[0] = parent[0].createFolder( splitpath[level] );
    }
    parent = [];
    parent = [].concat(child);
    child=[];
    }
    return parent[0];
    }
    /**
    * フォルダパスを指定してフォルダを取得する。
    *
    * @param {String} path フォルダパス
    * @param {Folder} base ベースフォルダ(省略時はルート)
    * @return {Folder} ファイルパスを指定してファイルを取得する。失敗時はnull。
    */
    function getFoldersByPathName(path,base)
    {
    if(typeof base === 'undefined'){
    base = DriveApp.getRootFolder();
    }
    var splitpath = path.split("/");
    if( splitpath[0] == "" ){
    splitpath.splice(0,1);
    }
    if( splitpath[0] == "" ){
    base = DriveApp.getRootFolder();
    splitpath.splice(0,1);
    }
    var parent= new Array();
    var child=new Array();
    parent[0] = base;

    for( var level=0; level < splitpath.length && splitpath[level]!=""; level++ ){
    for( var i = 0; i<parent.length; i++ ){
    var folders = parent[i].getFoldersByName(splitpath[level]);
    while( folders.hasNext() ){
    child.push( folders.next() );
    }
    }
    if( child.length != 0 ){
    parent = [];
    parent = [].concat(child);
    child=[];
    }else{
    return null;
    }
    }
    return parent;
    }

    2015年1月12日月曜日

    Google Apps Scriptのファイル/フォルダ操作(1)

    GASでGoogle Driveのファイルにアクセスするときには少し癖がある。例えば、"ABC/DEF"フォルダにアクセスするために"DocsList.getFolder(path)"という関数が提供されており、"/"をセパレータとしてフォルダやファイルを指定することができる。
     var folder = DocsList.getFolder('ABC/DEF/GHI');
    しかし、GASのReferenceによるとこの関数は"Deprecated. This function is deprecated and should not be used in new scripts."となっている。Deprecatedになった理由を考えてみるとGoogle Driveの癖のある仕様に行き着く。 Windows(DOS)やLinixなどではPATHでファイル/フォルダを識別しているが、Google Driveでは同じフォルダに同じ名前のファイルやフォルダを作成することができるため、PATHを指定しても一つのファイル/フォルダを特定できないのだ。 そのため以下の様な構成も可能なのであり、'ABC/DEF/GHI'と指定しても(1)〜(4)のどのフォルダなのか特定することができない。
    ABC/
    DEF/
    GHI/ ・・・(1)
    GHI/ ・・・(2)
    DEF/
    GHI/ ・・・(3)
    GHI/ ・・・(4)
    Google Driveで一つのファイルやフォルダを特定するのはIDであり、パスではないので注意が必要だ。例えば、スクリプトのログをひとつのファイルに保存し続けたい場合などは注意が必要だ。確実に同じファイルにアクセスするためには一度作成したファイルのIDを保存しておきそのIDを用いてアクセスしなければならない。
    今後作成するスクリプトでログを残したくなることがあると思うので、まずはScript/Logフォルダにログファイルを保存する仕組みを考えていきたい。
     目標仕様としては
    • ログファイルIDをスクリプトのプロパティとして保存する。
    • 初回起動時などプロパティにログファイルIDが保存されていない時は指定されたパスに従いファイルを探す。
    • 指定されたパスのファイルが存在しなかった場合には新規ファイルを作成し、IDをプロパティに保存する。
    • 指定されたパスのファイルが存在しているときは最初に見つかったものを採用し、IDをプロパティに保存する。
    注意事項としては以下の構成で"Script/Log/yyyLog.TXT"を見つけることだ。
    (1)のScriptフォルダに入り、(2)のLogフォルダに入り、"yyyLog.TXT"を検索し見つからなかった場合、(2)のフォルダに"yyyLog.TXT"を作っていはいけない。(1)フォルダ下の検索が完了したら(3)フォルダ、(4)フォルダと検索しyyyLog.TXTを見つけなければならない。
    Script/ ・・・(1)
    Log/ ・・・(2)
    Script/ ・・・(3)
    Log/ ・・・(4)
    yyyLog.TXT

    仕様として考えなければいけないこととしては"yyyLog.txt"が存在しない時にどこにファイルを作成するかだ。
    案1:最初に見つかったフォルダに作成
    Script/ ・・・(1)
    Log/ ・・・(2)
    yyyLog.TXT
    Script/ ・・・(3)
    Log/ ・・・(4)
    案2:最後に見つかったフォルダに作成
    Script/ ・・・(1)
    Log/ ・・・(2)
    Script/ ・・・(3)
    Log/ ・・・(4)
    yyyLog.TXT
    実際には同じフォルダに同じ名前のファイル/フォルダを作成することはないのだが、しっかり考えて見ると面倒なことに気がついた、、、

    2015年1月5日月曜日

    Chromebook(Acer C720) 購入

    以前から興味があったChromebookを購入した。興味があったと言ってもどのメーカーからどのような機種が発売されているかなどは調べていなかったので、ヨドバシ・ドット・コムで適当に調べ、価格的にも安く、デザインも気に入ったAcer C720を32,180円で購入した。もしかしたらAmazonなどでもう少し安く買えるかもしれないが、調べないようにしている。
    初回起動は時間がかかったが、起動完了後はGoogleのアカウントとパスワードを入力するだけですぐに使用できた。しかもパソコンで使用しているChromeブラウザのテーマやお気に入りなどが引き継がれておりすぐに使用できた。

    DesktopパソコンにリモートデスクトップするのがChromebookを購入した目的の一つだったので、早々にChrome RDPをインストールして接続を試してみたが、つまらないくらい簡単に接続出来た。
    後はWakeup-On-Lanのアプリケーションがあれば良いのだが、まだ見つかっていない。

    iPhoneのテザリングも問題なく接続でき、L2TP/IPSecによるVPN接続も問題なく接続できた。リモートデスクトップ端末としては最適の選択肢だったと思う。


    2012年4月23日月曜日

    Toshiba Bluetooth StackでContinua

    Toshiba Bluetooth StackでContinua対応機器との通信するソフト開発について調べて見た。どうやらContinua対応機器とBluetoothで通信するにはHDP (Health Device Profile)に対応している必要があるようだ。

    Toshiba Bluetooth StackのVersionについて

    Toshiba Bluetooth PortalのNewsページによるとVer.7.00.10でHDPに対応し、Ver.7.10.10 でCountinuaのロゴを取得している。

    2010-03-19:First Continua Health Alliance certified Toshiba Bluetooth Stack version 7.10.10 released

    2009-10-22:New Toshiba Bluetooth Stack v7.00.10 with Windows 7 and HDP profile support released
    まずはToshiba Bluetooth StackのVer.7.10.10以降が必要そうなので、手持ちのPLANEX:BT-MicroEDR2Xについて調べてみた。Toshiba Bluetooth Stackを採用しているが、2009/09/04以降にドライバのアップデートがされていないし、マニュアルを見てもHDPに対応していないようなので、Countinuaのロゴを取得する前のバージョンのようだ。

    いろいろ探したところ、Toshiba Bloutooth PortalのDownloadsページからVer.8.00.12をダウンロードできそうだが、「For TOSHIBA notebooks」となっているのでライセンス的に使用できない。(たぶんPLANEX:BT-MicroEDR2Xでも動くと思うが、大人なので我慢)

    Bluetoothドングルについて

    Toshiba Bluetooth Stackが付属していてVer.7.10.10以降のアップデータを公開しているドングルを購入する必要がある。最近のBluetoothドングル(特にBluetooth3.0対応)はToshiba以外のStackを採用していることが多いようだ。
    「コンティニュア対応のBluetoothアダプター用最新ドライバー公開」という記事を発見したがToshibaスタックとは書かれていない。対応商品として以下の2つが紹介されていた。

    • Bluetooth2.1+EDR対応 USBアダプター(class1)BSHSBD02BK
    • Bluetooth2.1+EDR対応 USBアダプター(class2)BSHSBD03シリーズ
    それぞれのダウンロードページ(BSHSBD02BKBSHSBD03)を確認したところContinua対応と書かれている。Stack更新日以降マニュアルが更新されていないので、最新のStackがToshiba製かどうか不明だが、古いマニュアル(BSHSBD02BKBSHSBD03)ではToshiba製Stackの画面を用いて説明をしているので、Toshiba製Stackが付属していると考えて問題がないだろう。市場在庫が少なくなってきているようなので今のうちに入手したほうがよい、いそいで探さないと!!
    ついでにBluetooth3.0や4.0に対応しているBSHSBD04BK/BSHSBD05BK/BSHSBD08BKのマニュアルを確認したらToshiba製Stackではないようだ。

    Toshiba Bluetooth Stack Software Development Kit(SDK)について

    SDKの入手方法についてはToshiba Bloutooth PortalのKnowledgeページ「How to obtain the TOSHIBA Bluetooth stack SDK」に書かれている。SDKは無料だが"License Agreement for using SDK"に同意が必要、"License Agreement for using SDK"はhttps://aps2.toshiba-tro.de/bluetooth_sdk/Bluetooth.aspxからの申し込みが必要だとさ。めんどくさい、こんなんだからBluetoothはそれほどはやらないのか、、、、といっても東芝が得するビジネスモデルでもないからSDKをばら撒いても仕方がないのか?

    とりあえず、申し込んでみたが回答待ちだ。

    その他情報源

    閥努 閻怒 の報われぬ日々でToshiba Bluetooth Stackについて書かれていた。


    Bluetoothドングル、Ver.7.10.10以降のToshiba Bluetooth Stack、Toshiba Bluetooth Stack SDKがそろったらまたいろいろ調べよう。ところでSDKの開発環境はどうなっているのだろうか?Freeのコンパイラでも開発できるのか?

    2012年4月7日土曜日

    Nike+で異常なデータを探す方法

    iPhoneのNike+GPSアプリやNike+ SportWatch GPSなどで記録し、Nike+でデータの管理を行っている。今年の初めに自己最高記録を確認したら0'05"/KMになっていた。1キロを5秒って、はやっ!!
    Nike+ SportWatch GPSで記録した場合は精度よく記録されるが、iPhoneで記録した場合にはGPSの精度が悪いようだ。SportWatchは腕につけるのでGPSを捕らえやすいが、iPhoneはズボンのポケットに入れているのでGPSのを捕らえにくいのが原因かもしれない。
    このGPSの精度が悪い異常なRUNデータを削除することで異常な自己最高記録を直せることは容易に想像できたが、異常なRUNデータを探す方法がわからなかった。Nike+のサポートフォームから問い合わせを行うと、4回程度メールをやり取りした結果、異常データの探し方を教わることができた。

    (1)Nike+にログインする。
    (2)RUNデータを表示する。
    (3)ルート表示に切り替える。
    (4)画面下方にあるSPLITSに異常なペースが無いことを確認する。
    (5)ペース表示に切り替え、次の日に切り替える。
    ※ (3)~(5)を繰り返し異常なRUNデータを探す。


    結果として、0'05"/KMと0'44"/KMというデータがあったのでRUNデータを削除することで自己最高記録を修正することができた。130個程度のRUNデータだったのですべてを確認できたが、もう少し多かったらさすがあきらめていたかもしれない。もう少し操作性を改善してほしいところだ。

    問い合わせのやり取りの中で、サポートの方からNike+のアカウント名とパスワードを聞かれた、、、新鮮!?というかメールでアカウントとパスワードを同時に送信するという初体験だった。


    2012年4月6日金曜日

    勤務時間をGoogleカレンダーにメモするためのスクリプト

    勤務時間を簡単にメモするためのgoogle apps scriptを作成してみた。サービスとして公開し出社時、退社時に実行すればよい。実行結果の表示はもう少し工夫が必要。
    function doGet(e){

    var now = new Date();
    var begin = new Date(now);
    begin.setHours(0);
    begin.setMinutes(0);
    begin.setSeconds(0);

    // デフォルトのカレンダーを取得
    var cal = CalendarApp.getDefaultCalendar();

    var events = cal.getEvents( begin, now);
    for(var i=0; i<events.length; i++){
    if( events[i].getTitle() == "勤務中" ){
    var start = events[i].getStartTime();
    events[i].setTime( start, now );
    return retComment(e,"勤務時間を更新しました。",start, now);
    }
    }
    cal.createEvent("勤務中", now, now);
    return retComment(e,"出勤登録をしました。",now, now);
    }


    function retComment(e,comment,start,end){
    var app = UiApp.createApplication();
    var panel = app.createVerticalPanel();
    panel.add(app.createLabel(comment));
    panel.add(app.createLabel(" "+start));
    panel.add(app.createLabel(" "+end));
    app.add(panel);
    return app;
    }