1. Core_2_Extreme

    OP Core_2_Extreme Member
    Newcomer

    Joined:
    Feb 11, 2019
    Messages:
    31
    Country:
    Japan
    Download (latest version v1.5.1)
    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 image ✅ (v1.4.0)
    • Send video ✅(*2) (v1.4.0)
    • Send sound ✅(*2) (v1.4.0)
    • Send sticker ✅ (*1) (v1.3.0)
    • Receive text ✅
    • Receive (View) image ✅ (v1.2.0)
    • Receive (Play) video ❌
    • Receive (Play) sound ⚠(*3) (v1.5.0)
    • Receive (View) sticker ✅(*1) (v1.3.0)
    • View old log ✅ (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)

    *1 The stickers must be included this list
    https://developers.line.biz/media/messaging-api/sticker_list.pdf

    *2 Google drive URL will be sent(not embed).

    *3 There is music player that can play .mp3 and .wav, but line return .m4a file so you can't play line audio file in this version.


    How to set up (v1.3.0~)
    Video
    (Guide) How to install and use

    • This guide compatible with ver 1.5.0
      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.
      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 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 (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 and 3DS's account name(Your favorite name).

      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 "who has access to the app" is Anyone,even anonymous, finally click deploy.


      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.
      2380c28d8c9f5f0fdba5bcaad06b5e09.png
      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 URL and click Update

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

      Please access https://free-url-shortener.rb.gy/ or 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 ((Guide) How to install and use (3DS))

    • This guide compatible with ver 1.4.01.4.2
      ⚠⚠⚠WARNING⚠⚠⚠ I strongly recommend you use the newest version ⚠⚠⚠WARNING⚠⚠⚠

      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.
      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 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 (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 and 3DS's account name(Your favorite name).

      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 = 4;//Do **NOT** edit this value.
      function log_save(message, user_name, write_sheet_name)
      {
        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_pos(write_sheet, (sheet_pos + 1));
      }
      
      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_pos(read_sheet, sheet_start);
            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();
        for(var i = 0; i < 300; i++)
        {
          if(sheet_data[i] == "")
            break;
       
          return_data += sheet_data[i];
        }
        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 write_cache_pos(sheet_object, cache_data)
      {
        sheet_object.getRange("B1").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_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);
        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);
        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);
          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);
          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);
          return return_message;
        }
      }
      
      function get_content_url(request_id, group_or_user_id, type)
      {
        var content_data;
        var content;
        var url = "";
        var folder_name;
        var folder;
        var sub_folder;
        var exist_folders;
        var exist_sub_folders;
        var response;
       
        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 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 = http_send_text_reply(reply_token, send_msg);
          if(response.getResponseCode() != 200)
            send_msg += "***The message failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
      
          log_save(send_msg, "BOT", "IDs");
          return;
        }
       
        if(group_id == "Unknown")
          response = http_get_user_name(user_id);
        else
          response = http_get_group_user_name(user_id, group_id);
       
        if(response.getResponseCode() != 200)
          user_name = "Unknown";
        else
          user_name = JSON.parse(response).displayName;
      
        user_message += "(" + time + ")";
        if(group_id == "Unknown")
          log_save(user_message, user_name, user_id);
        else
          log_save(user_message, user_name, group_id);
      }
      
      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);
            data += "<success>";
          }
          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 "who has access to the app" is Anyone,even anonymous, finally click deploy.


      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.
      2380c28d8c9f5f0fdba5bcaad06b5e09.png
      Copy this url and save.

      578f8adc76932a8223d45d904303d707.png

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

      Type your URL and click Update

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


    • ⚠⚠⚠WARNING⚠⚠⚠ I strongly recommend you use the newest version ⚠⚠⚠WARNING⚠⚠⚠
      This guide compatible with ver 1.3.01.3.1
      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.
      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 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 (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 and 3DS's account name(Your favorite name).

      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 = 3;//Do **NOT** edit this value.
      function log_save(message, user_name, write_sheet_name)
      {
        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_pos(write_sheet, (sheet_pos + 1));
      }
      
      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_pos(read_sheet, sheet_start);
            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();
        for(var i = 0; i < 300; i++)
        {
          if(sheet_data[i] == "")
            break;
       
          return_data += sheet_data[i];
        }
        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 write_cache_pos(sheet_object, cache_data)
      {
        sheet_object.getRange("B1").setValue(cache_data);
      }
      
      function send_msg(id, send_message, time)
      {
         var return_message = "Success";
         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_message,
                  "type": "text",
               }],
              'notificationDisabled': 'false',
            }),
           muteHttpExceptions: true,
          });
       
          if(response.getResponseCode() != 200)
          {
            var cache = "***Send failed. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message + "*** ";
            cache += send_message;
            send_message = cache;
            return_message = "Send message failed. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
          }
        send_message += "(" + time + ")";
        log_save(send_message, account_name_of_3ds, id);
        return return_message;
      }
      
      function send_sticker(id, package_id, sticker_id, time)
      {
        var return_message = "Success";
        var send_message = "";
        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,
          });
          if(response.getResponseCode() != 200)
          {
           send_message = "***Send failed. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message + "*** ";
           return_message = "Send sticker failed. 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);
        return return_message;
      }
      
      function get_content_url(request_id, group_or_user_id, type)
      {
        var content_url = "https://api.line.me/v2/bot/message/" + request_id + "/content";
        var url = "";
        var folder_name;
        var folder;
        var sub_folder;
        var folder_exist = false;
        var sub_folder_exist = false;
      
       try
       {
          if(type == "image")
            folder_name = "Line_images";
          else if(type == "audio")
            folder_name = "Line_audio";
          else if(type == "video")
            folder_name = "Line_videos";
       
          var exist_folders = DriveApp.searchFolders("'me' in owners");
          while (exist_folders.hasNext())
          {
            folder = exist_folders.next();
            if(folder_name == folder.getName())
            {
              folder_exist = true;
              break;
            }
          }
       
          if(!folder_exist)
            folder = DriveApp.createFolder(folder_name);
       
       
          var exist_sub_folders = folder.searchFolders("'me' in owners");
          while (exist_sub_folders.hasNext())
          {
            sub_folder = exist_sub_folders.next();
            if(group_or_user_id == sub_folder.getName())
            {
              sub_folder_exist = true;
              break;
            }
          }
       
          if(!sub_folder_exist)
            sub_folder = folder.createFolder(group_or_user_id);
       
          var response = UrlFetchApp.fetch(content_url,
          {
          'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
              }
          });
       
          if(type == "image")
          {
            var image_data = response.getBlob().getAs("image/jpeg").setName(request_id + ".jpg");
            var image = sub_folder.createFile(image_data);
            image.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
            url = "https://drive.google.com/uc?export=download&id=" + image.getId();
          }
          else if(type == "audio")
          {
            var audio_data = response.getBlob().setName(request_id + ".mp3");
            var audio = sub_folder.createFile(audio_data);
            audio.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
            url = "https://drive.google.com/uc?export=download&id=" + audio.getId();
          }
          else if(type == "video")
          {
            var video_data = response.getBlob().setName(request_id + ".mp4");
            var video = sub_folder.createFile(video_data);
            video.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
            url = "https://drive.google.com/uc?export=download&id=" + video.getId();
          }
        }
         catch(error)
        {
          if(type == "image")
            url = "Generate image url failed.";
          else if(type == "audio")
            url = "Generate audio url failed.";
          else if(type == "video")
            url = "Generate video url failed.";
        }
        return url;
      }
      
      
      function receive_msg_from_line(user_message, user_id, group_id, replyToken, time)
      {
        var url_reply = 'https://api.line.me/v2/bot/message/reply';
        var url_profile = 'https://api.line.me/v2/bot/profile/';
        if(user_message == "getid" || user_message == "getgroupid")
        {
          var send_id;
          if(user_message == "getid")
            send_id = user_id;
          else if(user_message == "getgroupid")
            send_id = group_id;
       
          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': send_id ,
              }],
              'notificationDisabled': 'true',
            }),
          });
          log_save(send_id, "BOT", "IDs");
          return;
        }
      
        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";
        }
      
        user_message += "(" + time + ")";
      
        if(group_id == "Unknown")
          log_save(user_message, profile_name, user_id);
        else
          log_save(user_message, profile_name, group_id);
      }
      
      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;
      
        if(type == undefined)
        {
          var msg_id = JSON.parse(post_data.postData.contents).events[0].message.id;
          var user_message = JSON.parse(post_data.postData.contents).events[0].message.text;
          var user_id = JSON.parse(post_data.postData.contents).events[0].source.userId;
          var group_id = JSON.parse(post_data.postData.contents).events[0].source.groupId;
          var replyToken = JSON.parse(post_data.postData.contents).events[0].replyToken;
          var type = JSON.parse(post_data.postData.contents).events[0].message.type;
       
          if(user_id == undefined)
            user_id = "Unknown";
          if(group_id == undefined)
            group_id = "Unknown";
      
          if(type == "sticker")
          {
            var sticker_sticker_id  = JSON.parse(post_data.postData.contents).events[0].message.stickerId;
            user_message = "<sticker>" + 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, replyToken, time);
           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)
          {
            if(type == "send_text")
            {
              var id = JSON.parse(post_data.postData.contents).id;
              var send_message = JSON.parse(post_data.postData.contents).message;
              result = send_msg(id, send_message, time);
            }
            else if(type == "send_sticker")
            {
              var id = JSON.parse(post_data.postData.contents).id;
              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
              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.";
       
        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);
            data += "<success>";
          }
          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 "who has access to the app" is Anyone,even anonymous, finally click deploy.


      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.
      2380c28d8c9f5f0fdba5bcaad06b5e09.png
      Copy this url and save.

      578f8adc76932a8223d45d904303d707.png

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

      Type your URL and click Update

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


    • ⚠⚠⚠WARNING⚠⚠⚠ I strongly recommend you use the newest version ⚠⚠⚠WARNING⚠⚠⚠
      This guide compatible with ver 1.2.01.2.2
      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.
      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 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 (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 and 3DS's account name(Your favorite name).

      Code:
      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 (Your favorite name)";
      function log_save(message, user_name, write_sheet_name)
      {
        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_name);
       
        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_pos(write_sheet_name, (sheet_pos + 1));
      }
      
      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(id);
       
        while(true)
        {
          sheet_data = read_sheet.getRange("A" + sheet_start).getValue();
          if(sheet_data == "")
          {
            write_cache_pos(id, sheet_start);
            if(sheet_start >= 301)
              sheet_start = (sheet_start - 300);
            else
              sheet_start = 1;
       
            break;
          }
          else
            sheet_start++;
        }
       
        for(var i = 0; i <= 299; i++)
        {
          sheet_data = read_sheet.getRange("A" + (sheet_start + i)).getValue();
          return_data = return_data + sheet_data;
        }
       
        return return_data;
      }
      
      function get_cache_pos(id)
      {
        var spreadsheet = SpreadsheetApp.openById(open_sheet_id);
        var read_cache_sheet = spreadsheet.getSheetByName(id);
        var cached_sheet_pos = read_cache_sheet.getRange("B1").getValue();
        var sheet_data;
       
        if(parseInt(cached_sheet_pos) > 0)
        {
          cached_sheet_pos = parseInt(cached_sheet_pos);
          sheet_data = read_cache_sheet.getRange("A" + (cached_sheet_pos - 1)).getValue();
       
          if(sheet_data != "")
            return cached_sheet_pos;
        }
        return 1;
      }
      
      function write_cache_pos(id, cache_data)
      {
        var spreadsheet = SpreadsheetApp.openById(open_sheet_id);
        var write_cache_sheet = spreadsheet.getSheetByName(id);
        write_cache_sheet.getRange("B1").setValue(cache_data);
      }
      
      function send_msg(id, send_message, time)
      {
         var url = 'https://api.line.me/v2/bot/message/push';
          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);
      }
      
      function get_image_url(request_id, group_or_user_id)
      {
       var content_url = "https://api.line.me/v2/bot/message/" + request_id + "/content";
       var url = "";
       var folder;
       var sub_folder;
       var folder_exist = false;
       var sub_folder_exist = false;
      
       try
       {
          var exist_folders = DriveApp.searchFolders("'me' in owners");
          while (exist_folders.hasNext())
          {
            folder = exist_folders.next();
            if("Line_images" == folder.getName())
            {
              folder_exist = true;
              break;
            }
          }
       
          if(!folder_exist)
            folder = DriveApp.createFolder("Line_images");
      
          var exist_sub_folders = folder.searchFolders("'me' in owners");
          while (exist_sub_folders.hasNext())
          {
            sub_folder = exist_sub_folders.next();
            if(group_or_user_id == sub_folder.getName())
            {
              sub_folder_exist = true;
              break;
            }
          }
       
          if(!sub_folder_exist)
            sub_folder = folder.createFolder(group_or_user_id);
       
          var response = UrlFetchApp.fetch(content_url,
          {
          'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + ACCESS_TOKEN,
              }
          });
       
          var image_data = response.getBlob().getAs("image/jpeg").setName("image.jpg")
          var image = sub_folder.createFile(image_data);
          image.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
          url = "https://drive.google.com/uc?export=download&id=" + image.getId()
        }
         catch(error)
        {
          url = "Generate image url failed."
        }
        return url;
      }
      
      
      function receive_msg_from_line(user_message, user_id, group_id, replyToken, type, msg_id, time)
      {
          var url_reply = 'https://api.line.me/v2/bot/message/reply';
          var url_profile = 'https://api.line.me/v2/bot/profile/';
         if(user_message == "getid" || user_message == "getgroupid")
        {
          var send_id;
          if(user_message == "getid")
            send_id = user_id;
          else if(user_message == "getgroupid")
            send_id = group_id;
       
          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': send_id ,
              }],
              'notificationDisabled': 'true',
            }),
          });
          log_save(send_id, "BOT", "IDs");
        }
      
        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)
        {
          if(type == "image")
          {
            if(group_id == "Unknown")
              user_message = "<image_url>" + get_image_url(msg_id, user_id) + "</image_url>";
            else
              user_message = "<image_url>" + get_image_url(msg_id, group_id) + "</image_url>";
          }
          else
            user_message += " : " + type + " " + msg_id;
        }
      
        user_message += "(" + time + ")";
      
        if(group_id == "Unknown")
          log_save(user_message, profile_name, user_id);
        else
          log_save(user_message, profile_name, group_id);
      }
      
      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;
        if(type == "send")
        {
           var send_message = JSON.parse(post_data.postData.contents).message;
           var id = JSON.parse(post_data.postData.contents).id;
           send_msg(id, send_message, time);
        }
        else
        {
        var user_message = JSON.parse(post_data.postData.contents).events[0].message.text;
        var user_id = JSON.parse(post_data.postData.contents).events[0].source.userId;
        var group_id = JSON.parse(post_data.postData.contents).events[0].source.groupId;
        var replyToken = JSON.parse(post_data.postData.contents).events[0].replyToken;
        var type = JSON.parse(post_data.postData.contents).events[0].message.type;
        var msg_id = JSON.parse(post_data.postData.contents).events[0].message.id;
       
          if(user_id == undefined)
          user_id="Unknown";
          if(group_id == undefined)
          group_id="Unknown";
      
          receive_msg_from_line(user_message, user_id, group_id, replyToken, type, msg_id, time);
        }
        return;
      }
      
      function doGet(post_data)
      {
        var data = "";
        data = log_read(post_data.parameter.id);
        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.


      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.
      2380c28d8c9f5f0fdba5bcaad06b5e09.png
      Copy this url and save.

      578f8adc76932a8223d45d904303d707.png

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

      Type your URL and click Update

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



    (Guide) How to install and use (3DS)


    • This guide compatible with ver 1.5.0
      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).

      Next step there are 2 methods
      Method 1 (Easy)
      Press L + R button (or tap Change main URL (short)) and type your short url

      Method 2 (Very hard or HELL)
      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 url

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

      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).

      Tap "Advanced setting" and Press X button and type your url



    • This guide compatible with ver 1.5.0
      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
      And send "getid".


      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

    • This guide compatible with ver 1.2.01.4.2
      ⚠⚠⚠WARNING⚠⚠⚠ I strongly recommend you use the newest version ⚠⚠⚠WARNING⚠⚠⚠
      Find Bot information and scan your bot's QR code or search friends by BOT basic ID.
      c5fce08f621dcbde7f904b526a0dde38.png
      And send "getid".
      84e6960b691e2c38b5bc7ba76856115a.png

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


    Enjoy!
     

    Attached Files:

    Last edited by Core_2_Extreme, Jun 30, 2020
  2. BORTZ

    BORTZ The Amazing
    Supervisor

    Joined:
    Dec 2, 2007
    Messages:
    12,995
    Country:
    United States
    This is the kinda homebrew I love to see. Nice work, OP.
     
    Core_2_Extreme likes this.
  3. Issac

    Issac I
    Supervisor

    Joined:
    Apr 10, 2004
    Messages:
    6,680
    Country:
    Sweden
    Wow, really cool! Nice work!

    Edit:
    Do you have any plans to try to implement stamps? Or the other features that it can't do right now :)
     
    Last edited by Issac, May 28, 2019
    Core_2_Extreme likes this.
  4. pilladoll

    pilladoll GBAtemp Regular
    Member

    Joined:
    Nov 14, 2004
    Messages:
    192
    Country:
    Mexico
    Nice!
     
    Core_2_Extreme likes this.
  5. Core_2_Extreme

    OP Core_2_Extreme Member
    Newcomer

    Joined:
    Feb 11, 2019
    Messages:
    31
    Country:
    Japan

    I will try add picture and stamp view. (and send)
    But I don't know it's possible.
     
  6. Issac

    Issac I
    Supervisor

    Joined:
    Apr 10, 2004
    Messages:
    6,680
    Country:
    Sweden
    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?
     
    Core_2_Extreme likes this.
  7. Core_2_Extreme

    OP Core_2_Extreme Member
    Newcomer

    Joined:
    Feb 11, 2019
    Messages:
    31
    Country:
    Japan
    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
    [​IMG]

    3DS
    [​IMG]
     
    Issac likes this.
  8. Issac

    Issac I
    Supervisor

    Joined:
    Apr 10, 2004
    Messages:
    6,680
    Country:
    Sweden
    Thank you! That's interesting :)
     
    Core_2_Extreme likes this.
  9. 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.
     
    Core_2_Extreme likes this.
  10. lone_wolf323

    lone_wolf323 GBAtemp Psycho!
    Member

    Joined:
    May 27, 2011
    Messages:
    3,348
    Country:
    Canada
    discord was already done. and it was shown that it could and highly likely ban your discord account using it.
     
    Core_2_Extreme likes this.
  11. Oh yeah I'm aware but I was thinking ab a client w/ WebSockets
     
    Core_2_Extreme likes this.
  12. Zurdonx

    Zurdonx Advanced Member
    Newcomer

    Joined:
    Oct 2, 2018
    Messages:
    72
    Country:
    Venezuela
    Looks interesting. Great work!
     
    Core_2_Extreme likes this.
  13. HIDE810

    HIDE810 Member
    Newcomer

    Joined:
    Apr 22, 2019
    Messages:
    28
    Country:
    Japan
    Nice work!:D
     
    Core_2_Extreme likes this.
  14. triplekiller
    This message by triplekiller has been removed from public view by Quantumcat, Jun 14, 2019, Reason: Empty/bumping.
    Jun 13, 2019 Show
  15. Deleted-481927
    This message by Deleted-481927 has been removed from public view by Quantumcat, Jun 14, 2019, Reason: Reply to deleted post.
    Jun 13, 2019 Show
  16. Core_2_Extreme

    OP Core_2_Extreme Member
    Newcomer

    Joined:
    Feb 11, 2019
    Messages:
    31
    Country:
    Japan
  17. Core_2_Extreme

    OP Core_2_Extreme Member
    Newcomer

    Joined:
    Feb 11, 2019
    Messages:
    31
    Country:
    Japan
    Last edited by Core_2_Extreme, Mar 17, 2020
    Zurdonx likes this.
  18. junk16

    junk16 Newbie
    Newcomer

    Joined:
    Dec 15, 2019
    Messages:
    1
    Country:
    Japan
    Nice work!! but,when I do it, it crash... sad please tell me how to do ver 1.1
     
    Core_2_Extreme likes this.
  19. Core_2_Extreme

    OP Core_2_Extreme Member
    Newcomer

    Joined:
    Feb 11, 2019
    Messages:
    31
    Country:
    Japan
    I updated guide, please try again.
     
  20. PokeNev

    PokeNev GBAtemp Fan
    Member

    Joined:
    Nov 11, 2018
    Messages:
    304
    Country:
    United States
    Will you ever add the feature to send videos? Or is that out of the question at this point?
     
    Core_2_Extreme likes this.
  21. Core_2_Extreme

    OP Core_2_Extreme Member
    Newcomer

    Joined:
    Feb 11, 2019
    Messages:
    31
    Country:
    Japan
    I think it's impossible to send pictures or videos to line server directly.(but it's maybe possible view pictures)
     
    Zurdonx likes this.
  22. PokeNev

    PokeNev GBAtemp Fan
    Member

    Joined:
    Nov 11, 2018
    Messages:
    304
    Country:
    United States
    Nice
     
    Core_2_Extreme likes this.
Draft saved Draft deleted
Loading...

Hide similar threads Similar threads with keywords - [Release][Guide],