はじめに
ポートフォリオサイトを作っていて、今までに作成したGoogle Slidesの一覧ページをつくりたくなりました。
いわゆる「スライド共有サービス」というものもいくつかありますが、それらはスライドを画像やPDFに変換してからアップロードする必要があります。そのため、アニメーションや動画の埋め込みなどの表現は失われてしまいます。また、公開後にスライドを修正する場合には、修正の度に画像化とアップロードが必要になります。
それに対してGoogle Slidesは、Google Docsなどと同じように「ウェブに公開」することができます。「ウェブに公開」することで、以下のような共有URLが発行されます。
docs.google.com
「ウェブに公開」機能を使ってスライドの共有をすれば、スライドの表現も失われず、修正もそのまま反映されます。
今回は、このGoogle Slidesの共有URLをサムネイル付きで一覧表示するWebページを作ってみました。
https://w-haibara.com/#/slides

要件定義
スライド一覧ページを作るにあたって、以下の要件を定義しました。
- スライドの表現(アニメーション・動画埋め込みなど)が失われない
- 公開後の修正が簡単
- 一覧ページへスライドを登録する手順が簡単
- スライドのサムネイルを表示できる
- 既存のポートフォリオサイト(Vue.js製)に埋め込める
スライドの表現が失われない・公開後の修正が簡単
これらはGoogle Slidesを使えば満たすことができます。
一覧ページへスライドを登録する手順が簡単
Google Drive上に公開用のフォルダを作り、一覧ページで公開したいスライドはそのフォルダに入れることにしました。これなら一覧ページへの登録・解除は簡単です。ここで、何らかの方法で「Google Drive上の特定のフォルダ内のスライドの情報を取得する」必要があります。これはGASで実装することにしました。やはり餅は餅屋です。
スライドのサムネイルを表示できる
GASのgetThumbnailメソッドを使います。これは、Google Drive上のファイルのサムネイルを取得するものです。
Class File | Apps Script | Google Developers
このメソッドの返り値はBlobというGAS独自のオブジェクトなので、これをbase64でエンコードしてフロントに返すようにしました。GASのBlobについては以下の記事が参考になりました。
GAS の Blob とファイル変換まとめ - Qiita
GAS側の実装
GASのコードは以下のようになります。
// HTTP GETリクエストで発火
function doGet(){
// 公開用フォルダ内のファイル情報を取得
let data = [];
const files = DriveApp.getFolderById("<公開用フォルダのID>").getFiles();
while (files.hasNext()) {
const file = files.next();
data.push({
"name": file.getName(), // ファイル名
"url": file.getUrl(), // 共有URL
"created": file.getDateCreated(), // ファイル作成日時
"thumbnail": blob2base64(file.getThumbnail()), // サムネイル画像(base64)
});
}
// ファイルの作成日時が新しい順にソート
data.sort(function(a, b){
if( a.created > b.created ) return -1;
if( a.created < b.created ) return 1;
return 0;
});
// dataをjsonとして返す
const json = JSON.stringify(data);
const output = ContentService.createTextOutput(json);
output.setMimeType(ContentService.MimeType.JSON);
return output;
}
// blob から base64 image への変換
function blob2base64(blob) {
const contentType = blob.getContentType();
const base64Data = Utilities.base64Encode(blob.getBytes());
// 単にbase64エンコーディングするだけでなく、ヘッダも必要
return "data:" + contentType + ";base64," + base64Data;
}
Vue.js側の実装
Vue.jsのコードは以下のようにしました。
portfolio/Slides.vue at main · w-haibara/portfolio · GitHub
<template>
<v-sheet class="blue-grey--text text--darken-4" height="100%" tile>
<v-container>
<h1 class="font-weight-medium">Slides</h1>
<div v-if="!slidesLoaded">
<v-progress-linear
indeterminate
color="blue-grey darken-5"
bottom
></v-progress-linear>
</div>
<div v-else>
<v-layout wrap>
<v-flex v-for="slide in slides" :key="slide.url">
<v-hover>
<template v-slot="{ hover }">
<v-card
:class="`elevation-${hover ? 4 : 0}`"
class="transition-swing my-1"
flat
tile
color="grey lighten-4"
width="24vw"
:href="slide.url"
target="_blank"
rel="noopener"
>
<v-img :src="slide.thumbnail"></v-img>
<v-card-title>
<span>
{{ slide.name }}
<v-icon color="blue-grey darken-5" x-small right>
fas fa-external-link-alt
</v-icon>
</span>
</v-card-title>
<v-card-text>
{{ slide.created }}
</v-card-text>
</v-card>
</template>
</v-hover>
</v-flex>
</v-layout>
</div>
</v-container>
</v-sheet>
</template>
<script>
export default {
data: () => ({
slides: {
id: {
name: "",
created: "",
thumbnail: "",
url: "",
},
},
slidesLoaded: false,
}),
created() {
this.axios
.get(
"<GASでウェブアプリケーションとして公開したURL>"
)
.then((response) => {
this.slides = response.data;
this.slidesLoaded = true;
});
},
};
</script>
おわりに
こういうときにGASは便利ですねー。