TelegramPoster/main.py

294 lines
13 KiB
Python

import os
import random
import shutil
import subprocess
import sys
from threading import Thread
import time
import traceback
from modules.logging import logWrite
from modules.utils import configGet, jsonLoad, jsonSave
# Args =====================================================================================================================================
if "--move-sent" in sys.argv:
for entry in jsonLoad(configGet("index", "locations"))["sent"]:
try:
shutil.move(configGet("queue", "locations")+os.sep+entry, configGet("sent", "locations")+os.sep+entry)
except FileNotFoundError:
logWrite(f"File '{entry}' is already moved or does not exist")
except Exception as exp:
logWrite(f"Could not move sent file '{entry}' to '{configGet('sent', 'locations')}' due to {exp}")
logWrite(f"Moved all sent files to the sent folder")
if "--cleanup" in sys.argv:
if "--confirm" in sys.argv:
index = jsonLoad(configGet("index", "locations"))
for entry in index["sent"]:
try:
try:
os.remove(configGet("queue", "locations")+os.sep+entry)
except FileNotFoundError:
pass
try:
os.remove(configGet("sent", "locations")+os.sep+entry)
except FileNotFoundError:
pass
except Exception as exp:
logWrite(f"Could not remove '{entry}' due to {exp}")
jsonSave(index, jsonLoad(configGet("index", "locations")))
logWrite(f"Performed cleanup of the sent files")
else:
logWrite(f"Requested cleanup of sent files but not authorized. Please pass '--confirm' to perform that")
if "--cleanup-index" in sys.argv:
if "--confirm" in sys.argv:
index = jsonLoad(configGet("index", "locations"))
index["sent"] = []
jsonSave(index, jsonLoad(configGet("index", "locations")))
logWrite(f"Performed cleanup of sent files index")
else:
logWrite(f"Requested cleanup of sent files index but not authorized. Please pass '--confirm' to perform that")
if "--norun" in sys.argv:
logWrite("Argument --norun passed, not running the main script")
sys.exit()
#===========================================================================================================================================
# Import ===================================================================================================================================
try:
import schedule # type: ignore
from pyrogram import Client, filters, idle # type: ignore
from pyrogram.types import ChatPermissions, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton, BotCommand, BotCommandScopeChat # type: ignore
except ModuleNotFoundError:
print(f"Required modules are not installed. Run 'pip3 install -r requirements.txt' and restart the program.", flush=True)
sys.exit()
#===========================================================================================================================================
pid = os.getpid()
app = Client("duptsiaposter", bot_token=configGet("bot_token", "bot"), api_id=configGet("api_id", "bot"), api_hash=configGet("api_hash", "bot"))
def send_content():
try:
list_sent = jsonLoad(configGet("index", "locations"))
list_queue = os.listdir(configGet("queue", "locations"))
for file in list_queue:
if not file in list_sent["sent"]:
ext_match = False
for ext in configGet("photo", "posting", "extensions"):
if file.endswith(ext):
ext_match = True
ext_type = "photo"
break
for ext in configGet("video", "posting", "extensions"):
if file.endswith(ext):
ext_match = True
ext_type = "video"
break
if not ext_match:
list_queue.remove(file)
else:
list_queue.remove(file)
if len(list_queue) > 0:
candidate_file = random.choice(list_queue)
candidate = configGet("queue", "locations")+os.sep+candidate_file
else:
logWrite(f"Could not send content due to queue folder empty with allowed extensions")
if configGet("error", "reports"):
app.send_message(configGet("admin", "reports"), f"Could not send content: `Queue folder is empty or contains only unsupported or already sent files.`") # type: ignore
return
if ext_type == "photo": # type: ignore
if configGet("enabled", "caption"):
if configGet("link", "caption") != None:
sent = app.send_photo(configGet("channel", "posting"), candidate, caption=f"[{configGet('text', 'caption')}]({configGet('link', 'caption')})", disable_notification=configGet("silent", "posting")) # type: ignore
else:
sent = app.send_photo(configGet("channel", "posting"), candidate, caption=configGet('text', 'caption'), disable_notification=configGet("silent", "posting")) # type: ignore
else:
sent = app.send_photo(configGet("channel", "posting"), candidate, disable_notification=configGet("silent", "posting")) # type: ignore
elif ext_type == "video": # type: ignore
if configGet("enabled", "caption"):
if configGet("link", "caption") != None:
sent = app.send_video(configGet("channel", "posting"), candidate, caption=f"[{configGet('text', 'caption')}]({configGet('link', 'caption')})", disable_notification=configGet("silent", "posting")) # type: ignore
else:
sent = app.send_video(configGet("channel", "posting"), candidate, caption=configGet('text', 'caption'), disable_notification=configGet("silent", "posting")) # type: ignore
else:
sent = app.send_video(configGet("channel", "posting"), candidate, disable_notification=configGet("silent", "posting")) # type: ignore
list_sent["sent"].append(candidate_file)
jsonSave(list_sent, configGet("index", "locations"))
if configGet("move_sent", "posting"):
shutil.move(candidate, configGet("sent", "locations")+os.sep+candidate_file)
if configGet("sent", "reports"):
app.send_message(configGet("admin", "reports"), f"Posted `{candidate_file}`", disable_web_page_preview=True, reply_markup=InlineKeyboardMarkup([
[InlineKeyboardButton("View in channel", url=sent.link)] # type: ignore
])) # type: ignore
except Exception as exp:
logWrite(f"Could not send content due to {exp}")
if configGet("error", "reports"):
app.send_message(configGet("admin", "reports"), f"Could not send content due to `{exp}`\n\nTraceback:\n```{traceback.format_exc()}```") # type: ignore
@app.on_message(~ filters.scheduled & filters.command(["kill", "die", "reboot"], prefixes=["", "/"]))
def kill(app, msg):
if msg.from_user.id == configGet("admin", "reports"):
msg.reply_text(f"Shutting down bot with pid `{pid}`")
os.system('kill -9 '+str(pid))
# Submission =====================================================================================================================================
def subLimit(user):
submit = jsonLoad(configGet("submit", "locations"))
submit[str(user.id)] = time.time()
jsonSave(submit, configGet("submit", "locations"))
def subLimited(user):
if user.id == configGet("admin", "reports"):
return False
else:
submit = jsonLoad(configGet("submit", "locations"))
if str(user.id) in submit:
if (time.time() - submit[str(user.id)]) < configGet("timeout", "submission"):
return True
else:
return False
else:
return False
def subBlock(user):
blocked = jsonLoad(configGet("blocked", "locations"))
if user.id not in blocked:
blocked.append(user.id)
jsonSave(blocked, configGet("blocked", "locations"))
def subUnblock(user):
blocked = jsonLoad(configGet("blocked", "locations"))
if user.id in blocked:
blocked.remove(user.id)
jsonSave(blocked, configGet("blocked", "locations"))
@app.on_message(filters.photo | filters.video | filters.animation)
def get_submission(_, msg):
if msg.from_user.id not in jsonLoad(configGet("blocked", "locations")):
if not subLimited(msg.from_user):
msg.copy(configGet("admin", "reports"), reply_markup=InlineKeyboardMarkup([
[
InlineKeyboardButton(text="✅ Accept", callback_data=f"sub_yes_{msg.from_user.id}_{msg.id}"),
InlineKeyboardButton(text="❌ Deny", callback_data=f"sub_no_{msg.from_user.id}_{msg.id}")
],
[
InlineKeyboardButton(text="☠️ Block sender", callback_data=f"sub_block_{msg.from_user.id}")
],
[
InlineKeyboardButton(text="🏳️ Unblock sender", callback_data=f"sub_unblock_{msg.from_user.id}")
]
]
))
msg.reply_text(f"Media has been submitted.\nWe'll notify you whether it will be accepted or not soon.", quote=True)
subLimit(msg.from_user)
else:
msg.reply_text(f'You can only submit 1 media per {configGet("timeout", "submission")} seconds')
@app.on_callback_query(filters.regex("sub_yes_[\s\S]*_[\s\S]*")) # type: ignore
def callback_query_yes(app, clb): # type: ignore
fullclb = clb.data.split("_")
try:
submission = app.get_messages(int(fullclb[2]), int(fullclb[3]))
except:
clb.answer(text=f"Submission message no longer exist", show_alert=True)
return
try:
app.download_media(submission, file_name=configGet("queue", "locations")+os.sep)
except:
clb.answer(text=f"Could not download submission", show_alert=True)
return
submission.reply_text(f"✅ Submission approved and accepted", quote=True)
clb.answer(text=f"✅ Submission approved", show_alert=True)
@app.on_callback_query(filters.regex("sub_no_[\s\S]*_[\s\S]*")) # type: ignore
def callback_query_no(app, clb): # type: ignore
fullclb = clb.data.split("_")
try:
submission = app.get_messages(int(fullclb[2]), int(fullclb[3]))
except:
clb.answer(text=f"Submission message no longer exist", show_alert=True)
return
submission.reply_text(f"❌ Submission reviewed and declined", quote=True)
clb.answer(text=f"❌ Submission declined", show_alert=True)
@app.on_callback_query(filters.regex("sub_block_[\s\S]*")) # type: ignore
def callback_query_block(app, clb): # type: ignore
fullclb = clb.data.split("_")
app.send_message(int(fullclb[2]), "You were blocked and you can't submit media anymore.")
subBlock(int(fullclb[2]))
clb.answer(text=f"User {fullclb[2]} has been blocked", show_alert=True)
@app.on_callback_query(filters.regex("sub_unblock_[\s\S]*")) # type: ignore
def callback_query_unblock(app, clb): # type: ignore
fullclb = clb.data.split("_")
app.send_message(int(fullclb[2]), "You were unblocked and you can now submit media.")
subUnblock(int(fullclb[2]))
clb.answer(text=f"User {fullclb[2]} has been unblocked", show_alert=True)
#===========================================================================================================================================
for entry in configGet("time", "posting"):
schedule.every().day.at(entry).do(send_content)
def background_task():
try:
while True:
try:
schedule.run_pending()
time.sleep(1)
except:
pass
except Exception as exp:
logWrite(f"Exception {exp} happened on task execution")
except KeyboardInterrupt:
logWrite('\nShutting down...')
app.send_message(configGet("admin", "reports"), f"Shutting down with PID `{pid}`") # type: ignore
os.system('kill -9 '+str(pid))
if __name__ == "__main__":
logWrite(f'Starting with PID {pid}')
app.start() # type: ignore
app.send_message(configGet("admin", "reports"), f"Starting with pid `{pid}`") # type: ignore
t = Thread(target=background_task)
t.start()
app.set_bot_commands([ # type: ignore
BotCommand("reboot", "Reboot the bot"),
],
scope=BotCommandScopeChat(chat_id=configGet("admin", "reports")))
idle()
app.send_message(configGet("admin", "reports"), f"Shutting down with pid `{pid}`") # type: ignore
logWrite(f'Shutting down with PID {pid}')
subprocess.call(f'kill -9 {pid}', shell=True) # type: ignore