-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbot.js
More file actions
338 lines (272 loc) · 11.8 KB
/
bot.js
File metadata and controls
338 lines (272 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
const { Telegraf, Markup } = require('telegraf');
const dotenv = require('dotenv');
const mongoose = require('mongoose');
const { Video } = require('./models/video'); // Assuming you have a Video model
dotenv.config();
let dbConnection;
const connectToMongoDB = async () => {
if (!dbConnection) {
try {
dbConnection = await mongoose.connect(process.env.MONGODB_URI);
console.log('Connected to MongoDB');
} catch (err) {
console.error('Failed to connect to MongoDB:', err);
}
}
return dbConnection;
};
connectToMongoDB(); // Ensure the connection is established when the bot is initialized
const bot = new Telegraf(process.env.TELEGRAM_BOT_TOKEN);
// Function to convert bytes to MB
const bytesToMB = (bytes) => {
if (bytes === 0) return '0 MB';
const mb = bytes / (1024 * 1024);
return mb.toFixed(2) + ' MB';
};
// Function to truncate text to a specified length
const truncateText = (text, maxLength) => {
return text.length > maxLength ? text.substring(0, maxLength - 3) + "..." : text;
};
// Function to generate inline keyboard buttons for a specific page
const generateButtons = (videos, page, totalPages) => {
const maxButtonsPerPage = 8;
const startIndex = (page - 1) * maxButtonsPerPage;
const endIndex = Math.min(startIndex + maxButtonsPerPage, videos.length);
const buttons = videos.slice(startIndex, endIndex).map(video => {
const sizeMB = bytesToMB(video.size);
const truncatedCaption = truncateText(video.caption, 30); // Truncate the caption to 30 characters
const videoLink = `https://t.me/movie_cast_bot?start=watch_${video._id}`;
return [Markup.button.url(`${sizeMB != 'NaN MB' ? `[${sizeMB}]` : ''} ${truncatedCaption}`, videoLink)];
});
// Add navigation buttons if necessary
const navigationButtons = [];
if (page > 1) {
navigationButtons.push(Markup.button.callback('Prev 🢢', `prev_${page}`));
}
if (page < totalPages) {
navigationButtons.push(Markup.button.callback('Next 🢣', `next_${page}`));
}
if (navigationButtons.length > 0) {
buttons.push(navigationButtons);
}
return buttons;
};
// Function to delete messages after a specified time
const deleteMessageAfter = (ctx, messageId, seconds) => {
setTimeout(async () => {
try {
if (ctx.message && ctx.message.chat) {
await ctx.telegram.deleteMessage(ctx.message.chat.id, messageId);
} else {
console.warn('Message or chat is undefined. Cannot delete message.');
}
} catch (error) {
console.error('Error deleting message:', error);
}
}, seconds * 1000); // Convert seconds to milliseconds
};
// Handle /start command with specific video ID
bot.start(async (ctx) => {
const callbackData = ctx.update.message.text;
if (callbackData.startsWith('/start watch_')) {
const videoId = callbackData.split('_')[1]; // Extract video ID from the callback data
try {
const video = await Video.findById(videoId);
if (!video) {
ctx.reply(`Video with ID '${videoId}' not found.`);
return;
}
// Add "Join ➥ @moviecastback" to the end of the caption
const captionWithLink = `${video.caption}\n\nJoin ➥ @moviecastback`;
// Send the video file to the user
const sentMessage = await ctx.replyWithVideo(video.fileId, {
caption: captionWithLink,
parse_mode: 'HTML',
reply_markup: {
inline_keyboard: [
[
{ text: 'Watch Movie', url: `https://t.me/movie_cast_bot?start=watch_${videoId}` }
]
]
}
});
// Delete the message after 2 minutes
deleteMessageAfter(ctx, sentMessage.message_id, 120);
} catch (error) {
console.error(`Error fetching video with ID '${videoId}':`, error);
ctx.reply(`Failed to fetch video. Please try again later.`);
}
} else {
await ctx.reply("Welcome to Movie Cast Bot!", {
reply_markup: {
inline_keyboard: [
[
{ text: 'Go to Website', url: 'https://yourwebsite.com' },
{ text: 'View Movies', callback_data: 'view_movies' }
]
]
}
});
// Delete the message after 2 minutes
deleteMessageAfter(ctx, ctx.message.message_id, 120);
}
});
// Telegram bot handlers
bot.command("moviecounts", async (ctx) => {
try {
const count = await Video.countDocuments();
const sentMessage = await ctx.reply(`Total movies in the database: ${count}`);
// Delete the message after 2 minutes
deleteMessageAfter(ctx, sentMessage.message_id, 120);
} catch (error) {
console.error("Error fetching movie count:", error);
const sentMessage = await ctx.reply("Failed to fetch movie count. Please try again later.");
// Delete the message after 2 minutes
deleteMessageAfter(ctx, sentMessage.message_id, 120);
}
});
// Telegram bot handlers
bot.command("moviecounts", async (ctx) => {
try {
const count = await Video.countDocuments();
const sentMessage = await ctx.reply(`Total movies in the database: ${count}`);
// Delete the message after 2 minutes
deleteMessageAfter(ctx, sentMessage.message_id, 120);
} catch (error) {
console.error("Error fetching movie count:", error);
const sentMessage = await ctx.reply("Failed to fetch movie count. Please try again later.");
// Delete the message after 2 minutes
deleteMessageAfter(ctx, sentMessage.message_id, 120);
}
});
bot.on("text", async (ctx) => {
const movieName = ctx.message.text.trim();
const username = ctx.from.first_name || ctx.from.username || 'user';
try {
if (!movieName) {
ctx.reply("Please enter a valid movie name.", { reply_to_message_id: ctx.message.message_id });
return;
}
// Create a case-insensitive, gap insensitive regex pattern
const cleanMovieName = movieName.replace(/[^\w\s]/gi, '').replace(/\s\s+/g, ' ').trim();
const searchPattern = cleanMovieName.split(/\s+/).map(word => `(?=.*${word})`).join('');
const regex = new RegExp(`${searchPattern}`, 'i');
// Find matching videos with case-insensitive regex
const matchingVideos = await Video.find({ caption: { $regex: regex } }).sort({ caption: -1 });
if (matchingVideos.length === 0) {
return;
}
const totalPages = Math.ceil(matchingVideos.length / 8);
let currentPage = 1;
const buttons = generateButtons(matchingVideos, currentPage, totalPages);
const sentMessage = await ctx.reply(
`@${username}, found 📖${matchingVideos.length}📖 videos matching '${movieName}'. Select one to watch:`,
{
reply_to_message_id: ctx.message.message_id,
...Markup.inlineKeyboard(buttons)
}
);
// Delete the message after 2 minutes
deleteMessageAfter(ctx, sentMessage.message_id, 120);
} catch (error) {
console.error("Error searching for videos:", error);
const sentMessage = await ctx.reply("Failed to search for videos. Please try again later.", { reply_to_message_id: ctx.message.message_id });
// Delete the message after 2 minutes
deleteMessageAfter(ctx, sentMessage.message_id, 120);
}
});
// Handle next page action
bot.action(/next_(\d+)/, async (ctx) => {
const currentPage = parseInt(ctx.match[1]);
const nextPage = currentPage + 1;
const movieName = ctx.callbackQuery.message.text.split("'")[1]; // Extract movieName from message text
const regex = new RegExp(movieName, "i");
const matchingVideos = await Video.find({ caption: regex });
const totalPages = Math.ceil(matchingVideos.length / 8);
if (nextPage <= totalPages) {
const buttons = generateButtons(matchingVideos, nextPage, totalPages);
const sentMessage = await ctx.editMessageText(
`Page ${nextPage}/${totalPages}: Found ${matchingVideos.length} videos matching '${movieName}'. Select one to watch:`,
Markup.inlineKeyboard(buttons)
);
// Delete the message after 2 minutes
deleteMessageAfter(ctx, sentMessage.message_id, 120);
}
await ctx.answerCbQuery();
});
// Handle previous page action
bot.action(/prev_(\d+)/, async (ctx) => {
const currentPage = parseInt(ctx.match[1]);
const prevPage = currentPage - 1;
const movieName = ctx.callbackQuery.message.text.split("'")[1]; // Extract movieName from message text
const regex = new RegExp(movieName, "i");
const matchingVideos = await Video.find({ caption: regex });
const totalPages = Math.ceil(matchingVideos.length / 8);
if (prevPage > 0) {
const buttons = generateButtons(matchingVideos, prevPage, totalPages);
const sentMessage = await ctx.editMessageText(
`Page ${prevPage}/${totalPages}: Found ${matchingVideos.length} videos matching '${movieName}'. Select one to watch:`,
Markup.inlineKeyboard(buttons)
);
// Delete the message after 2 minutes
deleteMessageAfter(ctx, sentMessage.message_id, 120);
}
await ctx.answerCbQuery();
});
// Function to store video data in MongoDB
const storeVideoData = async (fileId, caption, size) => {
const video = new Video({
fileId: fileId,
caption: caption,
size: size
});
await video.save();
};
// Function to clean the caption by removing unwanted elements
const cleanCaption = (caption) => {
// Remove links, special characters, stickers, emojis, extra spaces, and mentions except "@moviecastback"
return caption
.replace(/(?:https?|ftp):\/\/[\n\S]+/g, "") // Remove URLs
.replace(/[^\w\s@.]/g, "") // Remove special characters except "@" and "."
.replace(/\./g, " ") // Replace dots with a single space
.replace(/\s\s+/g, " ") // Replace multiple spaces with a single space
.replace(/@[A-Za-z0-9_]+/g, "@moviecastback") // Replace all mentions with "@moviecastback"
.trim();
};
bot.on("video", async (ctx) => {
const { message } = ctx.update;
try {
if (message.caption) {
let caption = cleanCaption(message.caption);
const videoFileId = message.video.file_id;
const videoSize = message.video.file_size;
// Check if the video already exists based on fileId, caption, and fileSize
const existingVideo = await Video.findOne({
caption: caption,
size: videoSize
});
if (existingVideo) {
if (ctx.from.username === 'knox7489' || ctx.from.username === 'deepak74893') {
throw new Error("Video already exists in the database.");
}
}
// Store video data in MongoDB
await storeVideoData(videoFileId, caption, videoSize);
if (ctx.from.username === 'knox7489' || ctx.from.username === 'deepak74893') {
await ctx.reply("Video uploaded successfully.");
}
console.log(`Video uploaded`);
// Delete the message after 2 minutes
deleteMessageAfter(ctx, message.message_id, 120);
}
} catch (error) {
console.error("Error forwarding video with modified caption:", error);
ctx.reply(`Failed to upload video: ${error.message}`);
}
});
// Catch Telegraf errors
bot.catch((err, ctx) => {
console.error('Telegraf error:', err);
ctx.reply('Oops! Something went wrong.');
});
module.exports = bot;