Line for 3DS: Difference between revisions

From GameBrew
No edit summary
No edit summary
Line 3: Line 3:
| image = https://dlhb.gamebrew.org/3dshomebrew/Line-for-3DS.png|250px
| image = https://dlhb.gamebrew.org/3dshomebrew/Line-for-3DS.png|250px
| type = Other Apps
| type = Other Apps
| version = v1.3.1
| version = v1.7.2
| licence = Mixed
| licence = Mixed
| author = Core-2-Extreme
| author = Core-2-Extreme
| website = https://gbatemp.net/threads/v0-2-0-release-guide-line-for-3ds.539530/
| website = https://gbatemp.net/threads/v0-2-0-release-guide-line-for-3ds.539530/
| download = https://dlhb.gamebrew.org/3dshomebrew/Line_for_3DS-1.3.1.rar
| download = https://dlhb.gamebrew.org/3dshomebrew/Line_for_3DSv1.7.2.7z
| source = https://github.com/Core-2-Extreme/Line_for_3DS
| source = https://github.com/Core-2-Extreme/Line_for_3DS
}}
}}
<youtube>1T90ZQxDnOc</youtube>
<youtube>5K2fCr0lyoM</youtube>


= Line for 3DS =
= Line for 3DS =


https://user-images.githubusercontent.com/45873899/77541203-a9977e80-6ee7-11ea-8479-53aed389ab64.png
https://user-images.githubusercontent.com/45873899/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 ==
== Official Discord ==
Line 20: Line 39:
[https://discord.gg/EqK3Kpb https://discord.gg/EqK3Kpb]
[https://discord.gg/EqK3Kpb https://discord.gg/EqK3Kpb]


== Index ==
== How to use ==


* [https://github.com/Core-2-Extreme/Line_for_3DS#Patch-note Patch-note]
'''*1 The stickers must be included this list'''
* [https://github.com/Core-2-Extreme/Line_for_3DS#summary Summary]
[https://dlhb.gamebrew.org/3dshomebrew/sticker_list.pdf sticker_list.pdf]
* [https://github.com/Core-2-Extreme/Line_for_3DS#How-to-use How-to-use]


== Patch note ==
'''*2 Google drive URL will be sent(not embed).'''
 
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
 
== Summary ==
 
= [https://www.youtube.com/watch?v=5K2fCr0lyoM Video] =
 
* Send text ?
* Send picture ?
* Send video ?
* Send sound ?
* Send stamp ?
* Receive text ?
* Receive (View) picture ? (v1.2.0)
* Receive (Play) video ?
* Receive (Play) sound ?
* Receive (View) stamp ?
* View old log ? (Until max 300 logs)
* Auto update ? (v0.2.0)
* Group chat ?
* Night mode ? (v0.2.0)
* Password ? (v0.3.0)
* Save log to SD card ? (v0.3.0)
 
== How to use ==
 
How to install and use for version 1.3.0~


===How to setup Google apps script===
'''Please access this site.<br />
'''Please access this site.<br />
[https://developers.line.biz/en/ <span style="font-size: 15px"><span style="color: rgb(0, 0, 0)">'''https://developers.line.biz/en/'''</span></span>]<br />
[https://developers.line.biz/en/ <span style="font-size: 15px"><span style="color: rgb(0, 0, 0)">'''https://developers.line.biz/en/'''</span></span>]<br />
Line 104: Line 85:
'''<br />
'''<br />


<pre>
Code:


<ul class="tabs" data-tab>
  <li class="tab-title active"><a href="#panel1">For Ver 1.7.0</a></li>
  <li class="tab-title"><a href="#panel2">For Ver 1.6.0</a></li>
  <li class="tab-title"><a href="#panel3">For Ver 1.5.0~1.5.2</a></li>
</ul>
<div class="tabs-content">
  <div class="content active" id="panel1">
    <p>This is the first panel of the basic tab example. You can place all sorts of content here including a grid.</p>
  </div>
  <div class="content" id="panel2">
    <p>This is the second panel of the basic tab example. This is the second panel of the basic tab example.</p>
  </div>
  <div class="content" id="panel3">
    <p>This is the third panel of the basic tab example. This is the third panel of the basic tab example.</p>
  </div>
</div>
</div>
<pre>var ACCESS_TOKEN = &quot;Your acces token here&quot;;
var open_sheet_id = &quot;Your sheet id here&quot;;
var account_name_of_3ds = &quot;Your 3ds's account name here&quot;;
var script_password = &quot;Your google apps script password here&quot;;


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


  if(!write_sheet)
  {
    spreadsheet.insertSheet(write_sheet_name);
    write_sheet = spreadsheet.getSheetByName(write_sheet_name);
  }
  sheet_pos = get_cache_pos(write_sheet);
  while(true)
  {
  var sheet_data = write_sheet.getRange(&quot;A&quot; + sheet_pos).getValue();


  if(sheet_data == &quot;&quot;)
  {
    write_sheet.getRange(&quot;A&quot; + sheet_pos).setValue(&quot;&quot; + user_name + &quot; : &quot; + message);
    break;
  }
  else
    sheet_pos++;
  }
  write_cache_pos(write_sheet, (sheet_pos + 1));
}


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


  while(true)
  {
    sheet_data = read_sheet.getRange(&quot;A&quot; + sheet_start).getValue();
    if(sheet_data == &quot;&quot;)
    {
      write_cache_pos(read_sheet, sheet_start);
      if(sheet_start &gt;= 301)
        sheet_start = (sheet_start - 300);
      else
        sheet_start = 1;
      break;
    }
    else
      sheet_start++;
  }
  sheet_data = read_sheet.getRange(sheet_start, 1, 300).getValues();
  for(var i = 0; i &lt; 300; i++)
  {
    if(sheet_data[i] == &quot;&quot;)
      break;
    return_data += sheet_data[i];
  }
  return return_data;
}


function get_cache_pos(sheet_object)
{
  var cached_sheet_pos = sheet_object.getRange(&quot;B1&quot;).getValue();
  var sheet_data;
  if(parseInt(cached_sheet_pos) &gt; 0)
  {
    cached_sheet_pos = parseInt(cached_sheet_pos);
    sheet_data = sheet_object.getRange(&quot;A&quot; + (cached_sheet_pos - 1)).getValue();
    if(sheet_data != &quot;&quot;)
      return cached_sheet_pos;
  }
  return 1;
}


function write_cache_pos(sheet_object, cache_data)
{
  sheet_object.getRange(&quot;B1&quot;).setValue(cache_data);
}


function send_msg(id, send_message, time)
How to install and use for version 1.3.0~
{
  var return_message = &quot;Success&quot;;
  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({
    &quot;to&quot;: id,
    &quot;messages&quot;:
      [
        {
            &quot;text&quot;: send_message,
            &quot;type&quot;: &quot;text&quot;,
        }],
        'notificationDisabled': 'false',
      }),
    muteHttpExceptions: true,
    });
    if(response.getResponseCode() != 200)
    {
      var cache = &quot;***Send failed. Status code = &quot; + response.getResponseCode() + &quot;\n&quot; + JSON.parse(response.getContentText()).message + &quot;*** &quot;;
      cache += send_message;
      send_message = cache;
      return_message = &quot;Send message failed. Status code = &quot; + response.getResponseCode() + &quot;\n&quot; + JSON.parse(response.getContentText()).message;
    }
  send_message += &quot;(&quot; + time + &quot;)&quot;;
  log_save(send_message, account_name_of_3ds, id);
  return return_message;
}
 
function send_sticker(id, package_id, sticker_id, time)
{
  var return_message = &quot;Success&quot;;
  var send_message = &quot;&quot;;
  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({
    &quot;to&quot;: id,
    &quot;messages&quot;:
      [
        {
            &quot;type&quot;: &quot;sticker&quot;,
            &quot;packageId&quot;: package_id,
            &quot;stickerId&quot;: sticker_id,
        }],
        'notificationDisabled': 'false',
      }),
      muteHttpExceptions: true,
    });
    if(response.getResponseCode() != 200)
    {
    send_message = &quot;***Send failed. Status code = &quot; + response.getResponseCode() + &quot;\n&quot; + JSON.parse(response.getContentText()).message + &quot;*** &quot;;
    return_message = &quot;Send sticker failed. Status code = &quot; + response.getResponseCode() + &quot;\n&quot; + JSON.parse(response.getContentText()).message;
    }
  send_message += &quot;&lt;sticker&gt;&quot; + sticker_id + &quot;&lt;/sticker&gt;(&quot; + time + &quot;)&quot;;
  log_save(send_message, account_name_of_3ds, id);
  return return_message;
}
 
function get_content_url(request_id, group_or_user_id, type)
{
  var content_url = &quot;https://api.line.me/v2/bot/message/&quot; + request_id + &quot;/content&quot;;
  var url = &quot;&quot;;
  var folder_name;
  var folder;
  var sub_folder;
  var folder_exist = false;
  var sub_folder_exist = false;
 
try
{
    if(type == &quot;image&quot;)
      folder_name = &quot;Line_images&quot;;
    else if(type == &quot;audio&quot;)
      folder_name = &quot;Line_audio&quot;;
    else if(type == &quot;video&quot;)
      folder_name = &quot;Line_videos&quot;;
    var exist_folders = DriveApp.searchFolders(&quot;'me' in owners&quot;);
    while (exist_folders.hasNext())
    {
      folder = exist_folders.next();
      if(folder_name == folder.getName())
      {
        folder_exist = true;
        break;
      }
    }
    if(!folder_exist)
      folder = DriveApp.createFolder(folder_name);
    var exist_sub_folders = folder.searchFolders(&quot;'me' in owners&quot;);
    while (exist_sub_folders.hasNext())
    {
      sub_folder = exist_sub_folders.next();
      if(group_or_user_id == sub_folder.getName())
      {
        sub_folder_exist = true;
        break;
      }
    }
    if(!sub_folder_exist)
      sub_folder = folder.createFolder(group_or_user_id);
    var response = UrlFetchApp.fetch(content_url,
    {
    'headers': {
    'Content-Type': 'application/json; charset=UTF-8',
    'Authorization': 'Bearer ' + ACCESS_TOKEN,
        }
    });
    if(type == &quot;image&quot;)
    {
      var image_data = response.getBlob().getAs(&quot;image/jpeg&quot;).setName(request_id + &quot;.jpg&quot;);
      var image = sub_folder.createFile(image_data);
      image.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
      url = &quot;https://drive.google.com/uc?export=download&amp;id=&quot; + image.getId();
    }
    else if(type == &quot;audio&quot;)
    {
      var audio_data = response.getBlob().setName(request_id + &quot;.mp3&quot;);
      var audio = sub_folder.createFile(audio_data);
      audio.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
      url = &quot;https://drive.google.com/uc?export=download&amp;id=&quot; + audio.getId();
    }
    else if(type == &quot;video&quot;)
    {
      var video_data = response.getBlob().setName(request_id + &quot;.mp4&quot;);
      var video = sub_folder.createFile(video_data);
      video.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
      url = &quot;https://drive.google.com/uc?export=download&amp;id=&quot; + video.getId();
    }
  }
  catch(error)
  {
    if(type == &quot;image&quot;)
      url = &quot;Generate image url failed.&quot;;
    else if(type == &quot;audio&quot;)
      url = &quot;Generate audio url failed.&quot;;
    else if(type == &quot;video&quot;)
      url = &quot;Generate video url failed.&quot;;
  }
  return url;
}
 
 
function receive_msg_from_line(user_message, user_id, group_id, replyToken, time)
{
  var url_reply = 'https://api.line.me/v2/bot/message/reply';
  var url_profile = 'https://api.line.me/v2/bot/profile/';
  if(user_message == &quot;getid&quot; || user_message == &quot;getgroupid&quot;)
  {
    var send_id;
    if(user_message == &quot;getid&quot;)
      send_id = user_id;
    else if(user_message == &quot;getgroupid&quot;)
      send_id = group_id;
    UrlFetchApp.fetch(url_reply, {
      'headers': {
        'Content-Type': 'application/json; charset=UTF-8',
        'Authorization': 'Bearer ' + ACCESS_TOKEN,
      },
      'method': 'post',
      'payload': JSON.stringify({
        'replyToken': replyToken,
        'messages': [{
          'type': 'text',
          'text': send_id ,
        }],
        'notificationDisabled': 'true',
      }),
    });
    log_save(send_id, &quot;BOT&quot;, &quot;IDs&quot;);
    return;
  }
 
  try
  {
    var response = UrlFetchApp.fetch(url_profile + user_id, {
      'headers': {
        'Content-Type': 'application/json; charset=UTF-8',
        'Authorization': 'Bearer ' + ACCESS_TOKEN,
      },
    });
    var profile_name = JSON.parse(response).displayName;
  }
  catch(error)
  {
    profile_name = &quot;Unknown&quot;;
  }
 
  user_message += &quot;(&quot; + time + &quot;)&quot;;
 
  if(group_id == &quot;Unknown&quot;)
    log_save(user_message, profile_name, user_id);
  else
    log_save(user_message, profile_name, group_id);
}
 
function doPost(post_data)
{
  var date = new Date();
  var time = Utilities.formatDate( date, 'Asia/Tokyo', 'MM/dd hh:mm:ss');
  var type = JSON.parse(post_data.postData.contents).type;
  var result;


  if(type == undefined)
  {
    var msg_id = JSON.parse(post_data.postData.contents).events[0].message.id;
    var user_message = JSON.parse(post_data.postData.contents).events[0].message.text;
    var user_id = JSON.parse(post_data.postData.contents).events[0].source.userId;
    var group_id = JSON.parse(post_data.postData.contents).events[0].source.groupId;
    var replyToken = JSON.parse(post_data.postData.contents).events[0].replyToken;
    var type = JSON.parse(post_data.postData.contents).events[0].message.type;
    if(user_id == undefined)
      user_id = &quot;Unknown&quot;;
    if(group_id == undefined)
      group_id = &quot;Unknown&quot;;


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


    receive_msg_from_line(user_message, user_id, group_id, replyToken, time);
    return;
  }
  var client_auth = JSON.parse(post_data.postData.contents).auth;
  var client_gas_ver = JSON.parse(post_data.postData.contents).gas_ver;
  if(client_auth == undefined)
    client_auth = &quot;&quot;;
  if(client_gas_ver == undefined)
    client_gas_ver = -1;
  if(script_password == client_auth)
  {
    if(gas_ver == client_gas_ver)
    {
      if(type == &quot;send_text&quot;)
      {
        var id = JSON.parse(post_data.postData.contents).id;
        var send_message = JSON.parse(post_data.postData.contents).message;
        result = send_msg(id, send_message, time);
      }
      else if(type == &quot;send_sticker&quot;)
      {
        var id = JSON.parse(post_data.postData.contents).id;
        var package_id = JSON.parse(post_data.postData.contents).package_id;
        var sticker_id = JSON.parse(post_data.postData.contents).sticker_id;
        result = send_sticker(id, package_id, sticker_id, time);
      }
      else
        result = &quot;Unknown message type.&quot;;
    }
    else
      result = &quot;Google Apps Script version does not match. Server's GAS\nver is &quot; + gas_ver + &quot;, but 3DS's GAS ver is &quot; + client_gas_ver + &quot;. Please use the same version.&quot;;
  }
  else
    result = &quot;Auth failed. Please set correct password.&quot;;
  return ContentService.createTextOutput(result);
}


function doGet(post_data)
{
  var data = &quot;&quot;;
  var client_auth = post_data.parameter.script_auth;
  var client_gas_ver = post_data.parameter.gas_ver;
  if(client_auth == undefined)
    client_auth = &quot;&quot;;
  if(client_gas_ver == undefined)
    client_gas_ver = -1;
  if(script_password == client_auth)
  {
    if(gas_ver == client_gas_ver)
    {
      data = log_read(post_data.parameter.id);
      data += &quot;&lt;success&gt;&quot;;
    }
    else
      data = &quot;Google Apps Script version does not match. Server's GAS\nver is &quot; + gas_ver + &quot;, but 3DS's GAS ver is &quot; + client_gas_ver + &quot;. Please use the same version.&quot;;
  }
  else
    data = &quot;Auth failed. Please set correct password.&quot;;
  return ContentService.createTextOutput(data);
}</pre>




Line 554: Line 132:
''''''<span style="color: rgb(64, 64, 64)"><span style="font-size: 15px">And turn on </span></span><span style="color: rgb(0, 0, 255)"><span style="font-size: 15px">'''Use webhook'''</span></span>''''''<br />
''''''<span style="color: rgb(64, 64, 64)"><span style="font-size: 15px">And turn on </span></span><span style="color: rgb(0, 0, 255)"><span style="font-size: 15px">'''Use webhook'''</span></span>''''''<br />
https://dlhb.gamebrew.org/3dshomebrew/5dc4172fb531eacaf26757aa3fdb1b64.png
https://dlhb.gamebrew.org/3dshomebrew/5dc4172fb531eacaf26757aa3fdb1b64.png
== 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

Revision as of 04:45, 30 August 2021

Template:Infobox 3DS homebrew

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 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 is the first panel of the basic tab example. You can place all sorts of content here including a grid.

This is the second panel of the basic tab example. This is the second panel of the basic tab example.

This is the third panel of the basic tab example. This is the third panel of the basic tab example.





How to install and use for version 1.3.0~





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

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

'Back to Line Messaging API
Find Webhook URL and click edit.''''
Type your URL and click Update
003b8ec8407b4db43fef03a9a6337a6b.png
'And turn on Use webhook'
5dc4172fb531eacaf26757aa3fdb1b64.png


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: