2025年3月3日 星期一

[筆記][LINEBOT]訊息事件類別event type

參考:

  • https://developers.line.biz/en/docs/messaging-api/
  • ReceivedMessage.events[0].type
  • event.message.type


主要事件類型:
  • message - 使用者傳送訊息(文字、圖片、影片等)。
  • follow - 使用者加為好友或解除封鎖後再次加回。
  • unfollow - 使用者封鎖機器人。
  • join - 機器人被加入群組或聊天室。
  • leave - 機器人被移出群組或聊天室。
  • memberJoined - 有新成員加入群組或聊天室。
  • memberLeft - 有成員離開群組或聊天室。
  • postback - 使用者點擊 Postback Action 按鈕(會附帶 postback.data)。
  • beacon - 使用者進入 Beacon(LINE Beacon 訊號)。
  • accountLink - 使用者點擊 LINE Login 並綁定帳號。
  • things - 來自 LINE Things (IoT 相關) 的事件。

message 事件的子類型:
當 type 為 message 時,還會有 message.type 來指定訊息種類,例如:
  • text - 文字訊息
  • image - 圖片訊息
  • video - 影片訊息
  • audio - 音訊訊息
  • file - 檔案訊息
  • location - 位置訊息
  • sticker - 貼圖訊息

2025年1月14日 星期二

[筆記]瀏覽器可以正常取得JSON資料,但使用C#_HttpClient取資料,執行緩慢。

問題:瀏覽器可以正常取得JSON資料,但使用C# HttpClient取資料,執行緩慢。

ChatGPT:其中一種原因。可能有使用Proxy。
解法:將Proxy關閉。
HttpClientHandler handler = new HttpClientHandler
{
 Proxy = null,
 UseProxy = false
};
HttpClient client = new HttpClient(handler);


2024年11月10日 星期日

[筆記][GS]透過GoogleAppsScript(網頁應用程式)寫入檔案

需求: 
  • 類似表單訊息收集或是Log蒐集。 
  • 系統會在指定目錄下依照日期建立檔案(每天一個檔)
  • 也可以指定要產生哪種類型的檔案。(csv excel等)

 AI給的範例:
// 建立或獲取指定資料夾
function getOrCreateFolder(parentFolder, folderName) {
const folders = parentFolder.getFoldersByName(folderName);
if (folders.hasNext()) {
return folders.next();
} else {
return parentFolder.createFolder(folderName);
}
}
// 取得或創建當天的檔案
function getOrCreateDailyFile(format) {
const today = new Date();
const year = today.getFullYear().toString();
const month = Utilities.formatString("%02d", today.getMonth() + 1);
// 獲取或創建 GoogleAppsScript 目錄
const rootFolders = DriveApp.getFoldersByName("GoogleAppsScript");
let rootFolder;
if (rootFolders.hasNext()) {
rootFolder = rootFolders.next();
} else {
rootFolder = DriveApp.createFolder("GoogleAppsScript");
}
// 建立年份資料夾
const yearFolder = getOrCreateFolder(rootFolder, year);
// 建立月份資料夾
const monthFolder = getOrCreateFolder(yearFolder, `${year}-${month}`);
// 設定檔案名稱 (年-月-日)
const fileName = Utilities.formatDate(today, "GMT+8", "yyyy-MM-dd") + `.${format}`;
// 在月份資料夾中尋找今天的檔案
let file;
const files = monthFolder.getFilesByName(fileName);
if (files.hasNext()) {
file = files.next();
} else {
// 創建新的檔案
if (format === 'xlsx') {
const spreadsheet = SpreadsheetApp.create(fileName);
DriveApp.getFileById(spreadsheet.getId()).moveTo(monthFolder);
const sheet = spreadsheet.getSheets()[0];
sheet.getRange("A1:D1").setValues([["時間戳記", "訊息內容", "發送者", "其他資料"]]);
file = DriveApp.getFileById(spreadsheet.getId());
} else {
file = monthFolder.createFile(fileName, "時間戳記,訊息內容,發送者,其他資料\n", MimeType.PLAIN_TEXT);
}
}
return file;
}
// 寫入數據的 doGet 函數
function doGet(e) {
const action = e.parameter.action || 'write';
const format = e.parameter.format || 'xlsx'; // 預設為 xlsx 格式
if (action === 'read') {
return getSheetData(e);
}
try {
const params = e.parameter;
const file = getOrCreateDailyFile(format);
// 準備要寫入的數據
const timestamp = new Date().toLocaleString("zh-TW", {timeZone: "Asia/Taipei"});
const rowData = `${timestamp},${params.message || ""},${params.sender || ""},${params.extraData || ""}\n`;
if (format === 'xlsx') {
const spreadsheet = SpreadsheetApp.openById(file.getId());
const sheet = spreadsheet.getSheets()[0];
sheet.appendRow([timestamp, params.message || "", params.sender || "", params.extraData || ""]);
} else {
const content = file.getBlob().getDataAsString() + rowData;
file.setContent(content);
}
return ContentService.createTextOutput(JSON.stringify({
status: "success",
message: "數據已成功儲存",
data: params
})).setMimeType(ContentService.MimeType.JSON);
} catch (error) {
return ContentService.createTextOutput(JSON.stringify({
status: "error",
message: error.toString()
})).setMimeType(ContentService.MimeType.JSON);
}
}
// 讀取數據的函數
function getSheetData(e) {
try {
const params = e.parameter;
const targetDate = params.date || Utilities.formatDate(new Date(), "GMT+8", "yyyy-MM-dd");
const format = params.format || 'xlsx';
// 解析目標日期
const dateParts = targetDate.split('-');
const year = dateParts[0];
const month = dateParts[1];
// 獲取 GoogleAppsScript 目錄
const rootFolder = DriveApp.getFoldersByName("GoogleAppsScript").next();
const yearFolder = rootFolder.getFoldersByName(year).next();
const monthFolder = yearFolder.getFoldersByName(`${year}-${month}`).next();
const files = monthFolder.getFilesByName(`${targetDate}.${format}`);
if (!files.hasNext()) {
return ContentService.createTextOutput(JSON.stringify({
status: "error",
message: "找不到指定日期的檔案"
})).setMimeType(ContentService.MimeType.JSON);
}
const file = files.next();
let data;
if (format === 'xlsx') {
const spreadsheet = SpreadsheetApp.openById(file.getId());
const sheet = spreadsheet.getSheets()[0];
data = sheet.getDataRange().getValues();
} else {
const content = file.getBlob().getDataAsString();
data = content.split('\n').map(line => line.split(','));
}
// 將數據轉換為 JSON 格式
const headers = data[0];
const jsonData = data.slice(1).filter(row => row.length > 1).map(row => {
let obj = {};
headers.forEach((header, index) => {
obj[header] = row[index];
});
return obj;
});
return ContentService.createTextOutput(JSON.stringify({
status: "success",
date: targetDate,
data: jsonData
})).setMimeType(ContentService.MimeType.JSON);
} catch (error) {
return ContentService.createTextOutput(JSON.stringify({
status: "error",
message: error.toString()
})).setMimeType(ContentService.MimeType.JSON);
}
}
view raw MsgCreate.gs hosted with ❤ by GitHub

2024年9月21日 星期六

markmap 範例


title: markmap markmap:

colorFreezeLevel: 2

Related Projects

Features

Note that if blocks and lists appear at the same level, the lists will be ignored.

Lists

  • strong ~~del~~ italic ==highlight==
  • inline code
  • [x] checkbox
  • Katex: $x = {-b \pm \sqrt{b^2-4ac} \over 2a}$
  • More Katex Examples
  • Now we can wrap very very very very long text based on maxWidth option

Blocks

console.log('hello, JavaScript')

| Products | Price | |-|-| | Apple | 4 | | Banana | 2 |

2024年9月19日 星期四

[markdown]測試

hello world

第一行寫 markdown

  1. markdown
  2. ## hello world ##

[筆記][Markdown]在Blogger使用Markdown

 參考:

目前本blogger簡易作法
引用:
<script
 src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.6.4/showdown.min.js">
</script>  

<script>  
 var converter = new showdown.Converter();  
 var posts = document.querySelectorAll(".post-body,.snippet-item");
 Array.prototype.forEach.call(posts, function(el, i){  
  if(el.innerHTML.indexOf("markdown") <= 1){ 
   el.innerHTML = converter.makeHtml(el.innerHTML.replace("markdown",""));  
  }});  
 var pres = document.querySelectorAll("pre"); 
 Array.prototype.forEach.call(pres,  function(el, i){ 
  el.classList.add("prettyprint");  
 });  
</script>  

<script  
 src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?skin=sunburst">
</script>

之後在blogger側欄加入一個javascrpit的語法區塊。(放其他區塊也可以,放側欄 是因為這個版型每頁都有側欄。

 

2024年9月13日 星期五

[筆記]Chrome快取,網頁登入後顯示舊資料

 問題:asp.net MVC 網站登入登出後,畫面維持在舊畫面。
             原本要顯示使用者資訊的區塊還維持在未登入。

  • 到開發人員工具>網路,看頁面上面的要求標頭顯示以下畫面。
  • 停用快取才可以顯示資訊。(才正常)

暫時解法:cache-control改no-store

[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult Index(){}




其它問題類:參考