From 9aeec1f2f2205dd050063087592ceba0eb716d20 Mon Sep 17 00:00:00 2001 From: Okabe Rintaro Date: Wed, 6 Feb 2019 15:39:59 +0200 Subject: [PATCH] v2.0.9 --- actions/chapter-page.js | 11 +- actions/choosen-inline-query.js | 10 ++ actions/index.js | 1 + actions/inline-query.js | 21 +++- actions/user-reading-list.js | 3 + commands/get-cache-pool.js | 76 ++++++++++++++ commands/index.js | 1 + core/database/index.js | 2 +- lib/cache-file.js | 60 ----------- lib/get-files.js | 181 ++++++++++++++++---------------- lib/telegraph-upload.js | 67 ++++++++++++ lib/template.js | 4 +- package.json | 2 +- 13 files changed, 280 insertions(+), 159 deletions(-) create mode 100644 actions/choosen-inline-query.js create mode 100644 actions/user-reading-list.js create mode 100644 commands/get-cache-pool.js delete mode 100644 lib/cache-file.js create mode 100644 lib/telegraph-upload.js diff --git a/actions/chapter-page.js b/actions/chapter-page.js index cb919a2..af764e1 100644 --- a/actions/chapter-page.js +++ b/actions/chapter-page.js @@ -15,10 +15,19 @@ composer.action([ const copy = ctx.match[3] === 'true' const offset = ctx.match[4] const history = ctx.match[5] + if (getFiles.getCacheBlockingValue()) { + return ctx.answerCbQuery( + `Sorry, caching isn't available right now.\nThis can be because of bot update or malfunction.`, + true, + { cache_time: 10 } + ) + } let chapter = await getChapter(chapterId) const manga = await getManga(chapter.manga_id, false) chapter = await getFiles(chapter, manga, ctx, offset, history) - if (!chapter) { return ctx.answerCbQuery('') } + if (!chapter) { + return ctx.answerCbQuery('') + } const keyboard = [ [ { diff --git a/actions/choosen-inline-query.js b/actions/choosen-inline-query.js new file mode 100644 index 0000000..aabc3bb --- /dev/null +++ b/actions/choosen-inline-query.js @@ -0,0 +1,10 @@ +const { Composer } = require('telegraf').default +const composer = new Composer() + +// composer.on('chosen_inline_result', async ctx => { +// console.log(ctx.update.chosen_inline_result) +// }) + +module.exports = app => { + app.use(composer.middleware()) +} diff --git a/actions/index.js b/actions/index.js index ee45059..58d03e8 100644 --- a/actions/index.js +++ b/actions/index.js @@ -6,4 +6,5 @@ module.exports = app => { require('./chapter-list')(app) require('./delete')(app) require('./mark-as-read')(app) + require('./choosen-inline-query')(app) } diff --git a/actions/inline-query.js b/actions/inline-query.js index c04eef8..12ab902 100644 --- a/actions/inline-query.js +++ b/actions/inline-query.js @@ -127,10 +127,18 @@ composer.on('inline_query', async ctx => { }, reply_markup: { inline_keyboard: [ - [{ - text: 'Read manga', - url: `https://t.me/${ctx.me}?start=${buffer.encode(`manga:${title.id}`)}` - }] + [ + { + text: 'Read manga', + url: `https://t.me/${ctx.me}?start=${buffer.encode(`manga:${title.id}`)}` + } + ] + // ,[ + // { + // text: 'Want to read', + // callback_data: `test:1` + // } + // ] ] }, thumb_url: title.image_url @@ -143,6 +151,11 @@ composer.on('inline_query', async ctx => { } }) +// composer.action(/test:(\S+)/i, async ctx => { +// console.log(ctx.update) +// ctx.answerCbQuery('Hello there!') +// }) + module.exports = app => { app.use(composer.middleware()) } diff --git a/actions/user-reading-list.js b/actions/user-reading-list.js new file mode 100644 index 0000000..e41e1b7 --- /dev/null +++ b/actions/user-reading-list.js @@ -0,0 +1,3 @@ +const Composer = require('telegraf/composer') +const composer = new Composer() +const getFiles = require('../lib/get-files') \ No newline at end of file diff --git a/commands/get-cache-pool.js b/commands/get-cache-pool.js new file mode 100644 index 0000000..58ce088 --- /dev/null +++ b/commands/get-cache-pool.js @@ -0,0 +1,76 @@ +const Composer = require('telegraf/composer') +const composer = new Composer() +const getFiles = require('../lib/get-files') + +composer.command('pool', async ctx => { + if (ctx.from.id === Number.parseInt(process.env.ADMIN_ID)) { + ctx.reply(`Here's ${Object.keys(getFiles.cachePool()).length} chapters waiting to be cached.`, { + reply_markup: { + inline_keyboard: cacheKeyboard( + getFiles.getCacheBlockingValue(), + getFiles.getUpdateCachingBlockingValue() + ) + } + }) + } +}) +composer.action(/^cachepool=(\S+)$/i, async ctx => { + if (ctx.from.id === Number.parseInt(process.env.ADMIN_ID)) { + switch (ctx.match[1]) { + case 'on': + getFiles.setCachingBlocking(true) + break + case 'off': + getFiles.setCachingBlocking(false) + break + } + ctx.editMessageReplyMarkup({ + inline_keyboard: cacheKeyboard( + getFiles.getCacheBlockingValue(), + getFiles.getUpdateCachingBlockingValue() + ) + }) + } else { + return ctx.editMessageReplyMarkup({ inline_keyboard: [] }) + } +}) + +composer.action(/^updatecache=(\S+)$/i, async ctx => { + if (ctx.from.id === Number.parseInt(process.env.ADMIN_ID)) { + switch (ctx.match[1]) { + case 'on': + getFiles.setUpdateCachingBlocking(true) + break + case 'off': + getFiles.setUpdateCachingBlocking(false) + break + } + ctx.editMessageReplyMarkup({ + inline_keyboard: cacheKeyboard( + getFiles.getCacheBlockingValue(), + getFiles.getUpdateCachingBlockingValue() + ) + }) + } else { + return ctx.editMessageReplyMarkup({ inline_keyboard: [] }) + } +}) + +module.exports = app => { + app.use(composer.middleware()) +} + +function cacheKeyboard (cacheBlock, updateBlock) { + return [ + [ + { + text: `${cacheBlock ? 'Enable' : 'Disable'} caching`, + callback_data: `cachepool=${cacheBlock ? 'off' : 'on'}` + }, + { + text: `${updateBlock ? 'Enable' : 'Disable'} updating`, + callback_data: `updatecache=${updateBlock ? 'off' : 'on'}` + } + ] + ] +} diff --git a/commands/index.js b/commands/index.js index 8cadfc8..8883af7 100644 --- a/commands/index.js +++ b/commands/index.js @@ -1,4 +1,5 @@ module.exports = app => { require('./start')(app) require('./search')(app) + require('./get-cache-pool')(app) } diff --git a/core/database/index.js b/core/database/index.js index eac7e56..20d0a6c 100644 --- a/core/database/index.js +++ b/core/database/index.js @@ -131,4 +131,4 @@ module.exports = collectionName => { } else { throw new Error('Collection not found') } -} \ No newline at end of file +} diff --git a/lib/cache-file.js b/lib/cache-file.js deleted file mode 100644 index 0351323..0000000 --- a/lib/cache-file.js +++ /dev/null @@ -1,60 +0,0 @@ -const Telegraph = require('telegra.ph') -const client = new Telegraph(process.env.TELEGRAPH_TOKEN) -const buffer = require('./buffer') -const getGroupName = require('./get-group-name') -module.exports.telegraph = async (chapter, manga, images, botUsername) => { - const imageList = images.map(el => ({ - tag: 'img', - attrs: { - src: `https://telegra.ph${el}` - } - })) - - const mangaTitle = manga.manga.title - - return client.createPage( - `Chapter ${chapter.id}${chapter.title ? ` "${chapter.title}"` : ''}`, - [{ - tag: 'h1', - children: [`${mangaTitle} ${chapter.volume ? `Vol. ${chapter.volume} ` : ''}Ch. ${chapter.chapter}`] - }, { - tag: 'br' - }, { - tag: 'a', - children: ['Manga description on '] - }, { - tag: 'a', - attrs: { - href: `https://mangadex.org/title/${chapter.manga_id}` - }, - children: ['Mangadex'] - }, { - tag: 'a', - children: [' and in '] - }, { - tag: 'a', - attrs: { - href: `https://t.me/${botUsername}?start=${buffer.encode(`manga:${chapter.manga_id}`)}` - }, - children: ['Mangadex bot'] - }, { - tag: 'br' - }, { - tag: 'a', - attrs: { - href: `https://` - } - }, { - tag: 'br' - }, { - tag: 'a', - attrs: { - href: `https://mangadex.org/chapter/${chapter.id}` - }, - children: ['This chapter on Mangadex'] - }].concat(imageList), - 'Mangadex bot', - 'https://t.me/mymanga_bot', - true - ) -} diff --git a/lib/get-files.js b/lib/get-files.js index 716335b..e180f5b 100644 --- a/lib/get-files.js +++ b/lib/get-files.js @@ -1,46 +1,32 @@ const axios = require('axios').default const collection = require('../core/database') -const cacheFile = require('./cache-file') +const telegraphUpload = require('./telegraph-upload') const sharp = require('sharp') const FormData = require('form-data') -const cachePoll = {} -const updatePoll = {} // soon +let blockCaching = false +let blockUpdateCache = false + +const cachePool = {} +const updatePool = {} module.exports = async (chapter, manga, ctx, offset = 0, history = 'p=1:o=0') => { - const cachedData = await collection('chapters').findOne({ id: chapter.id }).exec() - if (cachedData) { - if (cachedData.timestamp === chapter.timestamp) { - chapter.telegraph = cachedData.telegraph + const cachedChapter = await collection('chapters').findOne({ id: chapter.id }).exec() + if (cachedChapter) { + if (cachedChapter.timestamp === chapter.timestamp) { + chapter.telegraph = cachedChapter.telegraph return chapter } else { - // This needs to send chapter to user immediately return new Promise(async (resolve) => { - chapter.telegraph = cachedData.telegraph + chapter.telegraph = cachedChapter.telegraph resolve(chapter) - if (updatePoll[chapter.id]) return - else { updatePoll[chapter.id] = true } - const pics = [] - // console.log(`${chapter.server}${chapter.hash}/${img}`) - for (const img of chapter.page_array) { - const buffer = await downloadImage(img) - // console.log(img) - const pic = sharp(buffer) - const meta = await pic.metadata() - let picEdited = false - if (meta.size > 5 * 1e6) { - pic.resize(1500) - var picBuff = await pic.toBuffer() - picEdited = true - } - const file = await uploadFile({ name: img, file: picEdited ? picBuff : buffer }) - // console.log(file) - pics.push(file[0].src) - // const { photo } = await cacheFile(picEdited ? await pic.toBuffer() : buffer) - // fileIds.push(photo[photo.length - 1].file_id) + if (updatePool[chapter.id]) { + return + } else { + if (blockUpdateCache) { return } + updatePool[chapter.id] = true } - const telegraphPage = await cacheFile.telegraph(chapter, pics, ctx.me) - // console.log(telegraphPage) + const telegraphPage = await uploadChapter(chapter, ctx.me) await collection('chapters').updateOne({ id: chapter.id }, { @@ -52,6 +38,9 @@ module.exports = async (chapter, manga, ctx, offset = 0, history = 'p=1:o=0') => }) } } else { + if (blockCaching) { + return null + } try { await ctx.answerCbQuery( 'This chapter has been not cached yet, I\'ll let you know when it will be ready!\nUsually it takes ~1 min to cache all pages.', @@ -61,40 +50,21 @@ module.exports = async (chapter, manga, ctx, offset = 0, history = 'p=1:o=0') => } ) } catch (e) {} - if (cachePoll[chapter.id]) { - if (!cachePoll[chapter.id].find(el => el.userId === ctx.from.id)) { - cachePoll[chapter.id].push({ + if (cachePool[chapter.id]) { + if (!cachePool[chapter.id].some(el => el.userId === ctx.from.id)) { + cachePool[chapter.id].push({ userId: ctx.from.id }) } return null } - cachePoll[chapter.id] = [{ - userId: ctx.from.id - }] - // console.log(chapter) - const pics = [] - for (const img of chapter.page_array) { - // console.log(`${chapter.server}${chapter.hash}/${img}`) - const buffer = await downloadImage(img) - // console.log(img) - const pic = sharp(buffer) - const meta = await pic.metadata() - let picEdited = false - if (meta.size > 5 * 1e6) { - pic.resize(1500) - var picBuff = await pic.toBuffer() - picEdited = true + cachePool[chapter.id] = [ + { + userId: ctx.from.id } - const file = await uploadFile({ name: img, file: picEdited ? picBuff : buffer }) - // console.log(file) - pics.push(file[0].src) - // const { photo } = await cacheFile(picEdited ? await pic.toBuffer() : buffer) - // fileIds.push(photo[photo.length - 1].file_id) - } - const telegraphPage = await cacheFile.telegraph(chapter, manga, pics, ctx.me) - // console.log(telegraphPage) + ] + const telegraphPage = await uploadChapter(chapter, manga, ctx.me) await collection('chapters').create({ id: chapter.id, telegraph: telegraphPage.url, @@ -103,45 +73,51 @@ module.exports = async (chapter, manga, ctx, offset = 0, history = 'p=1:o=0') => manga_title: manga.manga.title }) chapter.telegraph = telegraphPage.url - await Promise.all( - cachePoll[chapter.id] - .map(el => - ctx.telegram.sendMessage( - el.userId, - `${chapter.volume ? `Vol. ${chapter.volume} ` : ''}Chapter ${chapter.chapter} ready for reading!`, - { - reply_to_message_id: ctx.callbackQuery.message.message_id, - reply_markup: { - inline_keyboard: [ - [ - { - text: 'Ok!', - callback_data: 'delete' - } - ], - [ - { - text: 'Load chapter!', - callback_data: `chapter=${chapter.id}:read=false:copy=true:offset=${offset}:${history}` - } - ] - ] - } - } - ) - ) + for (const promise of cachePool[chapter.id].map(el => + ctx.telegram.sendMessage( + el.userId, + `${chapter.volume ? `Vol. ${chapter.volume} ` : ''}Chapter ${chapter.chapter} ready for reading!`, + { + reply_to_message_id: ctx.callbackQuery.message.message_id, + reply_markup: { + inline_keyboard: [ + [ + { + text: 'Ok!', + callback_data: 'delete' + }, + { + text: 'Load chapter', + callback_data: `chapter=${chapter.id}:read=false:copy=true:offset=${offset}:${history}` + } + ] + ] + } + } + ) ) + ) { + try { + await promise + } catch (e) {} + } return null } } -module.exports.cachePoll = () => cachePoll -module.exports.updatePoll = () => updatePoll +module.exports.cachePool = () => cachePool +module.exports.updatePool = () => updatePool +module.exports.getCacheBlockingValue = () => blockCaching +module.exports.setCachingBlocking = value => { + blockCaching = value +} +module.exports.getUpdateCachingBlockingValue = () => blockUpdateCache +module.exports.setUpdateCachingBlocking = value => { + blockUpdateCache = value +} async function downloadImage (url) { - const response = await axios({ - url, - method: 'GET', + const response = await axios.get(url, { responseType: 'arraybuffer' }) @@ -165,3 +141,28 @@ async function uploadFile (file) { }) }) } + +async function uploadChapter (chapter, manga, me) { + const pics = [] + for (const img of chapter.page_array) { + const buffer = await downloadImage(img) + const pic = sharp(buffer) + const meta = await pic.metadata() + let picEdited = false + if (meta.size > 5 * 1e6) { + pic.resize(1500) + var picBuff = await pic.toBuffer() + picEdited = true + } + let file + try { + file = await uploadFile({ name: img, file: picEdited ? picBuff : buffer }) + } catch (e) { + pic.resize(1280) + picBuff = await pic.toBuffer() + file = await uploadFile({ name: img, file: picBuff }) + } + pics.push(file[0].src) + } + return telegraphUpload(chapter, manga, pics, me) +} diff --git a/lib/telegraph-upload.js b/lib/telegraph-upload.js new file mode 100644 index 0000000..93f8169 --- /dev/null +++ b/lib/telegraph-upload.js @@ -0,0 +1,67 @@ +const Telegraph = require('telegra.ph') +const client = new Telegraph(process.env.TELEGRAPH_TOKEN) +const buffer = require('./buffer') +// const getGroupName = require('./get-group-name') +module.exports = async (chapter, manga, images, botUsername) => { + const imageList = images.map(el => + ({ + tag: 'img', + attrs: { + src: `https://telegra.ph${el}` + } + }) + ) + + const mangaTitle = manga.manga.title + + return client.createPage( + `Chapter ${chapter.id}${chapter.title ? ` "${chapter.title}"` : ''}`, + [ + { + tag: 'h1', + children: [ + `${mangaTitle} ${chapter.volume ? `Vol. ${chapter.volume} ` : ''}Ch. ${chapter.chapter}` + ] + }, { + tag: 'br' + }, { + tag: 'a', + children: [ + 'Manga description on ' + ] + }, { + tag: 'a', + attrs: { + href: `https://mangadex.org/title/${chapter.manga_id}` + }, + children: [ + 'Mangadex' + ] + }, { + tag: 'a', + children: [ + ' and in ' + ] + }, { + tag: 'a', + attrs: { + href: `https://t.me/${botUsername}?start=${buffer.encode(`manga:${chapter.manga_id}`)}` + }, + children: [ + 'Mangadex bot' + ] + }, { + tag: 'br' + }, { + tag: 'a', + attrs: { + href: `https://mangadex.org/chapter/${chapter.id}` + }, + children: ['This chapter on Mangadex'] + } + ].concat(imageList), + 'Mangadex bot', + 'https://t.me/mymanga_bot', + true + ) +} diff --git a/lib/template.js b/lib/template.js index 00dccf5..398d625 100644 --- a/lib/template.js +++ b/lib/template.js @@ -20,8 +20,8 @@ const templates = { }, chapter (chapter, manga = null, message = null) { let messageText = `${chapter.telegraph ? `` : ''}Read on Mangadex\n` - messageText += `${decode(manga.manga.title)} ${chapter.volume ? `Vol. ${chapter.volume} ` : ''}Ch. ${chapter.chapter}\n` - messageText += `${chapter.title ? `\nChapter title: ${chapter.title}` : ''}\n${message ? storeHistory(message) : ''}` + messageText += `${decode(manga.manga.title)} ${chapter.volume ? `Vol. ${chapter.volume} ` : ''}Ch. ${chapter.chapter}` + messageText += `${chapter.title ? `\n\nChapter title: ${chapter.title}` : ''}\n${message ? storeHistory(message) : ''}` return messageText }, // inlineChapterView (chapterId, chapter) { diff --git a/package.json b/package.json index 5364317..d724ea8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mangadex_bot", - "version": "2.0.8", + "version": "2.0.9", "description": "telegram-bot for reading manga on mangadex right in telegram", "main": "app.js", "dependencies": {