From c0c501dddebcbfeb4f018fb6bff827f484877ed5 Mon Sep 17 00:00:00 2001 From: michelkaporin Date: Wed, 4 Nov 2020 23:44:06 +0100 Subject: [PATCH] move from procedural to oo approach --- app.ts | 76 +++++------------------------------------------- bot.ts | 43 +++++++++++++++++++++++++++ package.json | 1 - tsconfig.json | 2 +- voices-loader.ts | 69 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 71 deletions(-) create mode 100644 bot.ts create mode 100644 voices-loader.ts diff --git a/app.ts b/app.ts index cff8ee9..46892ce 100644 --- a/app.ts +++ b/app.ts @@ -1,75 +1,13 @@ -import TelegramBot, { InlineQueryResultCachedVoice } from 'node-telegram-bot-api'; -import fs from 'fs'; -import { LocalVoiceMap, TelegramVoiceMap } from './types'; -import lodash from 'lodash'; -const { isEqual } = lodash; import dotenv from 'dotenv'; +import { BotWrapper } from './bot'; +import { VoicesLoader } from './voices-loader'; dotenv.config(); -const token = process.env.TELEGRAM_BOT_TOKEN as string; - -const localVoicesFilepath = './assets/local_voice_map.json'; -const localVoicesFile = fs.readFileSync(localVoicesFilepath, 'utf-8'); -const files: LocalVoiceMap = JSON.parse(localVoicesFile); // Create a bot that uses 'polling' to fetch new updates -const bot = new TelegramBot(token, { polling: true }); - -const voiceMapFilepath = './assets/telegram_voice_map.json'; -const voiceMapFile = fs.readFileSync(voiceMapFilepath, 'utf-8'); -const voiceMap: TelegramVoiceMap = JSON.parse(voiceMapFile); -const latestVoiceMap: TelegramVoiceMap = JSON.parse(voiceMapFile); - -for (const file of files.voices) { - const voice = voiceMap.voices.find(v => v.id === file.id); - - // Upload if voice doesn't exist - if (!voice) { - const data = fs.createReadStream(file.path); - const msg = await bot.sendVoice(459393176, data); // send to my chat id - - if (!msg.voice) { - throw Error("Did not get an expected file_id from Telegram"); - } - - latestVoiceMap.voices.push({ - id: file.id, - file_id: msg.voice.file_id, - title: file.title, - }); - } -} -if (!isEqual(voiceMap, latestVoiceMap)) { - fs.writeFileSync(voiceMapFilepath, JSON.stringify(latestVoiceMap), { encoding: 'utf-8' }); -} - -latestVoiceMap.voices = latestVoiceMap.voices.sort((a, b) => { - if (a.title > b.title) { - return 1; - } else if (a.title < b.title) { - return -1; - } - return 0; -}) - -bot.on('inline_query', async query => { - const inlineMsg = query.query.toLowerCase(); - let results = latestVoiceMap.voices; - - if (inlineMsg.length > 1) { - results = latestVoiceMap.voices.filter(v => v.title.toLowerCase().includes(inlineMsg)); - } - - if (results.length > 50) { - results = results.slice(0, 49); - } - - const voices = results.map(v => ({ - id: v.id, - title: v.title, - voice_file_id: v.file_id, - type: 'voice' - }) as InlineQueryResultCachedVoice); +const botWrapper = new BotWrapper(); +const bot = botWrapper.init(); +const loader = new VoicesLoader(bot); +const voiceMap = loader.load(); - bot.answerInlineQuery(query.id, voices); -}); \ No newline at end of file +botWrapper.bind(voiceMap); \ No newline at end of file diff --git a/bot.ts b/bot.ts new file mode 100644 index 0000000..54c80e8 --- /dev/null +++ b/bot.ts @@ -0,0 +1,43 @@ +import TelegramBot, { InlineQueryResultCachedVoice } from "node-telegram-bot-api"; +import { TelegramVoiceMap } from "./types"; + +export class BotWrapper { + + private bot?: TelegramBot; + private readonly token: string; + + constructor() { + this.token = process.env.TELEGRAM_BOT_TOKEN as string; + } + + init(): TelegramBot { + // Create a bot that uses 'polling' to fetch new updates + this.bot = new TelegramBot(this.token, { polling: true }); + return this.bot; + } + + async bind(voiceMap: Promise) { + const map = await voiceMap; + this.bot?.on('inline_query', async query => { + const inlineMsg = query.query.toLowerCase(); + let results = map.voices; + + if (inlineMsg.length > 1) { + results = map.voices.filter(v => v.title.toLowerCase().includes(inlineMsg)); + } + + if (results.length > 50) { + results = results.slice(0, 49); + } + + const voices = results.map(v => ({ + id: v.id, + title: v.title, + voice_file_id: v.file_id, + type: 'voice' + }) as InlineQueryResultCachedVoice); + + this.bot?.answerInlineQuery(query.id, voices); + }); + } +} \ No newline at end of file diff --git a/package.json b/package.json index 4486262..3481ba4 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ "lodash": "^4.17.20", "node-telegram-bot-api": "^0.50.0" }, - "type": "module", "devDependencies": { "@types/lodash": "^4.14.162", "tslint": "^6.1.3", diff --git a/tsconfig.json b/tsconfig.json index b3e1934..3ec0923 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ "target": "ES2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "esnext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ diff --git a/voices-loader.ts b/voices-loader.ts new file mode 100644 index 0000000..aa8a5d9 --- /dev/null +++ b/voices-loader.ts @@ -0,0 +1,69 @@ +import { LocalVoiceMap, TelegramVoiceMap } from "./types"; +import fs from 'fs'; +import TelegramBot from "node-telegram-bot-api"; +import { isEqual } from "lodash"; + +export class VoicesLoader { + private readonly localVoicesFilepath = './assets/local_voice_map.json'; + private readonly voiceMapFilepath = './assets/telegram_voice_map.json'; + private readonly myChatId = 459393176; + + private bot: TelegramBot; + + constructor(bot: TelegramBot) { + this.bot = bot; + } + + async load(): Promise { + const localVoicesFile = fs.readFileSync(this.localVoicesFilepath, 'utf-8'); + const files: LocalVoiceMap = JSON.parse(localVoicesFile); + + const voiceMapFile = fs.readFileSync(this.voiceMapFilepath, 'utf-8'); + const voiceMap: TelegramVoiceMap = JSON.parse(voiceMapFile); + const latestVoiceMap: TelegramVoiceMap = JSON.parse(voiceMapFile); + + await this.uploadNewVoices(files, voiceMap, latestVoiceMap); + + this.sortVoices(latestVoiceMap); + + return latestVoiceMap; + } + + private async uploadNewVoices(files: LocalVoiceMap, voiceMap: TelegramVoiceMap, newVoiceMap: TelegramVoiceMap) { + for (const file of files.voices) { + const voice = voiceMap.voices.find(v => v.id === file.id); + + // Upload if voice doesn't exist + if (!voice) { + const data = fs.createReadStream(file.path); + const msg = await this.bot.sendVoice(this.myChatId, data); // send to my chat id + + if (!msg.voice) { + throw Error("Did not get an expected file_id from Telegram"); + } + + newVoiceMap.voices.push({ + id: file.id, + file_id: msg.voice.file_id, + title: file.title, + }); + } + } + + // Persist new voice map + if (!isEqual(voiceMap, newVoiceMap)) { + fs.writeFileSync(this.voiceMapFilepath, JSON.stringify(newVoiceMap), { encoding: 'utf-8' }); + } + } + + private sortVoices(latestVoiceMap: TelegramVoiceMap) { + latestVoiceMap.voices = latestVoiceMap.voices.sort((a, b) => { + if (a.title > b.title) { + return 1; + } else if (a.title < b.title) { + return -1; + } + return 0; + }); + } +} \ No newline at end of file