LoginSignup
27
8

More than 1 year has passed since last update.

スマホ中の写真 埋もれてない?

本記事は前回記事:3タップで完了するLINEフォトアルバム の続編です

スマホがこの世に誕生し、写真の撮影枚数はそれ以前の1,500倍に、
1スマホの中に少なくとも1,000枚以上の写真があるそうです。
①.PNG

せっかく撮影しても、整理できずにいませんか?。
思い出が埋もれたり、写真と一緒に消えてしまうのは悲しい。
とはいえ新たにアプリを使うのはめんどくさい。(ですよね?)

そこで・・・

プログラミングの「プ」の字も知らなかった初心者ですが、
日本一簡単操作のLINEフォトアルバムアプリを自分で作ります💪

写ルだけじゃなく残ルンです!! その名も「のこるん」ぜひ覚えて下さい♪

前回までの記事はこちら👇

最終ゴールはWEBアプリ 今はスプレッドシート

【目指すゴール】
LINEで写真とコメントを送ると、即アルバムが完成するwebアプリを作りたい。

【第1ステップ】
まずはLINEで送付された ①写真 と ②コメント の情報を取得し、
スプレッドシート上にデータ保存していく状態を目指しています。

②.PNG

第一ステップ「スプレッドシート上にデータを保存」のLINE操作と全体図です。

③.PNG

コメントが取得できない→解決!!

前回期の記事で、画像は取得できるものの
コメントを取得できず、スプレッドシートに画像しか保存できませんでした。

苦節数日。やっと解決し、LINE上の写真とコメントをシートに保存できるようになりました!!

うまくいかなかった前回の全体コード (クリックで表示)



// 応答メッセージURL
const REPLY = "https://api.line.me/v2/bot/message/reply";

// アクセストークン
const ACCESS_TOKEN = "********";

// スプレッドシート情報

const SHEET_ID   = '********';
const SHEET      = SpreadsheetApp.openById(SHEET_ID).getSheetByName('シート1');

// Google Drive ID
const GOOGLE_DRIVE_ID = "********";

// LINEから送られてきたデータを取得 doPost()
function doPost(e) {

  //メッセージ受信
  const data = JSON.parse(e.postData.contents).events[0];
  //ユーザーID取得
  const lineUserId = data.source.userId;
  // リプレイトークン取得
  const replyToken = data.replyToken;
  // 送信されたメッセージの種類を取得
  // https://developers.line.biz/ja/docs/messaging-api/message-types/#sticker-messages
  const postType = data.message.type;

  //コメント入力のために追加しているか箇所①
  const json = JSON.parse(e.postData.contents);
  const message = json.events[0].message.text; 
  const messageParameter = message.split(/\r\n|\n/);
  var lastRow = SHEET.getLastRow();
  //追加①ここまで

  // if文書き変え 写真の時データ取得
  if ( "image" === postType ) {
    imageSave(replyToken, lineUserId, data);

   //そうじゃない時はG2に文字入力

  } else {
      var lastRow = SHEET.getLastRow();
  SHEET.getRange('G' +  2).setValue(messageParameter[0]);
  }

  //書き変えここまで

}




// 送信された画像を保存 imageSave()
function imageSave(replyToken, lineUserId, data) {

  // LINEから画像取得 getImg()
  const imgData = getImg(data);

  // Googleドライブに保存 saveImg()
  const imgInfo = saveImg(imgData, lineUserId);

  // //「保存完了」とLINEにメッセージを送る
  sendMessage(replyToken, imgInfo);

}

// LINEから画像取得 getImg()
function getImg(data) {

  const IMG_URL = 'https://api-data.line.me/v2/bot/message/' + data.message.id + '/content';
  const HEAD = {
    "method":"get",
    "headers": {
      "Authorization" : "Bearer " + ACCESS_TOKEN
    }
  }
  const imgData = UrlFetchApp.fetch(IMG_URL, HEAD);
  return imgData;

}

// Googleドライブに保存 saveImg()
function saveImg(imgBinary, lineUserId){

  //GoogleDriveフォルダID
  const folder = DriveApp.getFolderById(GOOGLE_DRIVE_ID);
  //ランダムな文字列を生成して、画像のファイル名とする
  const fileName = Math.random().toString(36).slice(-8);
  //Googleドライブのフォルダに画像を生成
  const imageFile = folder.createFile(imgBinary.getBlob().setName(fileName));
  //「保存しました」としたメッセージを変数に代入
  const imgInfo = '保存したよ!https://docs.google.com/spreadsheets/d/1X8sR_aCzZydKSdAInkBZG9TcDeWInoq38TeTKRt9-KA/edit#gid=0';

  //画像ファイルURL取得
  const imageURL = 'https://drive.google.com/uc?export=view&id=' + imageFile.getId();

  //画像ファイルにリンクでアクセスの権限付与
  imageFile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);

  debugImgLog(imageURL, lineUserId);
  return imgInfo;

}

// スプレッドシートに画像を保存 debugImgLog()
function debugImgLog(text, userId) {

  if ('' == text) {
    return;
  }

  const date = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss')
  const userName = getUserDisplayName(userId)
  const userImg = getUserDisplayImg(userId)

  SHEET.appendRow([userId, userImg, userName, text, date,'=image("'+text+'")']);
  // 日付順に並び替え
  const numColumn = SHEET.getLastColumn(); // 最後列の列番号を取得
  const numRow    = SHEET.getLastRow()-1;  // 最後行の行番号を取得
  const dataRange = SHEET.getRange(2, 1, numRow, numColumn);
  dataRange.sort([{column: 5, ascending: false}]);

}

// ユーザーのプロフィール名取得 getUserDisplayName()
function getUserDisplayName(userId) {

  const url = 'https://api.line.me/v2/bot/profile/' + userId;
  const userProfile = UrlFetchApp.fetch(url,{
    'headers': {
      'Authorization' : 'Bearer ' + ACCESS_TOKEN,
    },
  })
  return JSON.parse(userProfile).displayName;

}

// ユーザーのプロフィール画像取得 getUserDisplayImg()
function getUserDisplayImg(userId) {

  const url = 'https://api.line.me/v2/bot/profile/' + userId;
  const userProfile = UrlFetchApp.fetch(url,{
    'headers': {
      'Authorization' :  'Bearer ' + ACCESS_TOKEN,
    },
  })
  return JSON.parse(userProfile).pictureUrl;

}

// LINEにメッセージ送信 sendMessage()
function sendMessage(replyToken, replyText) {

  const postData = {
    "replyToken" : replyToken,
    "messages" : [
      {
        "type" : "text",
        "text" : replyText
      }
    ]
  };

  const headers = {
    "Content-Type" : "application/json; charset=UTF-8",
    "Authorization" : "Bearer " + ACCESS_TOKEN
  };

  const options = {
    "method" : "POST",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  };

  return UrlFetchApp.fetch(REPLY, options);

}

改善① LINE上のメッセージ取得コードを変更

改善前のfunction doPost(e)の中身

  const json = JSON.parse(e.postData.contents);
  const message = json.events[0].message.text; 
  const messageParameter = message.split(/\r\n|\n/);
  var lastRow = SHEET.getLastRow();

改善後

 const userMessage = JSON.parse(e.postData.contents).events[0].message.text;

改善②if文の書き変え

改善前のif文

 if ( "image" === postType ) {
    imageSave(replyToken, lineUserId, data);
  } else {
      var lastRow = SHEET.getLastRow();
  SHEET.getRange('G' +  2).setValue(messageParameter[0]);
  }

改善後

if ( "image" === postType ) {
imageSave(replyToken, lineUserId, data);
} else {
SHEET.getRange('G' + 2).setValue(userMessage);
}

写真・コメントもLINE取得シート貼付成功コード (クリックで表示)



// 応答メッセージURL
const REPLY = "https://api.line.me/v2/bot/message/reply";

// アクセストークン
const ACCESS_TOKEN = "********";

// スプレッドシート情報

const SHEET_ID = '********';
const SHEET = SpreadsheetApp.openById(SHEET_ID).getSheetByName('シート1');

// Google Drive ID
const GOOGLE_DRIVE_ID = "********";

// LINEから送られてきたデータを取得 doPost()
function doPost(e) {

//メッセージ受信
const data = JSON.parse(e.postData.contents).events[0];
//ユーザーID取得
const lineUserId = data.source.userId;
// リプレイトークン取得
const replyToken = data.replyToken;
// 送信されたメッセージの種類を取得
// https://developers.line.biz/ja/docs/messaging-api/message-types/#sticker-messages
const postType = data.message.type;

//沖中追加①
const userMessage = JSON.parse(e.postData.contents).events[0].message.text;
//追加①ここまで

// 写真の時
if ( "image" === postType ) {
imageSave(replyToken, lineUserId, data);

} else {

SHEET.getRange('G' + 2).setValue(userMessage);
}

}

// 送信された画像を保存 imageSave()
function imageSave(replyToken, lineUserId, data) {

// LINEから画像取得 getImg()
const imgData = getImg(data);

// Googleドライブに保存 saveImg()
const imgInfo = saveImg(imgData, lineUserId);

// //「保存完了」とLINEにメッセージを送る
sendMessage(replyToken, imgInfo);

}

// LINEから画像取得 getImg()
function getImg(data) {

const IMG_URL = 'https://api-data.line.me/v2/bot/message/' + data.message.id + '/content';
const HEAD = {
"method":"get",
"headers": {
"Authorization" : "Bearer " + ACCESS_TOKEN
}
}
const imgData = UrlFetchApp.fetch(IMG_URL, HEAD);
return imgData;

}

// Googleドライブに保存 saveImg()
function saveImg(imgBinary, lineUserId){

//GoogleDriveフォルダID
const folder = DriveApp.getFolderById(GOOGLE_DRIVE_ID);
//ランダムな文字列を生成して、画像のファイル名とする
const fileName = Math.random().toString(36).slice(-8);
//Googleドライブのフォルダに画像を生成
const imageFile = folder.createFile(imgBinary.getBlob().setName(fileName));
//「保存しました」としたメッセージを変数に代入
const imgInfo = '保存したよ!https://docs.google.com/spreadsheets/d/1X8sR_aCzZydKSdAInkBZG9TcDeWInoq38TeTKRt9-KA/edit#gid=0';

//画像ファイルURL取得
const imageURL = 'https://drive.google.com/uc?export=view&id=' + imageFile.getId();

//画像ファイルにリンクでアクセスの権限付与
imageFile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);

debugImgLog(imageURL, lineUserId);
return imgInfo;

}

// スプレッドシートに画像を保存 debugImgLog()
function debugImgLog(text, userId) {

if ('' == text) {
return;
}

const date = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss')
const userName = getUserDisplayName(userId)
const userImg = getUserDisplayImg(userId)

SHEET.appendRow([userId, userImg, userName, text, date,'=image("'+text+'")']);
// 日付順に並び替え
const numColumn = SHEET.getLastColumn(); // 最後列の列番号を取得
const numRow = SHEET.getLastRow()-1; // 最後行の行番号を取得
const dataRange = SHEET.getRange(2, 1, numRow, numColumn);
dataRange.sort([{column: 5, ascending: false}]);

}

// ユーザーのプロフィール名取得 getUserDisplayName()
function getUserDisplayName(userId) {

const url = 'https://api.line.me/v2/bot/profile/' + userId;
const userProfile = UrlFetchApp.fetch(url,{
'headers': {
'Authorization' : 'Bearer ' + ACCESS_TOKEN,
},
})
return JSON.parse(userProfile).displayName;

}

// ユーザーのプロフィール画像取得 getUserDisplayImg()
function getUserDisplayImg(userId) {

const url = 'https://api.line.me/v2/bot/profile/' + userId;
const userProfile = UrlFetchApp.fetch(url,{
'headers': {
'Authorization' : 'Bearer ' + ACCESS_TOKEN,
},
})
return JSON.parse(userProfile).pictureUrl;

}

// LINEにメッセージ送信 sendMessage()
function sendMessage(replyToken, replyText) {

const postData = {
"replyToken" : replyToken,
"messages" : [
{
"type" : "text",
"text" : replyText
}
]
};

const headers = {
"Content-Type" : "application/json; charset=UTF-8",
"Authorization" : "Bearer " + ACCESS_TOKEN
};

const options = {
"method" : "POST",
"headers" : headers,
"payload" : JSON.stringify(postData)
};

return UrlFetchApp.fetch(REPLY, options);

}

LINEで写真・コメントを送付すると、スプレッドシートにデータを保存することに成功!!

image.png

せっかくなのでデザインも、アルバムっぽく整えました。「のこるん」いい感じ!

image.png

操作感の分かる動画はこちらです👇

いよいよ「のこるん」WEBアプリ化へ挑戦!!

スプレッドシートではやっぱり見にくいので、WEBアプリでの実装にトライします。

数か月前までプログラミングの「プ」も知らなかったのに、WEBアプリを作るなんて・・・

次回はAppSheetを使って、スプレッドシートからWEBアプリ化していきます♪
この先の挑戦もまた記事にします(*^^)vお楽しみに!!

最後に宣伝させてください。
私には『思い出を消さない未来を作りたい』という夢があります。

「のこるん」は夢の実現のための第一歩です。
どこまで実現できるか分かりませんが、1月中旬にはクラウドファンディングにも挑戦します!
「のこるん」誕生に向け、よければ応援してください!!(´ω`) ではまた次回の記事で!!

image.png

image.png
image.png

27
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
8