From 6d889d364624b51397e8233c52b4989105d4250e Mon Sep 17 00:00:00 2001
From: Abhi <85984486+AbhiTheModder@users.noreply.github.com>
Date: Sun, 6 Apr 2025 08:09:46 +0530
Subject: [PATCH] feat: refactor rentry paste and implement cleanup job
---
main.py | 3 ++
modules/open.py | 15 +++---
utils/rentry.py | 126 ++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 133 insertions(+), 11 deletions(-)
diff --git a/main.py b/main.py
index e975f78..3246391 100644
--- a/main.py
+++ b/main.py
@@ -59,6 +59,7 @@ from utils import config
from utils.db import db
from utils.misc import gitrepo, userbot_version
from utils.scripts import restart, load_module
+from utils.rentry import rentry_cleanup_job
SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__))
if SCRIPT_PATH != os.getcwd():
@@ -183,6 +184,8 @@ async def main():
logging.info("Moon-Userbot started!")
+ app.loop.create_task(rentry_cleanup_job())
+
await idle()
await app.stop()
diff --git a/modules/open.py b/modules/open.py
index d89f790..dd6da30 100644
--- a/modules/open.py
+++ b/modules/open.py
@@ -25,7 +25,7 @@ from pyrogram.types import Message
from utils.misc import modules_help, prefix
from utils.scripts import edit_or_reply, format_exc, progress
-from utils.rentry import new
+from utils.rentry import paste as rentry_paste
async def read_file(file_path):
@@ -96,17 +96,20 @@ async def openfile(client: Client, message: Message):
"File Content is too long... Pasting to rentry..."
)
content_new = f"```{code_start[11:-2]}\n{content}```"
- paste = new(url="", edit_code="", text=content_new)
- if paste["status"] != "200":
- await ms.edit_text(f"Error: {paste['content']}")
+ try:
+ rentry_url, edit_code = await rentry_paste(
+ text=content_new, return_edit=True
+ )
+ except RuntimeError:
+ await ms.edit_text("Error: Failed to paste to rentry")
return
await client.send_message(
"me",
- f"Here's your edit code for Url: {paste['url']}\nEdit code: {paste['edit_code']}",
+ f"Here's your edit code for Url: {rentry_url}\nEdit code: {edit_code}",
disable_web_page_preview=True,
)
await ms.edit_text(
- f"File Name: {file_name[0]}\nSize: {file_size} bytes\nLast Modified: {last_modified}\nContent: {paste['url']}\nNote: Edit Code has been sent to your saved messages",
+ f"File Name: {file_name[0]}\nSize: {file_size} bytes\nLast Modified: {last_modified}\nContent: {rentry_url}\nNote: Edit Code has been sent to your saved messages",
disable_web_page_preview=True,
)
diff --git a/utils/rentry.py b/utils/rentry.py
index f38d811..dd6d7ad 100644
--- a/utils/rentry.py
+++ b/utils/rentry.py
@@ -1,13 +1,18 @@
#!/usr/bin/env python3
# @source: https://github.com/radude/rentry/blob/master/rentry.py
-
+import asyncio
import http.cookiejar
import urllib.parse
import urllib.request
+
+from uuid import uuid4
+from datetime import datetime, timedelta
from http.cookies import SimpleCookie
from json import loads as json_loads
+from utils.db import db
+
BASE_PROTOCOL = "https://"
BASE_URL = "rentry.co"
@@ -44,12 +49,12 @@ class UrllibClient:
return response
-def raw(url):
+def raw(url: str):
client = UrllibClient()
return json_loads(client.get(f"{BASE_PROTOCOL}{BASE_URL}/api/raw/{url}").data)
-def new(url, edit_code, text):
+def new(text: str, edit_code: str = "", url: str = ""):
client, cookie = UrllibClient(), SimpleCookie()
cookie.load(vars(client.get(f"{BASE_PROTOCOL}{BASE_URL}"))["headers"]["Set-Cookie"])
@@ -69,7 +74,7 @@ def new(url, edit_code, text):
)
-def edit(url, edit_code, text):
+def edit(url_short: str, edit_code: str, text: str):
client, cookie = UrllibClient(), SimpleCookie()
cookie.load(vars(client.get(f"{BASE_PROTOCOL}{BASE_URL}"))["headers"]["Set-Cookie"])
@@ -79,6 +84,117 @@ def edit(url, edit_code, text):
return json_loads(
client.post(
- f"{BASE_PROTOCOL}{BASE_URL}/api/edit/{url}", payload, headers=_headers
+ f"{BASE_PROTOCOL}{BASE_URL}/api/edit/{url_short}", payload, headers=_headers
).data
)
+
+
+def delete(url_short: str, edit_code: str):
+ client, cookie = UrllibClient(), SimpleCookie()
+ cookie.load(vars(client.get(f"{BASE_PROTOCOL}{BASE_URL}"))["headers"]["Set-Cookie"])
+ csrftoken = cookie["csrftoken"].value
+ payload = {"csrfmiddlewaretoken": csrftoken, "edit_code": edit_code}
+ return json_loads(
+ client.post(
+ f"{BASE_PROTOCOL}{BASE_URL}/api/delete/{url_short}",
+ payload,
+ headers=_headers,
+ ).data
+ )
+
+
+async def paste(
+ text: str,
+ return_edit: bool = False,
+ edit_bin: bool = False,
+ edit_code: str = None,
+ url: str = None,
+ permanent: bool = False,
+) -> str | tuple[str, str]:
+ """Pastes some text to rentry bin.
+ args:
+ text: Input text to paste
+ return_edit: If it should return edit code also
+ edit_bin: If this request is to edit an already existing bin
+ edit_code: Only required if edit_bin is True. It is the edit code used to edit bin.
+ url: Only required if edit_bin is True. It is the url on which the bin is located.
+ permanent: If the pasted content should not be deleted automatically
+
+ returns:
+ The url of the paste or return a tuple containing url and edit code
+ """
+ if not str(text):
+ return
+
+ if edit_bin:
+ if not (url and edit_code):
+ raise ValueError("Please provide both, url and edit code")
+ response = edit(url_short=url, edit_code=edit_code, text=text)
+ else:
+ response = new(text=text)
+
+ if response.get("status") != "200":
+ raise RuntimeError(
+ f"paste task terminated with status: {response.get('status')}\n"
+ f"Message: {response.get('content', 'No message provided')}"
+ )
+
+ url = response["url"]
+ edit_code = response["edit_code"]
+
+ if not permanent:
+ short_url = response["url_short"]
+ time_now = datetime.now()
+ ftime = time_now.strftime("%d %I:%M:%S %p %Y")
+
+ print(f"URL: {url} - Edit Code: {edit_code} - Time: {ftime}")
+
+ rallUrls = db.get("core.rentry", "urls", default={"allUrls": {}})
+ entry_id = str(uuid4())
+ rallUrls["allUrls"][entry_id] = {
+ "url": short_url,
+ "edit_code": edit_code,
+ "time": ftime,
+ }
+ db.set("core.rentry", "urls", rallUrls)
+
+ if return_edit:
+ return (url, edit_code)
+ return url
+
+
+async def rentry_cleanup_job():
+ """Periodically checks and deletes rentry pastes older than 24 hours"""
+ while True:
+ try:
+ rallUrls = db.get("core.rentry", "urls", default={"allUrls": {}})
+ now = datetime.now()
+ deleted_count = 0
+ error_count = 0
+
+ for entry_id, entry in list(rallUrls["allUrls"].items()):
+ url = entry["url"]
+ entry_time = datetime.strptime(entry["time"], "%d %I:%M:%S %p %Y")
+
+ if now - entry_time > timedelta(days=1):
+ try:
+ delete(url, entry["edit_code"])
+ del rallUrls["allUrls"][entry_id]
+ deleted_count += 1
+ print(f"[#] Deleted expired rentry paste: {url}")
+ except Exception as e:
+ error_count += 1
+ print(f"[!] Failed to delete rentry paste {url}: {str(e)}")
+
+ if deleted_count or error_count:
+ print(
+ f"[*] Cleanup summary: {deleted_count} deleted, {error_count} failed"
+ )
+
+ if deleted_count:
+ db.set("core.rentry", "urls", rallUrls)
+
+ except Exception as e:
+ print(f"[!] Error in rentry cleanup job: {str(e)}")
+
+ await asyncio.sleep(12 * 60 * 60)