From 016e5153f8859ea94678adb7ab404f37a23bdb77 Mon Sep 17 00:00:00 2001 From: gnehs Date: Fri, 21 Jul 2023 08:45:51 +0800 Subject: [PATCH] format codes --- components/dayoff.js | 111 ++++---- components/db.js | 6 +- components/gonokami.js | 280 +++++++++++--------- components/help.js | 25 +- components/inline/alphabet.js | 123 ++++++--- components/inline/index.js | 61 +++-- components/inline/puffy.js | 184 +++++++------ components/inline/sticker.js | 348 ++++++++++++++++--------- components/inline/url.js | 36 +-- components/rate.js | 39 ++- components/simple-reply.js | 106 +++++--- components/start.js | 73 +++--- components/subscribe/apple-ncc.js | 58 +++-- components/subscribe/bahamut-anime.js | 76 +++--- components/subscribe/github-release.js | 115 ++++---- components/subscribe/gonokamitw.js | 71 ++--- components/subscribe/index.js | 215 ++++++++------- components/subscribe/manage.js | 92 +++---- components/telegram.js | 6 +- 19 files changed, 1194 insertions(+), 831 deletions(-) diff --git a/components/dayoff.js b/components/dayoff.js index c39dbb8..e9c13a3 100644 --- a/components/dayoff.js +++ b/components/dayoff.js @@ -1,59 +1,74 @@ -const Composer = require('telegraf/composer') -const bot = new Composer() -const cheerio = require('cheerio'); -const fetch = require('node-fetch'); -let dayoff = null +const Composer = require("telegraf/composer"); +const bot = new Composer(); +const cheerio = require("cheerio"); +const fetch = require("node-fetch"); +let dayoff = null; //十分鐘定時清除 setInterval(cleanDayoff, 1000 * 60 * 10); //10min function cleanDayoff() { - dayoff = null; -}; + dayoff = null; +} async function getDayoff() { - return dayoff || await dayoffReq() + return dayoff || (await dayoffReq()); } async function dayoffReq() { - let body = await fetch('https://www.dgpa.gov.tw/typh/daily/nds.html').then(res => res.text()) - var $ = cheerio.load(body), - city, status, time, city_status, city_name, data = { - "typhoon": [], - "update_time": "" - }; - city = $('.Table_Body > tr > td:nth-child(1):not([colspan="3"])'); - status = $(".Table_Body > tr > td:nth-child(2)"); - for (var i = 0; i < city.length; i++) { - city_name = $(city[i]).text() - city_status = $(status[i]).text().replace(/。/g, "。\n").replace(/ /g, "").trim() - if (city_status.length > 40) - city_status = city_status.substring(0, 40) + '...' - if (city_status.match(/上午|下午|停止上班|停止上課/)) - city_name = `❗️${city_name}`; - else - city_name = `🔹${city_name}`; + let body = await fetch("https://www.dgpa.gov.tw/typh/daily/nds.html").then( + (res) => res.text() + ); + var $ = cheerio.load(body), + city, + status, + time, + city_status, + city_name, + data = { + typhoon: [], + update_time: "", + }; + city = $('.Table_Body > tr > td:nth-child(1):not([colspan="3"])'); + status = $(".Table_Body > tr > td:nth-child(2)"); + for (var i = 0; i < city.length; i++) { + city_name = $(city[i]).text(); + city_status = $(status[i]) + .text() + .replace(/。/g, "。\n") + .replace(/ /g, "") + .trim(); + if (city_status.length > 40) + city_status = city_status.substring(0, 40) + "..."; + if (city_status.match(/上午|下午|停止上班|停止上課/)) + city_name = `❗️${city_name}`; + else city_name = `🔹${city_name}`; - data.typhoon.push({ - "city_name": city_name, - "city_status": city_status - }) - } - //更新時間 - time = $("div.f_right > h4:nth-child(1)").text().match(/[0-9]+/g); - data.update_time = `${time[3]}:${time[4]}:${time[5]}` - dayoff = data - return dayoff + data.typhoon.push({ + city_name: city_name, + city_status: city_status, + }); + } + //更新時間 + time = $("div.f_right > h4:nth-child(1)") + .text() + .match(/[0-9]+/g); + data.update_time = `${time[3]}:${time[4]}:${time[5]}`; + dayoff = data; + return dayoff; } -bot.command('dayoff', async ctx => { - let data = await getDayoff(), - resp = '' - for ({ city_name, city_status } of data.typhoon) { - resp += `${city_name} ${city_status}\n`; - } - //更新時間 - time = `更新時間 ${data.update_time} `; - //送訊息囉 - resp += `--- +bot.command("dayoff", async (ctx) => { + let data = await getDayoff(), + resp = ""; + for ({ city_name, city_status } of data.typhoon) { + resp += `${city_name} ${city_status}\n`; + } + //更新時間 + time = `更新時間 ${data.update_time} `; + //送訊息囉 + resp += `--- \`詳細及最新情報以\` [行政院人事行政總處](goo.gl/GjmZnR) \`公告為主\` ${time}`; - ctx.reply(resp, { parse_mode: "markdown", reply_to_message_id: ctx.message.message_id }) -}) -module.exports = bot \ No newline at end of file + ctx.reply(resp, { + parse_mode: "markdown", + reply_to_message_id: ctx.message.message_id, + }); +}); +module.exports = bot; diff --git a/components/db.js b/components/db.js index 30548bd..092c4bc 100644 --- a/components/db.js +++ b/components/db.js @@ -1,3 +1,3 @@ -const JSONdb = require('simple-json-db'); -const db = new JSONdb('./database.json'); -module.exports = db \ No newline at end of file +const JSONdb = require("simple-json-db"); +const db = new JSONdb("./database.json"); +module.exports = db; diff --git a/components/gonokami.js b/components/gonokami.js index a234fc5..ff9a487 100644 --- a/components/gonokami.js +++ b/components/gonokami.js @@ -1,165 +1,201 @@ -const Composer = require('telegraf/composer') -const telegram = require('./telegram') -const crypto = require('crypto') -const bot = new Composer() -const fetch = require('node-fetch'); -const os = require('os') -const salt = os.hostname() || 'salt' -const JSONdb = require('simple-json-db'); -const voteData = new JSONdb('./votes.json', { jsonSpaces: false }) +const Composer = require("telegraf/composer"); +const telegram = require("./telegram"); +const crypto = require("crypto"); +const bot = new Composer(); +const fetch = require("node-fetch"); +const os = require("os"); +const salt = os.hostname() || "salt"; +const JSONdb = require("simple-json-db"); +const voteData = new JSONdb("./votes.json", { jsonSpaces: false }); function hash(str) { - const hash = crypto.createHash('sha256') - hash.update(str.toString() + salt, 'utf8') - return hash.digest('hex').slice(0, 8) + const hash = crypto.createHash("sha256"); + hash.update(str.toString() + salt, "utf8"); + return hash.digest("hex").slice(0, 8); } -bot.command('number', async ctx => { - ctx.telegram.sendChatAction(ctx.chat.id, 'typing') - let res = await fetch("https://dxc.tagfans.com/mighty?_field%5B%5D=*&%24gid=10265&%24description=anouncingNumbers") - .then(x => x.json()); - let currentNumber = JSON.parse(res[0].detail_json).selections["目前號碼"] - let responseText = `目前五之神號碼為 *${currentNumber}*` - ctx.reply(responseText, { parse_mode: "markdown", reply_to_message_id: ctx.message.message_id }) -}) +bot.command("number", async (ctx) => { + ctx.telegram.sendChatAction(ctx.chat.id, "typing"); + let res = await fetch( + "https://dxc.tagfans.com/mighty?_field%5B%5D=*&%24gid=10265&%24description=anouncingNumbers" + ).then((x) => x.json()); + let currentNumber = JSON.parse(res[0].detail_json).selections["目前號碼"]; + let responseText = `目前五之神號碼為 *${currentNumber}*`; + ctx.reply(responseText, { + parse_mode: "markdown", + reply_to_message_id: ctx.message.message_id, + }); +}); // vote -bot.command('vote', async ctx => { - let args = ctx.state.command.splitArgs - let voteTitle = args[0] == '' ? '限定拉麵' : args[0] - let byeOptions = ['ㄅㄅ', 'QQ', '🥞'] - let byeOption = args[1] ? args[1] : byeOptions[Math.floor(Math.random() * byeOptions.length)] - let voteOptions = ['+1', '+2', '+4', byeOption] - let data = await ctx.replyWithPoll( - voteTitle, - voteOptions, - { - allows_multiple_answers: true, - is_anonymous: false, - reply_to_message_id: ctx.message.message_id, - reply_markup: { - inline_keyboard: [ - [{ text: '✖️停止投票', callback_data: `stopvote_${hash(ctx.message.from.id)}` }] - ] - } - } - ) +bot.command("vote", async (ctx) => { + let args = ctx.state.command.splitArgs; + let voteTitle = args[0] == "" ? "限定拉麵" : args[0]; + let byeOptions = ["ㄅㄅ", "QQ", "🥞"]; + let byeOption = args[1] + ? args[1] + : byeOptions[Math.floor(Math.random() * byeOptions.length)]; + let voteOptions = ["+1", "+2", "+4", byeOption]; + let data = await ctx.replyWithPoll(voteTitle, voteOptions, { + allows_multiple_answers: true, + is_anonymous: false, + reply_to_message_id: ctx.message.message_id, + reply_markup: { + inline_keyboard: [ + [ + { + text: "✖️停止投票", + callback_data: `stopvote_${hash(ctx.message.from.id)}`, + }, + ], + ], + }, + }); updatePollData(data.poll.id, { ...data.poll, chat_id: ctx.chat.id, chat_name: ctx.chat.title || ctx.chat.first_name, chat_type: ctx.chat.type, - votes: {} - }) -}) -bot.action(/stopvote_(.+)/, async ctx => { - let hashStr = ctx.match[1] + votes: {}, + }); +}); +bot.action(/stopvote_(.+)/, async (ctx) => { + let hashStr = ctx.match[1]; if (hashStr == hash(ctx.update.callback_query.from.id)) { - let poll = await telegram.stopPoll(ctx.update.callback_query.message.chat.id, ctx.update.callback_query.message.message_id) - let count = poll.options.slice(0, -1).reduce((acc, cur) => acc + (cur.voter_count * cur.text.replace('+', '')), 0) - ctx.replyWithMarkdown(`*${poll.question}投票結果*\n共 ${count} 人`, { reply_to_message_id: ctx.update.callback_query.message.message_id }) + let poll = await telegram.stopPoll( + ctx.update.callback_query.message.chat.id, + ctx.update.callback_query.message.message_id + ); + let count = poll.options + .slice(0, -1) + .reduce( + (acc, cur) => acc + cur.voter_count * cur.text.replace("+", ""), + 0 + ); + ctx.replyWithMarkdown(`*${poll.question}投票結果*\n共 ${count} 人`, { + reply_to_message_id: ctx.update.callback_query.message.message_id, + }); } else { - ctx.answerCbQuery('✖️ 只有發起人才能停止投票') + ctx.answerCbQuery("✖️ 只有發起人才能停止投票"); } -}) +}); // ramen vote -bot.command('voteramen', async ctx => { - let args = ctx.state.command.splitArgs - let voteTitle = args[0] == '' ? '限定拉麵' : args[0] - let byeOptions = ['ㄅㄅ', 'QQ', '🥞'] - let byeOption = args[1] ? args[1] : byeOptions[Math.floor(Math.random() * byeOptions.length)] +bot.command("voteramen", async (ctx) => { + let args = ctx.state.command.splitArgs; + let voteTitle = args[0] == "" ? "限定拉麵" : args[0]; + let byeOptions = ["ㄅㄅ", "QQ", "🥞"]; + let byeOption = args[1] + ? args[1] + : byeOptions[Math.floor(Math.random() * byeOptions.length)]; let voteOptions = [ - '+1 | 🍜 單點', - '+2 | 🍜 單點', - '+1 | 🥚 加蛋', - '+2 | 🥚 加蛋', - '+1 | ✨ 超值', - '+2 | ✨ 超值', - byeOption - ] - let data = await ctx.replyWithPoll( - voteTitle, - voteOptions, - { - allows_multiple_answers: true, - is_anonymous: false, - reply_to_message_id: ctx.message.message_id, - reply_markup: { - inline_keyboard: [ - [{ text: '✖️停止投票', callback_data: `stopramenvote_${hash(ctx.message.from.id)}` }] - ] - } - } - ) + "+1 | 🍜 單點", + "+2 | 🍜 單點", + "+1 | 🥚 加蛋", + "+2 | 🥚 加蛋", + "+1 | ✨ 超值", + "+2 | ✨ 超值", + byeOption, + ]; + let data = await ctx.replyWithPoll(voteTitle, voteOptions, { + allows_multiple_answers: true, + is_anonymous: false, + reply_to_message_id: ctx.message.message_id, + reply_markup: { + inline_keyboard: [ + [ + { + text: "✖️停止投票", + callback_data: `stopramenvote_${hash(ctx.message.from.id)}`, + }, + ], + ], + }, + }); updatePollData(data.poll.id, { ...data.poll, chat_id: ctx.chat.id, chat_name: ctx.chat.title || ctx.chat.first_name, chat_type: ctx.chat.type, - votes: {} - }) -}) + votes: {}, + }); +}); // watch user vote -bot.on('poll_answer', async ctx => { - let pollAnswer = ctx.update.poll_answer +bot.on("poll_answer", async (ctx) => { + let pollAnswer = ctx.update.poll_answer; // update user - let users = voteData.get('users') || {} + let users = voteData.get("users") || {}; users[pollAnswer.user.id] = { first_name: pollAnswer.user?.first_name, username: pollAnswer.user?.username, - } - voteData.set('users', users) + }; + voteData.set("users", users); // update poll - let polls = voteData.get('polls') || {} - let poll = polls[pollAnswer.poll_id] - let options = pollAnswer.option_ids - poll.votes[pollAnswer.user.id] = options - updatePollData(pollAnswer.poll_id, poll) - console.log(`[vote] ${pollAnswer.user?.first_name} voted ${options.length ? options : 'retract'} in poll ${poll.question}(${pollAnswer.poll_id}) at ${poll.chat_name}(${poll.chat_id})`) -}) + let polls = voteData.get("polls") || {}; + let poll = polls[pollAnswer.poll_id]; + let options = pollAnswer.option_ids; + poll.votes[pollAnswer.user.id] = options; + updatePollData(pollAnswer.poll_id, poll); + console.log( + `[vote] ${pollAnswer.user?.first_name} voted ${ + options.length ? options : "retract" + } in poll ${poll.question}(${pollAnswer.poll_id}) at ${poll.chat_name}(${ + poll.chat_id + })` + ); +}); -bot.action(/stopramenvote_(.+)/, async ctx => { - let hashStr = ctx.match[1] +bot.action(/stopramenvote_(.+)/, async (ctx) => { + let hashStr = ctx.match[1]; if (hashStr == hash(ctx.update.callback_query.from.id)) { - let poll = await telegram.stopPoll(ctx.update.callback_query.message.chat.id, ctx.update.callback_query.message.message_id) - let options = [...new Set(poll.options.slice(0, -1).map(x => x.text.split('|')[1].trim()))] - let result = {} - options.forEach(x => result[x] = 0) - poll.options.slice(0, -1).forEach(x => { - let option = x.text.split('|')[1].trim() - result[option] += x.voter_count * x.text.replace('+', '').split('|')[0].trim() - }) - let count = Object.values(result).reduce((acc, cur) => acc + cur, 0) - let responseText = `*${poll.question}投票結果*\n` + let poll = await telegram.stopPoll( + ctx.update.callback_query.message.chat.id, + ctx.update.callback_query.message.message_id + ); + let options = [ + ...new Set( + poll.options.slice(0, -1).map((x) => x.text.split("|")[1].trim()) + ), + ]; + let result = {}; + options.forEach((x) => (result[x] = 0)); + poll.options.slice(0, -1).forEach((x) => { + let option = x.text.split("|")[1].trim(); + result[option] += + x.voter_count * x.text.replace("+", "").split("|")[0].trim(); + }); + let count = Object.values(result).reduce((acc, cur) => acc + cur, 0); + let responseText = `*${poll.question}投票結果*\n`; for (let key in result) { - responseText += `${key}:${result[key]} 人\n` + responseText += `${key}:${result[key]} 人\n`; } - responseText += `---\n` - responseText += `共 ${count} 人\n` - ctx.replyWithMarkdown(responseText, { reply_to_message_id: ctx.update.callback_query.message.message_id }) + responseText += `---\n`; + responseText += `共 ${count} 人\n`; + ctx.replyWithMarkdown(responseText, { + reply_to_message_id: ctx.update.callback_query.message.message_id, + }); - updatePollData(poll.id, poll) + updatePollData(poll.id, poll); } else { - ctx.answerCbQuery('✖️ 只有發起人才能停止投票') + ctx.answerCbQuery("✖️ 只有發起人才能停止投票"); } -}) +}); function updatePollData(id, data) { - let polls = voteData.get('polls') || {} - let poll = polls[id] || {} + let polls = voteData.get("polls") || {}; + let poll = polls[id] || {}; poll = { ...poll, ...data, - update_time: Date.now() - } - delete poll.id - delete poll.is_anonymous - delete poll.type - delete poll.allows_multiple_answers + update_time: Date.now(), + }; + delete poll.id; + delete poll.is_anonymous; + delete poll.type; + delete poll.allows_multiple_answers; - polls[id] = poll - voteData.set('polls', polls) + polls[id] = poll; + voteData.set("polls", polls); } -module.exports = bot \ No newline at end of file +module.exports = bot; diff --git a/components/help.js b/components/help.js index 41a317f..f558de2 100644 --- a/components/help.js +++ b/components/help.js @@ -1,10 +1,13 @@ -const Composer = require('telegraf/composer') -const bot = new Composer() -const telegram = require('./telegram') -const subscribeIdList = Object.entries(require('../list').subscribeIdList).map(([id, name]) => `${id} - ${name}\n`).join('') -bot.help(async ctx => { - let { first_name } = await telegram.getMe() - ctx.replyWithMarkdown(`*${first_name}的指令清單* +const Composer = require("telegraf/composer"); +const bot = new Composer(); +const telegram = require("./telegram"); +const subscribeIdList = Object.entries(require("../list").subscribeIdList) + .map(([id, name]) => `${id} - ${name}\n`) + .join(""); +bot.help(async (ctx) => { + let { first_name } = await telegram.getMe(); + ctx.replyWithMarkdown( + `*${first_name}的指令清單* /about - 關於 /date - 傳回伺服器的時間 /dayoff - 台灣行政院人事局的停班課 @@ -20,6 +23,8 @@ bot.help(async ctx => { ${subscribeIdList} *測試* /admin - 檢查是否具此聊天室的管理權限 -`, { reply_to_message_id: ctx.message.message_id }) -}) -module.exports = bot \ No newline at end of file +`, + { reply_to_message_id: ctx.message.message_id } + ); +}); +module.exports = bot; diff --git a/components/inline/alphabet.js b/components/inline/alphabet.js index 2d1b89e..7989b72 100644 --- a/components/inline/alphabet.js +++ b/components/inline/alphabet.js @@ -1,39 +1,100 @@ -const letterList = { "A": "ÁÀĂẮẰẴẲÂẤẦẪẨǍÅǺÄǞÃȦǠĄĀẢȀȂẠẶẬḀȺ", "a": "áàăắằẵẳâấầẫẩǎåǻäǟãȧǡąāảȁȃạặậḁⱥ", "B": "ḂḄḆɃƁ", "b": "ḃḅḇƀᵬƂᵬᶀ", "C": "ĆĈČĊÇḈȻƇ", "c": "ćĉčċçḉȼƈ", "D": "ĎḊḐḌḒḎĐƉƊ", "d": "ďḋḑḍḓḏđɖɗ", "E": "ÉÈĔÊẾỀỄỂĚËẼĖȨḜĘĒḖḔẺȄȆẸỆḘḚɆ", "e": "éèĕêếềễểěëẽėȩḝęēḗḕẻȅȇẹệḙḛɇ", "F": "ḞƑ", "f": "ḟƒᵮᶂ", "G": "ǴĞĜǦĠĢḠǤ", "g": "ǵğĝǧġģḡǥ", "H": "ĤȞḦḢḨḤḪHĦⱧ", "h": "ĥȟḧḣḩḥḫẖħⱨ", "I": "ÍÌĬÎǏÏḮĨİĮĪỈȈȊỊḬIƗ", "i": "íìĭîǐïḯĩiįīỉȉȋịḭıɨ", "J": "ĴɈ", "j": "ĵɉ", "K": "ḰǨĶḲḴⱩ", "k": "ḱǩķḳḵƘⱪ", "L": "ĹĽĻḶḸḼḺŁĿȽⱠⱢ", "l": "ĺľļḷḹḽḻłŀƚⱡɫ", "M": "ḾṀṂM", "m": "ḿṁṃ", "N": "ŃǸŇÑṄŅṆṊṈ", "n": "ńǹňñṅņṇṋṉ", "O": "ÓÒŎÔỐỒỖỔǑÖȪŐÕṌṎȬȮȰØǾǪǬŌṒṐỎȌȎƠỚỜỠỞỢỌỘƟ", "o": "óòŏôốồỗổǒöȫőõṍṏȭȯȱøǿǫǭōṓṑỏȍȏơớờỡởợọộɵ", "P": "ṔṖⱣƤ", "p": "ṕṗᵽƥ", "Q": "Ɋ", "q": "ɋ", "R": "ŔŘṘŖȐȒṚṜṞɌ", "r": "ŕřṙŗȑȓṛṝṟɍ", "S": "ŚṤŜŠṦṠŞṢṨȘ$", "s": "śṥŝšṧṡşṣṩș", "T": "ŤTṪŢṬȚṰṮŦȾ", "t": "ťẗṫţṭțṱṯŧⱦ", "U": "ÚÙŬÛǓŮÜǗǛǙǕŰŨṸŲŪṺỦȔȖƯỨỪỮỬỰỤṲṶṴɄ", "u": "úùŭûǔůüǘǜǚǖűũṹųūṻủȕȗưứừữửựụṳṷṵʉ", "V": "ṼṾ", "v": "ṽṿ", "W": "ẂẀŴẄẆ", "w": "ẃẁŵẘẅẇẉ", "X": "ẌẊ", "x": "ẍẋ", "Y": "ÝỲŶYŸỸẎȲỶỴ", "y": "ẙÿỹẏȳỷỵýỳŷ", "Z": "ŹẐŽŻẒẔƵ", "z": "źẑžżẓẕƶ" } -const chooseRandomElementFromArray = arr => arr[Math.floor(Math.random() * arr.length)] +const letterList = { + A: "ÁÀĂẮẰẴẲÂẤẦẪẨǍÅǺÄǞÃȦǠĄĀẢȀȂẠẶẬḀȺ", + a: "áàăắằẵẳâấầẫẩǎåǻäǟãȧǡąāảȁȃạặậḁⱥ", + B: "ḂḄḆɃƁ", + b: "ḃḅḇƀᵬƂᵬᶀ", + C: "ĆĈČĊÇḈȻƇ", + c: "ćĉčċçḉȼƈ", + D: "ĎḊḐḌḒḎĐƉƊ", + d: "ďḋḑḍḓḏđɖɗ", + E: "ÉÈĔÊẾỀỄỂĚËẼĖȨḜĘĒḖḔẺȄȆẸỆḘḚɆ", + e: "éèĕêếềễểěëẽėȩḝęēḗḕẻȅȇẹệḙḛɇ", + F: "ḞƑ", + f: "ḟƒᵮᶂ", + G: "ǴĞĜǦĠĢḠǤ", + g: "ǵğĝǧġģḡǥ", + H: "ĤȞḦḢḨḤḪHĦⱧ", + h: "ĥȟḧḣḩḥḫẖħⱨ", + I: "ÍÌĬÎǏÏḮĨİĮĪỈȈȊỊḬIƗ", + i: "íìĭîǐïḯĩiįīỉȉȋịḭıɨ", + J: "ĴɈ", + j: "ĵɉ", + K: "ḰǨĶḲḴⱩ", + k: "ḱǩķḳḵƘⱪ", + L: "ĹĽĻḶḸḼḺŁĿȽⱠⱢ", + l: "ĺľļḷḹḽḻłŀƚⱡɫ", + M: "ḾṀṂM", + m: "ḿṁṃ", + N: "ŃǸŇÑṄŅṆṊṈ", + n: "ńǹňñṅņṇṋṉ", + O: "ÓÒŎÔỐỒỖỔǑÖȪŐÕṌṎȬȮȰØǾǪǬŌṒṐỎȌȎƠỚỜỠỞỢỌỘƟ", + o: "óòŏôốồỗổǒöȫőõṍṏȭȯȱøǿǫǭōṓṑỏȍȏơớờỡởợọộɵ", + P: "ṔṖⱣƤ", + p: "ṕṗᵽƥ", + Q: "Ɋ", + q: "ɋ", + R: "ŔŘṘŖȐȒṚṜṞɌ", + r: "ŕřṙŗȑȓṛṝṟɍ", + S: "ŚṤŜŠṦṠŞṢṨȘ$", + s: "śṥŝšṧṡşṣṩș", + T: "ŤTṪŢṬȚṰṮŦȾ", + t: "ťẗṫţṭțṱṯŧⱦ", + U: "ÚÙŬÛǓŮÜǗǛǙǕŰŨṸŲŪṺỦȔȖƯỨỪỮỬỰỤṲṶṴɄ", + u: "úùŭûǔůüǘǜǚǖűũṹųūṻủȕȗưứừữửựụṳṷṵʉ", + V: "ṼṾ", + v: "ṽṿ", + W: "ẂẀŴẄẆ", + w: "ẃẁŵẘẅẇẉ", + X: "ẌẊ", + x: "ẍẋ", + Y: "ÝỲŶYŸỸẎȲỶỴ", + y: "ẙÿỹẏȳỷỵýỳŷ", + Z: "ŹẐŽŻẒẔƵ", + z: "źẑžżẓẕƶ", +}; +const chooseRandomElementFromArray = (arr) => + arr[Math.floor(Math.random() * arr.length)]; async function answer({ inlineQuery, answerInlineQuery }) { - let results = [] - // parse text - let text = inlineQuery.query.split(' ') - text.shift() // remove first element - text = text.join(' ') + let results = []; + // parse text + let text = inlineQuery.query.split(" "); + text.shift(); // remove first element + text = text.join(" "); - let pushResult = (title, result) => { - results.push({ - type: 'article', - id: `Aa_${title}`, - title: title, - description: result, - input_message_content: { - message_text: result - } - }) - } - pushResult("25% 轉換", transformLetter(text, 0.25)) - pushResult("100% 通通轉換", transformLetter(text, 1)) + let pushResult = (title, result) => { + results.push({ + type: "article", + id: `Aa_${title}`, + title: title, + description: result, + input_message_content: { + message_text: result, + }, + }); + }; + pushResult("25% 轉換", transformLetter(text, 0.25)); + pushResult("100% 通通轉換", transformLetter(text, 1)); - console.log(`[${inlineQuery.from.username ? '@' : ''} + ${(inlineQuery.from.username || inlineQuery.from.first_name)}][letter][${text}]處理完畢`) - return answerInlineQuery(results, { cache_time: 60 * 60 /* second */ }) + console.log( + `[${inlineQuery.from.username ? "@" : ""} + ${ + inlineQuery.from.username || inlineQuery.from.first_name + }][letter][${text}]處理完畢` + ); + return answerInlineQuery(results, { cache_time: 60 * 60 /* second */ }); } function transformLetter(text, randomRate = 1) { - let result = '' - for (let letter of text) { - if (Object.keys(letterList).includes(letter) && randomRate >= Math.random()) { - result += chooseRandomElementFromArray(letterList[letter]) - } else { - result += letter - } + let result = ""; + for (let letter of text) { + if ( + Object.keys(letterList).includes(letter) && + randomRate >= Math.random() + ) { + result += chooseRandomElementFromArray(letterList[letter]); + } else { + result += letter; } - return result + } + return result; } -module.exports = answer \ No newline at end of file +module.exports = answer; diff --git a/components/inline/index.js b/components/inline/index.js index 2eaf0bb..a6b51f7 100644 --- a/components/inline/index.js +++ b/components/inline/index.js @@ -1,32 +1,37 @@ -const Composer = require('telegraf/composer') -const telegram = require('../telegram') -const inlineProcessorList = require('../../list').inlineProcessorList -const bot = new Composer() -bot.on('inline_query', async ({ inlineQuery, answerInlineQuery }) => { - let text = inlineQuery.query.split(' ') - try { - - if (text.length > 1) { - for (let inlineProcessor of inlineProcessorList) { - if (inlineProcessor.keywords.includes(text[0])) { - return require(inlineProcessor.js)({ inlineQuery, answerInlineQuery }) - } - } - } - if (text[0]?.startsWith('http')) { - return require('./url')({ inlineQuery, answerInlineQuery }) +const Composer = require("telegraf/composer"); +const telegram = require("../telegram"); +const inlineProcessorList = require("../../list").inlineProcessorList; +const bot = new Composer(); +bot.on("inline_query", async ({ inlineQuery, answerInlineQuery }) => { + let text = inlineQuery.query.split(" "); + try { + if (text.length > 1) { + for (let inlineProcessor of inlineProcessorList) { + if (inlineProcessor.keywords.includes(text[0])) { + return require(inlineProcessor.js)({ + inlineQuery, + answerInlineQuery, + }); } - } catch (e) { - console.log(e) - return answerInlineQuery([], { switch_pm_text: `❌ 出錯了,請稍後再試`, switch_pm_parameter: 'inline_error' }) + } + } + if (text[0]?.startsWith("http")) { + return require("./url")({ inlineQuery, answerInlineQuery }); } - // send help message - let { first_name } = await telegram.getMe() + } catch (e) { + console.log(e); return answerInlineQuery([], { - cache_time: 60 * 60, /* second */ - switch_pm_text: `📘 查看「${first_name}」行內機器人使用說明`, - switch_pm_parameter: 'inline_help' - }) -}) + switch_pm_text: `❌ 出錯了,請稍後再試`, + switch_pm_parameter: "inline_error", + }); + } + // send help message + let { first_name } = await telegram.getMe(); + return answerInlineQuery([], { + cache_time: 60 * 60 /* second */, + switch_pm_text: `📘 查看「${first_name}」行內機器人使用說明`, + switch_pm_parameter: "inline_help", + }); +}); -module.exports = bot \ No newline at end of file +module.exports = bot; diff --git a/components/inline/puffy.js b/components/inline/puffy.js index a42d97d..3b66330 100644 --- a/components/inline/puffy.js +++ b/components/inline/puffy.js @@ -1,96 +1,110 @@ -const db = require('../db') -const telegram = require('../telegram') -const fs = require('fs'); -const chats = require('../../config').chats; -const getRandomChat = () => chats[Math.floor(Math.random() * chats.length)] -let puffyList = {} -let cacheFinished = false +const db = require("../db"); +const telegram = require("../telegram"); +const fs = require("fs"); +const chats = require("../../config").chats; +const getRandomChat = () => chats[Math.floor(Math.random() * chats.length)]; +let puffyList = {}; +let cacheFinished = false; async function imageFiletoId(file) { - let cacheData = db.get('puffyCache') || {} - if (cacheData[file]) return cacheData[file] // check cache && return - let msg = await telegram.sendPhoto(getRandomChat(), { - source: require('fs').readFileSync('./components/inline/puffy/' + file) - }) - let photoId = msg.photo.pop().file_id - cacheData[file] = photoId - db.set('puffyCache', cacheData); - return photoId + let cacheData = db.get("puffyCache") || {}; + if (cacheData[file]) return cacheData[file]; // check cache && return + let msg = await telegram.sendPhoto(getRandomChat(), { + source: require("fs").readFileSync("./components/inline/puffy/" + file), + }); + let photoId = msg.photo.pop().file_id; + cacheData[file] = photoId; + db.set("puffyCache", cacheData); + return photoId; } async function search(text, limit = 100) { - await new Promise(resolve => { - let length = Object.keys(puffyList).length - if (length == 0) { - setTimeout(resolve, 1000) - } else { - resolve() - } - }) - let letters = text.split('') - let result = Object.keys(puffyList).sort((a, b) => { - let aCount = 0 - let bCount = 0 - for (let letter of letters) { - if (a.includes(letter)) aCount++ - if (b.includes(letter)) bCount++ - } - return bCount - aCount - }) - return result.slice(0, limit).map(x => puffyList[x]) -} -async function answer({ inlineQuery, answerInlineQuery }) { - let text = inlineQuery.query.split(' ')[1] - let searchResult = await search(text, cacheFinished ? 12 : 4) - let results = [] - let tasks = [] - async function parseImage(name, file) { - results.push({ - type: 'photo', - id: name, - title: name, - description: file, - photo_file_id: await imageFiletoId(file) - }) + await new Promise((resolve) => { + let length = Object.keys(puffyList).length; + if (length == 0) { + setTimeout(resolve, 1000); + } else { + resolve(); } - for (let file of searchResult) { - let name = file.replace('.jpg', '') - tasks.push(parseImage(name, file)) + }); + let letters = text.split(""); + let result = Object.keys(puffyList).sort((a, b) => { + let aCount = 0; + let bCount = 0; + for (let letter of letters) { + if (a.includes(letter)) aCount++; + if (b.includes(letter)) bCount++; } - await Promise.all(tasks) - console.log(`[${inlineQuery.from.username ? '@' : ''}${(inlineQuery.from.username || inlineQuery.from.first_name)}][${text}] 處理完畢 (${searchResult.length})`) - return answerInlineQuery(results, Object.assign( - { cache_time: 60 * 60 /* second */ }, - (!results.length ? { switch_pm_text: `❌ 找不到你要的圖片,按這裡查看可供搜尋的圖片名稱`, switch_pm_parameter: 'inline_puffy_404' } : {})) + return bCount - aCount; + }); + return result.slice(0, limit).map((x) => puffyList[x]); +} +async function answer({ inlineQuery, answerInlineQuery }) { + let text = inlineQuery.query.split(" ")[1]; + let searchResult = await search(text, cacheFinished ? 12 : 4); + let results = []; + let tasks = []; + async function parseImage(name, file) { + results.push({ + type: "photo", + id: name, + title: name, + description: file, + photo_file_id: await imageFiletoId(file), + }); + } + for (let file of searchResult) { + let name = file.replace(".jpg", ""); + tasks.push(parseImage(name, file)); + } + await Promise.all(tasks); + console.log( + `[${inlineQuery.from.username ? "@" : ""}${ + inlineQuery.from.username || inlineQuery.from.first_name + }][${text}] 處理完畢 (${searchResult.length})` + ); + return answerInlineQuery( + results, + Object.assign( + { cache_time: 60 * 60 /* second */ }, + !results.length + ? { + switch_pm_text: `❌ 找不到你要的圖片,按這裡查看可供搜尋的圖片名稱`, + switch_pm_parameter: "inline_puffy_404", + } + : {} ) + ); } -fs.readdir('./components/inline/puffy/', async (err, files) => { - files = files.filter(x => x != '.DS_Store') - files.forEach(file => { - let name = file.replace('.jpg', '') - puffyList[name] = file - }); - // 移除已經不存在的圖片 - let cacheData = db.get('puffyCache') || {} - for (let cachedfile of Object.keys(cacheData)) { - if (!files.includes(cachedfile)) { - delete cacheData[cachedfile] - } +fs.readdir("./components/inline/puffy/", async (err, files) => { + files = files.filter((x) => x != ".DS_Store"); + files.forEach((file) => { + let name = file.replace(".jpg", ""); + puffyList[name] = file; + }); + // 移除已經不存在的圖片 + let cacheData = db.get("puffyCache") || {}; + for (let cachedfile of Object.keys(cacheData)) { + if (!files.includes(cachedfile)) { + delete cacheData[cachedfile]; } - // 快取 - const delay = (s) => { - return new Promise(resolve => { - setTimeout(resolve, s); - }); - }; - for (let file of files) { - cacheData = db.get('puffyCache') || {} - if (!cacheData[file]) { - console.log(`[${Object.keys(cacheData).length}/${files.length}]正在快取 ${file}`) - imageFiletoId(file) - await delay(1200) - } + } + // 快取 + const delay = (s) => { + return new Promise((resolve) => { + setTimeout(resolve, s); + }); + }; + for (let file of files) { + cacheData = db.get("puffyCache") || {}; + if (!cacheData[file]) { + console.log( + `[${Object.keys(cacheData).length}/${files.length}]正在快取 ${file}` + ); + imageFiletoId(file); + await delay(1200); } - cacheFinished = true - console.log(`${Object.keys(puffyList).length} 張圖片快取完畢`); + } + cacheFinished = true; + console.log(`${Object.keys(puffyList).length} 張圖片快取完畢`); }); -module.exports = answer \ No newline at end of file +module.exports = answer; diff --git a/components/inline/sticker.js b/components/inline/sticker.js index 9bf9483..7cb7773 100644 --- a/components/inline/sticker.js +++ b/components/inline/sticker.js @@ -1,131 +1,241 @@ -const telegram = require('../telegram') -const sharp = require('sharp'); -const chats = require('../../config').chats; -const getRandomChat = () => chats[Math.floor(Math.random() * chats.length)] -const svgNotoBold = require('text-to-svg').loadSync('./components/inline/sticker/font/NotoSansCJKtc-Bold.otf'); -const svgHuninn = require('text-to-svg').loadSync('./components/inline/sticker/font/jf-openhuninn-1.1.ttf'); -let cacheResult = {} -let cacheStickerId = {} -let moretextplz, tooManyRequests +const telegram = require("../telegram"); +const sharp = require("sharp"); +const chats = require("../../config").chats; +const getRandomChat = () => chats[Math.floor(Math.random() * chats.length)]; +const svgNotoBold = require("text-to-svg").loadSync( + "./components/inline/sticker/font/NotoSansCJKtc-Bold.otf" +); +const svgHuninn = require("text-to-svg").loadSync( + "./components/inline/sticker/font/jf-openhuninn-1.1.ttf" +); +let cacheResult = {}; +let cacheStickerId = {}; +let moretextplz, tooManyRequests; async function start() { - moretextplz = await stickerFiletoId('./components/inline/sticker/img/moretextplz.webp') - tooManyRequests = await stickerFiletoId('./components/inline/sticker/img/tooManyRequests.webp') + moretextplz = await stickerFiletoId( + "./components/inline/sticker/img/moretextplz.webp" + ); + tooManyRequests = await stickerFiletoId( + "./components/inline/sticker/img/tooManyRequests.webp" + ); } async function stickerFiletoId(url) { - if (cacheStickerId[url]) - return cacheStickerId[url] - let msg = await telegram.sendDocument(getRandomChat(), { - source: require('fs').readFileSync(url), - filename: 'sticker-gen.webp' - }) - cacheStickerId[url] = msg.sticker.file_id - return msg.sticker.file_id + if (cacheStickerId[url]) return cacheStickerId[url]; + let msg = await telegram.sendDocument(getRandomChat(), { + source: require("fs").readFileSync(url), + filename: "sticker-gen.webp", + }); + cacheStickerId[url] = msg.sticker.file_id; + return msg.sticker.file_id; } async function stickerFileBuffertoId(source) { - let msg = await telegram.sendDocument(getRandomChat(), { - source, - filename: 'sticker-gen.webp' - }) - return msg.sticker.file_id + let msg = await telegram.sendDocument(getRandomChat(), { + source, + filename: "sticker-gen.webp", + }); + return msg.sticker.file_id; } async function answer({ inlineQuery, answerInlineQuery }) { - let text = inlineQuery.query.split(' ')[1] - if (cacheResult[text]) { - console.log(`[${(inlineQuery.from.username || inlineQuery.from.first_name)}][${text}] cached`) - return answerInlineQuery(cacheResult[text], { cache_time: 60 * 40 /* second */ }) + let text = inlineQuery.query.split(" ")[1]; + if (cacheResult[text]) { + console.log( + `[${ + inlineQuery.from.username || inlineQuery.from.first_name + }][${text}] cached` + ); + return answerInlineQuery(cacheResult[text], { + cache_time: 60 * 40 /* second */, + }); + } + if (text.length < 1) { + return answerInlineQuery( + [{ type: "sticker", id: "plz", sticker_file_id: moretextplz }], + { cache_time: 60 * 40 /* second */ } + ); + } + let results = []; + try { + async function genBlobbies() { + let attributes, options, textRes, stickerRes; + attributes = { fill: "#bcbdc8", stroke: "white" }; + options = { x: 0, y: 0, fontSize: 196, anchor: "top", attributes }; + textRes = await sharp(Buffer.from(svgNotoBold.getSVG(text, options))) + .resize(332 - 30, 136 - 50, { + fit: "contain", + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .extend({ + top: 25, + bottom: 25, + left: 15, + right: 15, + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .toBuffer(); + stickerRes = await sharp("./components/inline/sticker/img/blobbies.png") + .composite([{ input: textRes, top: 10, left: 0 }]) + .webp() + .toBuffer(); + results.push({ + type: "sticker", + id: "blobbies", + sticker_file_id: await stickerFileBuffertoId(stickerRes), + }); } - if (text.length < 1) { - return answerInlineQuery([{ type: 'sticker', id: 'plz', sticker_file_id: moretextplz }], { cache_time: 60 * 40 /* second */ }) + async function genDuck() { + let attributes, options, textRes, stickerRes; + attributes = { fill: "white" }; + options = { + x: 0, + y: 0, + fontSize: 196, + anchor: "top", + attributes, + y: -18, + }; + textRes = await sharp(Buffer.from(svgHuninn.getSVG(text, options))) + .resize(512 - 30, 225 - 80, { + fit: "contain", + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .extend({ + top: 40, + bottom: 40, + left: 15, + right: 15, + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .toBuffer(); + stickerRes = await sharp("./components/inline/sticker/img/duck.png") + .composite([{ input: textRes, top: 0, left: 0 }]) + .webp() + .toBuffer(); + results.push({ + type: "sticker", + id: "duck", + sticker_file_id: await stickerFileBuffertoId(stickerRes), + }); } - let results = [] - try { - async function genBlobbies() { - let attributes, options, textRes, stickerRes - attributes = { fill: '#bcbdc8', stroke: 'white' }; - options = { x: 0, y: 0, fontSize: 196, anchor: 'top', attributes }; - textRes = await sharp(Buffer.from(svgNotoBold.getSVG(text, options))) - .resize(332 - 30, 136 - 50, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) - .extend({ - top: 25, bottom: 25, left: 15, right: 15, background: { r: 0, g: 0, b: 0, alpha: 0 } - }) - .toBuffer() - stickerRes = await sharp('./components/inline/sticker/img/blobbies.png').composite([{ input: textRes, top: 10, left: 0 }]).webp().toBuffer() - results.push({ type: 'sticker', id: 'blobbies', sticker_file_id: await stickerFileBuffertoId(stickerRes) }) - } - async function genDuck() { - let attributes, options, textRes, stickerRes - attributes = { fill: 'white' }; - options = { x: 0, y: 0, fontSize: 196, anchor: 'top', attributes, y: -18 }; - textRes = await sharp(Buffer.from(svgHuninn.getSVG(text, options))) - .resize(512 - 30, 225 - 80, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) - .extend({ - top: 40, bottom: 40, left: 15, right: 15, background: { r: 0, g: 0, b: 0, alpha: 0 } - }) - .toBuffer() - stickerRes = await sharp('./components/inline/sticker/img/duck.png').composite([{ input: textRes, top: 0, left: 0 }]).webp().toBuffer() - results.push({ type: 'sticker', id: 'duck', sticker_file_id: await stickerFileBuffertoId(stickerRes) }) - } - async function genDono() { - let attributes, options, textRes, stickerRes - attributes = { fill: 'black' }; - options = { x: 0, y: 0, fontSize: 196, anchor: 'top', attributes, y: -18 }; - textRes = await sharp(Buffer.from(svgHuninn.getSVG(text, options))) - .resize(512 - 30, 106 - 20, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) - .extend({ - top: 10, bottom: 10, left: 15, right: 15, background: { r: 0, g: 0, b: 0, alpha: 0 } - }) - .toBuffer() - async function pushDono() { - stickerRes = await sharp('./components/inline/sticker/img/dono.webp').composite([{ input: textRes, top: 0, left: 0 }]).webp().toBuffer() - results.push({ type: 'sticker', id: 'dono', sticker_file_id: await stickerFileBuffertoId(stickerRes) }) - } - async function pushIknow() { - stickerRes = await sharp('./components/inline/sticker/img/iknow.webp').composite([{ input: textRes, top: 0, left: 0 }]).webp().toBuffer() - results.push({ type: 'sticker', id: 'iknow', sticker_file_id: (await stickerFileBuffertoId(stickerRes)) }) - } - return Promise.all([pushDono(), pushIknow()]) - } - async function genLeaf() { - let attributes, options, textRes, stickerRes - attributes = { fill: 'black' }; - options = { x: 0, y: 0, fontSize: 72, anchor: 'top', attributes, y: -18 }; - textRes = await sharp(Buffer.from(svgNotoBold.getSVG(text, options))) - .resize(346 - 30, 38 - 6, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) - .extend({ - top: 3, bottom: 3, left: 15, right: 15, background: { r: 0, g: 0, b: 0, alpha: 0 } - }) - .toBuffer() - stickerRes = await sharp('./components/inline/sticker/img/leaf.png').composite([{ input: textRes, top: 262, left: 83 }]).webp().toBuffer() - results.push({ type: 'sticker', id: 'leaf', sticker_file_id: (await stickerFileBuffertoId(stickerRes)) }) - } - async function genSuck() { - let attributes, options, textRes, stickerRes - attributes = { fill: 'black', stroke: 'white' }; - options = { x: 0, y: 0, fontSize: 96, anchor: 'top', attributes, y: -18 }; - textRes = await sharp(Buffer.from(svgNotoBold.getSVG(text, options))) - .resize(496 - 30, 112 - 6, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) - .extend({ - top: 3, bottom: 3, left: 15, right: 15, background: { r: 0, g: 0, b: 0, alpha: 0 } - }) - .toBuffer() - stickerRes = await sharp('./components/inline/sticker/img/suck.webp').composite([{ input: textRes, top: 400, left: 0 }]).webp().toBuffer() - results.push({ type: 'sticker', id: 'suck', sticker_file_id: (await stickerFileBuffertoId(stickerRes)) }) - } - await Promise.all([ - genBlobbies(), - genDono(), - genDuck(), - genSuck() - ]) - } catch (e) { - console.log(e) - results.push({ type: 'sticker', id: 'tooManyRequests', sticker_file_id: tooManyRequests }) - return answerInlineQuery(results, { cache_time: 20 /* second */ }) + async function genDono() { + let attributes, options, textRes, stickerRes; + attributes = { fill: "black" }; + options = { + x: 0, + y: 0, + fontSize: 196, + anchor: "top", + attributes, + y: -18, + }; + textRes = await sharp(Buffer.from(svgHuninn.getSVG(text, options))) + .resize(512 - 30, 106 - 20, { + fit: "contain", + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .extend({ + top: 10, + bottom: 10, + left: 15, + right: 15, + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .toBuffer(); + async function pushDono() { + stickerRes = await sharp("./components/inline/sticker/img/dono.webp") + .composite([{ input: textRes, top: 0, left: 0 }]) + .webp() + .toBuffer(); + results.push({ + type: "sticker", + id: "dono", + sticker_file_id: await stickerFileBuffertoId(stickerRes), + }); + } + async function pushIknow() { + stickerRes = await sharp("./components/inline/sticker/img/iknow.webp") + .composite([{ input: textRes, top: 0, left: 0 }]) + .webp() + .toBuffer(); + results.push({ + type: "sticker", + id: "iknow", + sticker_file_id: await stickerFileBuffertoId(stickerRes), + }); + } + return Promise.all([pushDono(), pushIknow()]); } - console.log(`[${inlineQuery.from.username ? '@' : ''}${(inlineQuery.from.username || inlineQuery.from.first_name)}][${text}] 處理完畢`) - cacheResult[text] = results - return answerInlineQuery(results, { cache_time: 60 * 40 /* second */ }) + async function genLeaf() { + let attributes, options, textRes, stickerRes; + attributes = { fill: "black" }; + options = { x: 0, y: 0, fontSize: 72, anchor: "top", attributes, y: -18 }; + textRes = await sharp(Buffer.from(svgNotoBold.getSVG(text, options))) + .resize(346 - 30, 38 - 6, { + fit: "contain", + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .extend({ + top: 3, + bottom: 3, + left: 15, + right: 15, + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .toBuffer(); + stickerRes = await sharp("./components/inline/sticker/img/leaf.png") + .composite([{ input: textRes, top: 262, left: 83 }]) + .webp() + .toBuffer(); + results.push({ + type: "sticker", + id: "leaf", + sticker_file_id: await stickerFileBuffertoId(stickerRes), + }); + } + async function genSuck() { + let attributes, options, textRes, stickerRes; + attributes = { fill: "black", stroke: "white" }; + options = { x: 0, y: 0, fontSize: 96, anchor: "top", attributes, y: -18 }; + textRes = await sharp(Buffer.from(svgNotoBold.getSVG(text, options))) + .resize(496 - 30, 112 - 6, { + fit: "contain", + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .extend({ + top: 3, + bottom: 3, + left: 15, + right: 15, + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .toBuffer(); + stickerRes = await sharp("./components/inline/sticker/img/suck.webp") + .composite([{ input: textRes, top: 400, left: 0 }]) + .webp() + .toBuffer(); + results.push({ + type: "sticker", + id: "suck", + sticker_file_id: await stickerFileBuffertoId(stickerRes), + }); + } + await Promise.all([genBlobbies(), genDono(), genDuck(), genSuck()]); + } catch (e) { + console.log(e); + results.push({ + type: "sticker", + id: "tooManyRequests", + sticker_file_id: tooManyRequests, + }); + return answerInlineQuery(results, { cache_time: 20 /* second */ }); + } + console.log( + `[${inlineQuery.from.username ? "@" : ""}${ + inlineQuery.from.username || inlineQuery.from.first_name + }][${text}] 處理完畢` + ); + cacheResult[text] = results; + return answerInlineQuery(results, { cache_time: 60 * 40 /* second */ }); } -start() -module.exports = answer \ No newline at end of file +start(); +module.exports = answer; diff --git a/components/inline/url.js b/components/inline/url.js index 00209be..ea460db 100644 --- a/components/inline/url.js +++ b/components/inline/url.js @@ -1,31 +1,35 @@ async function answer({ inlineQuery, answerInlineQuery }) { - let results = [] + let results = []; // parse text - let url = inlineQuery.query + let url = inlineQuery.query; let link = new URL(url); - let isShorted = false + let isShorted = false; if (link.host == `24h.pchome.com.tw`) { - url = url.replace('https://24h.pchome.com.tw/', 'https://p.pancake.tw/') - isShorted = true + url = url.replace("https://24h.pchome.com.tw/", "https://p.pancake.tw/"); + isShorted = true; } if (url.match(/^https:\/\/twitter\.com\/(.+)/)) { - link.search = ''; - link.hash = ''; - link.host = 'vxtwitter.com'; + link.search = ""; + link.hash = ""; + link.host = "vxtwitter.com"; url = link.href; isShorted = true; } results.push({ - type: 'article', + type: "article", id: `URL`, - title: `URL 短網址 [${isShorted ? '已縮短' : '未縮短'}]`, + title: `URL 短網址 [${isShorted ? "已縮短" : "未縮短"}]`, description: `自動移除追蹤連結並產生合適的網址`, input_message_content: { - message_text: url - } - }) - console.log(`[${inlineQuery.from.username ? '@' : ''}${(inlineQuery.from.username || inlineQuery.from.first_name)}][URL][${url}]處理完畢`) - return answerInlineQuery(results, { cache_time: 60 * 60 /* second */ }) + message_text: url, + }, + }); + console.log( + `[${inlineQuery.from.username ? "@" : ""}${ + inlineQuery.from.username || inlineQuery.from.first_name + }][URL][${url}]處理完畢` + ); + return answerInlineQuery(results, { cache_time: 60 * 60 /* second */ }); } -module.exports = answer \ No newline at end of file +module.exports = answer; diff --git a/components/rate.js b/components/rate.js index 3073bcb..c9f1af5 100644 --- a/components/rate.js +++ b/components/rate.js @@ -1,18 +1,31 @@ -const Composer = require('telegraf/composer') -const bot = new Composer() -const fetch = require('node-fetch'); -bot.command('rate', async ctx => { - const match = ctx.state.command.args.toUpperCase().match(/(\d+|\d+\.\d+)([A-Z]{1,4})=([A-Z]{1,4})/); +const Composer = require("telegraf/composer"); +const bot = new Composer(); +const fetch = require("node-fetch"); +bot.command("rate", async (ctx) => { + const match = ctx.state.command.args + .toUpperCase() + .match(/(\d+|\d+\.\d+)([A-Z]{1,4})=([A-Z]{1,4})/); if (!match) { - return ctx.reply('請輸入正確格式,例如:`/rate 100USD=JPY`', { parse_mode: "markdown", reply_to_message_id: ctx.message.message_id }) + return ctx.reply("請輸入正確格式,例如:`/rate 100USD=JPY`", { + parse_mode: "markdown", + reply_to_message_id: ctx.message.message_id, + }); } - ctx.telegram.sendChatAction(ctx.chat.id, 'typing') + ctx.telegram.sendChatAction(ctx.chat.id, "typing"); const [, amount, from, to] = match; - const resp = await fetch(`https://api.exchangerate.host/convert?from=${from}&to=${to}&amount=${amount}`) - const { success, result } = await resp.json() + const resp = await fetch( + `https://api.exchangerate.host/convert?from=${from}&to=${to}&amount=${amount}` + ); + const { success, result } = await resp.json(); if (!success || !result) { - return ctx.reply('查無此貨幣代碼或轉換時發生錯誤', { parse_mode: "markdown", reply_to_message_id: ctx.message.message_id }) + return ctx.reply("查無此貨幣代碼或轉換時發生錯誤", { + parse_mode: "markdown", + reply_to_message_id: ctx.message.message_id, + }); } - ctx.reply(`${amount} ${from} = ${result} ${to}`, { parse_mode: "markdown", reply_to_message_id: ctx.message.message_id }) -}) -module.exports = bot \ No newline at end of file + ctx.reply(`${amount} ${from} = ${result} ${to}`, { + parse_mode: "markdown", + reply_to_message_id: ctx.message.message_id, + }); +}); +module.exports = bot; diff --git a/components/simple-reply.js b/components/simple-reply.js index def62d6..5168d5d 100644 --- a/components/simple-reply.js +++ b/components/simple-reply.js @@ -1,47 +1,83 @@ -const Composer = require('telegraf/composer') -const bot = new Composer() -const telegram = require('./telegram') - -bot.command('removekbd', ({ reply, replyWithSticker, message }) => { - replyWithSticker('https://data.gnehs.net/stickers/bye.webp', { reply_to_message_id: message.message_id }) - reply(`鍵盤掰掰`, { reply_markup: JSON.stringify({ remove_keyboard: true }), reply_to_message_id: message.message_id }) -}) -bot.command('date', ({ reply, message }) => reply(`Server time: ${Date()}`, { reply_to_message_id: message.message_id })) -bot.command('about', async ({ replyWithMarkdown, message }) => { - let { first_name } = await telegram.getMe() - replyWithMarkdown(`「${first_name}」由 [🥞pancake](https://github.com/gnehs/pancake-bot) 驅動!`, { reply_to_message_id: message.message_id }) -}) +const Composer = require("telegraf/composer"); +const bot = new Composer(); +const telegram = require("./telegram"); + +bot.command("removekbd", ({ reply, replyWithSticker, message }) => { + replyWithSticker("https://data.gnehs.net/stickers/bye.webp", { + reply_to_message_id: message.message_id, + }); + reply(`鍵盤掰掰`, { + reply_markup: JSON.stringify({ remove_keyboard: true }), + reply_to_message_id: message.message_id, + }); +}); +bot.command("date", ({ reply, message }) => + reply(`Server time: ${Date()}`, { reply_to_message_id: message.message_id }) +); +bot.command("about", async ({ replyWithMarkdown, message }) => { + let { first_name } = await telegram.getMe(); + replyWithMarkdown( + `「${first_name}」由 [🥞pancake](https://github.com/gnehs/pancake-bot) 驅動!`, + { reply_to_message_id: message.message_id } + ); +}); // Ping -bot.command('ping', ({ replyWithMarkdown, message }) => replyWithMarkdown(`*PONG*`, { reply_to_message_id: message.message_id })) -bot.hears('ping', ({ replyWithMarkdown, message }) => replyWithMarkdown(`*PONG*`, { reply_to_message_id: message.message_id })) +bot.command("ping", ({ replyWithMarkdown, message }) => + replyWithMarkdown(`*PONG*`, { reply_to_message_id: message.message_id }) +); +bot.hears("ping", ({ replyWithMarkdown, message }) => + replyWithMarkdown(`*PONG*`, { reply_to_message_id: message.message_id }) +); // 髒話偵測 -bot.hears("幹", ({ replyWithMarkdown }) => replyWithMarkdown('_QQ_')); +bot.hears("幹", ({ replyWithMarkdown }) => replyWithMarkdown("_QQ_")); -bot.hears("怕", ({ reply, message }) => reply('嚇到吃手手', { reply_to_message_id: message.message_id })); +bot.hears("怕", ({ reply, message }) => + reply("嚇到吃手手", { reply_to_message_id: message.message_id }) +); -bot.hears("逼比", ({ reply, message }) => reply('蹦蹦', { reply_to_message_id: message.message_id })); +bot.hears("逼比", ({ reply, message }) => + reply("蹦蹦", { reply_to_message_id: message.message_id }) +); -bot.hears("喵", ({ replyWithMarkdown, message }) => replyWithMarkdown('`HTTP /3.0 200 OK.`', { reply_to_message_id: message.message_id })); +bot.hears("喵", ({ replyWithMarkdown, message }) => + replyWithMarkdown("`HTTP /3.0 200 OK.`", { + reply_to_message_id: message.message_id, + }) +); -bot.hears("嗨", ({ replyWithSticker, message }) => replyWithSticker('https://data.gnehs.net/stickers/hello.webp', { reply_to_message_id: message.message_id })); +bot.hears("嗨", ({ replyWithSticker, message }) => + replyWithSticker("https://data.gnehs.net/stickers/hello.webp", { + reply_to_message_id: message.message_id, + }) +); bot.hears("晚安", ({ reply, message, replyWithSticker }) => { - if (message.from.username == 'seadog007') { - replyWithSticker('https://gcdnb.pbrd.co/images/ZLjQQi8gqHui.webp', { reply_to_message_id: message.message_id }) - } else if (message.from.username == 'Vincent550102') { - replyWithSticker('https://gcdnb.pbrd.co/images/4UdVojF7Ss9F.webp', { reply_to_message_id: message.message_id }) - } else if (Math.random() < 0.5) { - replyWithSticker('https://data.gnehs.net/stickers/good%20night.webp', { reply_to_message_id: message.message_id }) - } else { - replyWithSticker('https://gcdnb.pbrd.co/images/ZLjQQi8gqHui.webp', { reply_to_message_id: message.message_id }) - } - if (message.from.username == 'seadog007') { - reply(`笨豹豹,晚安`, { reply_to_message_id: message.message_id }) - } else { - reply(`${message.from.first_name},晚安❤️`, { reply_to_message_id: message.message_id }) - } + if (message.from.username == "seadog007") { + replyWithSticker("https://gcdnb.pbrd.co/images/ZLjQQi8gqHui.webp", { + reply_to_message_id: message.message_id, + }); + } else if (message.from.username == "Vincent550102") { + replyWithSticker("https://gcdnb.pbrd.co/images/4UdVojF7Ss9F.webp", { + reply_to_message_id: message.message_id, + }); + } else if (Math.random() < 0.5) { + replyWithSticker("https://data.gnehs.net/stickers/good%20night.webp", { + reply_to_message_id: message.message_id, + }); + } else { + replyWithSticker("https://gcdnb.pbrd.co/images/ZLjQQi8gqHui.webp", { + reply_to_message_id: message.message_id, + }); + } + if (message.from.username == "seadog007") { + reply(`笨豹豹,晚安`, { reply_to_message_id: message.message_id }); + } else { + reply(`${message.from.first_name},晚安❤️`, { + reply_to_message_id: message.message_id, + }); + } }); -module.exports = bot \ No newline at end of file +module.exports = bot; diff --git a/components/start.js b/components/start.js index 3787479..1a81081 100644 --- a/components/start.js +++ b/components/start.js @@ -1,35 +1,50 @@ -const Composer = require('telegraf/composer') -const bot = new Composer() -const telegram = require('./telegram') -const parsedInlineProcessorList = require('../list').inlineProcessorList - .map((x, i) => `*${x.name}*\n代號:${x.keywords.join(', ')}`) - .join('\n') -bot.start(async ctx => { - let splitedCommand = ctx.message.text.split(' ')[1] - let { first_name, username } = await telegram.getMe() - switch (splitedCommand) { - case 'inline_puffy_404': - ctx.replyWithMarkdown( - `你可以在 [這裡](https://github.com/gnehs/pancake-bot/tree/master/components/inline/puffy) 查看所有可供搜尋的圖片名稱`, - { reply_to_message_id: ctx.message.message_id, disable_web_page_preview: true } - ) - break; - case 'inline_error': - ctx.replyWithMarkdown(`*出錯原因*\n這可能是因為你輸入的指令有誤,或是機器人程式出錯,請檢查後再試一次。`, { reply_to_message_id: ctx.message.message_id }) - break; - case 'inline_help': - ctx.replyWithMarkdown(`*📘「${first_name}」行內機器人使用說明* +const Composer = require("telegraf/composer"); +const bot = new Composer(); +const telegram = require("./telegram"); +const parsedInlineProcessorList = require("../list") + .inlineProcessorList.map( + (x, i) => `*${x.name}*\n代號:${x.keywords.join(", ")}` + ) + .join("\n"); +bot.start(async (ctx) => { + let splitedCommand = ctx.message.text.split(" ")[1]; + let { first_name, username } = await telegram.getMe(); + switch (splitedCommand) { + case "inline_puffy_404": + ctx.replyWithMarkdown( + `你可以在 [這裡](https://github.com/gnehs/pancake-bot/tree/master/components/inline/puffy) 查看所有可供搜尋的圖片名稱`, + { + reply_to_message_id: ctx.message.message_id, + disable_web_page_preview: true, + } + ); + break; + case "inline_error": + ctx.replyWithMarkdown( + `*出錯原因*\n這可能是因為你輸入的指令有誤,或是機器人程式出錯,請檢查後再試一次。`, + { reply_to_message_id: ctx.message.message_id } + ); + break; + case "inline_help": + ctx.replyWithMarkdown( + `*📘「${first_name}」行內機器人使用說明* *👇 機器人可接受的格式如下:* @${username} \`<代號> <文字/關鍵字>\` @${username} \`<網址>\` *👇 可用的處理器清單:* -${parsedInlineProcessorList}`, { reply_to_message_id: ctx.message.message_id }) - break; - default: - ctx.replyWithSticker('https://data.gnehs.net/stickers/hello.webp', { reply_to_message_id: ctx.message.message_id }) - ctx.reply(`這裡是${first_name}!`, { reply_to_message_id: ctx.message.message_id }) - } -}) -module.exports = bot \ No newline at end of file +${parsedInlineProcessorList}`, + { reply_to_message_id: ctx.message.message_id } + ); + break; + default: + ctx.replyWithSticker("https://data.gnehs.net/stickers/hello.webp", { + reply_to_message_id: ctx.message.message_id, + }); + ctx.reply(`這裡是${first_name}!`, { + reply_to_message_id: ctx.message.message_id, + }); + } +}); +module.exports = bot; diff --git a/components/subscribe/apple-ncc.js b/components/subscribe/apple-ncc.js index c13361e..20a93c4 100644 --- a/components/subscribe/apple-ncc.js +++ b/components/subscribe/apple-ncc.js @@ -1,42 +1,44 @@ -const db = require('../db') -const { sendMessage } = require('./manage') -const cron = require('node-cron'); -const fetch = require('node-fetch'); -cron.schedule('*/5 * * * *', () => { - sendData() +const db = require("../db"); +const { sendMessage } = require("./manage"); +const cron = require("node-cron"); +const fetch = require("node-fetch"); +cron.schedule("*/5 * * * *", () => { + sendData(); }); async function sendData() { // check new - let data = await fetch('https://gnehs.github.io/apple-ncc-feed/').then(res => res.json()) - let sent = db.get('apple-ncc') || [] - let newData = data.filter(x => !sent.includes(x.new_id)) - db.set('apple-ncc', [...new Set([...sent, ...newData.map(x => x.new_id)])]) + let data = await fetch("https://gnehs.github.io/apple-ncc-feed/").then( + (res) => res.json() + ); + let sent = db.get("apple-ncc") || []; + let newData = data.filter((x) => !sent.includes(x.new_id)); + db.set("apple-ncc", [...new Set([...sent, ...newData.map((x) => x.new_id)])]); // check verifydate - newData = newData.filter(x => { + newData = newData.filter((x) => { // "verifydate": "2022/10/04", - let date = x.verifydate.split('/') - let now = new Date() - let verifydate = new Date(date[0], date[1] - 1, date[2]) + let date = x.verifydate.split("/"); + let now = new Date(); + let verifydate = new Date(date[0], date[1] - 1, date[2]); // check if verifydate is this week - if (now.getDate() - verifydate.getDate() > 7) return false - return true - }) + if (now.getDate() - verifydate.getDate() > 7) return false; + return true; + }); // 送資料 if (newData.length) { - let text = '' + let text = ""; for (let item of newData) { - text += `🍎 #Apple_NCC #${item.model}\n` - text += `產品名稱:${item.equip_name}\n` - text += `驗證號碼:
${item.new_id}
\n` - text += `產品型號:
${item.model}
\n` - text += `審驗日期:${item.verifydate}\n` - text += `🔗 詳細資料\n\n` + text += `🍎 #Apple_NCC #${item.model}\n`; + text += `產品名稱:${item.equip_name}\n`; + text += `驗證號碼:
${item.new_id}
\n`; + text += `產品型號:
${item.model}
\n`; + text += `審驗日期:${item.verifydate}\n`; + text += `🔗 詳細資料\n\n`; } sendMessage({ - chats: Object.keys(db.get('subscribe.apple-ncc')), + chats: Object.keys(db.get("subscribe.apple-ncc")), message: text, - key: 'apple-ncc' - }) + key: "apple-ncc", + }); } } -sendData() \ No newline at end of file +sendData(); diff --git a/components/subscribe/bahamut-anime.js b/components/subscribe/bahamut-anime.js index 30ef6c4..f593e2d 100644 --- a/components/subscribe/bahamut-anime.js +++ b/components/subscribe/bahamut-anime.js @@ -1,74 +1,72 @@ -const db = require('../db') -const { sendMessage } = require('./manage') -const cron = require('node-cron'); -const fetch = require('node-fetch'); -cron.schedule('50 0,30 * * * *', () => { - sendData() +const db = require("../db"); +const { sendMessage } = require("./manage"); +const cron = require("node-cron"); +const fetch = require("node-fetch"); +cron.schedule("50 0,30 * * * *", () => { + sendData(); }); async function fetchData() { - let data = await fetch('https://api.gamer.com.tw/mobile_app/anime/v1/index.php').then(res => res.json()) - let newEpisode = [] - let recentAdded = [] + let data = await fetch( + "https://api.gamer.com.tw/mobile_app/anime/v1/index.php" + ).then((res) => res.json()); + let newEpisode = []; + let recentAdded = []; for ({ video_sn, title, info } of data.new_anime.date) { - let episode = info.match(/\[(.+)\]/)[1] - episode = episode.length >= 2 ? episode : `0${episode}` - episode = episode.replace(/\[|\]/g, '') // to fix 5] [特別篇 + let episode = info.match(/\[(.+)\]/)[1]; + episode = episode.length >= 2 ? episode : `0${episode}`; + episode = episode.replace(/\[|\]/g, ""); // to fix 5] [特別篇 newEpisode.push({ id: video_sn, title, link: `https://ani.gamer.com.tw/animeVideo.php?sn=${video_sn}`, episode, - }) + }); } for ({ anime_sn, title, info } of data.new_added) { recentAdded.push({ id: `recent_${anime_sn}`, title, link: `https://ani.gamer.com.tw/animeRef.php?sn=${anime_sn}`, - }) + }); } return { newEpisode, - recentAdded - } + recentAdded, + }; } async function sendData() { //check new - let fetchedData = await fetchData() - let newEpisode = [] - let recentAdded = [] - let sentEpisode = db.get('bahamut-sent') || {} + let fetchedData = await fetchData(); + let newEpisode = []; + let recentAdded = []; + let sentEpisode = db.get("bahamut-sent") || {}; // 新增的內容 for (item of fetchedData.newEpisode) - if (!sentEpisode[item.id]) - newEpisode.push(item) + if (!sentEpisode[item.id]) newEpisode.push(item); for (item of fetchedData.recentAdded) - if (!sentEpisode[item.id]) - recentAdded.push(item) + if (!sentEpisode[item.id]) recentAdded.push(item); // 重置已發送ㄉ資料 - sentEpisode = {} - for ({ id } of fetchedData.newEpisode) - sentEpisode[id] = true - for ({ id } of fetchedData.recentAdded) - sentEpisode[id] = true - db.set('bahamut-sent', sentEpisode) + sentEpisode = {}; + for ({ id } of fetchedData.newEpisode) sentEpisode[id] = true; + for ({ id } of fetchedData.recentAdded) sentEpisode[id] = true; + db.set("bahamut-sent", sentEpisode); // 送資料 if (newEpisode.length || recentAdded.length) { - let resp = "#ㄅㄏ動畫瘋更新菌\n" + let resp = "#ㄅㄏ動畫瘋更新菌\n"; for ({ link, title, episode } of newEpisode) { - let ep = isNaN(episode) ? episode : `E${episode}` // 有時候會解析出「電影」之類的東西所以要過濾一下 - resp += `${ep} ${title}\n` + let ep = isNaN(episode) ? episode : `E${episode}`; // 有時候會解析出「電影」之類的東西所以要過濾一下 + resp += `${ep} ${title}\n`; } if (recentAdded.length) { - resp += `最近新增\n` + resp += `最近新增\n`; for ({ link, title } of recentAdded) { - resp += `${title}\n` + resp += `${title}\n`; } } sendMessage({ - chats: Object.keys(db.get('subscribe.baha')), + chats: Object.keys(db.get("subscribe.baha")), message: resp, - key: 'baha' - }) + key: "baha", + }); } -} \ No newline at end of file +} diff --git a/components/subscribe/github-release.js b/components/subscribe/github-release.js index 83410b2..f21ce38 100644 --- a/components/subscribe/github-release.js +++ b/components/subscribe/github-release.js @@ -1,61 +1,66 @@ -const db = require('../db') -const { sendMessage } = require('./manage') -const cron = require('node-cron'); -const fetch = require('node-fetch'); -const dbKey = "github-release" -cron.schedule('1,31 * * * *', () => { - sendData() +const db = require("../db"); +const { sendMessage } = require("./manage"); +const cron = require("node-cron"); +const fetch = require("node-fetch"); +const dbKey = "github-release"; +cron.schedule("1,31 * * * *", () => { + sendData(); }); function releaseId(repo, value) { - let releaseIdList = db.get(dbKey) || {} - if (value) { - releaseIdList[repo] = value - db.set(dbKey, releaseIdList) - } - return releaseIdList[repo] + let releaseIdList = db.get(dbKey) || {}; + if (value) { + releaseIdList[repo] = value; + db.set(dbKey, releaseIdList); + } + return releaseIdList[repo]; } async function checkRepo(repo) { - return (await fetch(`https://api.github.com/repos/${repo}/releases`).then(res => res.json())) + return await fetch(`https://api.github.com/repos/${repo}/releases`).then( + (res) => res.json() + ); } async function sendData() { - // 取得 Repo List - let repoSubscribeList = db.get('subscribe.github-release') || {} - let repoList = Object.keys(repoSubscribeList) - // 檢查更新 - for (repo of repoList) { - let localReleaseId = releaseId(repo) - let repoReleases = await checkRepo(repo) - if (repoReleases.message == 'Not Found' || !repoReleases.length) { - let resp = '' - resp += `找不到 ${repo},或是該 Repo 無任何 Release,已自動取消訂閱\n` - sendMessage({ - chats: repoSubscribeList[repo], - message: resp, - key: 'github-release', - value: repo - }) - function unsubscribe(value) { - let subscribe_list = repoSubscribeList - delete subscribe_list[value] - db.set('subscribe.github-release', subscribe_list); - } - unsubscribe(repo) - } else if (!repoReleases.message) { - let latestRelease = repoReleases[0] - if (!localReleaseId || latestRelease.id > localReleaseId && latestRelease.id) { - releaseId(repo, latestRelease.id) - // 發訊息 - let resp = '' - resp += `${repo} 已發布 ${latestRelease.name}\n` - resp += `更新日誌:\n${latestRelease.body}` - resp += `\n連結GitHub` - sendMessage({ - chats: Object.keys(repoSubscribeList[repo]), - message: resp, - key: 'github-release', - value: repo - }) - } - } - } -} \ No newline at end of file + // 取得 Repo List + let repoSubscribeList = db.get("subscribe.github-release") || {}; + let repoList = Object.keys(repoSubscribeList); + // 檢查更新 + for (repo of repoList) { + let localReleaseId = releaseId(repo); + let repoReleases = await checkRepo(repo); + if (repoReleases.message == "Not Found" || !repoReleases.length) { + let resp = ""; + resp += `找不到 ${repo},或是該 Repo 無任何 Release,已自動取消訂閱\n`; + sendMessage({ + chats: repoSubscribeList[repo], + message: resp, + key: "github-release", + value: repo, + }); + function unsubscribe(value) { + let subscribe_list = repoSubscribeList; + delete subscribe_list[value]; + db.set("subscribe.github-release", subscribe_list); + } + unsubscribe(repo); + } else if (!repoReleases.message) { + let latestRelease = repoReleases[0]; + if ( + !localReleaseId || + (latestRelease.id > localReleaseId && latestRelease.id) + ) { + releaseId(repo, latestRelease.id); + // 發訊息 + let resp = ""; + resp += `${repo} 已發布 ${latestRelease.name}\n`; + resp += `更新日誌:\n${latestRelease.body}`; + resp += `\n連結GitHub`; + sendMessage({ + chats: Object.keys(repoSubscribeList[repo]), + message: resp, + key: "github-release", + value: repo, + }); + } + } + } +} diff --git a/components/subscribe/gonokamitw.js b/components/subscribe/gonokamitw.js index 49f3aca..1349ed2 100644 --- a/components/subscribe/gonokamitw.js +++ b/components/subscribe/gonokamitw.js @@ -1,52 +1,55 @@ -const db = require('../db') -const { sendMessage } = require('./manage') -const cron = require('node-cron'); -const fetch = require('node-fetch'); -const dbKey = "gonokamitw" -cron.schedule('*/5 * * * *', () => { - let subscribeList = db.get('subscribe.gonokamitw') || {} - if (Object.keys(subscribeList).length) - sendData() +const db = require("../db"); +const { sendMessage } = require("./manage"); +const cron = require("node-cron"); +const fetch = require("node-fetch"); +const dbKey = "gonokamitw"; +cron.schedule("*/5 * * * *", () => { + let subscribeList = db.get("subscribe.gonokamitw") || {}; + if (Object.keys(subscribeList).length) sendData(); }); async function sendData() { - async function checkURL(url = 'https://gnehs.github.io/gonokamitw-feed/posts.json') { + async function checkURL( + url = "https://gnehs.github.io/gonokamitw-feed/posts.json" + ) { try { // get subscribe list - let subscribeList = db.get('subscribe.gonokamitw') || {} - let sentHashs = db.get('gonokamitw-sent') || [] + let subscribeList = db.get("subscribe.gonokamitw") || {}; + let sentHashs = db.get("gonokamitw-sent") || []; - let posts = await fetch(url).then(x => x.json()) - let latestPost = posts[0] - const content = latestPost.description - const postHash = latestPost.id - const ramenName = latestPost.limitRamenName + let posts = await fetch(url).then((x) => x.json()); + let latestPost = posts[0]; + const content = latestPost.description; + const postHash = latestPost.id; + const ramenName = latestPost.limitRamenName; if (sentHashs.includes(postHash) || !ramenName) { - return + return; } - sentHashs.push(postHash) - sentHashs = sentHashs.slice(-20) - db.set('gonokamitw-sent', sentHashs) + sentHashs.push(postHash); + sentHashs = sentHashs.slice(-20); + db.set("gonokamitw-sent", sentHashs); - const message = `#五之神限定 #${ramenName}\n${content}` + const message = `#五之神限定 #${ramenName}\n${content}`; - let imgs = [{ - type: 'photo', - media: `https://gnehs.github.io/gonokamitw-feed${latestPost.img}`, - caption: message, - parse_mode: 'html' - }] + let imgs = [ + { + type: "photo", + media: `https://gnehs.github.io/gonokamitw-feed${latestPost.img}`, + caption: message, + parse_mode: "html", + }, + ]; sendMessage({ chats: Object.keys(subscribeList), imgs, - key: dbKey - }) + key: dbKey, + }); } catch (e) { - console.log(e) + console.log(e); } } - await checkURL(`https://gnehs.github.io/gonokamitw-feed/posts.json`) - await checkURL(`https://gnehs.github.io/gonokamitw-feed/okuyama_posts.json`) + await checkURL(`https://gnehs.github.io/gonokamitw-feed/posts.json`); + await checkURL(`https://gnehs.github.io/gonokamitw-feed/okuyama_posts.json`); } -sendData() \ No newline at end of file +sendData(); diff --git a/components/subscribe/index.js b/components/subscribe/index.js index c760400..ab87323 100644 --- a/components/subscribe/index.js +++ b/components/subscribe/index.js @@ -1,94 +1,133 @@ -const { subscribe, unsubscribe } = require('./manage') -const Composer = require('telegraf/composer') -const telegram = require('../telegram') -const fetch = require('node-fetch'); -const bot = new Composer() -const subscribeIdList = require('../../list').subscribeIdList; +const { subscribe, unsubscribe } = require("./manage"); +const Composer = require("telegraf/composer"); +const telegram = require("../telegram"); +const fetch = require("node-fetch"); +const bot = new Composer(); +const subscribeIdList = require("../../list").subscribeIdList; -require('./bahamut-anime') -require('./github-release') -require('./gonokamitw') -require('./apple-ncc') -bot.command('admin', async ctx => { - try { - let isUserAdmin = await isAdmin(ctx) - return ctx.reply(`您${isUserAdmin ? '有' : '沒有'}此聊天室的管理權限,${isUserAdmin ? '可' : '不可'}於此操作訂閱與取消訂閱等功能。`, { reply_to_message_id: ctx.message.message_id }); - } catch (e) { - console.log(e) - } +require("./bahamut-anime"); +require("./github-release"); +require("./gonokamitw"); +require("./apple-ncc"); +bot.command("admin", async (ctx) => { + try { + let isUserAdmin = await isAdmin(ctx); + return ctx.reply( + `您${isUserAdmin ? "有" : "沒有"}此聊天室的管理權限,${ + isUserAdmin ? "可" : "不可" + }於此操作訂閱與取消訂閱等功能。`, + { reply_to_message_id: ctx.message.message_id } + ); + } catch (e) { + console.log(e); + } }); async function isAdmin(ctx) { - try { - if (ctx.chat.type == 'group' || ctx.chat.type == 'supergroup') { - let adminList = await telegram.getChatAdministrators(ctx.chat.id) - return adminList.some(adm => adm.user.id === ctx.from.id); - } - else { - return true - } - } catch (e) { - return false - } + try { + if (ctx.chat.type == "group" || ctx.chat.type == "supergroup") { + let adminList = await telegram.getChatAdministrators(ctx.chat.id); + return adminList.some((adm) => adm.user.id === ctx.from.id); + } else { + return true; + } + } catch (e) { + return false; + } } - -bot.command('subscribe', async ctx => { - try { - if (await isAdmin(ctx)) { - let args = ctx.state.command.splitArgs - let chatId = ctx.message.chat.id - if (args[0] !== '') { - for (id in subscribeIdList) { - if (args[0] == id) { - ctx.replyWithSticker('https://data.gnehs.net/stickers/ohohoh.webp', { - reply_to_message_id: ctx.message.message_id - }) - telegram.sendChatAction(ctx.chat.id, "typing"); - // GitHub 檢查有沒有這個 Repo - if (id === 'github-release') { - let testFetch = await fetch(`https://api.github.com/repos/${args[1]}/releases`).then(res => res.json()) - if (testFetch.message) - return ctx.replyWithMarkdown(`❌ 無法訂閱「${subscribeIdList[id]}」,請確定 Repo 名稱是否正確。\n錯誤訊息:\`${testFetch.message}\``, { reply_to_message_id: ctx.message.message_id }) - } - subscribe(id, args[1] || null, chatId) - ctx.replyWithMarkdown(`🎉 已訂閱「${subscribeIdList[id]}」,使用 \`/unsubscribe ${id}${args[1] ? ' ' + args[1] : ''}\` 來取消訂閱。`, { reply_to_message_id: ctx.message.message_id }) - console.log(`[Subscribe] ${ctx.from.username}(${ctx.from.id}) subscribe ${id}`, `${args[1] || ''} in ${ctx.chat.id}(${ctx.chat.title || ctx.from.first_name})`) - } - } - } else { - ctx.reply(`❌ 請在後面加上訂閱編號`, { reply_to_message_id: ctx.message.message_id }) - } - } else { - ctx.reply(`❌ 只有管理員能使用此指令`, { reply_to_message_id: ctx.message.message_id }) - } - } catch (e) { - console.log(e) - } -}) -bot.command('unsubscribe', async ctx => { - try { - if (await isAdmin(ctx)) { - let args = ctx.state.command.splitArgs - let chatId = ctx.message.chat.id - if (args[0] !== '') { - for (id in subscribeIdList) { - if (args[0] == id) { - ctx.replyWithSticker('https://data.gnehs.net/stickers/bye.webp', { reply_to_message_id: ctx.message.message_id }) - telegram.sendChatAction(ctx.chat.id, "typing"); - unsubscribe(id, args[1] || null, chatId) - ctx.replyWithMarkdown(`👋 取消訂閱「${subscribeIdList[id]}」成功。`, { reply_to_message_id: ctx.message.message_id }) - console.log(`[Unsubscribe] ${ctx.from.username}(${ctx.from.id}) unsubscribe ${id}`, `${args[1] || ''} in ${ctx.chat.id}(${ctx.chat.title || ctx.from.first_name})`) - } - } - } else { - ctx.reply(`❌ 請在後面加上訂閱編號`, { reply_to_message_id: ctx.message.message_id }) - } - } else { - ctx.reply(`❌ 只有管理員能使用此指令`, { reply_to_message_id: ctx.message.message_id }) - } - } catch (e) { - console.log(e) - } -}) -module.exports = bot \ No newline at end of file +bot.command("subscribe", async (ctx) => { + try { + if (await isAdmin(ctx)) { + let args = ctx.state.command.splitArgs; + let chatId = ctx.message.chat.id; + if (args[0] !== "") { + for (id in subscribeIdList) { + if (args[0] == id) { + ctx.replyWithSticker( + "https://data.gnehs.net/stickers/ohohoh.webp", + { + reply_to_message_id: ctx.message.message_id, + } + ); + telegram.sendChatAction(ctx.chat.id, "typing"); + // GitHub 檢查有沒有這個 Repo + if (id === "github-release") { + let testFetch = await fetch( + `https://api.github.com/repos/${args[1]}/releases` + ).then((res) => res.json()); + if (testFetch.message) + return ctx.replyWithMarkdown( + `❌ 無法訂閱「${subscribeIdList[id]}」,請確定 Repo 名稱是否正確。\n錯誤訊息:\`${testFetch.message}\``, + { reply_to_message_id: ctx.message.message_id } + ); + } + subscribe(id, args[1] || null, chatId); + ctx.replyWithMarkdown( + `🎉 已訂閱「${subscribeIdList[id]}」,使用 \`/unsubscribe ${id}${ + args[1] ? " " + args[1] : "" + }\` 來取消訂閱。`, + { reply_to_message_id: ctx.message.message_id } + ); + console.log( + `[Subscribe] ${ctx.from.username}(${ctx.from.id}) subscribe ${id}`, + `${args[1] || ""} in ${ctx.chat.id}(${ + ctx.chat.title || ctx.from.first_name + })` + ); + } + } + } else { + ctx.reply(`❌ 請在後面加上訂閱編號`, { + reply_to_message_id: ctx.message.message_id, + }); + } + } else { + ctx.reply(`❌ 只有管理員能使用此指令`, { + reply_to_message_id: ctx.message.message_id, + }); + } + } catch (e) { + console.log(e); + } +}); +bot.command("unsubscribe", async (ctx) => { + try { + if (await isAdmin(ctx)) { + let args = ctx.state.command.splitArgs; + let chatId = ctx.message.chat.id; + if (args[0] !== "") { + for (id in subscribeIdList) { + if (args[0] == id) { + ctx.replyWithSticker("https://data.gnehs.net/stickers/bye.webp", { + reply_to_message_id: ctx.message.message_id, + }); + telegram.sendChatAction(ctx.chat.id, "typing"); + unsubscribe(id, args[1] || null, chatId); + ctx.replyWithMarkdown( + `👋 取消訂閱「${subscribeIdList[id]}」成功。`, + { reply_to_message_id: ctx.message.message_id } + ); + console.log( + `[Unsubscribe] ${ctx.from.username}(${ctx.from.id}) unsubscribe ${id}`, + `${args[1] || ""} in ${ctx.chat.id}(${ + ctx.chat.title || ctx.from.first_name + })` + ); + } + } + } else { + ctx.reply(`❌ 請在後面加上訂閱編號`, { + reply_to_message_id: ctx.message.message_id, + }); + } + } else { + ctx.reply(`❌ 只有管理員能使用此指令`, { + reply_to_message_id: ctx.message.message_id, + }); + } + } catch (e) { + console.log(e); + } +}); +module.exports = bot; diff --git a/components/subscribe/manage.js b/components/subscribe/manage.js index 30bb3a7..5c9b4d0 100644 --- a/components/subscribe/manage.js +++ b/components/subscribe/manage.js @@ -1,53 +1,55 @@ -const db = require('../db') -const telegram = require('../telegram') +const db = require("../db"); +const telegram = require("../telegram"); function subscribe(key, value, id) { - key = 'subscribe.' + key - let subscribe_list = db.get(key) || {} - if (value) { - if (!subscribe_list[value]) subscribe_list[value] = {} - subscribe_list[value][id] = true - } else { - subscribe_list[id] = value || true - } - db.set(key, subscribe_list); + key = "subscribe." + key; + let subscribe_list = db.get(key) || {}; + if (value) { + if (!subscribe_list[value]) subscribe_list[value] = {}; + subscribe_list[value][id] = true; + } else { + subscribe_list[id] = value || true; + } + db.set(key, subscribe_list); } function unsubscribe(key, value, id) { - key = 'subscribe.' + key - let subscribe_list = db.get(key) || {} - if (value) { - if (!subscribe_list[value]) subscribe_list[value] = {} - delete subscribe_list[value][id] - if (!subscribe_list[value].length) - delete subscribe_list[value] - } else { - delete subscribe_list[id] - } - db.set(key, subscribe_list); + key = "subscribe." + key; + let subscribe_list = db.get(key) || {}; + if (value) { + if (!subscribe_list[value]) subscribe_list[value] = {}; + delete subscribe_list[value][id]; + if (!subscribe_list[value].length) delete subscribe_list[value]; + } else { + delete subscribe_list[id]; + } + db.set(key, subscribe_list); } async function sendMessage({ chats, message, imgs = [], key, value }) { - console.log(`[Notify][${key}${value ? `#${value}` : ''}] Sending messages to:`, chats) - for (chat of chats) { - try { - if (imgs.length) { - await telegram.sendMediaGroup(chat, imgs, { - parse_mode: "html", - disable_web_page_preview: true - }) - } else { - await telegram.sendMessage(chat, message, { - parse_mode: "html", - disable_web_page_preview: true - }) - } - } catch (e) { - console.log(e) - unsubscribe(key, value, chat) - } - } + console.log( + `[Notify][${key}${value ? `#${value}` : ""}] Sending messages to:`, + chats + ); + for (chat of chats) { + try { + if (imgs.length) { + await telegram.sendMediaGroup(chat, imgs, { + parse_mode: "html", + disable_web_page_preview: true, + }); + } else { + await telegram.sendMessage(chat, message, { + parse_mode: "html", + disable_web_page_preview: true, + }); + } + } catch (e) { + console.log(e); + unsubscribe(key, value, chat); + } + } } module.exports = { - subscribe, - unsubscribe, - sendMessage -}; \ No newline at end of file + subscribe, + unsubscribe, + sendMessage, +}; diff --git a/components/telegram.js b/components/telegram.js index e42b078..bc102a5 100644 --- a/components/telegram.js +++ b/components/telegram.js @@ -1,3 +1,3 @@ -const Telegram = require('telegraf/telegram') -const telegram = new Telegram(process.env.BOT_TOKEN) -module.exports = telegram \ No newline at end of file +const Telegram = require("telegraf/telegram"); +const telegram = new Telegram(process.env.BOT_TOKEN); +module.exports = telegram;