Homebrew v0.2.0 [Release][Guide] Line for 3DS

Core_2_Extreme

Well-Known Member
OP
Member
Joined
Feb 11, 2019
Messages
153
Trophies
0
Age
22
XP
1,163
Country
Japan
Line for 3DS

Discord channel : https://discord.gg/Zmx7Euf

Dead link in SETUP.md has been fixed, so version number in links were changed to v2.0.0.1.
Software (source code) is identical to v2.0.0

From v2.0.0, setup instructions have been moved to github.

You can find the link below.

v2.0.0
  • Line
    • Significant changes for internal code, so you need to setup your Google Apps Script again.
    • Setup instructions are updated.
    • 3DS
      • Chat log wrapping feature has been improved a lot.
      • Auto update feature (for chat logs) are removed temporary.
      • Clear cache feature (for downloaded files) are removed temporary.
    • Google Apps Script
      • Self tests are added so that it is much easier to trouble shoot.
  • Camera
    • Supported QR code scan (currently, only for Google Apps Script setup).
  • Video player
  • Overall
    • Application folder has been changed from /Line/ to /3ds/Line/ (old folder won't be deleted automatically, but you can delete it if you don't need it).
    • Sub application icon has been added.

Setup instructions : https://github.com/Core-2-Extreme/Line_for_3DS/blob/v2.0.0.1/SETUP.md
Download : https://github.com/Core-2-Extreme/Line_for_3DS/releases/tag/v2.0.0.1


menu.png
chat.png


Send text : Yes✅
Send stickers : Yes✅ (Only package ID 11537, 11538 and 11539 in sticker definitions are supported for now.)
Send pictures : Yes✅ (Up to 37.5MB per picture.)
Send videos : Yes✅ (Up to 37.5MB per picture.)
Send audio : Yes✅ (Up to 37.5MB per picture.)
Send files : Yes✅ (Up to 37.5MB per picture.)
View old chat logs : Yes✅ (Up to 4000 chat logs.)
Auto log update : No❌ (Temporary removed due to technical issues.)
Receive text : Yes✅
Receive stickers : Yes✅ (Only package ID 11537, 11538 and 11539 in sticker definitions are displayed for now.)
Receive pictures : Yes✅ (Very large images may not be displayed especially on OLD3DS.)
Receive audio : Yes✅
Receive videos : Yes✅ (Some videos may not be played at full speed or at all especially on OLD3DS.)
Direct message : Yes✅
Group chat : Yes✅ (If "Allow bot to join group chat" feature in LINE developer page (see Create your LINE BOT step 6) is enabled.)
Open chat : No❌
Voice call : No❌
Night mode : Yes✅

It is NOT recommended to use older version (and no supports exist for older versions).
If you really need to use older version, archived old guide is below :
Please open this site.
https://developers.line.biz/en/
Click log in.
Click Log in with LINE account.
Click Create.

43147207b4eb4e1684a075e305cb67a2.png
Type your name and click Create.
9cc90ea609fef8352e3bca436c3dfadb.png
Click Create a Messaging API channel.
2394c4de74d3c34c186f373a02b3f2f6.png
Type each item and click Create.
e611043d9c7da0be833f17bd36e62bc5.png
Click Messaging API.

73774f8d71e0ca5756e72fda20f94ebd.png

Find Channel access token (long-lived) and click Issue.
Then copy Channel access token (long-lived).

15ffd7c288cbf6ab5144158f5402e3a5.png

Please open this site.
https://www.google.com/intl/en_ALL/drive/
Click Go to google drive and login.
Click New and click Google sheets(1 time) and click More -> Google apps script (1 time).

5a603a93e5c14227b22e3bd661c43016.png


Open created Google sheets and copy sheet id.(DO NOT INCLUDE '/' )
f22b2c7b64acf04808a118983f744685.png


Open created Google apps script and Insert name.("Line main" in this guide)
cf714d96090d736cb42a24b7a8997deb.png

Copy this code to "Line main" and add your sheet ID, access token, client(3DS's ) account name(Your favorite name) and script password(if you want).

For ver 1.7.0For ver 1.6.0For ver 1.5.0~1.5.2


  1. This code compatible with ver 1.7.0
    2021/01/24 Edited : fixed unable to receive images, audio, videos and files.
    2022/08/21 Edited : fixed unable to receive messages on 3DS.
    2023/10/25 Edited : fixed some typo.
    Code:
    var ACCESS_TOKEN = "Your acces token here";
    var OPEN_SHEET_ID = "Your sheet id here";
    var SCRIPT_PASSWORD = "Your google apps script password here";
    var CLIENT_NAME = "Your 3ds's account name here";
    
    var gas_ver = 7;//Do **NOT** edit this value.
    function log_save(message, user_name, write_sheet_name, group_or_user_name, pic_url, msg_id)
    {
        var google_pic_url;
        var previous_pic_url;
        var response;
        var sheet_pos = 1;
        var spreadsheet = SpreadsheetApp.openById(OPEN_SHEET_ID);
        var write_sheet = spreadsheet.getSheetByName(write_sheet_name);
    
        if (!write_sheet)
        {
            spreadsheet.insertSheet(write_sheet_name);
            write_sheet = spreadsheet.getSheetByName(write_sheet_name);
        }
    
        sheet_pos = get_cache_pos(write_sheet);
    
        while (true)
        {
            var sheet_data = write_sheet.getRange("A" + sheet_pos).getValue();
    
            if (sheet_data == "")
            {
                write_sheet.getRange("A" + sheet_pos).setValue("\u007F" + user_name + " : " + message);
                write_sheet.getRange("C" + sheet_pos).setValue(msg_id);
                break;
            }
            else
                sheet_pos++;
        }
    
        write_cache_data(write_sheet, (sheet_pos + 1), "B1");
        if (group_or_user_name != "Do not save")
            write_cache_data(write_sheet, group_or_user_name, "B2");
    
        if (pic_url != "Do not save")
        {
            previous_pic_url = get_previous_pic_url(write_sheet);
            if (previous_pic_url != pic_url)
            {
                response = UrlFetchApp.fetch(pic_url,
                    {
                        'headers': {
                            'Content-Type': 'application/json; charset=UTF-8',
                            'Authorization': 'Bearer ' + ACCESS_TOKEN,
                        },
                        muteHttpExceptions: true,
                    });
    
                if (response.getResponseCode() == 200)
                {
                    google_pic_url = get_profile_pic_google_url(response, write_sheet_name);
                    write_cache_data(write_sheet, google_pic_url, "B3");
                    write_cache_data(write_sheet, pic_url, "B4");
                }
            }
        }
    }
    
    function unsend_msg(sheet_id, msg_id)
    {
        var spreadsheet = SpreadsheetApp.openById(OPEN_SHEET_ID);
        var write_sheet = spreadsheet.getSheetByName(sheet_id);
        var sheet_pos = 1;
    
        if (!write_sheet)
        {
            spreadsheet.insertSheet(sheet_id);
            write_sheet = spreadsheet.getSheetByName(sheet_id);
        }
    
        while (true)
        {
            var sheet_data = write_sheet.getRange("C" + sheet_pos).getValue();
    
            if (sheet_data == msg_id)
            {
                write_sheet.getRange("A" + sheet_pos).setValue("\u007F*****This message was unsent by user*****");
                break;
            }
            else
                sheet_pos++;
        }
    }
    
    function check_folder_exist(input_folders, name)
    {
        var folder;
        while (input_folders.hasNext())
        {
          folder = input_folders.next();
          if(name == folder.getName())
            return folder;
        }
        return undefined;
    }
    
    function log_read(id, num_of_logs)
    {
      var sheet_offset = 1;
      var sheet_start = 1;
      var return_data;
      var sheet_data;
      var spreadsheet = SpreadsheetApp.openById(OPEN_SHEET_ID);
      var read_sheet = spreadsheet.getSheetByName(id);
      if(!read_sheet)
        return "No such sheet.\nPlease duoble check your ID.";
    
      sheet_start = get_cache_pos(read_sheet);
    
      while(true)
      {
        sheet_data = read_sheet.getRange("A" + sheet_start).getValue();
        if(sheet_data == "")
        {
          write_cache_data(read_sheet, sheet_start, "B1");
          if(sheet_start > num_of_logs)
            sheet_start = (sheet_start - num_of_logs);
          else
            sheet_start = 1;
    
          break;
        }
        else
          sheet_start++;
      }
    
      sheet_offset = sheet_start;
      sheet_data = read_sheet.getRange(sheet_start, 1, num_of_logs).getValues();
      return_data = "<0>";
      for(var i = 0; i < num_of_logs; i++)
      {
        if(sheet_data[i] == "")
          break;
    
        return_data += sheet_data[i];
        sheet_offset++;
      }
    
      return_data += "</0>";
      return_data += "<1>" + get_cache_name(read_sheet) + "</1>";
      return_data += "<2>" + get_google_pic_url(read_sheet) + "</2>";
      return_data += "<3>" + sheet_offset + "</3>";
      return_data += "<4>Success</4>";
      return return_data;
    }
    
    function get_cache_pos(sheet_object)
    {
      var cached_sheet_pos = sheet_object.getRange("B1").getValue();
      var sheet_data;
    
      if(parseInt(cached_sheet_pos) > 0)
      {
        cached_sheet_pos = parseInt(cached_sheet_pos);
        sheet_data = sheet_object.getRange("A" + (cached_sheet_pos - 1)).getValue();
    
        if(sheet_data != "")
          return cached_sheet_pos;
      }
      return 1;
    }
    
    function get_cache_name(sheet_object)
    {
      var cached_name = sheet_object.getRange("B2").getValue();
      return cached_name;
    }
    
    function get_google_pic_url(sheet_object)
    {
        var cached_name = sheet_object.getRange("B3").getValue();
        return cached_name;
    }
    
    function get_previous_pic_url(sheet_object)
    {
        var cached_name = sheet_object.getRange("B4").getValue();
        return cached_name;
    }
    
    function write_cache_data(sheet_object, cache_data, pos)
    {
      sheet_object.getRange(pos).setValue(cache_data);
    }
    
    function http_get_content(request_id)
    {
      var response;
      var url = "https://api-data.line.me/v2/bot/message/" + request_id + "/content";
      response = UrlFetchApp.fetch(url,
      {
      'headers': {
        'Content-Type': 'application/json; charset=UTF-8',
        'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_get_user_name(id)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/profile/' + id;
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_get_group_user_name(id, group_id)
    {
      var response;
      var url = "https://api.line.me/v2/bot/group/" + group_id + "/member/" + id + "/";
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_get_group_name(group_id)
    {
      var response;
      var url = "https://api.line.me/v2/bot/group/" + group_id +"/summary/";
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_text_reply(reply_token, send_msg)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/reply/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
          'replyToken': reply_token,
          'messages': [{
            'type': 'text',
            'text': send_msg ,
          }],
          'notificationDisabled': 'true',
        }),
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_text(id, send_msg)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/push/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
      "to": id,
      "messages":
           [{
              "text": send_msg,
              "type": "text",
           }],
          'notificationDisabled': 'false',
        }),
       muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_sticker(id, package_id, sticker_id)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/push/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
      "to": id,
      "messages":
           [{
              "type": "sticker",
              "packageId": package_id,
              "stickerId": sticker_id,
           }],
          'notificationDisabled': 'false',
        }),
       muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_image(id, img_url, preview_url)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/push/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
      "to": id,
      "messages":
           [{
              "type": "image",
              "originalContentUrl": img_url,
              "previewImageUrl": preview_url,
           }],
          'notificationDisabled': 'false',
        }),
       muteHttpExceptions: true,
      });
      return response;
    }
    
    function send_msg(id, send_message, time)
    {
      var cache;
      var response;
      var return_message = "Success";
    
      response = http_send_text(id, send_message);
      if(response.getResponseCode() != 200)
      {
        cache = "***The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message + "*** ";
        cache += send_message;
        send_message = cache;
        return_message = "The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
      }
    
      send_message += "(" + time + ")";
      log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
      return return_message;
    }
    
    function send_sticker(id, package_id, sticker_id, time)
    {
      var response;
      var return_message = "Success";
      var send_message = "";
    
      response = http_send_sticker(id, package_id, sticker_id);
      if(response.getResponseCode() != 200)
      {
       send_message = "***The sticker failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
       return_message = "The sticker failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
      }
      send_message += "<sticker>" + sticker_id + "</sticker>(" + time + ")";
      log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
      return return_message;
    }
    
    function get_cache_data(id, cache_name, last_data)
    {
      var byte_data;
      var cache_data = "";
      var cache_data_1 = "";
      var cache_file;
      var cache_folder;
      var exist_cache_folders;
      var exist_folders;
      var exist_sub_folders;
      var folder;
      var folder_name = "Line_contents";
      var sub_folder;
    
      exist_folders = DriveApp.searchFolders("'me' in owners");
      folder = check_folder_exist(exist_folders, folder_name);
      if(folder == undefined)
        return undefined;
    
      exist_sub_folders = folder.searchFolders("'me' in owners");
      sub_folder = check_folder_exist(exist_sub_folders, id);
      if(sub_folder == undefined)
        return undefined;
    
      exist_cache_folders = sub_folder.searchFolders("'me' in owners");
      cache_folder = check_folder_exist(exist_cache_folders, cache_name);
      if(cache_folder == undefined)
        return undefined;
    
      for(var i = 0; i < 4096; i++)
      {
        try
        {
          cache_file = cache_folder.getFilesByName(i).next();
          cache_data += cache_file.getBlob().getDataAsString();
        }
        catch(error)
        {
          break;
        }
      }
    
      cache_data += last_data;
      cache_folder.setTrashed(true);
      return cache_data;
    }
    
    function upload_content(id, data, count, cache_name, last, time, data_type)
    {
      var cache_data;
      var cache_folder;
      var exist_cache_folders;
      var exist_folders;
      var exist_sub_folders;
      var folder;
      var folder_name = "Line_contents";
      var part_of_content;
      var part_of_content_data;
      var return_message = "Success";
      var send_message;
      var sub_folder;
    
      if(count == 0 && last == "true")
        return_message = send_content(id, cache_name, time, data, data_type);
      else if(last == "true")
      {
          cache_data = get_cache_data(id, cache_name, data);
          if(cache_data == undefined)
          {
            send_message = "***The content failed to send. The cache folder does not exist.*** (" + time + ")";
            log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
            return_message = "The content failed to send.\nThe cache folder does not exist.";
          }
          else
            return_message = send_content(id, cache_name, time, cache_data, data_type);
      }
      else
      {
        exist_folders = DriveApp.searchFolders("'me' in owners");
        folder = check_folder_exist(exist_folders, folder_name);
        if(folder == undefined)
          folder = DriveApp.createFolder(folder_name);
    
        exist_sub_folders = folder.searchFolders("'me' in owners");
        sub_folder = check_folder_exist(exist_sub_folders, id);
        if(sub_folder == undefined)
          sub_folder = folder.createFolder(id);
    
        exist_cache_folders = sub_folder.searchFolders("'me' in owners");
        cache_folder = check_folder_exist(exist_cache_folders, cache_name);
        if(cache_folder == undefined)
          cache_folder = sub_folder.createFolder(cache_name);
        else if(!(cache_folder == undefined) && count == 0)
        {
          cache_folder.setTrashed(true);
          cache_folder = sub_folder.createFolder(cache_name);
        }
    
        part_of_content_data = Utilities.newBlob(data).setName(count);
        part_of_content = cache_folder.createFile(part_of_content_data);
      }
      return return_message;
    }
    
    function send_content(id, cache_name, time, encoded_data, data_type)
    {
      var content;
      var content_data;
      var content_type;
      var content_url = "";
      var exist_folders;
      var exist_sub_folders;
      var folder;
      var folder_name = "Line_contents";
      var preview_content_url = "";
      var response;
      var return_message = "Success";
      var send_message = "";
      var sub_folder;
    
      exist_folders = DriveApp.searchFolders("'me' in owners");
      folder = check_folder_exist(exist_folders, folder_name);
      if(folder == undefined)
        folder = DriveApp.createFolder(folder_name);
    
      exist_sub_folders = folder.searchFolders("'me' in owners");
      sub_folder = check_folder_exist(exist_sub_folders, id);
      if(sub_folder == undefined)
        sub_folder = folder.createFolder(id);
    
      try
      {
        content_data = Utilities.newBlob(Utilities.base64Decode(encoded_data)).setName(cache_name);
      }
      catch (e)
      {
        return_message = "The content failed to send.\nCouldn't decode base64 data.";
        return return_message;
      }
    
      content = sub_folder.createFile(content_data);
      content_type = content.getMimeType();
      if(content_type == MimeType.BMP || content_type == MimeType.GIF || content_type == MimeType.JPEG || content_type == MimeType.PNG || content_type == MimeType.SVG)
      {
        content.setTrashed(true);
        folder_name = "Line_images";
        exist_folders = DriveApp.searchFolders("'me' in owners");
        folder = check_folder_exist(exist_folders, folder_name);
        if(folder == undefined)
          folder = DriveApp.createFolder(folder_name);
    
        exist_sub_folders = folder.searchFolders("'me' in owners");
        sub_folder = check_folder_exist(exist_sub_folders, id);
        if(sub_folder == undefined)
          sub_folder = folder.createFolder(id);
    
        content = sub_folder.createFile(content_data);
        content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
        content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
        preview_content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w240-h240";
    
        response = http_send_image(id, content_url, preview_content_url);
        if(response.getResponseCode() != 200)
        {
          send_message = "***The image failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
          return_message = "The image failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
        }
        send_message += "<image_url>" + content_url + "</image_url>(" + time + ")";
        log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
        return return_message;
      }
      else if(data_type == "audio")
      {
        content.setTrashed(true);
        folder_name = "Line_audio";
        exist_folders = DriveApp.searchFolders("'me' in owners");
        folder = check_folder_exist(exist_folders, folder_name);
        if(folder == undefined)
          folder = DriveApp.createFolder(folder_name);
    
        exist_sub_folders = folder.searchFolders("'me' in owners");
        sub_folder = check_folder_exist(exist_sub_folders, id);
        if(sub_folder == undefined)
          sub_folder = folder.createFolder(id);
    
        content = sub_folder.createFile(content_data);
        content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
        content_url = "https://docs.google.com/uc?id=" + content.getId();
        response = http_send_text(id, content_url + " (audio)");
        if(response.getResponseCode() != 200)
        {
          send_message = "***The audio failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
          return_message = "The audio failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
        }
    
        content_url = "https://drive.google.com/uc?export=download&id=" + content.getId();
        send_message += "<audio_url>" + content_url + "</audio_url>(" + time + ")";
        log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
        return return_message;
      }
      else if(data_type == "video")
      {
        content.setTrashed(true);
        folder_name = "Line_videos";
        exist_folders = DriveApp.searchFolders("'me' in owners");
        folder = check_folder_exist(exist_folders, folder_name);
        if(folder == undefined)
          folder = DriveApp.createFolder(folder_name);
    
        exist_sub_folders = folder.searchFolders("'me' in owners");
        sub_folder = check_folder_exist(exist_sub_folders, id);
        if(sub_folder == undefined)
          sub_folder = folder.createFolder(id);
    
        content = sub_folder.createFile(content_data);
        content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
        content_url = "https://docs.google.com/uc?id=" + content.getId();
        response = http_send_text(id, content_url);
        if(response.getResponseCode() != 200)
        {
          send_message = "***The video failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
          return_message = "The video failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
        }
    
        content_url = "https://drive.google.com/uc?export=download&id=" + content.getId();
        send_message += "<video_url>" + content_url + "</video_url>(" + time + ")";
        log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
        return return_message;
      }
      else
      {
        content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
        content_url = "https://drive.google.com/file/d/" + content.getId() + "/view";
        response = http_send_text(id, content_url);
        if(response.getResponseCode() != 200)
        {
          send_message = "***The content failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
          return_message = "The content failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
        }
        content_url = "https://drive.google.com/uc?export=download&id=" + content.getId();
        send_message += "<content_url>" + content_url + "</content_url>(" + time + ")";
        log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
        return return_message;
      }
    }
    
    function get_profile_pic_google_url(http_response, group_or_user_id)
    {
        var content_data;
        var content;
        var folder_name = "Line_images";
        var folder;
        var sub_folder;
        var exist_folders;
        var exist_sub_folders;
        var url = "";
    
        exist_folders = DriveApp.searchFolders("'me' in owners");
        folder = check_folder_exist(exist_folders, folder_name);
        if (folder == undefined)
            folder = DriveApp.createFolder(folder_name);
    
        exist_sub_folders = folder.searchFolders("'me' in owners");
        sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
        if (sub_folder == undefined)
            sub_folder = folder.createFolder(group_or_user_id);
    
        content_data = http_response.getBlob().getAs("image/jpeg").setName("icon");
        content = sub_folder.createFile(content_data);
        content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
        url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w32-h32";
    
        return url;
    }
    
    function get_content_url(request_id, group_or_user_id, type)
    {
      var content_data;
      var content;
      var exist_folders;
      var exist_sub_folders;
      var folder_name;
      var folder;
      var sub_folder;
      var response;
      var url = "";
    
      if(type == "image")
        folder_name = "Line_images";
      else if(type == "audio")
        folder_name = "Line_audio";
      else if(type == "video")
        folder_name = "Line_videos";
      else if(type == "file")
        folder_name = "Line_contens";
    
    
      exist_folders = DriveApp.searchFolders("'me' in owners");
      folder = check_folder_exist(exist_folders, folder_name);
      if(folder  == undefined)
        folder = DriveApp.createFolder(folder_name);
    
      exist_sub_folders = folder.searchFolders("'me' in owners");
      sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
      if(sub_folder  == undefined)
        sub_folder = folder.createFolder(group_or_user_id);
    
      response = http_get_content(request_id);
      if(response.getResponseCode() != 200)
      {
        if(type == "image")
          url = "***Couldn't generate an image URL. Status code = " + response.getResponseCode() + "*** ";
        else if(type == "audio")
          url = "***Couldn't generate a audio URL. Status code = " + response.getResponseCode() + "*** ";
        else if(type == "video")
          url = "***Couldn't generate a video URL. Status code = " + response.getResponseCode() + "*** ";
        else if(type == "file")
          url = "***Couldn't generate a file URL. Status code = " + response.getResponseCode() + "*** ";
      }
      else
      {
        if(type == "image")
        {
          content_data = response.getBlob().getAs("image/jpeg").setName(request_id);
          content = sub_folder.createFile(content_data);
          content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
          url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
        }
        else if(type == "audio" || type == "video" || type == "file")
        {
          content_data = response.getBlob().setName(request_id);
          content = sub_folder.createFile(content_data);
          content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
          url = "https://drive.google.com/uc?export=download&id=" + content.getId();
        }
      }
      return url;
    }
    
    function receive_msg_from_line(user_message, user_id, group_id, reply_token, time, msg_id)
    {
      var group_name;
      var picture_url = [ "", ""];
      var response = [ "", ""];
      var send_msg;
      var user_name;
    
      if(group_id == "Unknown")
        response[0] = http_get_user_name(user_id);
      else
      {
        response[0] = http_get_group_user_name(user_id, group_id);
        response[1] = http_get_group_name(group_id);
    
        if(response[1].getResponseCode() != 200)
          group_name = "Unknown";
        else
        {
          group_name = JSON.parse(response[1]).groupName;
          picture_url[1] = JSON.parse(response[1]).pictureUrl;
        }
      }
    
      if(response[0].getResponseCode() != 200)
        user_name = "Unknown";
      else
      {
        user_name = JSON.parse(response[0]).displayName;
        picture_url[0] = JSON.parse(response[0]).pictureUrl;
      }
    
      if(user_message == "getid" || user_message == "getgroupid")
      {
        if(user_message == "getid")
          send_msg = user_id;
        else if(user_message == "getgroupid")
          send_msg = group_id;
    
        response[0] = http_send_text_reply(reply_token, send_msg);
        send_msg = "<id>" + send_msg + "</id>";
        if(response[0].getResponseCode() != 200)
          send_msg += "***The message failed to send. Status code = " + response[0].getResponseCode() + " " + JSON.parse(response[0].getContentText()).message + "*** ";
    
        send_msg += "(" + time + ")";
        if(user_message == "getid")
        {
          log_save(send_msg, user_name, "IDs", "BOT", "Do not save", "0");
          user_message = "*****Added by user*****";
        }
        else if(user_message == "getgroupid")
        {
          log_save(send_msg, group_name, "IDs", "BOT", "Do not save", "0");
          user_message = "*****Invited by user*****";
        }
        user_name = CLIENT_NAME;
        msg_id = 0;
      }
      else if(user_message == "*****Removed by user*****" || user_message == "*****Blocked by user*****" || user_message == "*****Joined*****" || user_message == "*****Left*****")
      {
        msg_id = 0;
        if(user_message == "*****Removed by user*****" || user_message == "*****Blocked by user*****")
          user_name = CLIENT_NAME;
      }
    
      user_message += "(" + time + ")";
      if(group_id == "Unknown")
        log_save(user_message, user_name, user_id, user_name, picture_url[0], msg_id);
      else
        log_save(user_message, user_name, group_id, group_name, picture_url[1], msg_id);
    }
    
    function doPost(post_data)
    {
      var time = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'MM/dd hh:mm:ss');
      var data_type;
      var result;
      var client_auth = "Unknown";
      var client_gas_ver = "Unknown";
      var id = "Unknown";
      var last = "";
      var lock = LockService.getScriptLock();
      var lock_result;
      var logs = 100;
      try
      {
        data_type = JSON.parse(post_data.postData.contents).type;
      }
      catch(e)
      {
      }
      for(var i = 0; i < 100; i++)
      {
        lock_result = lock.tryLock(1000);
        if(lock_result)
          break;
    
        Utilities.sleep(1000);
      }
    
      if(data_type == undefined)
      {
        for(var i = 0; i < 50; i++)
        {
          var msg_id = "";
          var user_message = "";
          var user_id = "";
          var group_id = "";
          var reply_token = "";
          var msg_type = "";
          var type = "";
    
          try
          {
            type = JSON.parse(post_data.postData.contents).events[i].type;
            user_id = JSON.parse(post_data.postData.contents).events[i].source.userId;
            group_id = JSON.parse(post_data.postData.contents).events[i].source.groupId;
            reply_token = JSON.parse(post_data.postData.contents).events[i].replyToken;
            if(type == "unsend")
              msg_id = JSON.parse(post_data.postData.contents).events[i].unsend.messageId;
            else if(type == "message")
            {
              msg_id = JSON.parse(post_data.postData.contents).events[i].message.id;
              user_message = JSON.parse(post_data.postData.contents).events[i].message.text;
              msg_type = JSON.parse(post_data.postData.contents).events[i].message.type;
            }
          }
          catch(e)
          {
            break;
          }
    
          if(user_id == undefined)
            user_id = "Unknown";
          if(group_id == undefined)
            group_id = "Unknown";
    
    
          if(type == "follow")
            user_message = "getid";
          else if(type == "join")
            user_message = "getgroupid";
          else if(type == "leave")
            user_message = "*****Removed by user*****";
          else if(type == "unfollow")
            user_message = "*****Blocked by user*****";
          else if(type == "memberJoined")
          {
            user_message = "*****Joined*****";
            user_id = JSON.parse(post_data.postData.contents).events[i].joined.members[0].userId;
          }
          else if(type == "memberLeft")
          {
            user_message = "*****Left*****";
            user_id = JSON.parse(post_data.postData.contents).events[i].left.members[0].userId;
          }
          else if(type == "unsend")
          {
            if(group_id == "Unknown")
              unsend_msg(user_id, msg_id);
            else
              unsend_msg(group_id, msg_id);
          }
          else if(msg_type == "sticker")
          {
            var sticker_id  = JSON.parse(post_data.postData.contents).events[i].message.stickerId;
            user_message = "<sticker>" + sticker_id + "</sticker>";
          }
          else if(msg_type == "image")
          {
             if(group_id == "Unknown")
               user_message = "<image_url>" + get_content_url(msg_id, user_id, msg_type) + "</image_url>";
             else
               user_message = "<image_url>" + get_content_url(msg_id, group_id, msg_type) + "</image_url>";
          }
          else if(msg_type == "audio")
          {
           if(group_id == "Unknown")
             user_message = "<audio_url>" + get_content_url(msg_id, user_id, msg_type) + "</audio_url>";
           else
             user_message = "<audio_url>" + get_content_url(msg_id, group_id, msg_type) + "</audio_url>";
          }
          else if(msg_type == "video")
          {
           if(group_id == "Unknown")
             user_message = "<video_url>" + get_content_url(msg_id, user_id, msg_type) + "</video_url>";
           else
             user_message = "<video_url>" + get_content_url(msg_id, group_id, msg_type) + "</video_url>";
          }
          else if(msg_type == "file")
          {
           if(group_id == "Unknown")
             user_message = "<file_url>" + get_content_url(msg_id, user_id, msg_type) + "</file_url>";
           else
             user_message = "<file_url>" + get_content_url(msg_id, group_id, msg_type) + "</file_url>";
          }
          else if(user_message == undefined)
            user_message += " : " + msg_type + " " + msg_id;
    
          if(!(type == "unsend"))
            receive_msg_from_line(user_message, user_id, group_id, reply_token, time, msg_id);
        }
        lock.releaseLock();
        return;
      }
    
      try
      {
        client_auth = JSON.parse(post_data.postData.contents).auth;
        client_gas_ver = JSON.parse(post_data.postData.contents).gas_ver;
        id = JSON.parse(post_data.postData.contents).id;
      }
      catch(e)
      {
      }
    
      if(SCRIPT_PASSWORD == client_auth)
      {
        if(gas_ver == client_gas_ver)
        {
          if(data_type == "send_text")
          {
            var send_message = JSON.parse(post_data.postData.contents).message;
            result = send_msg(id, send_message, time);
          }
          else if(data_type == "send_sticker")
          {
            var package_id = JSON.parse(post_data.postData.contents).package_id;
            var sticker_id = JSON.parse(post_data.postData.contents).sticker_id;
            result = send_sticker(id, package_id, sticker_id, time);
          }
          else if(data_type == "upload_content")
          {
            var content_data = JSON.parse(post_data.postData.contents).content_data;
            var count = JSON.parse(post_data.postData.contents).count;
            var name = JSON.parse(post_data.postData.contents).name;
            var sub_data_type = "";
            last = JSON.parse(post_data.postData.contents).last;
            if(last == "true")
              sub_data_type = JSON.parse(post_data.postData.contents).data_type;
    
            result = upload_content(id, content_data, count, name, last, time, sub_data_type);
          }
          else
            result = "Unknown message type.";
    
          if(result == "Success" && ((data_type == "upload_content" && last == "true") || data_type == "send_sticker" || data_type == "send_text"))
          {
            logs = JSON.parse(post_data.postData.contents).logs;
            result = log_read(id, logs);
          }
        }
        else
          result = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
      }
      else
        result = "Auth failed. Please set correct password.";
    
      lock.releaseLock();
      return ContentService.createTextOutput(result);
    }
    
    function doGet(post_data)
    {
      var data = "";
      var client_auth = "";
      var client_gas_ver = "";
      var num_of_logs = "";
      var id = "";
      var lock = LockService.getScriptLock();
      var lock_result = lock.tryLock(1000);
      while(!lock_result)
      {
        Utilities.sleep(1000);
        lock_result = lock.tryLock(1000);
      }
      try
      {
        client_auth = post_data.parameter.script_auth;
        client_gas_ver = post_data.parameter.gas_ver;
        num_of_logs = post_data.parameter.logs;
        id = post_data.parameter.id;
      }
      catch(e)
      {
      }
      if(client_auth == undefined)
        client_auth = "";
      if(client_gas_ver == undefined)
        client_gas_ver = -1;
      if(num_of_logs == undefined)
        num_of_logs = 300;
      if(id == undefined)
        id = "unknown";
    
      if(SCRIPT_PASSWORD == client_auth)
      {
        if(gas_ver == client_gas_ver)
          data = log_read(id, num_of_logs);
        else
          data = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
      }
      else
        data = "Auth failed. Please set correct password.";
    
      lock.releaseLock();
      return ContentService.createTextOutput(data);
    }

  2. This code compatible with ver 1.6.0
    ⚠⚠⚠WARNING⚠⚠⚠ I strongly recommend you use the newest version ⚠⚠⚠WARNING⚠⚠⚠

    Code:
    var ACCESS_TOKEN = "Your acces token here";
    var OPEN_SHEET_ID = "Your sheet id here";
    var SCRIPT_PASSOWRD = "Your google apps script password here";
    var CLIENT_NAME = "Your 3ds's account name here";
    
    var gas_ver = 6;//Do **NOT** edit this value.
    function log_save(message, user_name, write_sheet_name, group_or_user_name, pic_url)
    {
        var google_pic_url;
        var previous_pic_url;
        var response;
        var sheet_pos = 1;
        var spreadsheet = SpreadsheetApp.openById(OPEN_SHEET_ID);
        var write_sheet = spreadsheet.getSheetByName(write_sheet_name);
    
        if (!write_sheet)
        {
            spreadsheet.insertSheet(write_sheet_name);
            write_sheet = spreadsheet.getSheetByName(write_sheet_name);
        }
    
        sheet_pos = get_cache_pos(write_sheet);
    
        while (true)
        {
            var sheet_data = write_sheet.getRange("A" + sheet_pos).getValue();
    
            if (sheet_data == "")
            {
                write_sheet.getRange("A" + sheet_pos).setValue("" + user_name + " : " + message);
                break;
            }
            else
                sheet_pos++;
        }
    
        write_cache_data(write_sheet, (sheet_pos + 1), "B1");
        if (group_or_user_name != "Do not save")
            write_cache_data(write_sheet, group_or_user_name, "B2");
    
        if (pic_url != "Do not save")
        {
            previous_pic_url = get_previous_pic_url(write_sheet);
            if (previous_pic_url != pic_url)
            {
                response = UrlFetchApp.fetch(pic_url,
                    {
                        'headers': {
                            'Content-Type': 'application/json; charset=UTF-8',
                            'Authorization': 'Bearer ' + ACCESS_TOKEN,
                        },
                        muteHttpExceptions: true,
                    });
    
                if (response.getResponseCode() == 200)
                {
                    google_pic_url = get_profile_pic_google_url(response, write_sheet_name);
                    write_cache_data(write_sheet, google_pic_url, "B3");
                    write_cache_data(write_sheet, pic_url, "B4");
                }
            }
    
        }
    }
    
    function check_folder_exist(input_folders, name)
    {
        var folder;
        while (input_folders.hasNext())
        {
          folder = input_folders.next();
          if(name == folder.getName())
            return folder;
        }
        return undefined;
    }
    
    function log_read(id, num_of_logs)
    {
      var sheet_offset = 1;
      var sheet_start = 1;
      var return_data;
      var sheet_data;
      var spreadsheet = SpreadsheetApp.openById(OPEN_SHEET_ID);
      var read_sheet = spreadsheet.getSheetByName(id);
      if(!read_sheet)
        return "No such sheet.\nPlease duoble check your ID.";
     
      sheet_start = get_cache_pos(read_sheet);
    
      while(true)
      {
        sheet_data = read_sheet.getRange("A" + sheet_start).getValue();
        if(sheet_data == "")
        {
          write_cache_data(read_sheet, sheet_start, "B1");
          if(sheet_start > num_of_logs)
            sheet_start = (sheet_start - num_of_logs);
          else
            sheet_start = 1;
    
          break;
        }
        else
          sheet_start++;
      }
    
      sheet_offset = sheet_start;
      sheet_data = read_sheet.getRange(sheet_start, 1, num_of_logs).getValues();
      return_data = "<0>";
      for(var i = 0; i < num_of_logs; i++)
      {
        if(sheet_data[i] == "")
          break;
    
        return_data += sheet_data[i];
        sheet_offset++;
      }
     
      return_data += "</0>";
      return_data += "<1>" + get_cache_name(read_sheet) + "</1>";
      return_data += "<2>" + get_google_pic_url(read_sheet) + "</2>";
      return_data += "<3>" + sheet_offset + "</3>";
      return_data += "<4>Success</4>";
      return return_data;
    }
    
    function get_cache_pos(sheet_object)
    {
      var cached_sheet_pos = sheet_object.getRange("B1").getValue();
      var sheet_data;
    
      if(parseInt(cached_sheet_pos) > 0)
      {
        cached_sheet_pos = parseInt(cached_sheet_pos);
        sheet_data = sheet_object.getRange("A" + (cached_sheet_pos - 1)).getValue();
    
        if(sheet_data != "")
          return cached_sheet_pos;
      }
      return 1;
    }
    
    function get_cache_name(sheet_object)
    {
      var cached_name = sheet_object.getRange("B2").getValue();
      return cached_name;
    }
    
    function get_google_pic_url(sheet_object)
    {
        var cached_name = sheet_object.getRange("B3").getValue();
        return cached_name;
    }
    
    function get_previous_pic_url(sheet_object)
    {
        var cached_name = sheet_object.getRange("B4").getValue();
        return cached_name;
    }
    
    function write_cache_data(sheet_object, cache_data, pos)
    {
      sheet_object.getRange(pos).setValue(cache_data);
    }
    
    function http_get_content(request_id)
    {
      var response;
      var url = "https://api.line.me/v2/bot/message/" + request_id + "/content";
      response = UrlFetchApp.fetch(url,
      {
      'headers': {
        'Content-Type': 'application/json; charset=UTF-8',
        'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_get_user_name(id)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/profile/' + id;
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_get_group_user_name(id, group_id)
    {
      var response;
      var url = "https://api.line.me/v2/bot/group/" + group_id + "/member/" + id + "/";
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_get_group_name(group_id)
    {
      var response;
      var url = "https://api.line.me/v2/bot/group/" + group_id +"/summary/";
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_text_reply(reply_token, send_msg)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/reply/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
          'replyToken': reply_token,
          'messages': [{
            'type': 'text',
            'text': send_msg ,
          }],
          'notificationDisabled': 'true',
        }),
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_text(id, send_msg)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/push/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
      "to": id,
      "messages":
           [{
              "text": send_msg,
              "type": "text",
           }],
          'notificationDisabled': 'false',
        }),
       muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_sticker(id, package_id, sticker_id)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/push/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
      "to": id,
      "messages":
           [{
              "type": "sticker",
              "packageId": package_id,
              "stickerId": sticker_id,
           }],
          'notificationDisabled': 'false',
        }),
       muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_image(id, img_url, preview_url)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/push/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
      "to": id,
      "messages":
           [{
              "type": "image",
              "originalContentUrl": img_url,
              "previewImageUrl": preview_url,
           }],
          'notificationDisabled': 'false',
        }),
       muteHttpExceptions: true,
      });
      return response;
    }
    
    function send_msg(id, send_message, time)
    {
      var cache;
      var response;
      var return_message = "Success";
    
      response = http_send_text(id, send_message);
      if(response.getResponseCode() != 200)
      {
        cache = "***The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message + "*** ";
        cache += send_message;
        send_message = cache;
        return_message = "The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
      }
     
      send_message += "(" + time + ")";
      log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save");
      return return_message;
    }
    
    function send_sticker(id, package_id, sticker_id, time)
    {
      var response;
      var return_message = "Success";
      var send_message = "";
    
      response = http_send_sticker(id, package_id, sticker_id);
      if(response.getResponseCode() != 200)
      {
       send_message = "***The sticker failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
       return_message = "The sticker failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
      }
      send_message += "<sticker>" + sticker_id + "</sticker>(" + time + ")";
      log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save");
      return return_message;
    }
    
    function get_cache_data(id, cache_name)
    {
      var cache_data = "";
      var cache_file;
      var cache_folder;
      var exist_cache_folders;
      var exist_folders;
      var exist_sub_folders;
      var folder;
      var folder_name = "Line_contents";
      var sub_folder;
    
      exist_folders = DriveApp.searchFolders("'me' in owners");
      folder = check_folder_exist(exist_folders, folder_name);
      if(folder == undefined)
        return undefined;
    
      exist_sub_folders = folder.searchFolders("'me' in owners");
      sub_folder = check_folder_exist(exist_sub_folders, id);
      if(sub_folder == undefined)
        return undefined;
    
      exist_cache_folders = sub_folder.searchFolders("'me' in owners");
      cache_folder = check_folder_exist(exist_cache_folders, cache_name);
      if(cache_folder == undefined)
        return undefined;
    
      for(var i = 0; i < 4096; i++)
      {
        try
        {
          cache_file = cache_folder.getFilesByName(i).next();
          cache_data += cache_file.getBlob().getDataAsString();
        }
        catch(error)
        {
          break;
        }
      }
      cache_folder.setTrashed(true);
      return cache_data;
    }
    
    function upload_content(id, data, count, cache_name, last, time)
    {
      var cache_data;
      var cache_folder;
      var exist_cache_folders;
      var exist_folders;
      var exist_sub_folders;
      var folder;
      var folder_name = "Line_contents";
      var part_of_content;
      var part_of_content_data;
      var return_message = "Success";
      var send_message;
      var sub_folder;
    
      if(count == 0 && last == "true")
        return_message = send_content(id, cache_name, time, data);
      else if(last == "true")
      {
          cache_data = get_cache_data(id, cache_name);
          if(cache_data == undefined)
          {
            send_message = "***The content failed to send. The cache folder does not exist.*** (" + time + ")";
            log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save");
            return_message = "The content failed to send.\nThe cache folder does not exist.";
          }
          else
          {
            cache_data += data;
            return_message = send_content(id, cache_name, time, cache_data);
          }
      }
      else
      {
        exist_folders = DriveApp.searchFolders("'me' in owners");
        folder = check_folder_exist(exist_folders, folder_name);
        if(folder == undefined)
          folder = DriveApp.createFolder(folder_name);
    
        exist_sub_folders = folder.searchFolders("'me' in owners");
        sub_folder = check_folder_exist(exist_sub_folders, id);
        if(sub_folder == undefined)
          sub_folder = folder.createFolder(id);
    
        exist_cache_folders = sub_folder.searchFolders("'me' in owners");
        cache_folder = check_folder_exist(exist_cache_folders, cache_name);
        if(cache_folder == undefined)
          cache_folder = sub_folder.createFolder(cache_name);
        else if(!(cache_folder == undefined) && count == 0)
        {
          cache_folder.setTrashed(true);
          cache_folder = sub_folder.createFolder(cache_name);
        }
    
        part_of_content_data = Utilities.newBlob(data).setName(count);
        part_of_content = cache_folder.createFile(part_of_content_data);
      }
      return return_message;
    }
    
    function send_content(id, cache_name, time, encoded_data)
    {
      var content;
      var content_data;
      var content_type;
      var content_url = "";
      var exist_folders;
      var exist_sub_folders;
      var folder;
      var folder_name = "Line_contents";
      var preview_content_url = "";
      var response;
      var return_message = "Success";
      var send_message = "";
      var sub_folder;
    
      exist_folders = DriveApp.searchFolders("'me' in owners");
      folder = check_folder_exist(exist_folders, folder_name);
      if(folder == undefined)
        folder = DriveApp.createFolder(folder_name);
    
      exist_sub_folders = folder.searchFolders("'me' in owners");
      sub_folder = check_folder_exist(exist_sub_folders, id);
      if(sub_folder == undefined)
        sub_folder = folder.createFolder(id);
    
      try
      {
        content_data = Utilities.newBlob(Utilities.base64Decode(encoded_data)).setName(cache_name);
      }
      catch (e)
      {
        return_message = "The content failed to send.\nCouldn't decode base64 data.";
        return return_message;
      }
    
      content = sub_folder.createFile(content_data);
      content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
      content_type = content.getMimeType();
      if(content_type == MimeType.BMP || content_type == MimeType.GIF || content_type == MimeType.JPEG || content_type == MimeType.PNG || content_type == MimeType.SVG)
      {
        content.setTrashed(true);
        folder_name = "Line_images";
        exist_folders = DriveApp.searchFolders("'me' in owners");
        folder = check_folder_exist(exist_folders, folder_name);
        if(folder == undefined)
        folder = DriveApp.createFolder(folder_name);
    
        exist_sub_folders = folder.searchFolders("'me' in owners");
        sub_folder = check_folder_exist(exist_sub_folders, id);
        if(sub_folder == undefined)
        sub_folder = folder.createFolder(id);
    
        content = sub_folder.createFile(content_data);
        content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
        content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
        preview_content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w240-h240";
    
        response = http_send_image(id, content_url, preview_content_url);
        if(response.getResponseCode() != 200)
        {
          send_message = "***The image failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
          return_message = "The image failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
        }
        send_message += "<image_url>" + content_url + "</image_url>(" + time + ")";
        log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save");
        return return_message;
      }
      else
      {
        content_url = "https://drive.google.com/file/d/" + content.getId() + "/view";
        response = http_send_text(id, content_url);
        if(response.getResponseCode() != 200)
        {
          send_message = "***The content failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
          return_message = "The content failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
        }
        content_url = "https://drive.google.com/uc?export=download&id=" + content.getId();
        send_message += "<content_url>" + content_url + "</content_url>(" + time + ")";
        log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save");
        return return_message;
      }
    }
    
    function get_profile_pic_google_url(http_response, group_or_user_id)
    {
        var content_data;
        var content;
        var folder_name = "Line_images";
        var folder;
        var sub_folder;
        var exist_folders;
        var exist_sub_folders;
        var url = "";
    
        exist_folders = DriveApp.searchFolders("'me' in owners");
        folder = check_folder_exist(exist_folders, folder_name);
        if (folder == undefined)
            folder = DriveApp.createFolder(folder_name);
    
        exist_sub_folders = folder.searchFolders("'me' in owners");
        sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
        if (sub_folder == undefined)
            sub_folder = folder.createFolder(group_or_user_id);
    
        content_data = http_response.getBlob().getAs("image/jpeg").setName("icon");
        content = sub_folder.createFile(content_data);
        content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
        url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w32-h32";
    
        return url;
    }
    
    function get_content_url(request_id, group_or_user_id, type)
    {
      var content_data;
      var content;
      var exist_folders;
      var exist_sub_folders;
      var folder_name;
      var folder;
      var sub_folder;
      var response;
      var url = "";
    
      if(type == "image")
        folder_name = "Line_images";
      else if(type == "audio")
        folder_name = "Line_audio";
      else if(type == "video")
        folder_name = "Line_videos";
      else if(type == "file")
        folder_name = "Line_contens";
    
    
      exist_folders = DriveApp.searchFolders("'me' in owners");
      folder = check_folder_exist(exist_folders, folder_name);
      if(folder  == undefined)
        folder = DriveApp.createFolder(folder_name);
    
      exist_sub_folders = folder.searchFolders("'me' in owners");
      sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
      if(sub_folder  == undefined)
        sub_folder = folder.createFolder(group_or_user_id);
    
      response = http_get_content(request_id);
      if(response.getResponseCode() != 200)
      {
        if(type == "image")
          url = "***Couldn't generate an image URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
        else if(type == "audio")
          url = "***Couldn't generate a audio URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
        else if(type == "video")
          url = "***Couldn't generate a video URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
      }
      else
      {
        if(type == "image")
        {
          content_data = response.getBlob().getAs("image/jpeg").setName(request_id);
          content = sub_folder.createFile(content_data);
          content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
          url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
        }
        else if(type == "audio" || type == "video" || type == "file")
        {
          content_data = response.getBlob().setName(request_id);
          content = sub_folder.createFile(content_data);
          content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
          url = "https://drive.google.com/uc?export=download&id=" + content.getId();
        }
      }
      return url;
    }
    
    function receive_msg_from_line(user_message, user_id, group_id, reply_token, time, reply)
    {
      var group_name;
      var picture_url = [ "", ""];
      var response = [ "", ""];
      var send_msg;
      var user_name;
    
      if(group_id == "Unknown")
        response[0] = http_get_user_name(user_id);
      else
      {
        response[0] = http_get_group_user_name(user_id, group_id);
        response[1] = http_get_group_name(group_id);
    
        if(response[1].getResponseCode() != 200)
          group_name = "Unknown";
        else
        {
          group_name = JSON.parse(response[1]).groupName;
          picture_url[1] = JSON.parse(response[1]).pictureUrl;
        }
      }
    
      if(response[0].getResponseCode() != 200)
        user_name = "Unknown";
      else
      {
        user_name = JSON.parse(response[0]).displayName;
        picture_url[0] = JSON.parse(response[0]).pictureUrl;
      }
    
      if(user_message == "getid" || user_message == "getgroupid")
      {
        if(user_message == "getid")
          send_msg = user_id;
        else if(user_message == "getgroupid")
          send_msg = group_id;
    
        response[0] = http_send_text_reply(reply_token, send_msg);
        send_msg = "<id>" + send_msg + "</id>";
        if(response[0].getResponseCode() != 200)
          send_msg += "***The message failed to send. Status code = " + response[0].getResponseCode() + " " + JSON.parse(response[0].getContentText()).message + "*** ";
    
        send_msg += "(" + time + ")";
        if(user_message == "getid")
          log_save(send_msg, user_name, "IDs", "BOT", "Do not save");
        else if(user_message == "getgroupid")
          log_save(send_msg, group_name, "IDs", "BOT", "Do not save");
        return;
      }
     
      user_message += "(" + time + ")";
      if(group_id == "Unknown")
        log_save(user_message, user_name, user_id, user_name, picture_url[0]);
      else
        log_save(user_message, user_name, group_id, group_name, picture_url[1]);
    }
    
    function doPost(post_data)
    {
      var time = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'MM/dd hh:mm:ss');
      var data_type;
      var result;
      var client_auth = "Unknown";
      var client_gas_ver = "Unknown";
      var id = "Unknown";
      var lock = LockService.getScriptLock();
      var lock_result = lock.tryLock(100);
      try
      {
        data_type = JSON.parse(post_data.postData.contents).type;
      }
      catch(e)
      {
      }
      while(!lock_result)
      {
        Utilities.sleep(100);
        lock_result = lock.tryLock(100);
      }
    
      if(data_type == undefined)
      {
        for(var i = 0; i < 50; i++)
        {
          var msg_id = "";
          var user_message = "";
          var user_id = "";
          var group_id = "";
          var reply_token = "";
          var msg_type = "";
          var type = "";
     
          try
          {
            type = JSON.parse(post_data.postData.contents).events[i].type;
            user_id = JSON.parse(post_data.postData.contents).events[i].source.userId;
            group_id = JSON.parse(post_data.postData.contents).events[i].source.groupId;
            reply_token = JSON.parse(post_data.postData.contents).events[i].replyToken;
            if(type == "message")
            {
              msg_id = JSON.parse(post_data.postData.contents).events[i].message.id;
              user_message = JSON.parse(post_data.postData.contents).events[i].message.text;
              msg_type = JSON.parse(post_data.postData.contents).events[i].message.type;
            }
          }
          catch(e)
          {
            break;
          }
    
          if(user_id == undefined)
            user_id = "Unknown";
          if(group_id == undefined)
            group_id = "Unknown";
    
    
          if(type == "follow")
            user_message = "getid";
          else if(type == "join")
            user_message = "getgroupid";
          if(type == "leave")
            user_message = "*****Removed by user*****";
          else if(type == "unfollow")
            user_message = "*****Blocked by user*****";
          else if(msg_type == "sticker")
          {
            var sticker_id  = JSON.parse(post_data.postData.contents).events[i].message.stickerId;
            user_message = "<sticker>" + sticker_id + "</sticker>";
          }
          else if(msg_type == "image")
          {
           if(group_id == "Unknown")
             user_message = "<image_url>" + get_content_url(msg_id, user_id, msg_type) + "</image_url>";
           else
             user_message = "<image_url>" + get_content_url(msg_id, group_id, msg_type) + "</image_url>";
          }
          else if(msg_type == "audio")
          {
           if(group_id == "Unknown")
             user_message = "<audio_url>" + get_content_url(msg_id, user_id, msg_type) + "</audio_url>";
           else
             user_message = "<audio_url>" + get_content_url(msg_id, group_id, msg_type) + "</audio_url>";
          }
          else if(msg_type == "video")
          {
           if(group_id == "Unknown")
             user_message = "<video_url>" + get_content_url(msg_id, user_id, msg_type) + "</video_url>";
           else
             user_message = "<video_url>" + get_content_url(msg_id, group_id, msg_type) + "</video_url>";
          }
          else if(msg_type == "file")
          {
           if(group_id == "Unknown")
             user_message = "<file_url>" + get_content_url(msg_id, user_id, msg_type) + "</file_url>";
           else
             user_message = "<file_url>" + get_content_url(msg_id, group_id, msg_type) + "</file_url>";
          }
          else if(user_message == undefined)
            user_message += " : " + msg_type + " " + msg_id;
    
          receive_msg_from_line(user_message, user_id, group_id, reply_token, time);
        }
        lock.releaseLock();
        return;
      }
    
      try
      {
        client_auth = JSON.parse(post_data.postData.contents).auth;
        client_gas_ver = JSON.parse(post_data.postData.contents).gas_ver;
        id = JSON.parse(post_data.postData.contents).id;
      }
      catch(e)
      {
      }
    
      if(SCRIPT_PASSOWRD == client_auth)
      {
        if(gas_ver == client_gas_ver)
        {
          if(data_type == "send_text")
          {
            var send_message = JSON.parse(post_data.postData.contents).message;
            result = send_msg(id, send_message, time);
          }
          else if(data_type == "send_sticker")
          {
            var package_id = JSON.parse(post_data.postData.contents).package_id;
            var sticker_id = JSON.parse(post_data.postData.contents).sticker_id;
            result = send_sticker(id, package_id, sticker_id, time);
          }
          else if(data_type == "upload_content")
          {
            var content_data = JSON.parse(post_data.postData.contents).content_data;
            var count = JSON.parse(post_data.postData.contents).count;
            var name = JSON.parse(post_data.postData.contents).name;
            var last = JSON.parse(post_data.postData.contents).last;
            result = upload_content(id, content_data, count, name, last, time);
          }
          else
            result = "Unknown message type.";
        }
        else
          result = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
      }
      else
        result = "Auth failed. Please set correct password.";
    
      lock.releaseLock();
      return ContentService.createTextOutput(result);
    }
    
    function doGet(post_data)
    {
      var data = "";
      var client_auth = "";
      var client_gas_ver = "";
      var num_of_logs = "";
      var id = "";
      var lock = LockService.getScriptLock();
      var lock_result = lock.tryLock(100);
      while(!lock_result)
      {
        Utilities.sleep(100);
        lock_result = lock.tryLock(100);
      }
      try
      {
        client_auth = post_data.parameter.script_auth;
        client_gas_ver = post_data.parameter.gas_ver;
        num_of_logs = post_data.parameter.logs;
        id = post_data.parameter.id;
      }
      catch(e)
      {
      }
      if(client_auth == undefined)
        client_auth = "";
      if(client_gas_ver == undefined)
        client_gas_ver = -1;
      if(num_of_logs == undefined)
        num_of_logs = 300;
      if(id == undefined)
        id = "unknown";
    
      if(SCRIPT_PASSOWRD == client_auth)
      {
        if(gas_ver == client_gas_ver)
          data = log_read(id, num_of_logs);
        else
          data = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
      }
      else
        data = "Auth failed. Please set correct password.";
    
      lock.releaseLock();
      return ContentService.createTextOutput(data);
    }

  3. This code compatible with ver 1.5.01.5.2
    ⚠⚠⚠WARNING⚠⚠⚠ I strongly recommend you use the newest version ⚠⚠⚠WARNING⚠⚠⚠

    Code:
    var ACCESS_TOKEN = "Your acces token here";
    var open_sheet_id = "Your sheet id here";
    var account_name_of_3ds = "Your 3ds's account name here";
    var script_password = "Your google apps script password here";
    
    var gas_ver = 5;//Do **NOT** edit this value.
    function log_save(message, user_name, write_sheet_name, group_or_user_name, pic_url)
    {
        var google_pic_url;
        var previous_pic_url;
        var response;
        var sheet_pos = 1;
        var spreadsheet = SpreadsheetApp.openById(open_sheet_id);
        var write_sheet = spreadsheet.getSheetByName(write_sheet_name);
    
        if (!write_sheet)
        {
            spreadsheet.insertSheet(write_sheet_name);
            write_sheet = spreadsheet.getSheetByName(write_sheet_name);
        }
    
        sheet_pos = get_cache_pos(write_sheet);
    
        while (true)
        {
            var sheet_data = write_sheet.getRange("A" + sheet_pos).getValue();
    
            if (sheet_data == "")
            {
                write_sheet.getRange("A" + sheet_pos).setValue("" + user_name + " : " + message);
                break;
            }
            else
                sheet_pos++;
        }
    
        write_cache_data(write_sheet, (sheet_pos + 1), "B1");
        if (group_or_user_name != "Do not save")
            write_cache_data(write_sheet, group_or_user_name, "B2");
    
        if (pic_url != "Do not save")
        {
            previous_pic_url = get_previous_pic_url(write_sheet);
            if (previous_pic_url != pic_url)
            {
                response = UrlFetchApp.fetch(pic_url,
                    {
                        'headers': {
                            'Content-Type': 'application/json; charset=UTF-8',
                            'Authorization': 'Bearer ' + ACCESS_TOKEN,
                        },
                        muteHttpExceptions: true,
                    });
    
                if (response.getResponseCode() == 200)
                {
                    google_pic_url = get_profile_pic_google_url(response, write_sheet_name);
                    write_cache_data(write_sheet, google_pic_url, "B3");
                    write_cache_data(write_sheet, pic_url, "B4");
                }
            }
    
        }
    }
    
    function check_folder_exist(input_folders, name)
    {
        var folder;
        while (input_folders.hasNext())
        {
          folder = input_folders.next();
          if(name == folder.getName())
            return folder;
        }
        return undefined;
    }
    
    function log_read(id)
    {
      var sheet_start = 1;
      var return_data;
      var sheet_data;
      var spreadsheet = SpreadsheetApp.openById(open_sheet_id);
      var read_sheet = spreadsheet.getSheetByName(id);
      sheet_start = get_cache_pos(read_sheet);
    
      while(true)
      {
        sheet_data = read_sheet.getRange("A" + sheet_start).getValue();
        if(sheet_data == "")
        {
          write_cache_data(read_sheet, sheet_start, "B1");
          if(sheet_start >= 301)
            sheet_start = (sheet_start - 300);
          else
            sheet_start = 1;
     
          break;
        }
        else
          sheet_start++;
      }
    
      sheet_data = read_sheet.getRange(sheet_start, 1, 300).getValues();
      return_data = "<0>";
      for(var i = 0; i < 300; i++)
      {
        if(sheet_data[i] == "")
          break;
    
        return_data += sheet_data[i];
      }
        return_data += "</0>";
        return_data += "<1>" + get_cache_name(read_sheet) + "</1>";
        return_data += "<2>" + get_google_pic_url(read_sheet) + "</2>";
        return_data += "<3>Success</3>";
      return return_data;
    }
    
    function get_cache_pos(sheet_object)
    {
      var cached_sheet_pos = sheet_object.getRange("B1").getValue();
      var sheet_data;
    
      if(parseInt(cached_sheet_pos) > 0)
      {
        cached_sheet_pos = parseInt(cached_sheet_pos);
        sheet_data = sheet_object.getRange("A" + (cached_sheet_pos - 1)).getValue();
     
        if(sheet_data != "")
          return cached_sheet_pos;
      }
      return 1;
    }
    
    function get_cache_name(sheet_object)
    {
      var cached_name = sheet_object.getRange("B2").getValue();
      return cached_name;
    }
    
    function get_google_pic_url(sheet_object)
    {
        var cached_name = sheet_object.getRange("B3").getValue();
        return cached_name;
    }
    
    function get_previous_pic_url(sheet_object)
    {
        var cached_name = sheet_object.getRange("B4").getValue();
        return cached_name;
    }
    
    function write_cache_data(sheet_object, cache_data, pos)
    {
      sheet_object.getRange(pos).setValue(cache_data);
    }
    
    function http_get_content(request_id)
    {
      var response;
      var url = "https://api.line.me/v2/bot/message/" + request_id + "/content";
      response = UrlFetchApp.fetch(url,
      {
      'headers': {
        'Content-Type': 'application/json; charset=UTF-8',
        'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_get_user_name(id)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/profile/' + id;
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_get_group_user_name(id, group_id)
    {
      var response;
      var url = "https://api.line.me/v2/bot/group/" + group_id + "/member/" + id + "/";
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_get_group_name(group_id)
    {
      var response;
      var url = "https://api.line.me/v2/bot/group/" + group_id +"/summary/";
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_text_reply(reply_token, send_msg)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/reply/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
          'replyToken': reply_token,
          'messages': [{
            'type': 'text',
            'text': send_msg ,
          }],
          'notificationDisabled': 'true',
        }),
        muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_text(id, send_msg)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/push/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
      "to": id,
      "messages":
           [{
              "text": send_msg,
              "type": "text",
           }],
          'notificationDisabled': 'false',
        }),
       muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_sticker(id, package_id, sticker_id)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/push/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
      "to": id,
      "messages":
           [{
              "type": "sticker",
              "packageId": package_id,
              "stickerId": sticker_id,
           }],
          'notificationDisabled': 'false',
        }),
       muteHttpExceptions: true,
      });
      return response;
    }
    
    function http_send_image(id, img_url, preview_url)
    {
      var response;
      var url = 'https://api.line.me/v2/bot/message/push/';
      response = UrlFetchApp.fetch(url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
        },
        'method': 'post',
        'payload': JSON.stringify({
      "to": id,
      "messages":
           [{
              "type": "image",
              "originalContentUrl": img_url,
              "previewImageUrl": preview_url,
           }],
          'notificationDisabled': 'false',
        }),
       muteHttpExceptions: true,
      });
      return response;
    }
    
    function send_msg(id, send_message, time)
    {
      var cache;
      var response;
      var return_message = "Success";
     
      response = http_send_text(id, send_message);
      if(response.getResponseCode() != 200)
      {
        cache = "***The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message + "*** ";
        cache += send_message;
        send_message = cache;
        return_message = "The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
      }
      send_message += "(" + time + ")";
      log_save(send_message, account_name_of_3ds, id, "Do not save", "Do not save");
      return return_message;
    }
    
    function send_sticker(id, package_id, sticker_id, time)
    {
      var response;
      var return_message = "Success";
      var send_message = "";
    
      response = http_send_sticker(id, package_id, sticker_id);
      if(response.getResponseCode() != 200)
      {
       send_message = "***The sticker failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
       return_message = "The sticker failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
      }
      send_message += "<sticker>" + sticker_id + "</sticker>(" + time + ")";
      log_save(send_message, account_name_of_3ds, id, "Do not save", "Do not save");
      return return_message;
    }
    
    function upload_content(id, data, count, cache_name)
    {
      var cache_folder;
      var exist_cache_folders;
      var exist_folders;
      var exist_sub_folders;
      var folder;
      var folder_name = "Line_contents";
      var part_of_content;
      var part_of_content_data;
      var return_message = "Success";
      var sub_folder;
    
      exist_folders = DriveApp.searchFolders("'me' in owners");
      folder = check_folder_exist(exist_folders, folder_name);
      if(folder == undefined)
        folder = DriveApp.createFolder(folder_name);
     
      exist_sub_folders = folder.searchFolders("'me' in owners");
      sub_folder = check_folder_exist(exist_sub_folders, id);
      if(sub_folder == undefined)
        sub_folder = folder.createFolder(id);
     
      exist_cache_folders = sub_folder.searchFolders("'me' in owners");
      cache_folder = check_folder_exist(exist_cache_folders, cache_name);
      if(cache_folder == undefined)
        cache_folder = sub_folder.createFolder(cache_name);
      else if(!(cache_folder == undefined) && count == 0)
      {
        cache_folder.setTrashed(true);
        cache_folder = sub_folder.createFolder(cache_name);
      }
    
      part_of_content_data = Utilities.newBlob(data).setName(count);
      part_of_content = cache_folder.createFile(part_of_content_data);
      return return_message;
    }
    
    function send_content(id, cache_name, time)
    {
      var cache_file;
      var cache_folder;
      var content;
      var content_data;
      var content_type;
      var content_url = "";
      var encoded_data = "";
      var exist_cache_folders;
      var exist_folders;
      var exist_sub_folders;
      var folder;
      var folder_name = "Line_contents";
      var preview_content_url = "";
      var response;
      var return_message = "Success";
      var send_message = "";
      var sub_folder;
    
      exist_folders = DriveApp.searchFolders("'me' in owners");
      folder = check_folder_exist(exist_folders, folder_name);
      if(folder == undefined)
        folder = DriveApp.createFolder(folder_name);
    
      exist_sub_folders = folder.searchFolders("'me' in owners");
      sub_folder = check_folder_exist(exist_sub_folders, id);
      if(sub_folder == undefined)
        sub_folder = folder.createFolder(id);
    
      exist_cache_folders = sub_folder.searchFolders("'me' in owners");
      cache_folder = check_folder_exist(exist_cache_folders, cache_name);
      if(cache_folder == undefined)
      {
        send_message = "***The content failed to send. The cache folder does not exist.*** (" + time + ")";
        log_save(send_message, account_name_of_3ds, id, "Do not save", "Do not save");
        return_message = "The content failed to send.\nThe cache folder does not exist."
        return return_message;
      }
    
      for(var i = 0; i < 4096; i++)
      {
        try
        {
          cache_file = cache_folder.getFilesByName(i).next();
          encoded_data += cache_file.getBlob().getDataAsString();
        }
        catch(error)
        {
          break;
        }
      }
    
      cache_folder.setTrashed(true);
      content_data = Utilities.newBlob(Utilities.base64Decode(encoded_data)).setName(cache_name);
      content = sub_folder.createFile(content_data);
      content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
      content_type = content.getMimeType();
      if(content_type == MimeType.BMP || content_type == MimeType.GIF || content_type == MimeType.JPEG || content_type == MimeType.PNG || content_type == MimeType.SVG)
      {
        content.setTrashed(true);
        folder_name = "Line_images";
        exist_folders = DriveApp.searchFolders("'me' in owners");
        folder = check_folder_exist(exist_folders, folder_name);
        if(folder == undefined)
        folder = DriveApp.createFolder(folder_name);
    
        exist_sub_folders = folder.searchFolders("'me' in owners");
        sub_folder = check_folder_exist(exist_sub_folders, id);
        if(sub_folder == undefined)
        sub_folder = folder.createFolder(id);
     
        content = sub_folder.createFile(content_data);
        content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
        content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
        preview_content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w240-h240";
     
        response = http_send_image(id, content_url, preview_content_url);
        if(response.getResponseCode() != 200)
        {
          send_message = "***The image failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
          return_message = "The image failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
        }
        send_message += "<image_url>" + content_url + "</image_url>(" + time + ")";
        log_save(send_message, account_name_of_3ds, id, "Do not save", "Do not save");
        return return_message;
      }
      else
      {
        content_url = "https://drive.google.com/file/d/" + content.getId() + "/view";
        response = http_send_text(id, content_url);
        if(response.getResponseCode() != 200)
        {
          send_message = "***The content failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
          return_message = "The content failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
        }
        content_url = "https://drive.google.com/uc?export=download&id=" + content.getId();
        send_message += "<content_url>" + content_url + "</content_url>(" + time + ")";
        log_save(send_message, account_name_of_3ds, id, "Do not save", "Do not save");
        return return_message;
      }
    }
    
    function get_profile_pic_google_url(http_response, group_or_user_id)
    {
        var content_data;
        var content;
        var folder_name = "Line_images";
        var folder;
        var sub_folder;
        var exist_folders;
        var exist_sub_folders;
        var url = "";
     
        exist_folders = DriveApp.searchFolders("'me' in owners");
        folder = check_folder_exist(exist_folders, folder_name);
        if (folder == undefined)
            folder = DriveApp.createFolder(folder_name);
    
        exist_sub_folders = folder.searchFolders("'me' in owners");
        sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
        if (sub_folder == undefined)
            sub_folder = folder.createFolder(group_or_user_id);
    
        content_data = http_response.getBlob().getAs("image/jpeg").setName("icon");
        content = sub_folder.createFile(content_data);
        content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
        url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w32-h32";
    
        return url;
    }
    
    function get_content_url(request_id, group_or_user_id, type)
    {
      var content_data;
      var content;
      var exist_folders;
      var exist_sub_folders;
      var folder_name;
      var folder;
      var sub_folder;
      var response;
      var url = "";
     
      if(type == "image")
        folder_name = "Line_images";
      else if(type == "audio")
        folder_name = "Line_audio";
      else if(type == "video")
        folder_name = "Line_videos";
     
      exist_folders = DriveApp.searchFolders("'me' in owners");
      folder = check_folder_exist(exist_folders, folder_name);
      if(folder  == undefined)
        folder = DriveApp.createFolder(folder_name);
     
      exist_sub_folders = folder.searchFolders("'me' in owners");
      sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
      if(sub_folder  == undefined)
        sub_folder = folder.createFolder(group_or_user_id);
    
      response = http_get_content(request_id);
      if(response.getResponseCode() != 200)
      {
        if(type == "image")
          url = "***Couldn't generate an image URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
        else if(type == "audio")
          url = "***Couldn't generate a audio URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
        else if(type == "video")
          url = "***Couldn't generate a video URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
      }
      else
      {
        if(type == "image")
        {
          content_data = response.getBlob().getAs("image/jpeg").setName(request_id);
          content = sub_folder.createFile(content_data);
          content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
          url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
        }
        else if(type == "audio" || type == "video")
        {
          content_data = response.getBlob().setName(request_id);
          content = sub_folder.createFile(content_data);
          content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
          url = "https://drive.google.com/uc?export=download&id=" + content.getId();
        }
      }
      return url;
    }
    
    function receive_msg_from_line(user_message, user_id, group_id, reply_token, time)
    {
      var group_name;
      var picture_url = [ "", ""];
      var response = [ "", ""];
      var send_msg;
      var user_name;
     
      if(user_message == "getid" || user_message == "getgroupid")
      {
        if(user_message == "getid")
          send_msg = user_id;
        else if(user_message == "getgroupid")
          send_msg = group_id;
     
        response[0] = http_send_text_reply(reply_token, send_msg);
        send_msg = "<id>" + send_msg + "</id>";
        if(response[0].getResponseCode() != 200)
          send_msg += "***The message failed to send. Status code = " + response[0].getResponseCode() + " " + JSON.parse(response[0].getContentText()).message + "*** ";
    
        log_save(send_msg, "BOT", "IDs", "BOT", "Do not save");
        return;
      }
    
      if(group_id == "Unknown")
        response[0] = http_get_user_name(user_id);
      else
      {
        response[0] = http_get_group_user_name(user_id, group_id);
        response[1] = http_get_group_name(group_id);
     
        if(response[1].getResponseCode() != 200)
          group_name = "Unknown";
        else
        {
          group_name = JSON.parse(response[1]).groupName;
          picture_url[1] = JSON.parse(response[1]).pictureUrl;
        }
      }
    
      if(response[0].getResponseCode() != 200)
        user_name = "Unknown";
      else
      {
        user_name = JSON.parse(response[0]).displayName;
        picture_url[0] = JSON.parse(response[0]).pictureUrl;
      }
     
      user_message += "(" + time + ")";
      if(group_id == "Unknown")
        log_save(user_message, user_name, user_id, user_name, picture_url[0]);
      else
        log_save(user_message, user_name, group_id, group_name, picture_url[1]);
    }
    
    function doPost(post_data)
    {
      var date = new Date();
      var time = Utilities.formatDate( date, 'Asia/Tokyo', 'MM/dd hh:mm:ss');
      var type = JSON.parse(post_data.postData.contents).type;
      var result;
      var lock = LockService.getScriptLock();
      var lock_result = lock.tryLock(1000);
      while(!lock_result)
      {
        Utilities.sleep(100);
        lock_result = lock.tryLock(1000);
      }
    
      if(type == undefined)
      {
        for(var i = 0; i < 30; i++)
        {
          try
          {
            var msg_id = JSON.parse(post_data.postData.contents).events[i].message.id;
            var user_message = JSON.parse(post_data.postData.contents).events[i].message.text;
            var user_id = JSON.parse(post_data.postData.contents).events[i].source.userId;
            var group_id = JSON.parse(post_data.postData.contents).events[i].source.groupId;
            var reply_token = JSON.parse(post_data.postData.contents).events[i].replyToken;
            var type = JSON.parse(post_data.postData.contents).events[i].message.type;
          }
          catch(error)
          {
            break;
          }
     
          if(user_id == undefined)
            user_id = "Unknown";
          if(group_id == undefined)
            group_id = "Unknown";
    
          if(type == "sticker")
          {
            var sticker_id  = JSON.parse(post_data.postData.contents).events[0].message.stickerId;
            user_message = "<sticker>" + sticker_id + "</sticker>";
          }
          else if(type == "image")
          {
           if(group_id == "Unknown")
             user_message = "<image_url>" + get_content_url(msg_id, user_id, type) + "</image_url>";
           else
             user_message = "<image_url>" + get_content_url(msg_id, group_id, type) + "</image_url>";
          }
          else if(type == "audio")
          {
           if(group_id == "Unknown")
             user_message = "<audio_url>" + get_content_url(msg_id, user_id, type) + "</audio_url>";
           else
             user_message = "<audio_url>" + get_content_url(msg_id, group_id, type) + "</audio_url>";
          }
          else if(type == "video")
          {
           if(group_id == "Unknown")
             user_message = "<video_url>" + get_content_url(msg_id, user_id, type) + "</video_url>";
           else
             user_message = "<video_url>" + get_content_url(msg_id, group_id, type) + "</video_url>";
          }
          else if(user_message == undefined)
            user_message += " : " + type + " " + msg_id;
    
          receive_msg_from_line(user_message, user_id, group_id, reply_token, time);
        }
        lock.releaseLock();
        return;
      }
    
      var client_auth = JSON.parse(post_data.postData.contents).auth;
      var client_gas_ver = JSON.parse(post_data.postData.contents).gas_ver;
      if(client_auth == undefined)
        client_auth = "";
      if(client_gas_ver == undefined)
        client_gas_ver = -1;
     
      if(script_password == client_auth)
      {
        if(gas_ver == client_gas_ver)
        {
          var id = JSON.parse(post_data.postData.contents).id;
     
          if(type == "send_text")
          {
            var send_message = JSON.parse(post_data.postData.contents).message;
            result = send_msg(id, send_message, time);
          }
          else if(type == "send_sticker")
          {
            var package_id = JSON.parse(post_data.postData.contents).package_id;
            var sticker_id = JSON.parse(post_data.postData.contents).sticker_id;
            result = send_sticker(id, package_id, sticker_id, time);
          }
          else if(type == "upload_content")
          {
            var content_data = JSON.parse(post_data.postData.contents).content_data;
            var count = JSON.parse(post_data.postData.contents).count;
            var name = JSON.parse(post_data.postData.contents).name;
            result = upload_content(id, content_data, count, name);
          }
          else if(type == "send_content")
          {
            var name = JSON.parse(post_data.postData.contents).name;
            result = send_content(id, name, time);
          }
          else
            result = "Unknown message type.";
        }
        else
          result = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
      }
      else
        result = "Auth failed. Please set correct password.";
    
      lock.releaseLock();
      return ContentService.createTextOutput(result);
    }
    
    function doGet(post_data)
    {
      var data = "";
      var client_auth = post_data.parameter.script_auth;
      var client_gas_ver = post_data.parameter.gas_ver;
      if(client_auth == undefined)
        client_auth = "";
      if(client_gas_ver == undefined)
        client_gas_ver = -1;
    
      if(script_password == client_auth)
      {
        if(gas_ver == client_gas_ver)
          data = log_read(post_data.parameter.id);
        else
          data = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
      }
      else
        data = "Auth failed. Please set correct password.";
     
      return ContentService.createTextOutput(data);
    }


Then click Publish -> Deploy as web app and set
"Project version" : New
"Execute the app as" : Me(***@gmail.com)

"Who has access to the app" : Anyone,even anonymous
finally click deploy.

2380c28d8c9f5f0fdba5bcaad06b5e09.png
Next click Review permissions and select your google account.
If "This app isn't verified or You should avoid this app" shown click Advanced and click "
Go to Line main (unsafe)" (⁂It's safe!) and click allow.
Copy this url and save.


578f8adc76932a8223d45d904303d707.png

Back to Line Messaging API
Find Webhook URL and click edit.

⁂ DO NOT TYPE SHORT URL HERE ⁂
Type your
Google apps script URL and click Update

003b8ec8407b4db43fef03a9a6337a6b.png
And turn on Use webhook
5dc4172fb531eacaf26757aa3fdb1b64.png

Click verify to check webhook works fine.
Check result and if "success" wasn't displayed, double check your Google apps script URL.
.
(delete whole url once and retyping is also good idea)

Please open https://free-url-shortener.rb.gy/ , https://tiny.cc/ or https://tinyurl.com/
Then shorten your Google apps script URL.
Your URL should be
http://tinyurl.com/****** or http://tiny.cc/****** or http://rb.gy/******
This short URL is needed by next section.
Then go to (Guide) How to setup (3DS).

If you have any problems fell free to ask me on this discord server.
https://discord.gg/bzGnu2a



Download this
https://github.com/Core-2-Extreme/Line_for_3DS/releases

Start app and select Line.
Set your password (if you don't want use password, enter as empty).

For ver 1.5.0~1.7.0


  1. This guide compatible with ver 1.5.01.7.0

    Next step there are 2 methods
    Press L + R button (or tap Change main URL (short)) and type your short url
    You MUST type short URL with http:// NOT https:// (I don't know why but https:// won't work.)

    I do NOT recommend this method because it is hell ;(
    if you want to type whole URL, press X button (or tap Change main URL) and type your google apps script URL.

Then go to (Guide)How to add friend.
If you have any problems fell free to ask me on this discord server.
https://discord.gg/bzGnu2a



PC or phone (or android emulator)
Find Bot information and scan your bot's QR code or search friends by BOT basic ID.

c5fce08f621dcbde7f904b526a0dde38.png



For ver 1.6.0~1.7.0For ver 1.2.0~1.5.2


  1. This guide compatible with ver 1.6.01.7.0

    3DS

    Press Y button (or tap Add new ID) and type "IDs".

    00000024.jpg
    00000021.jpg

    Select "IDs".
    00000032.jpg

    Tap "Receive" tab and press B button (or tap log update)
    00000030.jpg

    If you get No such sheet error,
    send "getid" to your 3DS account from your phone/PC account.
    Then try again.
    00000029.png


    You'll see touch to add this ID and tap it.

    00000029.jpg
    00000031.jpg
    00000033.jpg


  2. And send "getid".
    00000029.png


    For ver 1.5.0~1.5.2For ver 1.2.0~1.4.2


    1. This guide compatible with ver 1.5.01.5.2
      ⚠⚠⚠WARNING⚠⚠⚠ I strongly recommend you use the newest version ⚠⚠⚠WARNING⚠⚠⚠

      3DS

      Press Y button (or tap Add new ID) and type "IDs".
      00000024.jpg
      00000021.jpg

      Select "IDs".
      00000032.jpg

      Tap "Receive" tab and press B button (or tap log update)
      00000030.jpg

      You'll see touch to add this ID and tap it.
      00000029.jpg
      00000031.jpg
      00000033.jpg



    2. This guide compatible with ver 1.2.01.4.2
      ⚠⚠⚠WARNING⚠⚠⚠ I strongly recommend you use the newest version ⚠⚠⚠WARNING⚠⚠⚠

      3DS

      Tap "Advanced setting" and press Y button and type ID.



If you have any problems fell free to ask me on this discord server.
https://discord.gg/bzGnu2a

Enjoy!
 
Last edited by Core_2_Extreme,

Core_2_Extreme

Well-Known Member
OP
Member
Joined
Feb 11, 2019
Messages
153
Trophies
0
Age
22
XP
1,163
Country
Japan
I don't know how Line works, but it feels like it shouldn't be impossible :) What happens in the 3DS if you send a stamp or picture from the phone?

Send from 3DS
3DS -> Google server -> LINE server -> line app
Send from line app
line app -> LINE server -> Google server -> save to message log google server -> 3DS(Request data to google and receive data)

I will write tutorial how to use line on 3DS. But it will write a little later.

If you send picture, video, sound, or stamp. 3DS will be displayed "undefined".
PC
f4a736e8a04da27a011bbff46d0b2043.png


3DS
04f5c63b1d71204a936682163f971611.png
 
  • Like
Reactions: Issac

Issac

Iᔕᔕᗩᑕ
Supervisor
Joined
Apr 10, 2004
Messages
7,025
Trophies
3
Location
Sweden
XP
7,344
Country
Sweden
Send from 3DS
3DS -> Google server -> LINE server -> line app
Send from line app
line app -> LINE server -> Google server -> save to message log google server -> 3DS(Request data to google and receive data)

I will write tutorial how to use line on 3DS. But it will write a little later.

If you send picture, video, sound, or stamp. 3DS will be displayed "undefined".
PC
f4a736e8a04da27a011bbff46d0b2043.png


3DS
04f5c63b1d71204a936682163f971611.png
Thank you! That's interesting :)
 
  • Like
Reactions: Core_2_Extreme
D

Deleted-481927

Guest
This looks awesome!

How'd you do this?

I'd be interested to see if something similar could be done w/ Discord, but this is genuinely awesome this is what homebrew this community needs.
 
  • Like
Reactions: Core_2_Extreme

lone_wolf323

Well-Known Member
Member
Joined
May 27, 2011
Messages
5,485
Trophies
2
XP
4,928
Country
Canada
This looks awesome!

How'd you do this?

I'd be interested to see if something similar could be done w/ Discord, but this is genuinely awesome this is what homebrew this community needs.
discord was already done. and it was shown that it could and highly likely ban your discord account using it.
 

PokeNev

Well-Known Member
Member
Joined
Nov 11, 2018
Messages
336
Trophies
0
Age
26
XP
960
Country
United States
v1.0.1 release
* Fix- App icon
* Fix- .cia version
* Fix- Even if you type the correct password, it still will not verify

v1.0.0 release

This release is expected some issues


* Add- other app(Google translation etc)
* Fix- Some bugs


https://github.com/Core-2-Extreme/Line_for_3DS/releases

If you have any questions you can ask on this discord server.
https://discord.gg/Zmx7Euf


Supported function:
  • Send text ✅
  • Send picture ❌
  • Send video ❌
  • Send sound ❌
  • Send stamp ❌
  • Receive text ✅
  • Receive (View) picture ❌
  • Receive (Play) video ❌
  • Receive (Play) sound ❌
  • Receive (View) stamp ❌
  • View old log ✅ (Until max 300 logs)
  • Auto update ✅ (v0.2.0)
  • Group chat ✅
  • Night mode ✅ (v0.2.0)
  • Password ✅ (v0.3.0)
  • Save log to SD card ✅ (v0.3.0)




320b51ed51d0d3afe450d8f5f0cd11b5.png



Please access this site.
https://developers.line.biz/en/
Click log in.
Click Log in with LINE account.
Click Create.
43147207b4eb4e1684a075e305cb67a2.png


Type your name and click Create.
9cc90ea609fef8352e3bca436c3dfadb.png

Click Create a Messaging API channel.
82e0e983b00bd59dc96fd5e7d3b1149b.png


Type each item and click Create.
e13e2114c0a5e59ce66fc37eab6c94e1.png

Click Messaging API.
c83dd1e128675599398fb9af41eb9361.png


Find Channel access token (long-lived) and click Issue.
Then copy Channel access token (long-lived).
15ffd7c288cbf6ab5144158f5402e3a5.png


Please access this site.
https://www.google.com/intl/en_ALL/drive/
Click Go to google drive and login.
Click New and click Google sheets(1 time) and click More -> Google apps script (2 times).
ba42e4bbfe93bf4245858688ee0d02d9.png



Open created Google sheets and copy sheet id.(Do NOT include '/' )
f22b2c7b64acf04808a118983f744685.png



Open created Google apps script and rename google apps script name "Untitled project" to "Line main". (or your favorite name)
cf714d96090d736cb42a24b7a8997deb.png


Copy this code to "Line main" and add your sheet ID and access token.

var ACCESS_TOKEN = "Your access token here";
var open_sheet_id = "Your sheet id here";
function log_save(message, user_name, write_sheet_name)
{
var sheet_id = 1;
var spreadsheet = SpreadsheetApp.openById(open_sheet_id);
var write_sheet = spreadsheet.getSheetByName(write_sheet_name);
if(!write_sheet)
{
spreadsheet.insertSheet(write_sheet_name);
}
write_sheet = spreadsheet.getSheetByName(write_sheet_name);

while(true)
{
var target_sheet = write_sheet.getRange("A" + sheet_id);
var sheet_data = target_sheet.getValue();

if(sheet_data == "")
{
write_sheet.getRange("A" + sheet_id).setValue("" + user_name + " : " + message);
break;
}
else
{
sheet_id++;
}
}
}

function doPost(e)
{
var date = new Date();
var time = Utilities.formatDate( date, 'Asia/Tokyo', 'MM/dd hh:mm:ss');
var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
var user_message = JSON.parse(e.postData.contents).events[0].message.text;
var url_reply = 'https://api.line.me/v2/bot/message/reply';
var url_profile = 'https://api.line.me/v2/bot/profile/'
var user_id = JSON.parse(e.postData.contents).events[0].source.userId;
var group_id = JSON.parse(e.postData.contents).events[0].source.groupId;
var type = JSON.parse(e.postData.contents).events[0].message.type;
if(user_message == "getid")
{
UrlFetchApp.fetch(url_reply, {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + ACCESS_TOKEN,
},
'method': 'post',
'payload': JSON.stringify({
'replyToken': replyToken,
'messages': [{
'type': 'text',
'text': user_id ,
}],
'notificationDisabled': 'true',
}),
});
log_save(user_id, "BOT", "test");
}
else if(user_message == "getgroupid")
{
UrlFetchApp.fetch(url_reply, {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + ACCESS_TOKEN,
},
'method': 'post',
'payload': JSON.stringify({
'replyToken': replyToken,
'messages': [{
'type': 'text',
'text': group_id ,
}],
'notificationDisabled': 'true',
}),
});
log_save(group_id, "BOT", "test");
}

try
{
var response = UrlFetchApp.fetch(url_profile + user_id, {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + ACCESS_TOKEN,
},
});
var profile_name = JSON.parse(response).displayName;
}
catch(error)
{
profile_name = "Unknown";
}

if(user_message == undefined)
{
user_message += " : " + type;
}
user_message += "(" + time + ")";
if(group_id == undefined)
{
log_save(user_message, profile_name, user_id);
}
else
{
log_save(user_message, profile_name, group_id);
}

return;
}

function doGet(e)
{
var request_data = e.parameter;
var request_id = request_data.id;
var sheet_start;
var data = "";
var spreadsheet = SpreadsheetApp.openById(open_sheet_id);
var read_sheet = spreadsheet.getSheetByName(request_id);

for(var i = 1; i <= 10000000; i++)
{
var target_sheet = read_sheet.getRange("A" + i);
var sheet_data = target_sheet.getValue();
if(sheet_data == "")
{
if(i >= 301)
{
sheet_start = (i - 300);
}
else
{
sheet_start = 1;
}
break;
}

}

for(var i = 0; i <= 299; i++)
{
var target_sheet = read_sheet.getRange("A" + (sheet_start + i));
var sheet_data = target_sheet.getValue();
data = data + sheet_data;
}
return ContentService.createTextOutput(data);
}

Then click Publish -> Deploy as web app and set "who has access to the app" is Anyone,even anonymous, finally click deploy.
2380c28d8c9f5f0fdba5bcaad06b5e09.png

Next click Review permissions and select your google account.
If "This app isn't verified or You should avoid this app" shown click Advanced and click Go to Line main (unsafe) and click allow.

Copy this url and save.
This is url ①

578f8adc76932a8223d45d904303d707.png



Open created Google apps script and rename google apps script name "Untitled project" to "Line post". (or your favorite name)
cf714d96090d736cb42a24b7a8997deb.png


Copy this code to "Line post" and add your sheet ID and access token.

var ACCESS_TOKEN = "Your access token here";
var open_sheet_id = "Your sheet id here";
var account_name_of_3ds = "Your 3DS's account name here";
function log_save(message, user_name, write_sheet_name)
{
var sheet_id = 1;
var spreadsheet = SpreadsheetApp.openById(open_sheet_id);
var write_sheet = spreadsheet.getSheetByName(write_sheet_name);
if(!write_sheet)
{
spreadsheet.insertSheet(write_sheet_name);
}
write_sheet = spreadsheet.getSheetByName(write_sheet_name);

while(true)
{
var target_sheet = write_sheet.getRange("A" + sheet_id);
var sheet_data = target_sheet.getValue();

if(sheet_data == "")
{
write_sheet.getRange("A" + sheet_id).setValue("" + user_name + " : " + message);
break;
}
else
{
sheet_id++;
}
}
}

function doPost(e)
{
var date = new Date();
var time = Utilities.formatDate( date, 'Asia/Tokyo', 'MM/dd hh:mm:ss');
var send_message = JSON.parse(e.postData.contents).message;
var id = JSON.parse(e.postData.contents).to;

var url = 'https://api.line.me/v2/bot/message/push';
var url_profile = 'https://api.line.me/v2/bot/profile/'

UrlFetchApp.fetch(url, {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + ACCESS_TOKEN,
},
'method': 'post',
'payload': JSON.stringify({
"to": id,
"messages":
[
{
"text": send_message,
"type": "text",
}],
'notificationDisabled': 'false',
}),
});


send_message += "(" + time + ")";
log_save(send_message, account_name_of_3ds, id);
return;
}

Then click Publish -> Deploy as web app and set "who has access to the app" is Anyone,even anonymous, finally click deploy.
2380c28d8c9f5f0fdba5bcaad06b5e09.png

Next click Review permissions and select your google account.
If "This app isn't verified or You should avoid this app" shown click Advanced and click Go to Line main (unsafe) and click allow.

Copy this url and save.
This is url ②
578f8adc76932a8223d45d904303d707.png


Back to Line Messaging API
Find Webhook URL and click edit.

Type your URL① and click Update
3fd3e1947f6a65e8d2449ab3e466776b.png

And turn on Use webhook
5dc4172fb531eacaf26757aa3fdb1b64.png

3DS
Download this
https://github.com/Core-2-Extreme/Line_for_3DS/releases

Start app and select Line.

Set your password (if you don't want use password, enter as empty).

Press X button.
First, type url ①
Second, type url ②

How to add friend
2986011d823da85a8eec36cd6b3d1dfc.png

Please add your bot QR code your friends.
And type "getid".


3DS
Press Y button and type ID.
84e6960b691e2c38b5bc7ba76856115a.png
Control
A
: Send message
B : Update log
X : URL setting
Y : Add id
CPAD(Slide pad) UP, DOWN, LEFT and RIGHT : Move message
L and R : Change text size
DPAD(Analog pad) UP and DOWN : Change text interval
DPAD(Analog pad) LEDT and RIGHT : Change id
Start -> A : Exit app

Enjoy!

Will you ever add the feature to send videos? Or is that out of the question at this point?
 
  • Like
Reactions: Core_2_Extreme

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    Psionic Roshambo @ Psionic Roshambo: I think a raspberry pi zero could power a SNES cart emulator thing hmmm