From c8c5c7bff1cfb432fae7e88e8e6e13e943a6bbcb Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Thu, 6 May 2021 10:47:06 +0700 Subject: [PATCH] #4 added photo thumbs for posts --- package.json | 5 +- src/service/telegram/index.ts | 19 +++++- src/service/vk/handlers/PostNewHandler.ts | 71 ++++++++++++++++++----- templates/post_new.md | 2 +- yarn.lock | 28 ++++++++- 5 files changed, 107 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 10ba394..4f4b57d 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "build": "rm -rf ./dist && tsc && copyfiles -f ./config*.yml ./dist && copyfiles ./templates/*.md ./dist" }, "dependencies": { - "@types/node": "^14.14.37", + "axios": "^0.21.1", + "cross-fetch": "^3.1.4", "express": "^4.17.1", "handlebars": "^4.7.7", "http": "^0.0.1-security", @@ -37,6 +38,8 @@ "yup": "^0.32.9" }, "devDependencies": { + "@types/axios": "^0.14.0", + "@types/node": "^14.14.37", "@types/express": "^4.17.11", "@types/handlebars": "^4.1.0", "@types/ramda": "^0.27.39", diff --git a/src/service/telegram/index.ts b/src/service/telegram/index.ts index 498d8ca..efb149f 100644 --- a/src/service/telegram/index.ts +++ b/src/service/telegram/index.ts @@ -2,9 +2,10 @@ import { TelegramConfig, WebhookConfig } from "./types"; import { Telegraf } from "telegraf"; import logger from "../logger"; import { Response } from "express"; -import { Update } from "typegram"; +import { InputFile, Update } from "typegram"; import loggerTgMiddleware from "../logger/tg"; import { ExtraReplyMessage } from "telegraf/typings/telegram-types"; +import axios from "axios"; // import SocksProxyAgent from 'socks-proxy-agent'; @@ -87,4 +88,20 @@ export class TelegramService { logger.debug(`sending message "${message}" to chan "${channel}"`); return await this.bot.telegram.sendMessage(channel, message, extra); }; + + /** + * Sends simple message to channel + */ + public sendPhotoToChan = async ( + channel: string, + caption: string, + src: string, + extra?: ExtraReplyMessage + ) => { + logger.debug(`sending photo message "${caption}" to chan "${channel}"`); + return await this.bot.telegram.sendPhoto(channel, src, { + ...extra, + caption, + }); + }; } diff --git a/src/service/vk/handlers/PostNewHandler.ts b/src/service/vk/handlers/PostNewHandler.ts index e0f60e2..da35894 100644 --- a/src/service/vk/handlers/PostNewHandler.ts +++ b/src/service/vk/handlers/PostNewHandler.ts @@ -4,7 +4,12 @@ import { NextMiddleware } from "middleware-io"; import { UsersUserFull } from "vk-io/lib/api/schemas/objects"; import { ConfigGroup } from "../types"; import { ExtraReplyMessage } from "telegraf/typings/telegram-types"; -import { InlineKeyboardButton, InlineKeyboardMarkup, Update } from "typegram"; +import { + InlineKeyboardButton, + InlineKeyboardMarkup, + Message, + Update, +} from "typegram"; import { keys } from "ramda"; import { extractURLs } from "../../../utils/extract"; import logger from "../../logger"; @@ -34,6 +39,8 @@ interface Values { type LikeCtx = Composer.Context & { match: string[] }; +const PHOTO_CAPTION_LIMIT = 1000; + export class PostNewHandler extends VkEventHandler { constructor(...props: any) { // @ts-ignore @@ -70,22 +77,32 @@ export class PostNewHandler extends VkEventHandler { const text = context.wall.text.trim(); - const parsed = this.template.theme({ - user, - group: this.group, - text, - }); + const parsed = this.themeText(text, user); const extras: ExtraReplyMessage = { disable_web_page_preview: true, reply_markup: await this.createKeyboard(text), }; - const msg = await this.telegram.sendMessageToChan( - this.channel, - parsed, - extras - ); + let msg: Message; + + const images = context.wall.getAttachments("photo"); + const hasThumb = + this.template.fields.image && + images.length && + images.some((img) => img.mediumSizeUrl); + + if (hasThumb) { + const thumb = await images.find((img) => img.mediumSizeUrl); + msg = await this.telegram.sendPhotoToChan( + this.channel, + this.trimTextForPhoto(text, user), + thumb.mediumSizeUrl, + extras + ); + } else { + msg = await this.telegram.sendMessageToChan(this.channel, parsed, extras); + } const event = await this.createEvent( id, @@ -209,7 +226,7 @@ export class PostNewHandler extends VkEventHandler { /** * Reacts to like button press */ - onLikeAction = async (ctx: LikeCtx, next) => { + private onLikeAction = async (ctx: LikeCtx, next) => { const id = ctx.update.callback_query.message.message_id; const author = ctx.update.callback_query.from.id; const [, channel, emo] = ctx.match; @@ -257,7 +274,7 @@ export class PostNewHandler extends VkEventHandler { next(); }; - createOrUpdateLike = async ( + private createOrUpdateLike = async ( author: number, messageId: number, emo: string @@ -270,7 +287,33 @@ export class PostNewHandler extends VkEventHandler { ); }; - getLike = async (author: number, messageId: number) => { + private getLike = async (author: number, messageId: number) => { return await this.db.getLikeBy(this.channel, messageId, author); }; + + /** + * Applies template theming to photos + */ + private themeText = (text: string, user?: UsersUserFull): string => { + return this.template.theme({ + user, + group: this.group, + text, + }); + }; + + /** + * Calculates, how much should we cut off the text to match photo caption limitations + */ + private trimTextForPhoto = (text: string, user: UsersUserFull): string => { + // Full markup + const full = this.themeText(text, user); + // Rest info except text + const others = this.themeText("", user); + + // How much rest markup takes + const diff = full.length - others.length; + + return full.slice(0, PHOTO_CAPTION_LIMIT - diff); + }; } diff --git a/templates/post_new.md b/templates/post_new.md index a4df2df..5b1dd3f 100644 --- a/templates/post_new.md +++ b/templates/post_new.md @@ -17,5 +17,5 @@ {{text}} {{#if user}} -[{{user.first_name}} {{user.last_name}}](https://vk.com/id{{user.id}}) +-- [{{user.first_name}} {{user.last_name}}](https://vk.com/id{{user.id}}) {{/if}} diff --git a/yarn.lock b/yarn.lock index 7712e98..e3044ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,6 +23,13 @@ resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg== +"@types/axios@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@types/axios/-/axios-0.14.0.tgz#ec2300fbe7d7dddd7eb9d3abf87999964cafce46" + integrity sha1-7CMA++fX3d1+udOr+HmZlkyvzkY= + dependencies: + axios "*" + "@types/body-parser@*": version "1.19.0" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" @@ -236,6 +243,13 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= +axios@*, axios@^0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + bail@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" @@ -478,6 +492,13 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +cross-fetch@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" + integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== + dependencies: + node-fetch "2.6.1" + debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -648,6 +669,11 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== +follow-redirects@^1.10.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.0.tgz#f5d260f95c5f8c105894491feee5dc8993b402fe" + integrity sha512-0vRwd7RKQBTt+mgu87mtYeofLFZpTas2S9zY+jIeuLJMNvudIgF52nr19q40HOwH5RrhWIPuj9puybzSJiRrVg== + form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -1090,7 +1116,7 @@ nlcst-to-string@^2.0.0: resolved "https://registry.yarnpkg.com/nlcst-to-string/-/nlcst-to-string-2.0.4.tgz#9315dfab80882bbfd86ddf1b706f53622dc400cc" integrity sha512-3x3jwTd6UPG7vi5k4GEzvxJ5rDA7hVUIRNHPblKuMVP9Z3xmlsd9cgLcpAMkc5uPOBna82EeshROFhsPkbnTZg== -node-fetch@^2.6.1: +node-fetch@2.6.1, node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==