tanaike - Google Apps Script, Gemini API, and Developer Tips

The Thinker

Updated ggsrun to v141

ggsrun was updated to v.1.4.1

  • v1.4.1 (February 9, 2018)
    1. For uploading, the resumable-upload method was added.
      • The resumable-upload method is automatically used by the size of file.
        • “multipart/form-data” can upload files with the size less than 5 MB.
        • “resumable-upload” can upload files with the size more than 5 MB.
      • The chunk for resumable-upload is 100 MB as the default.
        • Users can also give this chunk size using an option.
      • $ ggsrun u -f filename -chunk 10
        • This means that a file with filename is uploaded by each chunk of 10 MB.

You can read “How to install” at here.

Copying Values from JSON to Struct using reflect Package

Gists

This is a sample script for copying values from JSON to a struct using reflect package.

Script :

package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)

type obj struct {
	Key1 string `json:"k1"`
	Key2 string `json:"k2"`
	Key3 int64  `json:"k3"`
	Key4 int    `json:"k4"`
	Key5 bool   `json:"k5"`
}

func main() {
	data := `{"k1": "v1", "k2": "v2", "k3": 1234567890, "k4": 456, "k5": true}`
	d := map[string]interface{}{}
	json.Unmarshal([]byte(data), &d)
	obj := &obj{}
	s := reflect.ValueOf(obj).Elem()
	typeOfT := s.Type()
	for i := 0; i < s.NumField(); i++ {
		for j, f := range d {
			if typeOfT.Field(i).Tag.Get("json") == j {
				fl := s.FieldByName(typeOfT.Field(i).Name)
				switch fl.Kind() {
				case reflect.Bool:
					fl.SetBool(f.(bool))
				case reflect.Int, reflect.Int64:
					c, _ := f.(float64)
					fl.SetInt(int64(c))
				case reflect.String:
					fl.SetString(f.(string))
				}
			}
		}
	}
	fmt.Printf("%+v\n", obj) // &{Key1:v1 Key2:v2 Key3:1234567890 Key4:456 Key5:true}
}

Result :

&{Key1:v1 Key2:v2 Key3:1234567890 Key4:456 Key5:true}

The Go Playground

https://play.golang.org/p/Rz-GNbFyDfh

Parsing JSON object (keys are number and changing every time)

Gists

This sample script is for parsing JSON object. In the object, the keys are number and changing every time.

Object:

{
    "key1": {
        "key2": [
            {"0": [{"key3": "value3a"}, {"key3": "value3b"}]},
            {"1": [{"key3": "value3c"}, {"key3": "value3d"}]}
        ]
    }
}

Script:

package main

import (
    "encoding/json"
    "fmt"
    "strconv"
)

type key1 struct {
    Key1 key2 `json:"key1"`
}

type key2 struct {
    Key2 []interface{} `json:"key2"`
}

func main() {
    data := `{"key1": {"key2": [{"0": [{"key3": "value3a"}, {"key3": "value3b"}]},{"1": [{"key3": "value3c"}, {"key3": "value3d"}]}]}}`
    k1 := &key1{}
    json.Unmarshal([]byte(data), &k1)
    for i, e := range k1.Key1.Key2 {
        if key, ok := e.(map[string]interface{})[strconv.Itoa(i)].([]interface{}); ok {
            for _, f := range key {
                fmt.Printf("%+v\n", f.(map[string]interface{})["key3"])
            }
        }
    }
}

Result:

value3a
value3b
value3c
value3d

The Go Playground

https://play.golang.org/p/xm2KvgOIkKH

Adding a Label to a Message using Message ID for Gmail

Gists

These are sample scripts for adding a label to a message using message ID for Gmail.

Sample 1

This sample adds a label to a thread using message ID. In this case, all messages in the thread have the label. Even if it adds a label to a message in the thread using addLabel(), all messages in the thread have the label, becauce addLabel can only be used for the thread.

How to Retrieve Replied Emails for Gmail

Gists

Description :

This sample script is for retrieving emails which replied for received mails. Because there are no samples which confirm whether the owner (me) replied to the received mails, I created this. The point is as follows.

  • When there are more than 2 messages in a thread, there might be a possibility to have replied.
  • For more than 2 messages in a thread
    • The email address of “from” for the 1st message is the sender’s address.
    • When the email address of “to” of after 2nd messages is the same to that of “from” of 1st one, it is indicates that the thread was replied by owner.

This sample script is made of Google Apps Script (GAS). But also this can be applied to other languages.

Updated: GAS Library - ManifestsApp

ManifestsApp was updated to v1.0.2.

  • v1.0.2 (January 29, 2018)

    • ProjectApp2 is published, and got to be able to use both standalone script type and container-bound script type.
      • By this, this library also got to be able to be used for the both projects.
    • For this update, please enable Apps Script API.

You can check this at https://github.com/tanaikech/ManifestsApp.

GAS Library - ProjectApp2

Overview

This is a GAS project library for Google Apps Script (GAS). This library can be used for the projects of both standalone script type and container-bound script type.

Description

There are Class SpreadsheetApp and Class DocumentApp for operating spreadsheet and document, respectively. But there is no Class for operating GAS project. If there is such Class ProjectApp, GAS project can be directly operated by GAS script. I thought that this will lead to new applications, and created ProjectApp. On the other hand, as a CLI tool for operating GAS project, there has already been ggsrun.

google.script.run and jQuery.Deferred

google.script.run doesn’t return values. So I tried this using jQuery.Deferred.

GAS : Code.gs

function doGet() {
  return HtmlService.createHtmlOutputFromFile('index')
      .setSandboxMode(HtmlService.SandboxMode.IFRAME);
}

function getValues(e) {
  return e + "hoge";
}

HTML : index.html

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<body>
  <input type="button" id="button" value="ok">
  <div id="result"></div>

  <script>
    $(() => {
      $("#button").click(() => {
        var str = "fuga";
        googleScriptRun(str).then((res) => {
          $('#result').text(res);
        });
      });
    });

    function googleScriptRun(str) {
      var d = new $.Deferred();
      google.script.run.withSuccessHandler((res) => {d.resolve(res)}).getValues(str);
      return d.promise();
    }
  </script>
</body>

Result :

fugahoge

Above sample can be also written as follows.

Updated ggsrun to v140

ggsrun was updated to v.1.4.0

You can read “How to install” at here.