feat: refactor rentry paste and implement cleanup job

This commit is contained in:
Abhi
2025-04-06 08:09:46 +05:30
parent 607b32b09e
commit 6d889d3646
3 changed files with 133 additions and 11 deletions

View File

@@ -59,6 +59,7 @@ from utils import config
from utils.db import db from utils.db import db
from utils.misc import gitrepo, userbot_version from utils.misc import gitrepo, userbot_version
from utils.scripts import restart, load_module from utils.scripts import restart, load_module
from utils.rentry import rentry_cleanup_job
SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__)) SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__))
if SCRIPT_PATH != os.getcwd(): if SCRIPT_PATH != os.getcwd():
@@ -183,6 +184,8 @@ async def main():
logging.info("Moon-Userbot started!") logging.info("Moon-Userbot started!")
app.loop.create_task(rentry_cleanup_job())
await idle() await idle()
await app.stop() await app.stop()

View File

@@ -25,7 +25,7 @@ from pyrogram.types import Message
from utils.misc import modules_help, prefix from utils.misc import modules_help, prefix
from utils.scripts import edit_or_reply, format_exc, progress 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): async def read_file(file_path):
@@ -96,17 +96,20 @@ async def openfile(client: Client, message: Message):
"<code>File Content is too long... Pasting to rentry...</code>" "<code>File Content is too long... Pasting to rentry...</code>"
) )
content_new = f"```{code_start[11:-2]}\n{content}```" content_new = f"```{code_start[11:-2]}\n{content}```"
paste = new(url="", edit_code="", text=content_new) try:
if paste["status"] != "200": rentry_url, edit_code = await rentry_paste(
await ms.edit_text(f"<b>Error:</b> <code>{paste['content']}</code>") text=content_new, return_edit=True
)
except RuntimeError:
await ms.edit_text("<b>Error:</b> <code>Failed to paste to rentry</code>")
return return
await client.send_message( await client.send_message(
"me", "me",
f"Here's your edit code for Url: {paste['url']}\nEdit code: <code>{paste['edit_code']}</code>", f"Here's your edit code for Url: {rentry_url}\nEdit code: <code>{edit_code}</code>",
disable_web_page_preview=True, disable_web_page_preview=True,
) )
await ms.edit_text( await ms.edit_text(
f"<b>File Name:</b> <code>{file_name[0]}</code>\n<b>Size:</b> <code>{file_size} bytes</code>\n<b>Last Modified:</b> <code>{last_modified}</code>\n<b>Content:</b> {paste['url']}\n<b>Note:</b> <code>Edit Code has been sent to your saved messages</code>", f"<b>File Name:</b> <code>{file_name[0]}</code>\n<b>Size:</b> <code>{file_size} bytes</code>\n<b>Last Modified:</b> <code>{last_modified}</code>\n<b>Content:</b> {rentry_url}\n<b>Note:</b> <code>Edit Code has been sent to your saved messages</code>",
disable_web_page_preview=True, disable_web_page_preview=True,
) )

View File

@@ -1,13 +1,18 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# @source: https://github.com/radude/rentry/blob/master/rentry.py # @source: https://github.com/radude/rentry/blob/master/rentry.py
import asyncio
import http.cookiejar import http.cookiejar
import urllib.parse import urllib.parse
import urllib.request import urllib.request
from uuid import uuid4
from datetime import datetime, timedelta
from http.cookies import SimpleCookie from http.cookies import SimpleCookie
from json import loads as json_loads from json import loads as json_loads
from utils.db import db
BASE_PROTOCOL = "https://" BASE_PROTOCOL = "https://"
BASE_URL = "rentry.co" BASE_URL = "rentry.co"
@@ -44,12 +49,12 @@ class UrllibClient:
return response return response
def raw(url): def raw(url: str):
client = UrllibClient() client = UrllibClient()
return json_loads(client.get(f"{BASE_PROTOCOL}{BASE_URL}/api/raw/{url}").data) 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() client, cookie = UrllibClient(), SimpleCookie()
cookie.load(vars(client.get(f"{BASE_PROTOCOL}{BASE_URL}"))["headers"]["Set-Cookie"]) 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() client, cookie = UrllibClient(), SimpleCookie()
cookie.load(vars(client.get(f"{BASE_PROTOCOL}{BASE_URL}"))["headers"]["Set-Cookie"]) 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( return json_loads(
client.post( 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 ).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)