Toggle menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Line for 3DS: Difference between revisions

From GameBrew
m (Text replacement - "{{Infobox-3DS-Homebrews" to "{{Infobox 3DS Homebrews")
m (Text replacement - "image = https://dlhb.gamebrew.org/3dshomebrew/" to "image = ")
Line 1: Line 1:
{{Infobox 3DS Homebrews
{{Infobox 3DS Homebrews
| title = Line for 3DS
| title = Line for 3DS
| image = https://dlhb.gamebrew.org/3dshomebrew/Line-for-3DS.png|250px
| image = Line-for-3DS.png|250px
| type = Other Apps
| type = Other Apps
| version=v1.7.2
| version=v1.7.2

Revision as of 01:54, 20 October 2021

Line for 3DS
File:Line-for-3DS.png
General
AuthorCore-2-Extreme
TypeOther Apps
Versionv1.7.2
Last Updated2021/01/07
Links
Download
Website
Source

Line for 3DS

77541203-a9977e80-6ee7-11ea-8479-53aed389ab64.png

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 ✅ (v1.7.0)
  • Receive (Play) sound ✅ (v1.7.0)
  • Receive (View) sticker ✅(*1) (v1.3.0)
  • View old log ✅ (~v1.5.2 Max 300 logs) (v1.6.0~ Max 4000 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)

Official Discord

https://discord.gg/EqK3Kpb

How to use

*1 The stickers must be included this list sticker_list.pdf

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

How to setup Google apps script

Please click here to see the contents:

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

  • <a href="#panel1">For Ver 1.7.0</a>
  • <a href="#panel2">For Ver 1.6.0</a>
  • <a href="#panel3">For Ver 1.5.0~1.5.2</a>

This code compatible with ver 1.7.0~! 2021/01/24 Edited : fixed unable to receive images, audio, videos and files.

var ACCESS_TOKEN = "Your acces token here";
var OPEN_SHEET_ID = "Your sheet id here";
var SCRIPT_PASSOWRD = "Your google apps script password here";
var CLIENT_NAME = "Your 3ds's account name here";

var gas_ver = 7;//Do **NOT** edit this value.
function log_save(message, user_name, write_sheet_name, group_or_user_name, pic_url, msg_id)
{
    var google_pic_url;
    var previous_pic_url;
    var response;
    var sheet_pos = 1;
    var spreadsheet = SpreadsheetApp.openById(OPEN_SHEET_ID);
    var write_sheet = spreadsheet.getSheetByName(write_sheet_name);

    if (!write_sheet)
    {
        spreadsheet.insertSheet(write_sheet_name);
        write_sheet = spreadsheet.getSheetByName(write_sheet_name);
    }

    sheet_pos = get_cache_pos(write_sheet);

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

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

    write_cache_data(write_sheet, (sheet_pos + 1), "B1");
    if (group_or_user_name != "Do not save")
        write_cache_data(write_sheet, group_or_user_name, "B2");

    if (pic_url != "Do not save")
    {
        previous_pic_url = get_previous_pic_url(write_sheet);
        if (previous_pic_url != pic_url)
        {
            response = UrlFetchApp.fetch(pic_url,
                {
                    'headers': {
                        'Content-Type': 'application/json; charset=UTF-8',
                        'Authorization': 'Bearer ' + ACCESS_TOKEN,
                    },
                    muteHttpExceptions: true,
                });

            if (response.getResponseCode() == 200)
            {
                google_pic_url = get_profile_pic_google_url(response, write_sheet_name);
                write_cache_data(write_sheet, google_pic_url, "B3");
                write_cache_data(write_sheet, pic_url, "B4");
            }
        }
    }
}

function unsend_msg(sheet_id, msg_id)
{
    var spreadsheet = SpreadsheetApp.openById(OPEN_SHEET_ID);
    var write_sheet = spreadsheet.getSheetByName(sheet_id);
    var sheet_pos = 1;
  
    if (!write_sheet)
    {
        spreadsheet.insertSheet(sheet_id);
        write_sheet = spreadsheet.getSheetByName(sheet_id);
    }
  
    while (true)
    {
        var sheet_data = write_sheet.getRange("C" + sheet_pos).getValue();

        if (sheet_data == msg_id)
        {
            write_sheet.getRange("A" + sheet_pos).setValue("?*****This message was unsent by user*****");
            break;
        }
        else
            sheet_pos++;
    }
}

function check_folder_exist(input_folders, name)
{
    var folder;
    while (input_folders.hasNext())
    {
      folder = input_folders.next();
      if(name == folder.getName())
        return folder;
    }
    return undefined;
}

function log_read(id, num_of_logs)
{
  var sheet_offset = 1;
  var sheet_start = 1;
  var return_data;
  var sheet_data;
  var spreadsheet = SpreadsheetApp.openById(OPEN_SHEET_ID);
  var read_sheet = spreadsheet.getSheetByName(id);
  if(!read_sheet)
    return "No such sheet.\nPlease duoble check your ID.";
  
  sheet_start = get_cache_pos(read_sheet);

  while(true)
  {
    sheet_data = read_sheet.getRange("A" + sheet_start).getValue();
    if(sheet_data == "")
    {
      write_cache_data(read_sheet, sheet_start, "B1");
      if(sheet_start > num_of_logs)
        sheet_start = (sheet_start - num_of_logs);
      else
        sheet_start = 1;

      break;
    }
    else
      sheet_start++;
  }

  sheet_offset = sheet_start;
  sheet_data = read_sheet.getRange(sheet_start, 1, num_of_logs).getValues();
  return_data = "<0>";
  for(var i = 0; i < num_of_logs; i++)
  {
    if(sheet_data[i] == "")
      break;

    return_data += sheet_data[i];
    sheet_offset++;
  }
 
  return_data += "</0>";
  return_data += "<1>" + get_cache_name(read_sheet) + "</1>";
  return_data += "<2>" + get_google_pic_url(read_sheet) + "</2>";
  return_data += "<3>" + sheet_offset + "</3>";
  return_data += "<4>Success</4>";
  return return_data;
}

function get_cache_pos(sheet_object)
{
  var cached_sheet_pos = sheet_object.getRange("B1").getValue();
  var sheet_data;

  if(parseInt(cached_sheet_pos) > 0)
  {
    cached_sheet_pos = parseInt(cached_sheet_pos);
    sheet_data = sheet_object.getRange("A" + (cached_sheet_pos - 1)).getValue();

    if(sheet_data != "")
      return cached_sheet_pos;
  }
  return 1;
}

function get_cache_name(sheet_object)
{
  var cached_name = sheet_object.getRange("B2").getValue();
  return cached_name;
}

function get_google_pic_url(sheet_object)
{
    var cached_name = sheet_object.getRange("B3").getValue();
    return cached_name;
}

function get_previous_pic_url(sheet_object)
{
    var cached_name = sheet_object.getRange("B4").getValue();
    return cached_name;
}

function write_cache_data(sheet_object, cache_data, pos)
{
  sheet_object.getRange(pos).setValue(cache_data);
}

function http_get_content(request_id)
{
  var response;
  var url = "https://api-data.line.me/v2/bot/message/" + request_id + "/content";
  response = UrlFetchApp.fetch(url,
  {
  'headers': {
    'Content-Type': 'application/json; charset=UTF-8',
    'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_get_user_name(id)
{
  var response;
  var url = 'https://api.line.me/v2/bot/profile/' + id;
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_get_group_user_name(id, group_id)
{
  var response;
  var url = "https://api.line.me/v2/bot/group/" + group_id + "/member/" + id + "/";
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_get_group_name(group_id)
{
  var response;
  var url = "https://api.line.me/v2/bot/group/" + group_id +"/summary/";
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_send_text_reply(reply_token, send_msg)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/reply/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': reply_token,
      'messages': [{
        'type': 'text',
        'text': send_msg ,
      }],
      'notificationDisabled': 'true',
    }),
    muteHttpExceptions: true,
  });
  return response;
}

function http_send_text(id, send_msg)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/push/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
  "to": id,
  "messages":
       [{
          "text": send_msg,
          "type": "text",
       }],
      'notificationDisabled': 'false',
    }),
   muteHttpExceptions: true,
  });
  return response;
}

function http_send_sticker(id, package_id, sticker_id)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/push/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
  "to": id,
  "messages":
       [{
          "type": "sticker",
          "packageId": package_id,
          "stickerId": sticker_id,
       }],
      'notificationDisabled': 'false',
    }),
   muteHttpExceptions: true,
  });
  return response;
}

function http_send_image(id, img_url, preview_url)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/push/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
  "to": id,
  "messages":
       [{
          "type": "image",
          "originalContentUrl": img_url,
          "previewImageUrl": preview_url,
       }],
      'notificationDisabled': 'false',
    }),
   muteHttpExceptions: true,
  });
  return response;
}

function send_msg(id, send_message, time)
{
  var cache;
  var response;
  var return_message = "Success";

  response = http_send_text(id, send_message);
  if(response.getResponseCode() != 200)
  {
    cache = "***The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message + "*** ";
    cache += send_message;
    send_message = cache;
    return_message = "The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
  }
 
  send_message += "(" + time + ")";
  log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
  return return_message;
}

function send_sticker(id, package_id, sticker_id, time)
{
  var response;
  var return_message = "Success";
  var send_message = "";

  response = http_send_sticker(id, package_id, sticker_id);
  if(response.getResponseCode() != 200)
  {
   send_message = "***The sticker failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
   return_message = "The sticker failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
  }
  send_message += "<sticker>" + sticker_id + "</sticker>(" + time + ")";
  log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
  return return_message;
}

function get_cache_data(id, cache_name, last_data)
{
  var byte_data;
  var cache_data = "";
  var cache_data_1 = "";
  var cache_file;
  var cache_folder;
  var exist_cache_folders;
  var exist_folders;
  var exist_sub_folders;
  var folder;
  var folder_name = "Line_contents";
  var sub_folder;

  exist_folders = DriveApp.searchFolders("'me' in owners");
  folder = check_folder_exist(exist_folders, folder_name);
  if(folder == undefined)
    return undefined;

  exist_sub_folders = folder.searchFolders("'me' in owners");
  sub_folder = check_folder_exist(exist_sub_folders, id);
  if(sub_folder == undefined)
    return undefined;

  exist_cache_folders = sub_folder.searchFolders("'me' in owners");
  cache_folder = check_folder_exist(exist_cache_folders, cache_name);
  if(cache_folder == undefined)
    return undefined;

  for(var i = 0; i < 4096; i++)
  {
    try
    {
      cache_file = cache_folder.getFilesByName(i).next();
      cache_data += cache_file.getBlob().getDataAsString();
    }
    catch(error)
    {
      break;
    }
  }

  cache_data += last_data;
  cache_folder.setTrashed(true);
  return cache_data;
}

function upload_content(id, data, count, cache_name, last, time, data_type)
{
  var cache_data;
  var cache_folder;
  var exist_cache_folders;
  var exist_folders;
  var exist_sub_folders;
  var folder;
  var folder_name = "Line_contents";
  var part_of_content;
  var part_of_content_data;
  var return_message = "Success";
  var send_message;
  var sub_folder;

  if(count == 0 && last == "true")
    return_message = send_content(id, cache_name, time, data, data_type);
  else if(last == "true")
  {
      cache_data = get_cache_data(id, cache_name, data);
      if(cache_data == undefined)
      {
        send_message = "***The content failed to send. The cache folder does not exist.*** (" + time + ")";
        log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
        return_message = "The content failed to send.\nThe cache folder does not exist.";
      }
      else
        return_message = send_content(id, cache_name, time, cache_data, data_type);
  }
  else
  {
    exist_folders = DriveApp.searchFolders("'me' in owners");
    folder = check_folder_exist(exist_folders, folder_name);
    if(folder == undefined)
      folder = DriveApp.createFolder(folder_name);

    exist_sub_folders = folder.searchFolders("'me' in owners");
    sub_folder = check_folder_exist(exist_sub_folders, id);
    if(sub_folder == undefined)
      sub_folder = folder.createFolder(id);

    exist_cache_folders = sub_folder.searchFolders("'me' in owners");
    cache_folder = check_folder_exist(exist_cache_folders, cache_name);
    if(cache_folder == undefined)
      cache_folder = sub_folder.createFolder(cache_name);
    else if(!(cache_folder == undefined) && count == 0)
    {
      cache_folder.setTrashed(true);
      cache_folder = sub_folder.createFolder(cache_name);
    }

    part_of_content_data = Utilities.newBlob(data).setName(count);
    part_of_content = cache_folder.createFile(part_of_content_data);
  }
  return return_message;
}

function send_content(id, cache_name, time, encoded_data, data_type)
{
  var content;
  var content_data;
  var content_type;
  var content_url = "";
  var exist_folders;
  var exist_sub_folders;
  var folder;
  var folder_name = "Line_contents";
  var preview_content_url = "";
  var response;
  var return_message = "Success";
  var send_message = "";
  var sub_folder;

  exist_folders = DriveApp.searchFolders("'me' in owners");
  folder = check_folder_exist(exist_folders, folder_name);
  if(folder == undefined)
    folder = DriveApp.createFolder(folder_name);

  exist_sub_folders = folder.searchFolders("'me' in owners");
  sub_folder = check_folder_exist(exist_sub_folders, id);
  if(sub_folder == undefined)
    sub_folder = folder.createFolder(id);

  try
  {
    content_data = Utilities.newBlob(Utilities.base64Decode(encoded_data)).setName(cache_name);
  }
  catch (e)
  {
    return_message = "The content failed to send.\nCouldn't decode base64 data.";
    return return_message;
  }

  content = sub_folder.createFile(content_data);
  content_type = content.getMimeType();
  if(content_type == MimeType.BMP || content_type == MimeType.GIF || content_type == MimeType.JPEG || content_type == MimeType.PNG || content_type == MimeType.SVG)
  {
    content.setTrashed(true);
    folder_name = "Line_images";
    exist_folders = DriveApp.searchFolders("'me' in owners");
    folder = check_folder_exist(exist_folders, folder_name);
    if(folder == undefined)
      folder = DriveApp.createFolder(folder_name);

    exist_sub_folders = folder.searchFolders("'me' in owners");
    sub_folder = check_folder_exist(exist_sub_folders, id);
    if(sub_folder == undefined)
      sub_folder = folder.createFolder(id);

    content = sub_folder.createFile(content_data);
    content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
    content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
    preview_content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w240-h240";

    response = http_send_image(id, content_url, preview_content_url);
    if(response.getResponseCode() != 200)
    {
      send_message = "***The image failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
      return_message = "The image failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
    }
    send_message += "<image_url>" + content_url + "</image_url>(" + time + ")";
    log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
    return return_message;
  }
  else if(data_type == "audio")
  {
    content.setTrashed(true);
    folder_name = "Line_audio";
    exist_folders = DriveApp.searchFolders("'me' in owners");
    folder = check_folder_exist(exist_folders, folder_name);
    if(folder == undefined)
      folder = DriveApp.createFolder(folder_name);

    exist_sub_folders = folder.searchFolders("'me' in owners");
    sub_folder = check_folder_exist(exist_sub_folders, id);
    if(sub_folder == undefined)
      sub_folder = folder.createFolder(id);

    content = sub_folder.createFile(content_data);
    content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
    content_url = "https://docs.google.com/uc?id=" + content.getId();
    response = http_send_text(id, content_url + " (audio)");
    if(response.getResponseCode() != 200)
    {
      send_message = "***The audio failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
      return_message = "The audio failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
    }
  
    content_url = "https://drive.google.com/uc?export=download&id=" + content.getId();
    send_message += "<audio_url>" + content_url + "</audio_url>(" + time + ")";
    log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
    return return_message;
  }
  else if(data_type == "video")
  {
    content.setTrashed(true);
    folder_name = "Line_videos";
    exist_folders = DriveApp.searchFolders("'me' in owners");
    folder = check_folder_exist(exist_folders, folder_name);
    if(folder == undefined)
      folder = DriveApp.createFolder(folder_name);

    exist_sub_folders = folder.searchFolders("'me' in owners");
    sub_folder = check_folder_exist(exist_sub_folders, id);
    if(sub_folder == undefined)
      sub_folder = folder.createFolder(id);

    content = sub_folder.createFile(content_data);
    content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
    content_url = "https://docs.google.com/uc?id=" + content.getId();
    response = http_send_text(id, content_url);
    if(response.getResponseCode() != 200)
    {
      send_message = "***The video failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
      return_message = "The video failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
    }
  
    content_url = "https://drive.google.com/uc?export=download&id=" + content.getId();
    send_message += "<video_url>" + content_url + "</video_url>(" + time + ")";
    log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
    return return_message;
  }
  else
  {
    content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
    content_url = "https://drive.google.com/file/d/" + content.getId() + "/view";
    response = http_send_text(id, content_url);
    if(response.getResponseCode() != 200)
    {
      send_message = "***The content failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
      return_message = "The content failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
    }
    content_url = "https://drive.google.com/uc?export=download&id=" + content.getId();
    send_message += "<content_url>" + content_url + "</content_url>(" + time + ")";
    log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save", "0");
    return return_message;
  }
}

function get_profile_pic_google_url(http_response, group_or_user_id)
{
    var content_data;
    var content;
    var folder_name = "Line_images";
    var folder;
    var sub_folder;
    var exist_folders;
    var exist_sub_folders;
    var url = "";

    exist_folders = DriveApp.searchFolders("'me' in owners");
    folder = check_folder_exist(exist_folders, folder_name);
    if (folder == undefined)
        folder = DriveApp.createFolder(folder_name);

    exist_sub_folders = folder.searchFolders("'me' in owners");
    sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
    if (sub_folder == undefined)
        sub_folder = folder.createFolder(group_or_user_id);

    content_data = http_response.getBlob().getAs("image/jpeg").setName("icon");
    content = sub_folder.createFile(content_data);
    content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
    url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w32-h32";

    return url;
}

function get_content_url(request_id, group_or_user_id, type)
{
  var content_data;
  var content;
  var exist_folders;
  var exist_sub_folders;
  var folder_name;
  var folder;
  var sub_folder;
  var response;
  var url = "";

  if(type == "image")
    folder_name = "Line_images";
  else if(type == "audio")
    folder_name = "Line_audio";
  else if(type == "video")
    folder_name = "Line_videos";
  else if(type == "file")
    folder_name = "Line_contens";


  exist_folders = DriveApp.searchFolders("'me' in owners");
  folder = check_folder_exist(exist_folders, folder_name);
  if(folder  == undefined)
    folder = DriveApp.createFolder(folder_name);

  exist_sub_folders = folder.searchFolders("'me' in owners");
  sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
  if(sub_folder  == undefined)
    sub_folder = folder.createFolder(group_or_user_id);

  response = http_get_content(request_id);
  if(response.getResponseCode() != 200)
  {
    if(type == "image")
      url = "***Couldn't generate an image URL. Status code = " + response.getResponseCode() + "*** ";
    else if(type == "audio")
      url = "***Couldn't generate a audio URL. Status code = " + response.getResponseCode() + "*** ";
    else if(type == "video")
      url = "***Couldn't generate a video URL. Status code = " + response.getResponseCode() + "*** ";
    else if(type == "file")
      url = "***Couldn't generate a file URL. Status code = " + response.getResponseCode() + "*** ";
  }
  else
  {
    if(type == "image")
    {
      content_data = response.getBlob().getAs("image/jpeg").setName(request_id);
      content = sub_folder.createFile(content_data);
      content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
      url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
    }
    else if(type == "audio" || type == "video" || type == "file")
    {
      content_data = response.getBlob().setName(request_id);
      content = sub_folder.createFile(content_data);
      content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
      url = "https://drive.google.com/uc?export=download&id=" + content.getId();
    }
  }
  return url;
}

function receive_msg_from_line(user_message, user_id, group_id, reply_token, time, msg_id)
{
  var group_name;
  var picture_url = [ "", ""];
  var response = [ "", ""];
  var send_msg;
  var user_name;

  if(group_id == "Unknown")
    response[0] = http_get_user_name(user_id);
  else
  {
    response[0] = http_get_group_user_name(user_id, group_id);
    response[1] = http_get_group_name(group_id);

    if(response[1].getResponseCode() != 200)
      group_name = "Unknown";
    else
    {
      group_name = JSON.parse(response[1]).groupName;
      picture_url[1] = JSON.parse(response[1]).pictureUrl;
    }
  }

  if(response[0].getResponseCode() != 200)
    user_name = "Unknown";
  else
  {
    user_name = JSON.parse(response[0]).displayName;
    picture_url[0] = JSON.parse(response[0]).pictureUrl;
  }

  if(user_message == "getid" || user_message == "getgroupid")
  {
    if(user_message == "getid")
      send_msg = user_id;
    else if(user_message == "getgroupid")
      send_msg = group_id;

    response[0] = http_send_text_reply(reply_token, send_msg);
    send_msg = "<id>" + send_msg + "</id>";
    if(response[0].getResponseCode() != 200)
      send_msg += "***The message failed to send. Status code = " + response[0].getResponseCode() + " " + JSON.parse(response[0].getContentText()).message + "*** ";

    send_msg += "(" + time + ")";
    if(user_message == "getid")
    {
      log_save(send_msg, user_name, "IDs", "BOT", "Do not save", "0");
      user_message = "*****Added by user*****";
    }
    else if(user_message == "getgroupid")
    {
      log_save(send_msg, group_name, "IDs", "BOT", "Do not save", "0");
      user_message = "*****Invited by user*****";
    }
    user_name = CLIENT_NAME;
    msg_id = 0;
  }
  else if(user_message == "*****Removed by user*****" || user_message == "*****Blocked by user*****" || user_message == "*****Joined*****" || user_message == "*****Left*****")
  {
    msg_id = 0;
    if(user_message == "*****Removed by user*****" || user_message == "*****Blocked by user*****")
      user_name = CLIENT_NAME;
  }
 
  user_message += "(" + time + ")";
  if(group_id == "Unknown")
    log_save(user_message, user_name, user_id, user_name, picture_url[0], msg_id);
  else
    log_save(user_message, user_name, group_id, group_name, picture_url[1], msg_id);
}

function doPost(post_data)
{
  var time = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'MM/dd hh:mm:ss');
  var data_type;
  var result;
  var client_auth = "Unknown";
  var client_gas_ver = "Unknown";
  var id = "Unknown";
  var last = "";
  var lock = LockService.getScriptLock();
  var lock_result;
  var logs = 100;
  try
  {
    data_type = JSON.parse(post_data.postData.contents).type;
  }
  catch(e)
  {
  }
  for(var i = 0; i < 1000; i++)
  {
    lock_result = lock.tryLock(1000);
    if(lock_result)
      break;
 
    Utilities.sleep(1000);
  }

  if(data_type == undefined)
  {
    for(var i = 0; i < 50; i++)
    {
      var msg_id = "";
      var user_message = "";
      var user_id = "";
      var group_id = "";
      var reply_token = "";
      var msg_type = "";
      var type = "";
    
      try
      {
        type = JSON.parse(post_data.postData.contents).events[i].type;
        user_id = JSON.parse(post_data.postData.contents).events[i].source.userId;
        group_id = JSON.parse(post_data.postData.contents).events[i].source.groupId;
        reply_token = JSON.parse(post_data.postData.contents).events[i].replyToken;
        if(type == "unsend")
          msg_id = JSON.parse(post_data.postData.contents).events[i].unsend.messageId;
        else if(type == "message")
        {
          msg_id = JSON.parse(post_data.postData.contents).events[i].message.id;
          user_message = JSON.parse(post_data.postData.contents).events[i].message.text;
          msg_type = JSON.parse(post_data.postData.contents).events[i].message.type;                
        }
      }
      catch(e)
      {
        break;
      }

      if(user_id == undefined)
        user_id = "Unknown";
      if(group_id == undefined)
        group_id = "Unknown";


      if(type == "follow")
        user_message = "getid";
      else if(type == "join")
        user_message = "getgroupid";
      else if(type == "leave")
        user_message = "*****Removed by user*****";
      else if(type == "unfollow")
        user_message = "*****Blocked by user*****";
      else if(type == "memberJoined")
      {
        user_message = "*****Joined*****";
        user_id = JSON.parse(post_data.postData.contents).events[i].joined.members[0].userId;
      }
      else if(type == "memberLeft")
      {
        user_message = "*****Left*****";
        user_id = JSON.parse(post_data.postData.contents).events[i].left.members[0].userId;
      }
      else if(type == "unsend")
      {
        if(group_id == "Unknown")
          unsend_msg(user_id, msg_id);
        else
          unsend_msg(group_id, msg_id);
      }
      else if(msg_type == "sticker")
      {
        var sticker_id  = JSON.parse(post_data.postData.contents).events[i].message.stickerId;
        user_message = "<sticker>" + sticker_id + "</sticker>";
      }
      else if(msg_type == "image")
      {        
         if(group_id == "Unknown")
           user_message = "<image_url>" + get_content_url(msg_id, user_id, msg_type) + "</image_url>";
         else
           user_message = "<image_url>" + get_content_url(msg_id, group_id, msg_type) + "</image_url>";
      }
      else if(msg_type == "audio")
      {
       if(group_id == "Unknown")
         user_message = "<audio_url>" + get_content_url(msg_id, user_id, msg_type) + "</audio_url>";
       else
         user_message = "<audio_url>" + get_content_url(msg_id, group_id, msg_type) + "</audio_url>";
      }
      else if(msg_type == "video")
      {
       if(group_id == "Unknown")
         user_message = "<video_url>" + get_content_url(msg_id, user_id, msg_type) + "</video_url>";
       else
         user_message = "<video_url>" + get_content_url(msg_id, group_id, msg_type) + "</video_url>";
      }
      else if(msg_type == "file")
      {
       if(group_id == "Unknown")
         user_message = "<file_url>" + get_content_url(msg_id, user_id, msg_type) + "</file_url>";
       else
         user_message = "<file_url>" + get_content_url(msg_id, group_id, msg_type) + "</file_url>";
      }
      else if(user_message == undefined)
        user_message += " : " + msg_type + " " + msg_id;

      if(!(type == "unsend"))
        receive_msg_from_line(user_message, user_id, group_id, reply_token, time, msg_id);
    }
    lock.releaseLock();
    return;
  }

  try
  {
    client_auth = JSON.parse(post_data.postData.contents).auth;
    client_gas_ver = JSON.parse(post_data.postData.contents).gas_ver;
    id = JSON.parse(post_data.postData.contents).id;
  }
  catch(e)
  {
  }

  if(SCRIPT_PASSOWRD == client_auth)
  {
    if(gas_ver == client_gas_ver)
    {
      if(data_type == "send_text")
      {
        var send_message = JSON.parse(post_data.postData.contents).message;
        result = send_msg(id, send_message, time);
      }
      else if(data_type == "send_sticker")
      {
        var package_id = JSON.parse(post_data.postData.contents).package_id;
        var sticker_id = JSON.parse(post_data.postData.contents).sticker_id;
        result = send_sticker(id, package_id, sticker_id, time);
      }
      else if(data_type == "upload_content")
      {
        var content_data = JSON.parse(post_data.postData.contents).content_data;
        var count = JSON.parse(post_data.postData.contents).count;
        var name = JSON.parse(post_data.postData.contents).name;
        var sub_data_type = "";
        last = JSON.parse(post_data.postData.contents).last;
        if(last == "true")
          sub_data_type = JSON.parse(post_data.postData.contents).data_type;
      
        result = upload_content(id, content_data, count, name, last, time, sub_data_type);
      }
      else
        result = "Unknown message type.";
      
      if(result == "Success" && ((data_type == "upload_content" && last == "true") || data_type == "send_sticker" || data_type == "send_text"))
      {
        logs = JSON.parse(post_data.postData.contents).logs;
        result = log_read(id, logs);
      }
    }
    else
      result = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
  }
  else
    result = "Auth failed. Please set correct password.";

  lock.releaseLock();
  return ContentService.createTextOutput(result);
}

function doGet(post_data)
{
  var data = "";
  var client_auth = "";
  var client_gas_ver = "";
  var num_of_logs = "";
  var id = "";
  var lock = LockService.getScriptLock();
  var lock_result = lock.tryLock(1000);
  while(!lock_result)
  {
    Utilities.sleep(1000);
    lock_result = lock.tryLock(1000);
  }
  try
  {
    client_auth = post_data.parameter.script_auth;
    client_gas_ver = post_data.parameter.gas_ver;
    num_of_logs = post_data.parameter.logs;
    id = post_data.parameter.id;
  }
  catch(e)
  {
  }
  if(client_auth == undefined)
    client_auth = "";
  if(client_gas_ver == undefined)
    client_gas_ver = -1;
  if(num_of_logs == undefined)
    num_of_logs = 300;
  if(id == undefined)
    id = "unknown";

  if(SCRIPT_PASSOWRD == client_auth)
  {
    if(gas_ver == client_gas_ver)
      data = log_read(id, num_of_logs);
    else
      data = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
  }
  else
    data = "Auth failed. Please set correct password.";

  lock.releaseLock();
  return ContentService.createTextOutput(data);
}

This code compatible with ver 1.6.0 !!!WARNING!!! I strongly recommend you use the newest version !!!WARNING!!!

var ACCESS_TOKEN = "Your acces token here";
var OPEN_SHEET_ID = "Your sheet id here";
var SCRIPT_PASSOWRD = "Your google apps script password here";
var CLIENT_NAME = "Your 3ds's account name here";

var gas_ver = 6;//Do **NOT** edit this value.
function log_save(message, user_name, write_sheet_name, group_or_user_name, pic_url)
{
    var google_pic_url;
    var previous_pic_url;
    var response;
    var sheet_pos = 1;
    var spreadsheet = SpreadsheetApp.openById(OPEN_SHEET_ID);
    var write_sheet = spreadsheet.getSheetByName(write_sheet_name);

    if (!write_sheet)
    {
        spreadsheet.insertSheet(write_sheet_name);
        write_sheet = spreadsheet.getSheetByName(write_sheet_name);
    }

    sheet_pos = get_cache_pos(write_sheet);

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

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

    write_cache_data(write_sheet, (sheet_pos + 1), "B1");
    if (group_or_user_name != "Do not save")
        write_cache_data(write_sheet, group_or_user_name, "B2");

    if (pic_url != "Do not save")
    {
        previous_pic_url = get_previous_pic_url(write_sheet);
        if (previous_pic_url != pic_url)
        {
            response = UrlFetchApp.fetch(pic_url,
                {
                    'headers': {
                        'Content-Type': 'application/json; charset=UTF-8',
                        'Authorization': 'Bearer ' + ACCESS_TOKEN,
                    },
                    muteHttpExceptions: true,
                });

            if (response.getResponseCode() == 200)
            {
                google_pic_url = get_profile_pic_google_url(response, write_sheet_name);
                write_cache_data(write_sheet, google_pic_url, "B3");
                write_cache_data(write_sheet, pic_url, "B4");
            }
        }

    }
}

function check_folder_exist(input_folders, name)
{
    var folder;
    while (input_folders.hasNext())
    {
      folder = input_folders.next();
      if(name == folder.getName())
        return folder;
    }
    return undefined;
}

function log_read(id, num_of_logs)
{
  var sheet_offset = 1;
  var sheet_start = 1;
  var return_data;
  var sheet_data;
  var spreadsheet = SpreadsheetApp.openById(OPEN_SHEET_ID);
  var read_sheet = spreadsheet.getSheetByName(id);
  if(!read_sheet)
    return "No such sheet.\nPlease duoble check your ID.";
 
  sheet_start = get_cache_pos(read_sheet);

  while(true)
  {
    sheet_data = read_sheet.getRange("A" + sheet_start).getValue();
    if(sheet_data == "")
    {
      write_cache_data(read_sheet, sheet_start, "B1");
      if(sheet_start > num_of_logs)
        sheet_start = (sheet_start - num_of_logs);
      else
        sheet_start = 1;

      break;
    }
    else
      sheet_start++;
  }

  sheet_offset = sheet_start;
  sheet_data = read_sheet.getRange(sheet_start, 1, num_of_logs).getValues();
  return_data = "<0>";
  for(var i = 0; i < num_of_logs; i++)
  {
    if(sheet_data[i] == "")
      break;

    return_data += sheet_data[i];
    sheet_offset++;
  }
 
  return_data += "</0>";
  return_data += "<1>" + get_cache_name(read_sheet) + "</1>";
  return_data += "<2>" + get_google_pic_url(read_sheet) + "</2>";
  return_data += "<3>" + sheet_offset + "</3>";
  return_data += "<4>Success</4>";
  return return_data;
}

function get_cache_pos(sheet_object)
{
  var cached_sheet_pos = sheet_object.getRange("B1").getValue();
  var sheet_data;

  if(parseInt(cached_sheet_pos) > 0)
  {
    cached_sheet_pos = parseInt(cached_sheet_pos);
    sheet_data = sheet_object.getRange("A" + (cached_sheet_pos - 1)).getValue();

    if(sheet_data != "")
      return cached_sheet_pos;
  }
  return 1;
}

function get_cache_name(sheet_object)
{
  var cached_name = sheet_object.getRange("B2").getValue();
  return cached_name;
}

function get_google_pic_url(sheet_object)
{
    var cached_name = sheet_object.getRange("B3").getValue();
    return cached_name;
}

function get_previous_pic_url(sheet_object)
{
    var cached_name = sheet_object.getRange("B4").getValue();
    return cached_name;
}

function write_cache_data(sheet_object, cache_data, pos)
{
  sheet_object.getRange(pos).setValue(cache_data);
}

function http_get_content(request_id)
{
  var response;
  var url = "https://api.line.me/v2/bot/message/" + request_id + "/content";
  response = UrlFetchApp.fetch(url,
  {
  'headers': {
    'Content-Type': 'application/json; charset=UTF-8',
    'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_get_user_name(id)
{
  var response;
  var url = 'https://api.line.me/v2/bot/profile/' + id;
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_get_group_user_name(id, group_id)
{
  var response;
  var url = "https://api.line.me/v2/bot/group/" + group_id + "/member/" + id + "/";
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_get_group_name(group_id)
{
  var response;
  var url = "https://api.line.me/v2/bot/group/" + group_id +"/summary/";
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_send_text_reply(reply_token, send_msg)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/reply/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': reply_token,
      'messages': [{
        'type': 'text',
        'text': send_msg ,
      }],
      'notificationDisabled': 'true',
    }),
    muteHttpExceptions: true,
  });
  return response;
}

function http_send_text(id, send_msg)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/push/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
  "to": id,
  "messages":
       [{
          "text": send_msg,
          "type": "text",
       }],
      'notificationDisabled': 'false',
    }),
   muteHttpExceptions: true,
  });
  return response;
}

function http_send_sticker(id, package_id, sticker_id)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/push/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
  "to": id,
  "messages":
       [{
          "type": "sticker",
          "packageId": package_id,
          "stickerId": sticker_id,
       }],
      'notificationDisabled': 'false',
    }),
   muteHttpExceptions: true,
  });
  return response;
}

function http_send_image(id, img_url, preview_url)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/push/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
  "to": id,
  "messages":
       [{
          "type": "image",
          "originalContentUrl": img_url,
          "previewImageUrl": preview_url,
       }],
      'notificationDisabled': 'false',
    }),
   muteHttpExceptions: true,
  });
  return response;
}

function send_msg(id, send_message, time)
{
  var cache;
  var response;
  var return_message = "Success";

  response = http_send_text(id, send_message);
  if(response.getResponseCode() != 200)
  {
    cache = "***The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message + "*** ";
    cache += send_message;
    send_message = cache;
    return_message = "The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
  }
 
  send_message += "(" + time + ")";
  log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save");
  return return_message;
}

function send_sticker(id, package_id, sticker_id, time)
{
  var response;
  var return_message = "Success";
  var send_message = "";

  response = http_send_sticker(id, package_id, sticker_id);
  if(response.getResponseCode() != 200)
  {
   send_message = "***The sticker failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
   return_message = "The sticker failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
  }
  send_message += "<sticker>" + sticker_id + "</sticker>(" + time + ")";
  log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save");
  return return_message;
}

function get_cache_data(id, cache_name)
{
  var cache_data = "";
  var cache_file;
  var cache_folder;
  var exist_cache_folders;
  var exist_folders;
  var exist_sub_folders;
  var folder;
  var folder_name = "Line_contents";
  var sub_folder;

  exist_folders = DriveApp.searchFolders("'me' in owners");
  folder = check_folder_exist(exist_folders, folder_name);
  if(folder == undefined)
    return undefined;

  exist_sub_folders = folder.searchFolders("'me' in owners");
  sub_folder = check_folder_exist(exist_sub_folders, id);
  if(sub_folder == undefined)
    return undefined;

  exist_cache_folders = sub_folder.searchFolders("'me' in owners");
  cache_folder = check_folder_exist(exist_cache_folders, cache_name);
  if(cache_folder == undefined)
    return undefined;

  for(var i = 0; i < 4096; i++)
  {
    try
    {
      cache_file = cache_folder.getFilesByName(i).next();
      cache_data += cache_file.getBlob().getDataAsString();
    }
    catch(error)
    {
      break;
    }
  }
  cache_folder.setTrashed(true);
  return cache_data;
}

function upload_content(id, data, count, cache_name, last, time)
{
  var cache_data;
  var cache_folder;
  var exist_cache_folders;
  var exist_folders;
  var exist_sub_folders;
  var folder;
  var folder_name = "Line_contents";
  var part_of_content;
  var part_of_content_data;
  var return_message = "Success";
  var send_message;
  var sub_folder;

  if(count == 0 && last == "true")
    return_message = send_content(id, cache_name, time, data);
  else if(last == "true")
  {
      cache_data = get_cache_data(id, cache_name);
      if(cache_data == undefined)
      {
        send_message = "***The content failed to send. The cache folder does not exist.*** (" + time + ")";
        log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save");
        return_message = "The content failed to send.\nThe cache folder does not exist.";
      }
      else
      {
        cache_data += data;
        return_message = send_content(id, cache_name, time, cache_data);
      }
  }
  else
  {
    exist_folders = DriveApp.searchFolders("'me' in owners");
    folder = check_folder_exist(exist_folders, folder_name);
    if(folder == undefined)
      folder = DriveApp.createFolder(folder_name);

    exist_sub_folders = folder.searchFolders("'me' in owners");
    sub_folder = check_folder_exist(exist_sub_folders, id);
    if(sub_folder == undefined)
      sub_folder = folder.createFolder(id);

    exist_cache_folders = sub_folder.searchFolders("'me' in owners");
    cache_folder = check_folder_exist(exist_cache_folders, cache_name);
    if(cache_folder == undefined)
      cache_folder = sub_folder.createFolder(cache_name);
    else if(!(cache_folder == undefined) && count == 0)
    {
      cache_folder.setTrashed(true);
      cache_folder = sub_folder.createFolder(cache_name);
    }

    part_of_content_data = Utilities.newBlob(data).setName(count);
    part_of_content = cache_folder.createFile(part_of_content_data);
  }
  return return_message;
}

function send_content(id, cache_name, time, encoded_data)
{
  var content;
  var content_data;
  var content_type;
  var content_url = "";
  var exist_folders;
  var exist_sub_folders;
  var folder;
  var folder_name = "Line_contents";
  var preview_content_url = "";
  var response;
  var return_message = "Success";
  var send_message = "";
  var sub_folder;

  exist_folders = DriveApp.searchFolders("'me' in owners");
  folder = check_folder_exist(exist_folders, folder_name);
  if(folder == undefined)
    folder = DriveApp.createFolder(folder_name);

  exist_sub_folders = folder.searchFolders("'me' in owners");
  sub_folder = check_folder_exist(exist_sub_folders, id);
  if(sub_folder == undefined)
    sub_folder = folder.createFolder(id);

  try
  {
    content_data = Utilities.newBlob(Utilities.base64Decode(encoded_data)).setName(cache_name);
  }
  catch (e)
  {
    return_message = "The content failed to send.\nCouldn't decode base64 data.";
    return return_message;
  }

  content = sub_folder.createFile(content_data);
  content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
  content_type = content.getMimeType();
  if(content_type == MimeType.BMP || content_type == MimeType.GIF || content_type == MimeType.JPEG || content_type == MimeType.PNG || content_type == MimeType.SVG)
  {
    content.setTrashed(true);
    folder_name = "Line_images";
    exist_folders = DriveApp.searchFolders("'me' in owners");
    folder = check_folder_exist(exist_folders, folder_name);
    if(folder == undefined)
    folder = DriveApp.createFolder(folder_name);

    exist_sub_folders = folder.searchFolders("'me' in owners");
    sub_folder = check_folder_exist(exist_sub_folders, id);
    if(sub_folder == undefined)
    sub_folder = folder.createFolder(id);

    content = sub_folder.createFile(content_data);
    content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
    content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
    preview_content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w240-h240";

    response = http_send_image(id, content_url, preview_content_url);
    if(response.getResponseCode() != 200)
    {
      send_message = "***The image failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
      return_message = "The image failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
    }
    send_message += "<image_url>" + content_url + "</image_url>(" + time + ")";
    log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save");
    return return_message;
  }
  else
  {
    content_url = "https://drive.google.com/file/d/" + content.getId() + "/view";
    response = http_send_text(id, content_url);
    if(response.getResponseCode() != 200)
    {
      send_message = "***The content failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
      return_message = "The content failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
    }
    content_url = "https://drive.google.com/uc?export=download&id=" + content.getId();
    send_message += "<content_url>" + content_url + "</content_url>(" + time + ")";
    log_save(send_message, CLIENT_NAME, id, "Do not save", "Do not save");
    return return_message;
  }
}

function get_profile_pic_google_url(http_response, group_or_user_id)
{
    var content_data;
    var content;
    var folder_name = "Line_images";
    var folder;
    var sub_folder;
    var exist_folders;
    var exist_sub_folders;
    var url = "";

    exist_folders = DriveApp.searchFolders("'me' in owners");
    folder = check_folder_exist(exist_folders, folder_name);
    if (folder == undefined)
        folder = DriveApp.createFolder(folder_name);

    exist_sub_folders = folder.searchFolders("'me' in owners");
    sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
    if (sub_folder == undefined)
        sub_folder = folder.createFolder(group_or_user_id);

    content_data = http_response.getBlob().getAs("image/jpeg").setName("icon");
    content = sub_folder.createFile(content_data);
    content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
    url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w32-h32";

    return url;
}

function get_content_url(request_id, group_or_user_id, type)
{
  var content_data;
  var content;
  var exist_folders;
  var exist_sub_folders;
  var folder_name;
  var folder;
  var sub_folder;
  var response;
  var url = "";

  if(type == "image")
    folder_name = "Line_images";
  else if(type == "audio")
    folder_name = "Line_audio";
  else if(type == "video")
    folder_name = "Line_videos";
  else if(type == "file")
    folder_name = "Line_contens";


  exist_folders = DriveApp.searchFolders("'me' in owners");
  folder = check_folder_exist(exist_folders, folder_name);
  if(folder  == undefined)
    folder = DriveApp.createFolder(folder_name);

  exist_sub_folders = folder.searchFolders("'me' in owners");
  sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
  if(sub_folder  == undefined)
    sub_folder = folder.createFolder(group_or_user_id);

  response = http_get_content(request_id);
  if(response.getResponseCode() != 200)
  {
    if(type == "image")
      url = "***Couldn't generate an image URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
    else if(type == "audio")
      url = "***Couldn't generate a audio URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
    else if(type == "video")
      url = "***Couldn't generate a video URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
  }
  else
  {
    if(type == "image")
    {
      content_data = response.getBlob().getAs("image/jpeg").setName(request_id);
      content = sub_folder.createFile(content_data);
      content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
      url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
    }
    else if(type == "audio" || type == "video" || type == "file")
    {
      content_data = response.getBlob().setName(request_id);
      content = sub_folder.createFile(content_data);
      content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
      url = "https://drive.google.com/uc?export=download&id=" + content.getId();
    }
  }
  return url;
}

function receive_msg_from_line(user_message, user_id, group_id, reply_token, time, reply)
{
  var group_name;
  var picture_url = [ "", ""];
  var response = [ "", ""];
  var send_msg;
  var user_name;

  if(group_id == "Unknown")
    response[0] = http_get_user_name(user_id);
  else
  {
    response[0] = http_get_group_user_name(user_id, group_id);
    response[1] = http_get_group_name(group_id);

    if(response[1].getResponseCode() != 200)
      group_name = "Unknown";
    else
    {
      group_name = JSON.parse(response[1]).groupName;
      picture_url[1] = JSON.parse(response[1]).pictureUrl;
    }
  }

  if(response[0].getResponseCode() != 200)
    user_name = "Unknown";
  else
  {
    user_name = JSON.parse(response[0]).displayName;
    picture_url[0] = JSON.parse(response[0]).pictureUrl;
  }

  if(user_message == "getid" || user_message == "getgroupid")
  {
    if(user_message == "getid")
      send_msg = user_id;
    else if(user_message == "getgroupid")
      send_msg = group_id;

    response[0] = http_send_text_reply(reply_token, send_msg);
    send_msg = "<id>" + send_msg + "</id>";
    if(response[0].getResponseCode() != 200)
      send_msg += "***The message failed to send. Status code = " + response[0].getResponseCode() + " " + JSON.parse(response[0].getContentText()).message + "*** ";

    send_msg += "(" + time + ")";
    if(user_message == "getid")
      log_save(send_msg, user_name, "IDs", "BOT", "Do not save");
    else if(user_message == "getgroupid")
      log_save(send_msg, group_name, "IDs", "BOT", "Do not save");
    return;
  }
 
  user_message += "(" + time + ")";
  if(group_id == "Unknown")
    log_save(user_message, user_name, user_id, user_name, picture_url[0]);
  else
    log_save(user_message, user_name, group_id, group_name, picture_url[1]);
}

function doPost(post_data)
{
  var time = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'MM/dd hh:mm:ss');
  var data_type;
  var result;
  var client_auth = "Unknown";
  var client_gas_ver = "Unknown";
  var id = "Unknown";
  var lock = LockService.getScriptLock();
  var lock_result = lock.tryLock(100);
  try
  {
    data_type = JSON.parse(post_data.postData.contents).type;
  }
  catch(e)
  {
  }
  while(!lock_result)
  {
    Utilities.sleep(100);
    lock_result = lock.tryLock(100);
  }

  if(data_type == undefined)
  {
    for(var i = 0; i < 50; i++)
    {
      var msg_id = "";
      var user_message = "";
      var user_id = "";
      var group_id = "";
      var reply_token = "";
      var msg_type = "";
      var type = "";
 
      try
      {
        type = JSON.parse(post_data.postData.contents).events[i].type;
        user_id = JSON.parse(post_data.postData.contents).events[i].source.userId;
        group_id = JSON.parse(post_data.postData.contents).events[i].source.groupId;
        reply_token = JSON.parse(post_data.postData.contents).events[i].replyToken;
        if(type == "message")
        {
          msg_id = JSON.parse(post_data.postData.contents).events[i].message.id;
          user_message = JSON.parse(post_data.postData.contents).events[i].message.text;
          msg_type = JSON.parse(post_data.postData.contents).events[i].message.type;
        }
      }
      catch(e)
      {
        break;
      }

      if(user_id == undefined)
        user_id = "Unknown";
      if(group_id == undefined)
        group_id = "Unknown";


      if(type == "follow")
        user_message = "getid";
      else if(type == "join")
        user_message = "getgroupid";
      if(type == "leave")
        user_message = "*****Removed by user*****";
      else if(type == "unfollow")
        user_message = "*****Blocked by user*****";
      else if(msg_type == "sticker")
      {
        var sticker_id  = JSON.parse(post_data.postData.contents).events[i].message.stickerId;
        user_message = "<sticker>" + sticker_id + "</sticker>";
      }
      else if(msg_type == "image")
      {
       if(group_id == "Unknown")
         user_message = "<image_url>" + get_content_url(msg_id, user_id, msg_type) + "</image_url>";
       else
         user_message = "<image_url>" + get_content_url(msg_id, group_id, msg_type) + "</image_url>";
      }
      else if(msg_type == "audio")
      {
       if(group_id == "Unknown")
         user_message = "<audio_url>" + get_content_url(msg_id, user_id, msg_type) + "</audio_url>";
       else
         user_message = "<audio_url>" + get_content_url(msg_id, group_id, msg_type) + "</audio_url>";
      }
      else if(msg_type == "video")
      {
       if(group_id == "Unknown")
         user_message = "<video_url>" + get_content_url(msg_id, user_id, msg_type) + "</video_url>";
       else
         user_message = "<video_url>" + get_content_url(msg_id, group_id, msg_type) + "</video_url>";
      }
      else if(msg_type == "file")
      {
       if(group_id == "Unknown")
         user_message = "<file_url>" + get_content_url(msg_id, user_id, msg_type) + "</file_url>";
       else
         user_message = "<file_url>" + get_content_url(msg_id, group_id, msg_type) + "</file_url>";
      }
      else if(user_message == undefined)
        user_message += " : " + msg_type + " " + msg_id;

      receive_msg_from_line(user_message, user_id, group_id, reply_token, time);
    }
    lock.releaseLock();
    return;
  }

  try
  {
    client_auth = JSON.parse(post_data.postData.contents).auth;
    client_gas_ver = JSON.parse(post_data.postData.contents).gas_ver;
    id = JSON.parse(post_data.postData.contents).id;
  }
  catch(e)
  {
  }

  if(SCRIPT_PASSOWRD == client_auth)
  {
    if(gas_ver == client_gas_ver)
    {
      if(data_type == "send_text")
      {
        var send_message = JSON.parse(post_data.postData.contents).message;
        result = send_msg(id, send_message, time);
      }
      else if(data_type == "send_sticker")
      {
        var package_id = JSON.parse(post_data.postData.contents).package_id;
        var sticker_id = JSON.parse(post_data.postData.contents).sticker_id;
        result = send_sticker(id, package_id, sticker_id, time);
      }
      else if(data_type == "upload_content")
      {
        var content_data = JSON.parse(post_data.postData.contents).content_data;
        var count = JSON.parse(post_data.postData.contents).count;
        var name = JSON.parse(post_data.postData.contents).name;
        var last = JSON.parse(post_data.postData.contents).last;
        result = upload_content(id, content_data, count, name, last, time);
      }
      else
        result = "Unknown message type.";
    }
    else
      result = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
  }
  else
    result = "Auth failed. Please set correct password.";

  lock.releaseLock();
  return ContentService.createTextOutput(result);
}

function doGet(post_data)
{
  var data = "";
  var client_auth = "";
  var client_gas_ver = "";
  var num_of_logs = "";
  var id = "";
  var lock = LockService.getScriptLock();
  var lock_result = lock.tryLock(100);
  while(!lock_result)
  {
    Utilities.sleep(100);
    lock_result = lock.tryLock(100);
  }
  try
  {
    client_auth = post_data.parameter.script_auth;
    client_gas_ver = post_data.parameter.gas_ver;
    num_of_logs = post_data.parameter.logs;
    id = post_data.parameter.id;
  }
  catch(e)
  {
  }
  if(client_auth == undefined)
    client_auth = "";
  if(client_gas_ver == undefined)
    client_gas_ver = -1;
  if(num_of_logs == undefined)
    num_of_logs = 300;
  if(id == undefined)
    id = "unknown";

  if(SCRIPT_PASSOWRD == client_auth)
  {
    if(gas_ver == client_gas_ver)
      data = log_read(id, num_of_logs);
    else
      data = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
  }
  else
    data = "Auth failed. Please set correct password.";

  lock.releaseLock();
  return ContentService.createTextOutput(data);
}

This code compatible with ver 1.5.0~1.5.2 !!!WARNING!!! I strongly recommend you use the newest version !!!WARNING!!!

var ACCESS_TOKEN = "Your acces token here";
var open_sheet_id = "Your sheet id here";
var account_name_of_3ds = "Your 3ds's account name here";
var script_password = "Your google apps script password here";

var gas_ver = 5;//Do **NOT** edit this value.
function log_save(message, user_name, write_sheet_name, group_or_user_name, pic_url)
{
    var google_pic_url;
    var previous_pic_url;
    var response;
    var sheet_pos = 1;
    var spreadsheet = SpreadsheetApp.openById(open_sheet_id);
    var write_sheet = spreadsheet.getSheetByName(write_sheet_name);

    if (!write_sheet)
    {
        spreadsheet.insertSheet(write_sheet_name);
        write_sheet = spreadsheet.getSheetByName(write_sheet_name);
    }

    sheet_pos = get_cache_pos(write_sheet);

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

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

    write_cache_data(write_sheet, (sheet_pos + 1), "B1");
    if (group_or_user_name != "Do not save")
        write_cache_data(write_sheet, group_or_user_name, "B2");

    if (pic_url != "Do not save")
    {
        previous_pic_url = get_previous_pic_url(write_sheet);
        if (previous_pic_url != pic_url)
        {
            response = UrlFetchApp.fetch(pic_url,
                {
                    'headers': {
                        'Content-Type': 'application/json; charset=UTF-8',
                        'Authorization': 'Bearer ' + ACCESS_TOKEN,
                    },
                    muteHttpExceptions: true,
                });

            if (response.getResponseCode() == 200)
            {
                google_pic_url = get_profile_pic_google_url(response, write_sheet_name);
                write_cache_data(write_sheet, google_pic_url, "B3");
                write_cache_data(write_sheet, pic_url, "B4");
            }
        }

    }
}

function check_folder_exist(input_folders, name)
{
    var folder;
    while (input_folders.hasNext())
    {
      folder = input_folders.next();
      if(name == folder.getName())
        return folder;
    }
    return undefined;
}

function log_read(id)
{
  var sheet_start = 1;
  var return_data;
  var sheet_data;
  var spreadsheet = SpreadsheetApp.openById(open_sheet_id);
  var read_sheet = spreadsheet.getSheetByName(id);
  sheet_start = get_cache_pos(read_sheet);

  while(true)
  {
    sheet_data = read_sheet.getRange("A" + sheet_start).getValue();
    if(sheet_data == "")
    {
      write_cache_data(read_sheet, sheet_start, "B1");
      if(sheet_start >= 301)
        sheet_start = (sheet_start - 300);
      else
        sheet_start = 1;
 
      break;
    }
    else
      sheet_start++;
  }

  sheet_data = read_sheet.getRange(sheet_start, 1, 300).getValues();
  return_data = "<0>";
  for(var i = 0; i < 300; i++)
  {
    if(sheet_data[i] == "")
      break;

    return_data += sheet_data[i];
  }
    return_data += "</0>";
    return_data += "<1>" + get_cache_name(read_sheet) + "</1>";
    return_data += "<2>" + get_google_pic_url(read_sheet) + "</2>";
    return_data += "<3>Success</3>";
  return return_data;
}

function get_cache_pos(sheet_object)
{
  var cached_sheet_pos = sheet_object.getRange("B1").getValue();
  var sheet_data;

  if(parseInt(cached_sheet_pos) > 0)
  {
    cached_sheet_pos = parseInt(cached_sheet_pos);
    sheet_data = sheet_object.getRange("A" + (cached_sheet_pos - 1)).getValue();
 
    if(sheet_data != "")
      return cached_sheet_pos;
  }
  return 1;
}

function get_cache_name(sheet_object)
{
  var cached_name = sheet_object.getRange("B2").getValue();
  return cached_name;
}

function get_google_pic_url(sheet_object)
{
    var cached_name = sheet_object.getRange("B3").getValue();
    return cached_name;
}

function get_previous_pic_url(sheet_object)
{
    var cached_name = sheet_object.getRange("B4").getValue();
    return cached_name;
}

function write_cache_data(sheet_object, cache_data, pos)
{
  sheet_object.getRange(pos).setValue(cache_data);
}

function http_get_content(request_id)
{
  var response;
  var url = "https://api.line.me/v2/bot/message/" + request_id + "/content";
  response = UrlFetchApp.fetch(url,
  {
  'headers': {
    'Content-Type': 'application/json; charset=UTF-8',
    'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_get_user_name(id)
{
  var response;
  var url = 'https://api.line.me/v2/bot/profile/' + id;
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_get_group_user_name(id, group_id)
{
  var response;
  var url = "https://api.line.me/v2/bot/group/" + group_id + "/member/" + id + "/";
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_get_group_name(group_id)
{
  var response;
  var url = "https://api.line.me/v2/bot/group/" + group_id +"/summary/";
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    muteHttpExceptions: true,
  });
  return response;
}

function http_send_text_reply(reply_token, send_msg)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/reply/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': reply_token,
      'messages': [{
        'type': 'text',
        'text': send_msg ,
      }],
      'notificationDisabled': 'true',
    }),
    muteHttpExceptions: true,
  });
  return response;
}

function http_send_text(id, send_msg)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/push/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
  "to": id,
  "messages":
       [{
          "text": send_msg,
          "type": "text",
       }],
      'notificationDisabled': 'false',
    }),
   muteHttpExceptions: true,
  });
  return response;
}

function http_send_sticker(id, package_id, sticker_id)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/push/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
  "to": id,
  "messages":
       [{
          "type": "sticker",
          "packageId": package_id,
          "stickerId": sticker_id,
       }],
      'notificationDisabled': 'false',
    }),
   muteHttpExceptions: true,
  });
  return response;
}

function http_send_image(id, img_url, preview_url)
{
  var response;
  var url = 'https://api.line.me/v2/bot/message/push/';
  response = UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
  "to": id,
  "messages":
       [{
          "type": "image",
          "originalContentUrl": img_url,
          "previewImageUrl": preview_url,
       }],
      'notificationDisabled': 'false',
    }),
   muteHttpExceptions: true,
  });
  return response;
}

function send_msg(id, send_message, time)
{
  var cache;
  var response;
  var return_message = "Success";
 
  response = http_send_text(id, send_message);
  if(response.getResponseCode() != 200)
  {
    cache = "***The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message + "*** ";
    cache += send_message;
    send_message = cache;
    return_message = "The message failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
  }
  send_message += "(" + time + ")";
  log_save(send_message, account_name_of_3ds, id, "Do not save", "Do not save");
  return return_message;
}

function send_sticker(id, package_id, sticker_id, time)
{
  var response;
  var return_message = "Success";
  var send_message = "";

  response = http_send_sticker(id, package_id, sticker_id);
  if(response.getResponseCode() != 200)
  {
   send_message = "***The sticker failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
   return_message = "The sticker failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
  }
  send_message += "<sticker>" + sticker_id + "</sticker>(" + time + ")";
  log_save(send_message, account_name_of_3ds, id, "Do not save", "Do not save");
  return return_message;
}

function upload_content(id, data, count, cache_name)
{
  var cache_folder;
  var exist_cache_folders;
  var exist_folders;
  var exist_sub_folders;
  var folder;
  var folder_name = "Line_contents";
  var part_of_content;
  var part_of_content_data;
  var return_message = "Success";
  var sub_folder;

  exist_folders = DriveApp.searchFolders("'me' in owners");
  folder = check_folder_exist(exist_folders, folder_name);
  if(folder == undefined)
    folder = DriveApp.createFolder(folder_name);
 
  exist_sub_folders = folder.searchFolders("'me' in owners");
  sub_folder = check_folder_exist(exist_sub_folders, id);
  if(sub_folder == undefined)
    sub_folder = folder.createFolder(id);
 
  exist_cache_folders = sub_folder.searchFolders("'me' in owners");
  cache_folder = check_folder_exist(exist_cache_folders, cache_name);
  if(cache_folder == undefined)
    cache_folder = sub_folder.createFolder(cache_name);
  else if(!(cache_folder == undefined) && count == 0)
  {
    cache_folder.setTrashed(true);
    cache_folder = sub_folder.createFolder(cache_name);
  }

  part_of_content_data = Utilities.newBlob(data).setName(count);
  part_of_content = cache_folder.createFile(part_of_content_data);
  return return_message;
}

function send_content(id, cache_name, time)
{
  var cache_file;
  var cache_folder;
  var content;
  var content_data;
  var content_type;
  var content_url = "";
  var encoded_data = "";
  var exist_cache_folders;
  var exist_folders;
  var exist_sub_folders;
  var folder;
  var folder_name = "Line_contents";
  var preview_content_url = "";
  var response;
  var return_message = "Success";
  var send_message = "";
  var sub_folder;

  exist_folders = DriveApp.searchFolders("'me' in owners");
  folder = check_folder_exist(exist_folders, folder_name);
  if(folder == undefined)
    folder = DriveApp.createFolder(folder_name);

  exist_sub_folders = folder.searchFolders("'me' in owners");
  sub_folder = check_folder_exist(exist_sub_folders, id);
  if(sub_folder == undefined)
    sub_folder = folder.createFolder(id);

  exist_cache_folders = sub_folder.searchFolders("'me' in owners");
  cache_folder = check_folder_exist(exist_cache_folders, cache_name);
  if(cache_folder == undefined)
  {
    send_message = "***The content failed to send. The cache folder does not exist.*** (" + time + ")";
    log_save(send_message, account_name_of_3ds, id, "Do not save", "Do not save");
    return_message = "The content failed to send.\nThe cache folder does not exist."
    return return_message;
  }

  for(var i = 0; i < 4096; i++)
  {
    try
    {
      cache_file = cache_folder.getFilesByName(i).next();
      encoded_data += cache_file.getBlob().getDataAsString();
    }
    catch(error)
    {
      break;
    }
  }

  cache_folder.setTrashed(true);
  content_data = Utilities.newBlob(Utilities.base64Decode(encoded_data)).setName(cache_name);
  content = sub_folder.createFile(content_data);
  content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
  content_type = content.getMimeType();
  if(content_type == MimeType.BMP || content_type == MimeType.GIF || content_type == MimeType.JPEG || content_type == MimeType.PNG || content_type == MimeType.SVG)
  {
    content.setTrashed(true);
    folder_name = "Line_images";
    exist_folders = DriveApp.searchFolders("'me' in owners");
    folder = check_folder_exist(exist_folders, folder_name);
    if(folder == undefined)
    folder = DriveApp.createFolder(folder_name);

    exist_sub_folders = folder.searchFolders("'me' in owners");
    sub_folder = check_folder_exist(exist_sub_folders, id);
    if(sub_folder == undefined)
    sub_folder = folder.createFolder(id);
 
    content = sub_folder.createFile(content_data);
    content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
    content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
    preview_content_url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w240-h240";
 
    response = http_send_image(id, content_url, preview_content_url);
    if(response.getResponseCode() != 200)
    {
      send_message = "***The image failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
      return_message = "The image failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
    }
    send_message += "<image_url>" + content_url + "</image_url>(" + time + ")";
    log_save(send_message, account_name_of_3ds, id, "Do not save", "Do not save");
    return return_message;
  }
  else
  {
    content_url = "https://drive.google.com/file/d/" + content.getId() + "/view";
    response = http_send_text(id, content_url);
    if(response.getResponseCode() != 200)
    {
      send_message = "***The content failed to send. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
      return_message = "The content failed to send. Status code = " + response.getResponseCode() + "\n" + JSON.parse(response.getContentText()).message;
    }
    content_url = "https://drive.google.com/uc?export=download&id=" + content.getId();
    send_message += "<content_url>" + content_url + "</content_url>(" + time + ")";
    log_save(send_message, account_name_of_3ds, id, "Do not save", "Do not save");
    return return_message;
  }
}

function get_profile_pic_google_url(http_response, group_or_user_id)
{
    var content_data;
    var content;
    var folder_name = "Line_images";
    var folder;
    var sub_folder;
    var exist_folders;
    var exist_sub_folders;
    var url = "";
 
    exist_folders = DriveApp.searchFolders("'me' in owners");
    folder = check_folder_exist(exist_folders, folder_name);
    if (folder == undefined)
        folder = DriveApp.createFolder(folder_name);

    exist_sub_folders = folder.searchFolders("'me' in owners");
    sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
    if (sub_folder == undefined)
        sub_folder = folder.createFolder(group_or_user_id);

    content_data = http_response.getBlob().getAs("image/jpeg").setName("icon");
    content = sub_folder.createFile(content_data);
    content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
    url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w32-h32";

    return url;
}

function get_content_url(request_id, group_or_user_id, type)
{
  var content_data;
  var content;
  var exist_folders;
  var exist_sub_folders;
  var folder_name;
  var folder;
  var sub_folder;
  var response;
  var url = "";
 
  if(type == "image")
    folder_name = "Line_images";
  else if(type == "audio")
    folder_name = "Line_audio";
  else if(type == "video")
    folder_name = "Line_videos";
 
  exist_folders = DriveApp.searchFolders("'me' in owners");
  folder = check_folder_exist(exist_folders, folder_name);
  if(folder  == undefined)
    folder = DriveApp.createFolder(folder_name);
 
  exist_sub_folders = folder.searchFolders("'me' in owners");
  sub_folder = check_folder_exist(exist_sub_folders, group_or_user_id);
  if(sub_folder  == undefined)
    sub_folder = folder.createFolder(group_or_user_id);

  response = http_get_content(request_id);
  if(response.getResponseCode() != 200)
  {
    if(type == "image")
      url = "***Couldn't generate an image URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
    else if(type == "audio")
      url = "***Couldn't generate a audio URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
    else if(type == "video")
      url = "***Couldn't generate a video URL. Status code = " + response.getResponseCode() + " " + JSON.parse(response.getContentText()).message + "*** ";
  }
  else
  {
    if(type == "image")
    {
      content_data = response.getBlob().getAs("image/jpeg").setName(request_id);
      content = sub_folder.createFile(content_data);
      content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
      url = "https://lh3.googleusercontent.com/d/" + content.getId() + "=w16383-h16383";
    }
    else if(type == "audio" || type == "video")
    {
      content_data = response.getBlob().setName(request_id);
      content = sub_folder.createFile(content_data);
      content.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
      url = "https://drive.google.com/uc?export=download&id=" + content.getId();
    }
  }
  return url;
}

function receive_msg_from_line(user_message, user_id, group_id, reply_token, time)
{
  var group_name;
  var picture_url = [ "", ""];
  var response = [ "", ""];
  var send_msg;
  var user_name;
 
  if(user_message == "getid" || user_message == "getgroupid")
  {
    if(user_message == "getid")
      send_msg = user_id;
    else if(user_message == "getgroupid")
      send_msg = group_id;
 
    response[0] = http_send_text_reply(reply_token, send_msg);
    send_msg = "<id>" + send_msg + "</id>";
    if(response[0].getResponseCode() != 200)
      send_msg += "***The message failed to send. Status code = " + response[0].getResponseCode() + " " + JSON.parse(response[0].getContentText()).message + "*** ";

    log_save(send_msg, "BOT", "IDs", "BOT", "Do not save");
    return;
  }

  if(group_id == "Unknown")
    response[0] = http_get_user_name(user_id);
  else
  {
    response[0] = http_get_group_user_name(user_id, group_id);
    response[1] = http_get_group_name(group_id);
 
    if(response[1].getResponseCode() != 200)
      group_name = "Unknown";
    else
    {
      group_name = JSON.parse(response[1]).groupName;
      picture_url[1] = JSON.parse(response[1]).pictureUrl;
    }
  }

  if(response[0].getResponseCode() != 200)
    user_name = "Unknown";
  else
  {
    user_name = JSON.parse(response[0]).displayName;
    picture_url[0] = JSON.parse(response[0]).pictureUrl;
  }
 
  user_message += "(" + time + ")";
  if(group_id == "Unknown")
    log_save(user_message, user_name, user_id, user_name, picture_url[0]);
  else
    log_save(user_message, user_name, group_id, group_name, picture_url[1]);
}

function doPost(post_data)
{
  var date = new Date();
  var time = Utilities.formatDate( date, 'Asia/Tokyo', 'MM/dd hh:mm:ss');
  var type = JSON.parse(post_data.postData.contents).type;
  var result;
  var lock = LockService.getScriptLock();
  var lock_result = lock.tryLock(1000);
  while(!lock_result)
  {
    Utilities.sleep(100);
    lock_result = lock.tryLock(1000);
  }

  if(type == undefined)
  {
    for(var i = 0; i < 30; i++)
    {
      try
      {
        var msg_id = JSON.parse(post_data.postData.contents).events[i].message.id;
        var user_message = JSON.parse(post_data.postData.contents).events[i].message.text;
        var user_id = JSON.parse(post_data.postData.contents).events[i].source.userId;
        var group_id = JSON.parse(post_data.postData.contents).events[i].source.groupId;
        var reply_token = JSON.parse(post_data.postData.contents).events[i].replyToken;
        var type = JSON.parse(post_data.postData.contents).events[i].message.type;
      }
      catch(error)
      {
        break;
      }
 
      if(user_id == undefined)
        user_id = "Unknown";
      if(group_id == undefined)
        group_id = "Unknown";

      if(type == "sticker")
      {
        var sticker_id  = JSON.parse(post_data.postData.contents).events[0].message.stickerId;
        user_message = "<sticker>" + sticker_id + "</sticker>";
      }
      else if(type == "image")
      {
       if(group_id == "Unknown")
         user_message = "<image_url>" + get_content_url(msg_id, user_id, type) + "</image_url>";
       else
         user_message = "<image_url>" + get_content_url(msg_id, group_id, type) + "</image_url>";
      }
      else if(type == "audio")
      {
       if(group_id == "Unknown")
         user_message = "<audio_url>" + get_content_url(msg_id, user_id, type) + "</audio_url>";
       else
         user_message = "<audio_url>" + get_content_url(msg_id, group_id, type) + "</audio_url>";
      }
      else if(type == "video")
      {
       if(group_id == "Unknown")
         user_message = "<video_url>" + get_content_url(msg_id, user_id, type) + "</video_url>";
       else
         user_message = "<video_url>" + get_content_url(msg_id, group_id, type) + "</video_url>";
      }
      else if(user_message == undefined)
        user_message += " : " + type + " " + msg_id;

      receive_msg_from_line(user_message, user_id, group_id, reply_token, time);
    }
    lock.releaseLock();
    return;
  }

  var client_auth = JSON.parse(post_data.postData.contents).auth;
  var client_gas_ver = JSON.parse(post_data.postData.contents).gas_ver;
  if(client_auth == undefined)
    client_auth = "";
  if(client_gas_ver == undefined)
    client_gas_ver = -1;
 
  if(script_password == client_auth)
  {
    if(gas_ver == client_gas_ver)
    {
      var id = JSON.parse(post_data.postData.contents).id;
 
      if(type == "send_text")
      {
        var send_message = JSON.parse(post_data.postData.contents).message;
        result = send_msg(id, send_message, time);
      }
      else if(type == "send_sticker")
      {
        var package_id = JSON.parse(post_data.postData.contents).package_id;
        var sticker_id = JSON.parse(post_data.postData.contents).sticker_id;
        result = send_sticker(id, package_id, sticker_id, time);
      }
      else if(type == "upload_content")
      {
        var content_data = JSON.parse(post_data.postData.contents).content_data;
        var count = JSON.parse(post_data.postData.contents).count;
        var name = JSON.parse(post_data.postData.contents).name;
        result = upload_content(id, content_data, count, name);
      }
      else if(type == "send_content")
      {
        var name = JSON.parse(post_data.postData.contents).name;
        result = send_content(id, name, time);
      }
      else
        result = "Unknown message type.";
    }
    else
      result = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
  }
  else
    result = "Auth failed. Please set correct password.";

  lock.releaseLock();
  return ContentService.createTextOutput(result);
}

function doGet(post_data)
{
  var data = "";
  var client_auth = post_data.parameter.script_auth;
  var client_gas_ver = post_data.parameter.gas_ver;
  if(client_auth == undefined)
    client_auth = "";
  if(client_gas_ver == undefined)
    client_gas_ver = -1;

  if(script_password == client_auth)
  {
    if(gas_ver == client_gas_ver)
      data = log_read(post_data.parameter.id);
    else
      data = "Google apps script version does not match. Server's gas\nver is " + gas_ver + ", but 3DS's gas ver is " + client_gas_ver + ". Please use the same version.";
  }
  else
    data = "Auth failed. Please set correct password.";
 
  return ContentService.createTextOutput(data);
}

'Then click Publish '-> Deploy as web app and set
"Project version" : New
"Execute the app as" : 'Me(***@gmail.com)''''''''
"Who has access to the app" : Anyone,even anonymous
'finally click deploy.
''''
2380c28d8c9f5f0fdba5bcaad06b5e09.png
Next click Review permissions and select your google account.
If "This app isn't verified or You should avoid this app" shown click Advanced and click "Go to Line main (unsafe)" (⁂It's safe!) and click allow.
Copy this url and save.
'
578f8adc76932a8223d45d904303d707.png

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

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

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

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

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

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

How To Setup (3DS)

Please click here to see the contents:

Download the latest Line For 3DS

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

For ver 1.5.0~1.7.0


'This guide compatible with ver 1.5.01.7.0'

Next step there are 2 methods

Method 1 (Easy)

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

Method 2 (Very very very very very very hard)

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

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

How To Add Friend

Please click here to see the contents:

PC or phone (or android emulator)
Find Bot information and scan your bot's QR code or search friends by BOT basic ID.
https://dlhb.gamebrew.org/3dshomebrew/c5fce08f621dcbde7f904b526a0dde38-png

  • <a href="#panel1">For ver 1.6.0~1.70</a>
  • <a href="#panel2">For ver 1.5.2~1.5.0</a>
  • <a href="#panel3">For ver 1.4.2~1.2.0</a>

This guide compatible with ver 1.6.0''''1.7.0'''' 3DS

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

213847-b395a998bbadc9da090a8a8c1643f28e.jpg 213848-a22714cf4f2c5ad4f8faee777fbb10df.jpg
Select "IDs".

213850-6584a852100d8425ac9eabb795203415.jpg
Tap "Receive" tab and press B button (or tap log update)

213851-a7224391e6bd5598948ce90f56e1fa82.jpg
You'll see touch to add this ID and tap it.

00000029.jpg 00000031.jpg 00000033.jpg


And send "
getid".
00000029.png

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

3DS

Press Y button (or tap Add new ID) and type "IDs".
213847-b395a998bbadc9da090a8a8c1643f28e.jpg 213848-a22714cf4f2c5ad4f8faee777fbb10df.jpg
Select "IDs".

https://dlhb.gamebrew.org/3dshomebrew/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⚠⚠⚠

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

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

Patch note

【App】 Ver 1.7.2

  • 【Line】 Fixed some bugs.
  • 【Vid】 Added debug infomation.
  • 【Vid】 Changed initial image size and position
  • 【App】 Some minor update to better user experience.

【App】 Ver 1.7.1

  • 【Line】 Added- Supported download all files.
  • 【Mup/Vid】 Added- Additional formats support(.ogg).
  • 【App】 Some minor update to better user experience.

【App】 Ver 1.7.0

  • 【App】 Fixed- Fonts was improved.
  • 【App】 Added- Video player.
  • 【Line】 Added- Now, you can play audio and video sent by user.
  • 【Cam】 Fixed- Framerate was improved.
  • 【Mup】 Added- Additional formats (like aac) are supported.
  • 【App】 Some minor update to better user experience.

V1.3.1

  • 【App】 Ver 1.3.1
  • 【Line】 Fixed- Common occurring [FSUSER_OpenArchive failed] error has been solved.
  • 【Line】 Fixed- Image display now activated by touching the message.
  • 【Setting】 Fixed- Setting menu framerate now improved.
  • 【Image viewer】 Fixed- Image display speed now improved.

v1.2.0

  • Fix- Some crashes
  • Fix- Some settings do not work
  • Fix- Log download (GAS processing) speed has been improved(GAS update required)
  • Add- Image viewer

Advertising: