Skip to content

Commit c267a78

Browse files
authored
Merge pull request #28 from CodeByStella/stella
add stop/start bot feature
2 parents 68fc5f6 + 93d0cf4 commit c267a78

File tree

2 files changed

+82
-1
lines changed

2 files changed

+82
-1
lines changed

src/bot/commands.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import UserType from "@/types/user";
66
import { formatDate, isEmpty } from "@/utils";
77
import { Markup, Telegraf } from "telegraf";
88
import { BroadcastMessageSceneName, ConfigSceneName } from "./scene";
9+
import { getScrapingStatus, startScraping, stopScraping } from "@/scraper";
910

1011
const commands: {
1112
command: string;
@@ -17,6 +18,14 @@ const commands: {
1718
command: "broadcast",
1819
description: "Broadcast a message to all users (admin only)",
1920
},
21+
{
22+
command: "start_scraping",
23+
description: "Start scraping job postings (admin only)",
24+
},
25+
{
26+
command: "stop_scraping",
27+
description: "Stop scraping job postings (admin only)",
28+
},
2029
];
2130

2231
const TELEGRAM_MSG_LIMIT = 3000;
@@ -40,7 +49,7 @@ const setup_commands = async (bot: Telegraf) => {
4049
const args = ctx.message.text.split(" ");
4150
const referrerId = args[1];
4251

43-
const username = ctx.update.message.from.username;
52+
const username = ctx.update.message.from.username || "Unknown";
4453
const userId = ctx.update.message.from.id;
4554

4655
const existUser = await User.findOne({
@@ -174,6 +183,53 @@ const setup_commands = async (bot: Telegraf) => {
174183
}
175184
});
176185

186+
let canStart = false;
187+
188+
bot.command("start_scraping", async (ctx) => {
189+
try {
190+
const userId = ctx.update.message.from.id;
191+
if (config.ADMIN_ID !== userId.toString())
192+
return ctx.reply(`🚫 This command is for admin only.`);
193+
194+
const scraping = getScrapingStatus();
195+
196+
if (scraping) return await ctx.reply("Scraping is already ongoing.");
197+
198+
if (!canStart)
199+
return await ctx.reply("Scraping is not allowed to start for now.");
200+
201+
await ctx.reply("🔍 Scraping started.");
202+
startScraping();
203+
} catch (error) {
204+
console.error("Error in /start_scraping:", error);
205+
ctx.reply("An error occurred. Please try again later.");
206+
}
207+
});
208+
209+
bot.command("stop_scraping", async (ctx) => {
210+
try {
211+
const userId = ctx.update.message.from.id;
212+
if (config.ADMIN_ID !== userId.toString())
213+
return ctx.reply(`🚫 This command is for admin only.`);
214+
215+
const scraping = getScrapingStatus();
216+
217+
if (!scraping) return await ctx.reply("Scraping is not ongoing.");
218+
219+
canStart = false;
220+
221+
setTimeout(() => {
222+
canStart = true;
223+
}, 60000);
224+
225+
await ctx.reply("🛑 Scraping stopped.");
226+
stopScraping();
227+
} catch (error) {
228+
console.error("Error in /stop_scraping:", error);
229+
ctx.reply("An error occurred. Please try again later.");
230+
}
231+
});
232+
177233
bot.hears(SOURCE_URL, async (ctx) => {
178234
try {
179235
ctx.reply(

src/scraper/index.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import processScrapedJob from "@/job.controller";
55
import User from "@/models/User";
66
import UserType from "@/types/user";
77

8+
let scraping = false;
9+
810
const useRealBrowser = async () => {
911
try {
1012
const { browser, page } = await connect({
@@ -129,6 +131,19 @@ export async function scrapeJobs() {
129131
let subscribedUsers: UserType[];
130132

131133
while (true) {
134+
if (!scraping) {
135+
try {
136+
if (page) await page.close().catch(() => {});
137+
} catch (err) {
138+
console.error("Error closing page:", (err as Error).message);
139+
}
140+
try {
141+
if (browser) await browser.close().catch(() => {});
142+
} catch (err) {
143+
console.error("Error closing browser:", (err as Error).message);
144+
}
145+
}
146+
132147
try {
133148
// Restart browser every N iterations or if not initialized
134149
if (iteration % RESTART_BROWSER_EVERY === 0 || !browser || !page) {
@@ -184,6 +199,7 @@ export async function scrapeJobs() {
184199
iteration++;
185200

186201
for (let index = 0; index < subscribedUsers.length; index++) {
202+
if (!scraping) break;
187203
try {
188204
const searchUrl = subscribedUsers[index].searchUrl || "";
189205
const userid = subscribedUsers[index].id;
@@ -336,6 +352,7 @@ export async function scrapeJobs() {
336352

337353
export const startScraping = async () => {
338354
try {
355+
scraping = true;
339356
await scrapeJobs();
340357
} catch (error) {
341358
console.error(
@@ -344,3 +361,11 @@ export const startScraping = async () => {
344361
);
345362
}
346363
};
364+
365+
export const stopScraping = () => {
366+
scraping = false;
367+
};
368+
369+
export const getScrapingStatus = () => {
370+
return scraping;
371+
};

0 commit comments

Comments
 (0)