commit cff1eaac49071a23f5b12cf4ea1faf15f9297429 Author: JianMiau Date: Tue Jan 10 12:01:05 2023 +0800 [add] first diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84a9f86 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules +.env +package-lock.json +*.pem +.foreverignore +.vscode \ No newline at end of file diff --git a/JoinClass.js b/JoinClass.js new file mode 100644 index 0000000..f168536 --- /dev/null +++ b/JoinClass.js @@ -0,0 +1,27 @@ +/** Join */ +class JoinClass { + constructor(bot, LineNotify) { + this.bot = bot; + this.LineNotify = LineNotify; + } + + Join(event) { + // switch (event.message.type) { + // case 'text': { + // this.Text(event); + // break; + // } + + // case 'sticker': { + // this.Sticker(event); + // break; + // } + + // default: + // break; + // } + console.log(`[Join] ${JSON.stringify(event)}`); + } +} + +module.exports = JoinClass \ No newline at end of file diff --git a/LineNotifyClass.js b/LineNotifyClass.js new file mode 100644 index 0000000..1c56cae --- /dev/null +++ b/LineNotifyClass.js @@ -0,0 +1,35 @@ +const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; + +/** LineNotify */ +class LineNotifyClass { + Send(message) { + const data = `message=\n${message}`; + + const xhr = new XMLHttpRequest(); + + xhr.addEventListener("readystatechange", function () { + if (this.readyState === 4) { + // console.log(this.responseText); + } + }); + + xhr.open("POST", "https://notify-api.line.me/api/notify"); + xhr.setRequestHeader("Authorization", "Bearer Dkv8Yh1Li3XsKFqZkmFMNP5o0JDSvan7qfcDmSv9GJr"); + xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + + xhr.send(data); + } + + SendBadmintonNotify() { + const xhr = new XMLHttpRequest(); + xhr.addEventListener("readystatechange", function () { + if (this.readyState === 4) { + // console.log(this.responseText); + } + }); + xhr.open("POST", "http://jianmiau.tk:1880/BadmintonNotify"); + xhr.send(); + } +} + +module.exports = LineNotifyClass \ No newline at end of file diff --git a/MemberJoinedClass.js b/MemberJoinedClass.js new file mode 100644 index 0000000..18f214d --- /dev/null +++ b/MemberJoinedClass.js @@ -0,0 +1,38 @@ +/** MemberJoined */ +class MemberJoinedClass { + constructor(bot, LineNotify) { + this.bot = bot; + this.LineNotify = LineNotify; + } + + MemberJoined(event) { + switch (event.source.groupId) { + case process.env.toBadminton: { + this.Badminton_MemberJoin(event) + break; + } + + default: + break; + } + } + + async Badminton_MemberJoin(event) { + const members = event.joined.members; + for (let i = 0; i < members.length; i++) { + const userId = members[i].userId; + this.SendBadminton_Welcome(event, event.source.groupId, userId) + } + } + + async SendBadminton_Welcome(event, groupId, userId) { + const userdata = await this.bot.getGroupMemberProfile(groupId, userId); + if (userdata && userdata.displayName) { + const message = `歡迎尊貴的 ${userdata.displayName} 降臨羽球團`; + event.reply(message); + this.LineNotify.SendBadmintonNotify(); + } + } +} + +module.exports = MemberJoinedClass \ No newline at end of file diff --git a/MessageClass.js b/MessageClass.js new file mode 100644 index 0000000..007503a --- /dev/null +++ b/MessageClass.js @@ -0,0 +1,152 @@ +/** Message */ +class MessageClass { + constructor(bot, ZhuHanbot, LineNotify) { + this.bot = bot; + this.ZhuHanbot = ZhuHanbot; + this.LineNotify = LineNotify; + } + + Message(event) { + switch (event.message.type) { + case 'text': { + this.Text(event); + break; + } + + case 'sticker': { + this.Sticker(event); + break; + } + + default: + break; + } + } + + Text(event) { + switch (event.source.type) { + case "user": { + this.User(event); + break; + } + + case "group": { + this.Group(event); + break; + } + + default: + break; + } + } + + async Sticker(event) { + switch (event.source.type) { + case "user": { + let userId = event.source.userId; + let displayName = ""; + let profile = await this.bot.getUserProfile(userId); + if (profile) { + displayName = profile.displayName; + } + let replyMsg = `https://liff.line.me/1657715144-m4W6lyjL?type=sticker&stk=noanim&sid=${event.message.stickerId}&pkg=${event.message.packageId}`; + let res_reply = event.reply(replyMsg).then(function (data) { + // 當訊息成功回傳後的處理 + }).catch(function (error) { + // 當訊息回傳失敗後的處理 + }); + break; + } + + case "group": { + break; + } + + default: + break; + } + } + + async User(event) { + let userId = event.source.userId; + let replyMsg = event.message.text; + let displayName = ""; + let profile = await this.bot.getUserProfile(userId); + if (profile) { + displayName = profile.displayName; + } + // JianMiau特別功能 + if (userId === process.env.toJianMiau || userId === process.env.toZhuHan) { + /** 訊息 */ + let Msg = event.message.text.split(" "); + + /** 指令 */ + let Instruction = Msg[0]; + switch (Instruction) { + case "msg": + case "Msg": + case "MSG": { + if (userId == process.env.toJianMiau) { + replyMsg = ""; + if (Msg[1] === "豬涵") { + if (Msg[2] === "豬涵") { + Msg[2] = process.env.toZhuHantoZhuHan; + } else if (Msg[2] === "建喵") { + Msg[2] = process.env.toZhuHantoJianMiau; + } + for (let i = 3; i < Msg.length; i++) { + replyMsg += Msg[i] + (i === Msg.length - 1 ? "" : " "); + } + let res_Msg = this.ZhuHanbot.push(Msg[2], replyMsg); + } else { + for (let i = 3; i < Msg.length; i++) { + replyMsg += Msg[i] + (i === Msg.length - 1 ? "" : " "); + } + let res_Msg = this.bot.push(Msg[2], replyMsg); + } + + let ToJM_message = "已發送訊息:"; + ToJM_message += `\nMyId: ${Msg[1]}`; + ToJM_message += `\nuserId: ${Msg[2]}`; + ToJM_message += `\nmessage: ${replyMsg}`; + let res_reply = event.reply(ToJM_message).then(function (data) { + // 當訊息成功回傳後的處理 + }).catch(function (error) { + // 當訊息回傳失敗後的處理 + }); + } + break; + } + + default: { + // 使用event.reply(要回傳的訊息)方法可將訊息回傳給使用者 + event.reply(replyMsg).then(function (data) { + // 當訊息成功回傳後的處理 + }).catch(function (error) { + // 當訊息回傳失敗後的處理 + }); + break; + } + } + } + } + + Group(event) { + switch (event.source.groupId) { + case process.env.toYoutube: { + let messagereplace = event.message.text; + messagereplace.replace("【IFTTT】 \n", ""); + let replyMsg = messagereplace; + // let res_toOusen = this.bot.push(process.env.toOusen, replyMsg); + let res_toUniversity = this.bot.push(process.env.toUniversity, replyMsg); + let res_toApex = this.bot.push(process.env.toApex, replyMsg); + break; + } + + default: + break; + } + } +} + +module.exports = MessageClass \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..efa7b4a --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# line-bot-js \ No newline at end of file diff --git a/ToolsClass.js b/ToolsClass.js new file mode 100644 index 0000000..248d1c3 --- /dev/null +++ b/ToolsClass.js @@ -0,0 +1,10 @@ +const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; + +/** Tools */ +class ToolsClass { + static Sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } +} + +module.exports = ToolsClass \ No newline at end of file diff --git a/app.js b/app.js new file mode 100644 index 0000000..46734f0 --- /dev/null +++ b/app.js @@ -0,0 +1,87 @@ +// 背景執行 forever start -a -l line-bot-js.log app.js +// 重新背景執行 forever restart -a -l line-bot-js.log app.js +// 監聽檔案變化 nodemon "npm start" +// Debug nodemon --inspect=192.168.1.15:9229 app.js + +require('dotenv').config() +const dateFormat = require('dateformat'); +// 引用linebot SDK +var linebot = require('linebot'); +const fs = require('fs'); +const express = require('express'); +const app = express(); + +//讀取憑證及金鑰 +const prikey = fs.readFileSync('../certificate/RSA-privkey.pem', 'utf8'); +const cert = fs.readFileSync('../certificate/RSA-cert.pem', 'utf8'); +const cafile = fs.readFileSync('../certificate/RSA-chain.pem', 'utf-8'); + +//建立憑證及金鑰 +const credentials = { + key: prikey, + cert: cert, + ca: cafile +}; + +// 用於辨識Line Channel的資訊 +var bot = linebot({ + channelId: process.env.toJianMiau, + channelSecret: process.env.channelSecret, + channelAccessToken: process.env.channelAccessToken +}); +var ZhuHanbot = linebot({ + channelId: process.env.toZhuHantoJianMiau, + channelSecret: process.env.ZhuHanchannelSecret, + channelAccessToken: process.env.ZhuHanchannelAccessToken +}); + +const LineNotifyClass = require('./LineNotifyClass') +const MessageClass = require('./MessageClass') +const JoinClass = require('./JoinClass') +const MemberJoinedClass = require('./MemberJoinedClass') +const LineNotify = new LineNotifyClass(); +const Message = new MessageClass(bot, ZhuHanbot, LineNotify); +const Join = new JoinClass(bot, LineNotify); +const MemberJoined = new MemberJoinedClass(bot, LineNotify); + +// 當有人傳送訊息給Bot時 +bot.on('event', function (event) { + try { + switch (event.type) { + case 'message': { + Message.Message(event); + break; + } + + case 'join': { + Join.Join(event); + break; + } + + case 'leave': + case 'follow': + case 'unfollow': + case 'memberJoined': { + MemberJoined.MemberJoined(event); + break; + } + + case 'memberLeave': + case 'postback': + case 'accountLink': + case 'fallback': + default: + break; + } + } catch (error) { + console.error(error); + } +}); + +// Bot所監聽的webhook路徑與port +const port = process.env.PORT || 3000; +bot.listen('/linewebhook', port, credentials, function () { + let datetime = dateFormat(new Date(), "yyyy-mm-dd HH:MM:ss"); + console.log(`${datetime} listening on ${port}`); + console.log(`${datetime} [BOT已準備就緒]`); +}); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..a81ecb5 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "line-bot-js", + "version": "1.0.0", + "description": "", + "main": "app.js", + "dependencies": { + "dateformat": "^4.5.1", + "dotenv": "^8.2.0", + "express": "^4.17.1", + "linebot": "^1.6.1", + "xmlhttprequest": "^1.8.0" + }, + "devDependencies": { + "nodemon": "^2.0.7" + }, + "scripts": { + "start": "forever start -a -l line-bot-js.log app.js", + "dev": "nodemon --inspect=192.168.1.15:9229 app.js" + }, + "keywords": [], + "author": "", + "license": "ISC" +}