Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
anasty17
GitHub Repository: anasty17/mirror-leech-telegram-bot
Path: blob/master/bot/modules/rss.py
1621 views
1
from httpx import AsyncClient
2
from apscheduler.triggers.interval import IntervalTrigger
3
from asyncio import Lock, sleep
4
from datetime import datetime, timedelta
5
from feedparser import parse as feed_parse
6
from functools import partial
7
from io import BytesIO
8
from pyrogram.filters import create
9
from pyrogram.handlers import MessageHandler
10
from time import time
11
from re import compile, I
12
13
from .. import scheduler, rss_dict, LOGGER
14
from ..core.config_manager import Config
15
from ..helper.ext_utils.bot_utils import new_task, arg_parser, get_size_bytes
16
from ..helper.ext_utils.status_utils import get_readable_file_size
17
from ..helper.ext_utils.db_handler import database
18
from ..helper.ext_utils.exceptions import RssShutdownException
19
from ..helper.ext_utils.help_messages import RSS_HELP_MESSAGE
20
from ..helper.telegram_helper.button_build import ButtonMaker
21
from ..helper.telegram_helper.filters import CustomFilters
22
from ..helper.telegram_helper.message_utils import (
23
send_message,
24
edit_message,
25
send_rss,
26
send_file,
27
delete_message,
28
)
29
30
rss_dict_lock = Lock()
31
handler_dict = {}
32
size_regex = compile(r"(\d+(\.\d+)?\s?(GB|MB|KB|GiB|MiB|KiB))", I)
33
34
headers = {
35
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36",
36
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
37
"Accept-Language": "en-US,en;q=0.5",
38
}
39
40
41
async def rss_menu(event):
42
user_id = event.from_user.id
43
buttons = ButtonMaker()
44
buttons.data_button("Subscribe", f"rss sub {user_id}")
45
buttons.data_button("Subscriptions", f"rss list {user_id} 0")
46
buttons.data_button("Get Items", f"rss get {user_id}")
47
buttons.data_button("Edit", f"rss edit {user_id}")
48
buttons.data_button("Pause", f"rss pause {user_id}")
49
buttons.data_button("Resume", f"rss resume {user_id}")
50
buttons.data_button("Unsubscribe", f"rss unsubscribe {user_id}")
51
if await CustomFilters.sudo("", event):
52
buttons.data_button("All Subscriptions", f"rss listall {user_id} 0")
53
buttons.data_button("Pause All", f"rss allpause {user_id}")
54
buttons.data_button("Resume All", f"rss allresume {user_id}")
55
buttons.data_button("Unsubscribe All", f"rss allunsub {user_id}")
56
buttons.data_button("Delete User", f"rss deluser {user_id}")
57
if scheduler.running:
58
buttons.data_button("Shutdown Rss", f"rss shutdown {user_id}")
59
else:
60
buttons.data_button("Start Rss", f"rss start {user_id}")
61
buttons.data_button("Close", f"rss close {user_id}")
62
button = buttons.build_menu(2)
63
msg = f"Rss Menu | Users: {len(rss_dict)} | Running: {scheduler.running}"
64
return msg, button
65
66
67
async def update_rss_menu(query):
68
msg, button = await rss_menu(query)
69
await edit_message(query.message, msg, button)
70
71
72
@new_task
73
async def get_rss_menu(_, message):
74
msg, button = await rss_menu(message)
75
await send_message(message, msg, button)
76
77
78
@new_task
79
async def rss_sub(_, message, pre_event):
80
user_id = message.from_user.id
81
handler_dict[user_id] = False
82
if username := message.from_user.username:
83
tag = f"@{username}"
84
else:
85
tag = message.from_user.mention
86
msg = ""
87
items = message.text.split("\n")
88
for index, item in enumerate(items, start=1):
89
args = item.split()
90
if len(args) < 2:
91
await send_message(
92
message,
93
f"{item}. Wrong Input format. Read help message before adding new subscription!",
94
)
95
continue
96
title = args[0].strip()
97
if (user_feeds := rss_dict.get(user_id, False)) and title in user_feeds:
98
await send_message(
99
message, f"This title {title} already subscribed! Choose another title!"
100
)
101
continue
102
feed_link = args[1].strip()
103
if feed_link.startswith(("-inf", "-exf", "-c")):
104
await send_message(
105
message,
106
f"Wrong input in line {index}! Add Title! Read the example!",
107
)
108
continue
109
inf_lists = []
110
exf_lists = []
111
if len(args) > 2:
112
arg_base = {"-c": None, "-inf": None, "-exf": None, "-stv": None}
113
arg_parser(args[2:], arg_base)
114
cmd = arg_base["-c"]
115
inf = arg_base["-inf"]
116
exf = arg_base["-exf"]
117
stv = arg_base["-stv"]
118
if stv is not None:
119
stv = stv.lower() == "true"
120
if inf is not None:
121
filters_list = inf.split("|")
122
for x in filters_list:
123
y = x.split(" or ")
124
inf_lists.append(y)
125
if exf is not None:
126
filters_list = exf.split("|")
127
for x in filters_list:
128
y = x.split(" or ")
129
exf_lists.append(y)
130
else:
131
inf = None
132
exf = None
133
cmd = None
134
stv = False
135
try:
136
async with AsyncClient(
137
headers=headers, follow_redirects=True, timeout=60, verify=False
138
) as client:
139
res = await client.get(feed_link)
140
html = res.text
141
rss_d = feed_parse(html)
142
last_title = rss_d.entries[0]["title"]
143
if rss_d.entries[0].get("size"):
144
size = int(rss_d.entries[0]["size"])
145
elif rss_d.entries[0].get("summary"):
146
summary = rss_d.entries[0]["summary"]
147
matches = size_regex.findall(summary)
148
sizes = [match[0] for match in matches]
149
size = get_size_bytes(sizes[0])
150
else:
151
size = 0
152
msg += "<b>Subscribed!</b>"
153
msg += f"\n<b>Title: </b><code>{title}</code>\n<b>Feed Url: </b>{feed_link}"
154
msg += f"\n<b>latest record for </b>{rss_d.feed.title}:"
155
msg += (
156
f"\nName: <code>{last_title.replace('>', '').replace('<', '')}</code>"
157
)
158
try:
159
last_link = rss_d.entries[0]["links"][1]["href"]
160
except IndexError:
161
last_link = rss_d.entries[0]["link"]
162
msg += f"\n<b>Link: </b><code>{last_link}</code>"
163
if size:
164
msg += f"\nSize: {get_readable_file_size(size)}"
165
msg += f"\n<b>Command: </b><code>{cmd}</code>"
166
msg += f"\n<b>Filters:-</b>\ninf: <code>{inf}</code>\nexf: <code>{exf}</code>\n<b>sensitive: </b>{stv}"
167
async with rss_dict_lock:
168
if rss_dict.get(user_id, False):
169
rss_dict[user_id][title] = {
170
"link": feed_link,
171
"last_feed": last_link,
172
"last_title": last_title,
173
"inf": inf_lists,
174
"exf": exf_lists,
175
"paused": False,
176
"command": cmd,
177
"sensitive": stv,
178
"tag": tag,
179
}
180
else:
181
rss_dict[user_id] = {
182
title: {
183
"link": feed_link,
184
"last_feed": last_link,
185
"last_title": last_title,
186
"inf": inf_lists,
187
"exf": exf_lists,
188
"paused": False,
189
"command": cmd,
190
"sensitive": stv,
191
"tag": tag,
192
}
193
}
194
LOGGER.info(
195
f"Rss Feed Added: id: {user_id} - title: {title} - link: {feed_link} - c: {cmd} - inf: {inf} - exf: {exf} - stv: {stv}"
196
)
197
except (IndexError, AttributeError) as e:
198
emsg = f"The link: {feed_link} doesn't seem to be a RSS feed or it's region-blocked!"
199
await send_message(message, emsg + "\nError: " + str(e))
200
except Exception as e:
201
await send_message(message, str(e))
202
if msg:
203
await database.rss_update(user_id)
204
await send_message(message, msg)
205
is_sudo = await CustomFilters.sudo("", message)
206
if scheduler.state == 2:
207
scheduler.resume()
208
elif is_sudo and not scheduler.running:
209
add_job()
210
scheduler.start()
211
await update_rss_menu(pre_event)
212
213
214
async def get_user_id(title):
215
async with rss_dict_lock:
216
return next(
217
(
218
(True, user_id)
219
for user_id, feed in rss_dict.items()
220
if feed["title"] == title
221
),
222
(False, False),
223
)
224
225
226
@new_task
227
async def rss_update(_, message, pre_event, state):
228
user_id = message.from_user.id
229
handler_dict[user_id] = False
230
titles = message.text.split()
231
is_sudo = await CustomFilters.sudo("", message)
232
updated = []
233
for title in titles:
234
title = title.strip()
235
if not (res := rss_dict[user_id].get(title, False)):
236
if is_sudo:
237
res, user_id = await get_user_id(title)
238
if not res:
239
user_id = message.from_user.id
240
await send_message(message, f"{title} not found!")
241
continue
242
istate = rss_dict[user_id][title].get("paused", False)
243
if istate and state == "pause" or not istate and state == "resume":
244
await send_message(message, f"{title} already {state}d!")
245
continue
246
async with rss_dict_lock:
247
updated.append(title)
248
if state == "unsubscribe":
249
del rss_dict[user_id][title]
250
elif state == "pause":
251
rss_dict[user_id][title]["paused"] = True
252
elif state == "resume":
253
rss_dict[user_id][title]["paused"] = False
254
if state == "resume":
255
if scheduler.state == 2:
256
scheduler.resume()
257
elif is_sudo and not scheduler.running:
258
add_job()
259
scheduler.start()
260
if is_sudo and Config.DATABASE_URL and user_id != message.from_user.id:
261
await database.rss_update(user_id)
262
if not rss_dict[user_id]:
263
async with rss_dict_lock:
264
del rss_dict[user_id]
265
await database.rss_delete(user_id)
266
if not rss_dict:
267
await database.trunc_table("rss")
268
if updated:
269
LOGGER.info(f"Rss link with Title(s): {updated} has been {state}d!")
270
await send_message(
271
message,
272
f"Rss links with Title(s): <code>{updated}</code> has been {state}d!",
273
)
274
if rss_dict.get(user_id):
275
await database.rss_update(user_id)
276
await update_rss_menu(pre_event)
277
278
279
async def rss_list(query, start, all_users=False):
280
user_id = query.from_user.id
281
buttons = ButtonMaker()
282
if all_users:
283
list_feed = f"<b>All subscriptions | Page: {int(start / 5)} </b>"
284
async with rss_dict_lock:
285
keysCount = sum(len(v.keys()) for v in rss_dict.values())
286
index = 0
287
for titles in rss_dict.values():
288
for index, (title, data) in enumerate(
289
list(titles.items())[start : 5 + start]
290
):
291
list_feed += f"\n\n<b>Title:</b> <code>{title}</code>\n"
292
list_feed += f"<b>Feed Url:</b> <code>{data['link']}</code>\n"
293
list_feed += f"<b>Command:</b> <code>{data['command']}</code>\n"
294
list_feed += f"<b>Inf:</b> <code>{data['inf']}</code>\n"
295
list_feed += f"<b>Exf:</b> <code>{data['exf']}</code>\n"
296
list_feed += f"<b>Sensitive:</b> <code>{data.get('sensitive', False)}</code>\n"
297
list_feed += f"<b>Paused:</b> <code>{data['paused']}</code>\n"
298
list_feed += f"<b>User:</b> {data['tag'].replace('@', '', 1)}"
299
index += 1
300
if index == 5:
301
break
302
else:
303
list_feed = f"<b>Your subscriptions | Page: {int(start / 5)} </b>"
304
async with rss_dict_lock:
305
keysCount = len(rss_dict.get(user_id, {}).keys())
306
for title, data in list(rss_dict[user_id].items())[start : 5 + start]:
307
list_feed += f"\n\n<b>Title:</b> <code>{title}</code>\n<b>Feed Url: </b><code>{data['link']}</code>\n"
308
list_feed += f"<b>Command:</b> <code>{data['command']}</code>\n"
309
list_feed += f"<b>Inf:</b> <code>{data['inf']}</code>\n"
310
list_feed += f"<b>Exf:</b> <code>{data['exf']}</code>\n"
311
list_feed += (
312
f"<b>Sensitive:</b> <code>{data.get('sensitive', False)}</code>\n"
313
)
314
list_feed += f"<b>Paused:</b> <code>{data['paused']}</code>\n"
315
buttons.data_button("Back", f"rss back {user_id}")
316
buttons.data_button("Close", f"rss close {user_id}")
317
if keysCount > 5:
318
for x in range(0, keysCount, 5):
319
buttons.data_button(
320
f"{int(x / 5)}", f"rss list {user_id} {x}", position="footer"
321
)
322
button = buttons.build_menu(2)
323
if query.message.text.html == list_feed:
324
return
325
await edit_message(query.message, list_feed, button)
326
327
328
@new_task
329
async def rss_get(_, message, pre_event):
330
user_id = message.from_user.id
331
handler_dict[user_id] = False
332
args = message.text.split()
333
if len(args) < 2:
334
await send_message(
335
message,
336
f"{args}. Wrong Input format. You should add number of the items you want to get. Read help message before adding new subscription!",
337
)
338
await update_rss_menu(pre_event)
339
return
340
try:
341
title = args[0]
342
count = int(args[1])
343
data = rss_dict[user_id].get(title, False)
344
if data and count > 0:
345
try:
346
msg = await send_message(
347
message, f"Getting the last <b>{count}</b> item(s) from {title}"
348
)
349
async with AsyncClient(
350
headers=headers, follow_redirects=True, timeout=60, verify=False
351
) as client:
352
res = await client.get(data["link"])
353
html = res.text
354
rss_d = feed_parse(html)
355
item_info = ""
356
for item_num in range(count):
357
try:
358
link = rss_d.entries[item_num]["links"][1]["href"]
359
except IndexError:
360
link = rss_d.entries[item_num]["link"]
361
item_info += f"<b>Name: </b><code>{rss_d.entries[item_num]['title'].replace('>', '').replace('<', '')}</code>\n"
362
item_info += f"<b>Link: </b><code>{link}</code>\n\n"
363
item_info_ecd = item_info.encode()
364
if len(item_info_ecd) > 4000:
365
with BytesIO(item_info_ecd) as out_file:
366
out_file.name = f"rssGet {title} items_no. {count}.txt"
367
await send_file(message, out_file)
368
await delete_message(msg)
369
else:
370
await edit_message(msg, item_info)
371
except IndexError as e:
372
LOGGER.error(str(e))
373
await edit_message(
374
msg, "Parse depth exceeded. Try again with a lower value."
375
)
376
except Exception as e:
377
LOGGER.error(str(e))
378
await edit_message(msg, str(e))
379
else:
380
await send_message(message, "Enter a valid title. Title not found!")
381
except Exception as e:
382
LOGGER.error(str(e))
383
await send_message(message, f"Enter a valid value!. {e}")
384
await update_rss_menu(pre_event)
385
386
387
@new_task
388
async def rss_edit(_, message, pre_event):
389
user_id = message.from_user.id
390
handler_dict[user_id] = False
391
items = message.text.split("\n")
392
updated = False
393
for item in items:
394
args = item.split()
395
title = args[0].strip()
396
if len(args) < 2:
397
await send_message(
398
message,
399
f"{item}. Wrong Input format. Read help message before editing!",
400
)
401
continue
402
elif not rss_dict[user_id].get(title, False):
403
await send_message(message, "Enter a valid title. Title not found!")
404
continue
405
updated = True
406
inf_lists = []
407
exf_lists = []
408
arg_base = {"-c": None, "-inf": None, "-exf": None, "-stv": None}
409
arg_parser(args[1:], arg_base)
410
cmd = arg_base["-c"]
411
inf = arg_base["-inf"]
412
exf = arg_base["-exf"]
413
stv = arg_base["-stv"]
414
async with rss_dict_lock:
415
if stv is not None:
416
stv = stv.lower() == "true"
417
rss_dict[user_id][title]["sensitive"] = stv
418
if cmd is not None:
419
if cmd.lower() == "none":
420
cmd = None
421
rss_dict[user_id][title]["command"] = cmd
422
if inf is not None:
423
if inf.lower() != "none":
424
filters_list = inf.split("|")
425
for x in filters_list:
426
y = x.split(" or ")
427
inf_lists.append(y)
428
rss_dict[user_id][title]["inf"] = inf_lists
429
if exf is not None:
430
if exf.lower() != "none":
431
filters_list = exf.split("|")
432
for x in filters_list:
433
y = x.split(" or ")
434
exf_lists.append(y)
435
rss_dict[user_id][title]["exf"] = exf_lists
436
if updated:
437
await database.rss_update(user_id)
438
await update_rss_menu(pre_event)
439
440
441
@new_task
442
async def rss_delete(_, message, pre_event):
443
handler_dict[message.from_user.id] = False
444
users = message.text.split()
445
for user in users:
446
user = int(user)
447
async with rss_dict_lock:
448
del rss_dict[user]
449
await database.rss_delete(user)
450
await update_rss_menu(pre_event)
451
452
453
async def event_handler(client, query, pfunc):
454
user_id = query.from_user.id
455
handler_dict[user_id] = True
456
start_time = time()
457
458
async def event_filter(_, __, event):
459
user = event.from_user or event.sender_chat
460
return bool(
461
user.id == user_id and event.chat.id == query.message.chat.id and event.text
462
)
463
464
handler = client.add_handler(MessageHandler(pfunc, create(event_filter)), group=-1)
465
while handler_dict[user_id]:
466
await sleep(0.5)
467
if time() - start_time > 60:
468
handler_dict[user_id] = False
469
await update_rss_menu(query)
470
client.remove_handler(*handler)
471
472
473
@new_task
474
async def rss_listener(client, query):
475
user_id = query.from_user.id
476
message = query.message
477
data = query.data.split()
478
if int(data[2]) != user_id and not await CustomFilters.sudo("", query):
479
await query.answer(
480
text="You don't have permission to use these buttons!", show_alert=True
481
)
482
elif data[1] == "close":
483
await query.answer()
484
handler_dict[user_id] = False
485
await delete_message(message.reply_to_message)
486
await delete_message(message)
487
elif data[1] == "back":
488
await query.answer()
489
handler_dict[user_id] = False
490
await update_rss_menu(query)
491
elif data[1] == "sub":
492
await query.answer()
493
handler_dict[user_id] = False
494
buttons = ButtonMaker()
495
buttons.data_button("Back", f"rss back {user_id}")
496
buttons.data_button("Close", f"rss close {user_id}")
497
button = buttons.build_menu(2)
498
await edit_message(message, RSS_HELP_MESSAGE, button)
499
pfunc = partial(rss_sub, pre_event=query)
500
await event_handler(client, query, pfunc)
501
elif data[1] == "list":
502
handler_dict[user_id] = False
503
if len(rss_dict.get(int(data[2]), {})) == 0:
504
await query.answer(text="No subscriptions!", show_alert=True)
505
else:
506
await query.answer()
507
start = int(data[3])
508
await rss_list(query, start)
509
elif data[1] == "get":
510
handler_dict[user_id] = False
511
if len(rss_dict.get(int(data[2]), {})) == 0:
512
await query.answer(text="No subscriptions!", show_alert=True)
513
else:
514
await query.answer()
515
buttons = ButtonMaker()
516
buttons.data_button("Back", f"rss back {user_id}")
517
buttons.data_button("Close", f"rss close {user_id}")
518
button = buttons.build_menu(2)
519
await edit_message(
520
message,
521
"Send one title with value separated by space get last X items.\nTitle Value\nTimeout: 60 sec.",
522
button,
523
)
524
pfunc = partial(rss_get, pre_event=query)
525
await event_handler(client, query, pfunc)
526
elif data[1] in ["unsubscribe", "pause", "resume"]:
527
handler_dict[user_id] = False
528
if len(rss_dict.get(int(data[2]), {})) == 0:
529
await query.answer(text="No subscriptions!", show_alert=True)
530
else:
531
await query.answer()
532
buttons = ButtonMaker()
533
buttons.data_button("Back", f"rss back {user_id}")
534
if data[1] == "pause":
535
buttons.data_button("Pause AllMyFeeds", f"rss uallpause {user_id}")
536
elif data[1] == "resume":
537
buttons.data_button("Resume AllMyFeeds", f"rss uallresume {user_id}")
538
elif data[1] == "unsubscribe":
539
buttons.data_button("Unsub AllMyFeeds", f"rss uallunsub {user_id}")
540
buttons.data_button("Close", f"rss close {user_id}")
541
button = buttons.build_menu(2)
542
await edit_message(
543
message,
544
f"Send one or more rss titles separated by space to {data[1]}.\nTimeout: 60 sec.",
545
button,
546
)
547
pfunc = partial(rss_update, pre_event=query, state=data[1])
548
await event_handler(client, query, pfunc)
549
elif data[1] == "edit":
550
handler_dict[user_id] = False
551
if len(rss_dict.get(int(data[2]), {})) == 0:
552
await query.answer(text="No subscriptions!", show_alert=True)
553
else:
554
await query.answer()
555
buttons = ButtonMaker()
556
buttons.data_button("Back", f"rss back {user_id}")
557
buttons.data_button("Close", f"rss close {user_id}")
558
button = buttons.build_menu(2)
559
msg = """Send one or more rss titles with new filters or command separated by new line.
560
Examples:
561
Title1 -c mirror -up remote:path/subdir -exf none -inf 1080 or 720 -stv true
562
Title2 -c none -inf none -stv false
563
Title3 -c mirror -rcf xxx -up xxx -z pswd -stv false
564
Note: Only what you provide will be edited, the rest will be the same like example 2: exf will stay same as it is.
565
Timeout: 60 sec. Argument -c for command and arguments
566
"""
567
await edit_message(message, msg, button)
568
pfunc = partial(rss_edit, pre_event=query)
569
await event_handler(client, query, pfunc)
570
elif data[1].startswith("uall"):
571
handler_dict[user_id] = False
572
if len(rss_dict.get(int(data[2]), {})) == 0:
573
await query.answer(text="No subscriptions!", show_alert=True)
574
return
575
await query.answer()
576
if data[1].endswith("unsub"):
577
async with rss_dict_lock:
578
del rss_dict[int(data[2])]
579
await database.rss_delete(int(data[2]))
580
await update_rss_menu(query)
581
elif data[1].endswith("pause"):
582
async with rss_dict_lock:
583
for info in rss_dict[int(data[2])].values():
584
info["paused"] = True
585
await database.rss_update(int(data[2]))
586
elif data[1].endswith("resume"):
587
async with rss_dict_lock:
588
for info in rss_dict[int(data[2])].values():
589
info["paused"] = False
590
if scheduler.state == 2:
591
scheduler.resume()
592
await database.rss_update(int(data[2]))
593
await update_rss_menu(query)
594
elif data[1].startswith("all"):
595
if len(rss_dict) == 0:
596
await query.answer(text="No subscriptions!", show_alert=True)
597
return
598
await query.answer()
599
if data[1].endswith("unsub"):
600
async with rss_dict_lock:
601
rss_dict.clear()
602
await database.trunc_table("rss")
603
await update_rss_menu(query)
604
elif data[1].endswith("pause"):
605
async with rss_dict_lock:
606
for user_feeds in rss_dict.values():
607
for feed in user_feeds.values():
608
feed["paused"] = True
609
if scheduler.running:
610
scheduler.pause()
611
await database.rss_update_all()
612
elif data[1].endswith("resume"):
613
async with rss_dict_lock:
614
for user_feeds in rss_dict.values():
615
for feed in user_feeds.values():
616
feed["paused"] = False
617
if scheduler.state == 2:
618
scheduler.resume()
619
elif not scheduler.running:
620
add_job()
621
scheduler.start()
622
await update_rss_menu(query)
623
await database.rss_update_all()
624
elif data[1] == "deluser":
625
if len(rss_dict) == 0:
626
await query.answer(text="No subscriptions!", show_alert=True)
627
else:
628
await query.answer()
629
buttons = ButtonMaker()
630
buttons.data_button("Back", f"rss back {user_id}")
631
buttons.data_button("Close", f"rss close {user_id}")
632
button = buttons.build_menu(2)
633
msg = "Send one or more user_id separated by space to delete their resources.\nTimeout: 60 sec."
634
await edit_message(message, msg, button)
635
pfunc = partial(rss_delete, pre_event=query)
636
await event_handler(client, query, pfunc)
637
elif data[1] == "listall":
638
if not rss_dict:
639
await query.answer(text="No subscriptions!", show_alert=True)
640
else:
641
await query.answer()
642
start = int(data[3])
643
await rss_list(query, start, all_users=True)
644
elif data[1] == "shutdown":
645
if scheduler.running:
646
await query.answer()
647
scheduler.shutdown(wait=False)
648
await sleep(0.5)
649
await update_rss_menu(query)
650
else:
651
await query.answer(text="Already Stopped!", show_alert=True)
652
elif data[1] == "start":
653
if not scheduler.running:
654
await query.answer()
655
add_job()
656
scheduler.start()
657
await update_rss_menu(query)
658
else:
659
await query.answer(text="Already Running!", show_alert=True)
660
661
662
async def rss_monitor():
663
chat = Config.RSS_CHAT
664
if not chat:
665
LOGGER.warning("RSS_CHAT not added! Shutting down rss scheduler...")
666
scheduler.shutdown(wait=False)
667
return
668
if len(rss_dict) == 0:
669
scheduler.pause()
670
return
671
all_paused = True
672
rss_topic_id = rss_chat_id = None
673
if isinstance(chat, int):
674
rss_chat_id = chat
675
elif "|" in chat:
676
rss_chat_id, rss_topic_id = list(
677
map(
678
lambda x: int(x) if x.lstrip("-").isdigit() else x,
679
chat.split("|", 1),
680
)
681
)
682
elif chat.lstrip("-").isdigit():
683
rss_chat_id = int(chat)
684
for user, items in list(rss_dict.items()):
685
for title, data in items.items():
686
try:
687
if data["paused"]:
688
continue
689
tries = 0
690
while True:
691
try:
692
async with AsyncClient(
693
headers=headers,
694
follow_redirects=True,
695
timeout=60,
696
verify=False,
697
) as client:
698
res = await client.get(data["link"])
699
html = res.text
700
break
701
except:
702
tries += 1
703
if tries > 3:
704
raise
705
continue
706
rss_d = feed_parse(html)
707
if not rss_d.entries:
708
LOGGER.warning(
709
f"No entries found for > Feed Title: {title} - Feed Link: {data['link']}"
710
)
711
continue
712
entry0 = rss_d.entries[0]
713
links = entry0.get("links", [])
714
if len(links) > 1:
715
last_link = links[1].get("href")
716
elif links:
717
last_link = links[0].get("href")
718
else:
719
last_link = entry0.get("link")
720
last_title = entry0.get("title")
721
all_paused = False
722
if data["last_feed"] == last_link or data["last_title"] == last_title:
723
continue
724
feed_count = 0
725
while True:
726
try:
727
await sleep(10)
728
except:
729
raise RssShutdownException("Rss Monitor Stopped!")
730
try:
731
item_title = rss_d.entries[feed_count]["title"]
732
try:
733
url = rss_d.entries[feed_count]["links"][1]["href"]
734
except IndexError:
735
url = rss_d.entries[feed_count]["link"]
736
if data["last_feed"] == url or data["last_title"] == item_title:
737
break
738
if rss_d.entries[feed_count].get("size"):
739
size = int(rss_d.entries[feed_count]["size"])
740
elif rss_d.entries[feed_count].get("summary"):
741
summary = rss_d.entries[feed_count]["summary"]
742
matches = size_regex.findall(summary)
743
sizes = [match[0] for match in matches]
744
size = get_size_bytes(sizes[0])
745
else:
746
size = 0
747
except IndexError:
748
LOGGER.warning(
749
f"Reached Max index no. {feed_count} for this feed: {title}. Maybe you need to use less RSS_DELAY to not miss some torrents"
750
)
751
break
752
parse = True
753
for flist in data["inf"]:
754
if (
755
data.get("sensitive", False)
756
and all(x.lower() not in item_title.lower() for x in flist)
757
) or (
758
not data.get("sensitive", False)
759
and all(x not in item_title for x in flist)
760
):
761
parse = False
762
feed_count += 1
763
break
764
if not parse:
765
continue
766
for flist in data["exf"]:
767
if (
768
data.get("sensitive", False)
769
and any(x.lower() in item_title.lower() for x in flist)
770
) or (
771
not data.get("sensitive", False)
772
and any(x in item_title for x in flist)
773
):
774
parse = False
775
feed_count += 1
776
break
777
if not parse:
778
continue
779
if command := data["command"]:
780
if (
781
size
782
and Config.RSS_SIZE_LIMIT
783
and Config.RSS_SIZE_LIMIT < size
784
):
785
feed_count += 1
786
continue
787
cmd = command.split(maxsplit=1)
788
cmd.insert(1, url)
789
feed_msg = " ".join(cmd)
790
if not feed_msg.startswith("/"):
791
feed_msg = f"/{feed_msg}"
792
else:
793
feed_msg = f"<b>Name: </b><code>{item_title.replace('>', '').replace('<', '')}</code>"
794
feed_msg += f"\n\n<b>Link: </b><code>{url}</code>"
795
if size:
796
feed_msg += f"\n<b>Size: </b>{get_readable_file_size(size)}"
797
feed_msg += (
798
f"\n<b>Tag: </b><code>{data['tag']}</code> <code>{user}</code>"
799
)
800
await send_rss(feed_msg, rss_chat_id, rss_topic_id)
801
feed_count += 1
802
async with rss_dict_lock:
803
if user not in rss_dict or not rss_dict[user].get(title, False):
804
continue
805
rss_dict[user][title].update(
806
{"last_feed": last_link, "last_title": last_title}
807
)
808
await database.rss_update(user)
809
LOGGER.info(f"Feed Name: {title}")
810
LOGGER.info(f"Last item: {last_link}")
811
except RssShutdownException as ex:
812
LOGGER.info(ex)
813
break
814
except Exception as e:
815
LOGGER.error(f"{e} - Feed Name: {title} - Feed Link: {data['link']}")
816
continue
817
if all_paused:
818
scheduler.pause()
819
820
821
def add_job():
822
scheduler.add_job(
823
rss_monitor,
824
trigger=IntervalTrigger(seconds=Config.RSS_DELAY),
825
id="0",
826
name="RSS",
827
misfire_grace_time=15,
828
max_instances=1,
829
next_run_time=datetime.now() + timedelta(seconds=20),
830
replace_existing=True,
831
)
832
833
834
add_job()
835
scheduler.start()
836
837