前回、Cloud Text-to-SpeechというGoogleのサービスを利用して、Gmailで受け取っているメルマガを音声ファイル化してGoogle Driveに保存するGoogle Apps Script(以下GAS)を紹介しました。
このスクリプトですが、早速バグというかCloud Text-to-Speechの仕様で、1回のリクエストあたりに音声化できるテキストの文字数が5000文字という制限があって、この制限を超えるメルマガでエラーが出ましたので、こちらの修正を行いたいと思います。
前回の記事はこちら
今回の方針としては、5000文字ごとにテキストを分割して、それぞれに連番を付与して音声ファイル化していきたいと思います。
汎用的に使えるtext2Audio_関数
まず前回のdemoText2Audio関数をベースに汎用的に使えるtext2Audio_関数を作っていました。
/** テキストから音声ファイルを生成する関数
* @parama {string} text - 音声化するテキストファイル
* @parama {string} fileName - 生成するファイル名
* @parama {Object} folder - 音声ファイルの保存先のFolderオブジェクト
* @return {Object} file - グーグルドライブのFileオブジェクト
*/
function text2Audio_(text, fileName, folder) {
// 音声ファイル変換パラメーター
const objText = {
input: {
text: text
},
voice: {
languageCode: 'ja-JP', // 言語コードを指定
name: 'ja-JP-Standard-B' // 音声の種類を指定
},
audioConfig: {
audioEncoding: 'MP3', // エンコードフォーマットを指定
speakingRate: 1.3 // 音声の速度
}
}
const payload = JSON.stringify(objText);
const options = {
contentType: 'application/json; charset=utf-8',
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
payload: payload,
};
const url = 'https://texttospeech.googleapis.com/v1/text:synthesize';
const response = UrlFetchApp.fetch(url, options); // JSON文字列
const objSpeech = JSON.parse(response); // JSONオブジェクトへ変換
const decoded = Utilities.base64Decode(objSpeech.audioContent); // audioContentプロパティにbase64-encoded文字列が格納されている
const blob = Utilities.newBlob(decoded, 'audio/mpeg', fileName); // base64-encoded文字列をデコードしてblobオブジェクトを生成
return folder.createFile(blob); // blobオブジェクトからファイルを生成
}
このtext2Audio_関数の仮引数textで受け取る文字列の数をカウントして5000文字ごとに分割するという処理を加えても良かったのですが、今回は急いでいたので5000文字オーバーの本文を5000文字ごとに分割して、その分割した文字列ごとにtext2Audio_関数を実行するようにスクリプトを書いてみました。
5000文字ごとに本文を分割して音声化
まず、5000文字を超えるメール本文を5000文字ごとに分割します。これには、引数として与えた数以上の最小の整数を返すMathオブジェクトのceil()メソッドを使用して、いくつのセクションに分割すべきかを算出します。
const body = '5000文字以上のメール本文、仮に13000文字とすると';
const numSection = Math.ceil(body.length / 5000); // 3
彼にメール本文(body)が13000文字あったとすると5000文字づつ分割するには3つのセクションに分ける必要があります。
分割するセクション数がわかれば、for…in文を利用してセクション数の数だけ実行するループ処理を用意します。
for (let i = 0; i < numSection; i++) {
const section = body.slice(i * 5000, (i + 1) * 5000);
}
ここで登場するのは、文字列に対して使用できるslice()メソッドです。slice()メソッドは、第1引数に返却する部分文字列に含める最初の文字のインデックス(0スタート)を指定し、第2引数に返却する部分文字列から除外する最初の文字のインデックスを指定します。
ということで完成したコードはこちら。
function lonfMail2Audio() {
const body = '5000文字以上のメール本文、仮に13000文字とすると';
const numSection = Math.ceil(body.length / 5000); // 期待される出力3:メール本文の文字数を5000で割って、小数点を切り上げた整数に
for (let i = 0; i < numSection; i++) {
const section = body.slice(i * 5000, (i + 1) * 5000); // sliceメソッドで1-5000文字,5001-10000文字... とループ毎に部分取得
const fileName = `サンプル${i + 1}.mp3`; // サンプル1.mp3,サンプル2.mp3... と連番付与
/* 保存先フォルダを指定する */
const folder = DriveApp.getFolderById('フォルダID'); // 保存先フォルダID
/* 音声ファイル化する */
const file = text2Audio_(section, fileName, folder);
const fileUrl = file.getUrl();
console.log(fileUrl); // 保存されたファイルのURL
Utilities.sleep(1000); // ループごとに1秒休止させる
}
}
これで5000文字ごとに分割され、また生成されたファイル名にxx1,xx2と連番を付与することができます。
私はこの生成したファイルのURLを自分宛てにSlack通知するスクリプトをさらに書き加えています。