feat: enhance download feature with caption support for Instagram
This commit is contained in:
parent
ce78952fec
commit
6e9d2e9b9e
@ -1,3 +1,4 @@
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
/* eslint-disable consistent-return */
|
||||
import { type Context } from '../context';
|
||||
import { logHandle } from '../helpers/logging';
|
||||
@ -7,6 +8,7 @@ import { getRedisInstance } from '@/utils/redis';
|
||||
import { getTiktokDownloadUrl } from '@/utils/tiktok';
|
||||
import { validateInstagramUrl, validateTikTokUrl, validateYoutubeUrl } from '@/utils/urls';
|
||||
import { getYoutubeDownloadUrl } from '@/utils/youtube';
|
||||
import { expandableBlockquote, fmt } from '@grammyjs/parse-mode';
|
||||
import { Composer, InputFile } from 'grammy';
|
||||
import { cluster } from 'radashi';
|
||||
|
||||
@ -15,6 +17,10 @@ const feature = composer.chatType('private');
|
||||
|
||||
const redis = getRedisInstance();
|
||||
|
||||
function formatCaption(caption: string) {
|
||||
return fmt`${expandableBlockquote} ${caption} ${expandableBlockquote}`;
|
||||
}
|
||||
|
||||
feature.on('message:text', logHandle('download-message'), async (context) => {
|
||||
const url = context.message.text.trim();
|
||||
|
||||
@ -29,22 +35,36 @@ feature.on('message:text', logHandle('download-message'), async (context) => {
|
||||
}
|
||||
|
||||
const cachedFileId = await redis.get(url);
|
||||
let cachedMessageId: number | undefined;
|
||||
if (cachedFileId) {
|
||||
return context.replyWithVideo(cachedFileId);
|
||||
const cachedMessage = await context.replyWithVideo(cachedFileId);
|
||||
cachedMessageId = cachedMessage.message_id;
|
||||
}
|
||||
|
||||
const cachedCaption = await redis.get(`caption:${url}`);
|
||||
if (cachedCaption) {
|
||||
const { entities, text } = formatCaption(cachedCaption);
|
||||
return context.reply(text, {
|
||||
entities,
|
||||
reply_parameters: cachedMessageId ? { message_id: cachedMessageId } : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
let imagesUrls: string[] | undefined;
|
||||
let videoUrl: string | undefined;
|
||||
let caption: string | undefined;
|
||||
|
||||
try {
|
||||
if (isTikTok) {
|
||||
const result = await getTiktokDownloadUrl(url);
|
||||
imagesUrls = result.images;
|
||||
videoUrl = result.play;
|
||||
caption = result.title;
|
||||
} else if (isInstagram) {
|
||||
const result = await getInstagramDownloadUrl(url);
|
||||
imagesUrls = result.images;
|
||||
videoUrl = result.play;
|
||||
caption = result.caption;
|
||||
} else if (isYoutube) {
|
||||
const result = await getYoutubeDownloadUrl(url);
|
||||
videoUrl = result.play;
|
||||
@ -63,21 +83,37 @@ feature.on('message:text', logHandle('download-message'), async (context) => {
|
||||
return context.reply(context.t('err-invalid-download-urls'));
|
||||
}
|
||||
|
||||
let contentMessageId: number | undefined;
|
||||
|
||||
if (imagesUrls?.length) {
|
||||
const chunks = cluster(imagesUrls, 10);
|
||||
for (const chunk of chunks) {
|
||||
await context.replyWithMediaGroup(
|
||||
const imageMessages = await context.replyWithMediaGroup(
|
||||
chunk.map((imageUrl) => ({ media: imageUrl, type: 'photo' })),
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
if (!contentMessageId && imageMessages.length) {
|
||||
contentMessageId = imageMessages.at(0)?.message_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (videoUrl) {
|
||||
const { video } = await context.replyWithVideo(new InputFile({ url: videoUrl }));
|
||||
const { video, ...videoMessage } = await context.replyWithVideo(
|
||||
new InputFile({ url: videoUrl }),
|
||||
);
|
||||
contentMessageId = videoMessage.message_id;
|
||||
await redis.set(url, video.file_id, 'EX', TTL_URLS);
|
||||
}
|
||||
|
||||
if (caption) {
|
||||
const { entities, text } = formatCaption(caption);
|
||||
await redis.set(`caption:${url}`, caption, 'EX', TTL_URLS);
|
||||
await context.reply(text, {
|
||||
entities,
|
||||
reply_parameters: contentMessageId ? { message_id: contentMessageId } : undefined,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export { composer as download };
|
||||
|
||||
@ -14,6 +14,7 @@ export type CarouselItem = {
|
||||
|
||||
export type Root = {
|
||||
authorInfo: AuthorInfo;
|
||||
caption: string;
|
||||
carouselItems: CarouselItem[];
|
||||
id: number;
|
||||
mediaUrls: string[];
|
||||
@ -31,15 +32,9 @@ export async function getInstagramDownloadUrl(url: string) {
|
||||
|
||||
const isVideo = data.type === 'video' || !data.carouselItems.length;
|
||||
|
||||
if (isVideo) {
|
||||
return {
|
||||
images: [],
|
||||
play: data.mediaUrls.at(0),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
images: data.mediaUrls,
|
||||
play: undefined,
|
||||
caption: data.caption,
|
||||
images: isVideo ? undefined : data.mediaUrls,
|
||||
play: isVideo ? data.mediaUrls.at(0) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user