rss.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. from asyncio import get_event_loop, sleep
  2. from feedparser import parse
  3. from pyrogram import filters
  4. from pyrogram.errors import (
  5. ChannelInvalid,
  6. ChannelPrivate,
  7. InputUserDeactivated,
  8. UserIsBlocked,
  9. )
  10. from pyrogram.types import Message
  11. from wbb import RSS_DELAY, app, log
  12. from wbb.core.decorators.errors import capture_err
  13. from wbb.utils.dbfunctions import (
  14. add_rss_feed,
  15. get_rss_feeds,
  16. is_rss_active,
  17. remove_rss_feed,
  18. update_rss_feed,
  19. )
  20. from wbb.utils.functions import (
  21. get_http_status_code,
  22. get_urls_from_text,
  23. is_safe_url,
  24. )
  25. from wbb.utils.rss import Feed
  26. __MODULE__ = "RSS"
  27. __HELP__ = f"""
  28. /add_feed [URL] - Add a feed to chat
  29. /rm_feed - Remove feed from chat
  30. **Note:**
  31. - This will check for updates every {RSS_DELAY // 60} minutes.
  32. - You can only add one feed per chat.
  33. - Currently RSS and ATOM feeds are supported.
  34. """
  35. def get_parsed_feed_url(parsed, fallback: str) -> str:
  36. href = parsed.get("href")
  37. if isinstance(href, str) and href:
  38. return href
  39. return fallback
  40. async def rss_worker():
  41. log.info("RSS Worker started")
  42. while not await sleep(RSS_DELAY):
  43. feeds = await get_rss_feeds()
  44. if not feeds:
  45. continue
  46. loop = get_event_loop()
  47. for _feed in feeds:
  48. chat = _feed["chat_id"]
  49. try:
  50. url = _feed["url"]
  51. if not is_safe_url(url):
  52. await remove_rss_feed(chat)
  53. log.info(f"Removed RSS Feed from {chat} (Unsafe URL)")
  54. continue
  55. last_title = _feed.get("last_title")
  56. parsed = await loop.run_in_executor(None, parse, url)
  57. final_url = get_parsed_feed_url(parsed, url)
  58. if not is_safe_url(final_url):
  59. await remove_rss_feed(chat)
  60. log.info(f"Removed RSS Feed from {chat} (Unsafe redirect)")
  61. continue
  62. feed = Feed(parsed)
  63. if feed.title == last_title:
  64. continue
  65. await app.send_message(
  66. chat, feed.parsed(), disable_web_page_preview=True
  67. )
  68. await update_rss_feed(chat, feed.title)
  69. except (
  70. ChannelInvalid,
  71. ChannelPrivate,
  72. InputUserDeactivated,
  73. UserIsBlocked,
  74. AttributeError,
  75. ):
  76. await remove_rss_feed(chat)
  77. log.info(f"Removed RSS Feed from {chat} (Invalid Chat)")
  78. except Exception as e:
  79. log.info(f"RSS in {chat}: {str(e)}")
  80. loop = get_event_loop()
  81. loop.create_task(rss_worker())
  82. @app.on_message(filters.command("add_feed"))
  83. @capture_err
  84. async def add_feed_func(_, m: Message):
  85. if len(m.command) != 2:
  86. return await m.reply("Read 'RSS' section in help menu.")
  87. url = m.text.split(None, 1)[1].strip()
  88. if not url:
  89. return await m.reply("[ERROR]: Invalid Argument")
  90. urls = get_urls_from_text(url)
  91. if not urls:
  92. return await m.reply("[ERROR]: Invalid URL")
  93. url = urls[0]
  94. if not is_safe_url(url):
  95. return await m.reply("[ERROR]: URL is not allowed (SSRF protection).")
  96. status = await get_http_status_code(url)
  97. if status != 200:
  98. return await m.reply("[ERROR]: Invalid Url")
  99. ns = "[ERROR]: This feed isn't supported."
  100. try:
  101. loop = get_event_loop()
  102. parsed = await loop.run_in_executor(None, parse, url)
  103. final_url = get_parsed_feed_url(parsed, url)
  104. if not is_safe_url(final_url):
  105. return await m.reply("[ERROR]: URL is not allowed (SSRF protection).")
  106. feed = Feed(parsed)
  107. except Exception:
  108. return await m.reply(ns)
  109. if not feed:
  110. return await m.reply(ns)
  111. chat_id = m.chat.id
  112. if await is_rss_active(chat_id):
  113. return await m.reply("[ERROR]: You already have an RSS feed enabled.")
  114. try:
  115. await m.reply(feed.parsed(), disable_web_page_preview=True)
  116. except Exception:
  117. return await m.reply(ns)
  118. await add_rss_feed(chat_id, final_url, feed.title)
  119. @app.on_message(filters.command("rm_feed"))
  120. async def rm_feed_func(_, m: Message):
  121. if await is_rss_active(m.chat.id):
  122. await remove_rss_feed(m.chat.id)
  123. await m.reply("Removed RSS Feed")
  124. else:
  125. await m.reply("There are no active RSS Feeds in this chat.")