import logging from datetime import datetime from os import makedirs, path from random import choice from shutil import rmtree from traceback import format_exc, print_exc from uuid import uuid4 import aiofiles from aiohttp import ClientSession from photosapi_client.errors import UnexpectedStatus from PIL import Image from pyrogram.client import Client from modules.api_client import ( authorize, client, photo_find, photo_get, photo_patch, video_find, video_get, video_patch, ) from modules.database import col_sent, col_submitted logger = logging.getLogger(__name__) async def send_content(app: Client, http_session: ClientSession) -> None: try: try: token = await authorize(http_session) except ValueError: await app.send_message( app.owner, app._("api_creds_invalid", "message"), ) return try: funcs = [] if app.config["posting"]["types"]["photo"]: funcs.append(photo_find) if ( app.config["posting"]["types"]["video"] or app.config["posting"]["types"]["animation"] ): funcs.append(video_find) func = choice(funcs) media = choice( ( await func( album=app.config["posting"]["api"]["album"], caption="queue", page_size=app.config["posting"]["page_size"], client=client, ) ).results ) except (KeyError, AttributeError, TypeError, IndexError): logger.info(app._("post_empty", "console")) if app.config["reports"]["error"]: await app.send_message( app.owner, app._("api_queue_empty", "message"), ) return except (ValueError, UnexpectedStatus): if app.config["reports"]["error"]: await app.send_message( app.owner, app._("api_queue_error", "message"), ) return try: if func is photo_find: response = await photo_get(id=media.id, client=client) else: response = await video_get(id=media.id, client=client) except Exception as exp: print_exc() logger.warning( "Media is invalid: %s", exp # app._("post_invalid_pic", "console").format( # response.status, str(await response.json()) # ) ) if app.config["reports"]["error"]: await app.send_message(app.owner, f"Media is invalid: {exp}") return # await app.send_message( # app.owner, # app._("post_invalid_pic", "message").format( # response.status, await response.json() # ), # ) tmp_dir = str(uuid4()) makedirs(path.join(app.config["locations"]["tmp"], tmp_dir), exist_ok=True) tmp_path = path.join(tmp_dir, media.filename) async with aiofiles.open( path.join(app.config["locations"]["tmp"], tmp_path), "wb" ) as out_file: await out_file.write(response.payload.read()) logger.info( f"Candidate {media.filename} ({media.id}) is {path.getsize(path.join(app.config['locations']['tmp'], tmp_path))} bytes big", ) if ( path.getsize(path.join(app.config["locations"]["tmp"], tmp_path)) > 5242880 ) and func is photo_find: image = Image.open(path.join(app.config["locations"]["tmp"], tmp_path)) width, height = image.size image = image.resize((int(width / 2), int(height / 2)), Image.ANTIALIAS) if tmp_path.lower().endswith(".jpeg") or tmp_path.lower().endswith(".jpg"): image.save( path.join(app.config["locations"]["tmp"], tmp_path), "JPEG", optimize=True, quality=50, ) elif tmp_path.lower().endswith(".png"): image.save( path.join(app.config["locations"]["tmp"], tmp_path), "PNG", optimize=True, compress_level=8, ) image.close() if ( path.getsize(path.join(app.config["locations"]["tmp"], tmp_path)) > 5242880 ) and func is photo_find: rmtree( path.join(app.config["locations"]["tmp"], tmp_dir), ignore_errors=True ) raise BytesWarning del response submitted = col_submitted.find_one({"temp.file": media.filename}) if submitted is not None and submitted["caption"] is not None: caption = submitted["caption"].strip() else: caption = "" if ( submitted is not None and app.config["posting"]["submitted_caption"]["enabled"] and ( (submitted["user"] not in app.admins) or ( app.config["posting"]["submitted_caption"]["ignore_admins"] is False ) ) ): caption = ( f"{caption}\n\n{app.config['posting']['submitted_caption']['text']}\n" ) else: caption = f"{caption}\n\n" if app.config["caption"]["enabled"]: if app.config["caption"]["link"] is not None: caption = f"{caption}[{choice(app.config['caption']['text'])}]({app.config['caption']['link']})" else: caption = f"{caption}{choice(app.config['caption']['text'])}" else: caption = caption try: if func is photo_find: sent = await app.send_photo( app.config["posting"]["channel"], path.join(app.config["locations"]["tmp"], tmp_path), caption=caption, disable_notification=app.config["posting"]["silent"], ) else: sent = await app.send_video( app.config["posting"]["channel"], path.join(app.config["locations"]["tmp"], tmp_path), caption=caption, disable_notification=app.config["posting"]["silent"], ) except Exception as exp: logger.error( f"Could not send media {media.filename} ({media.id}) due to {exp}" ) if app.config["reports"]["error"]: await app.send_message( app.owner, app._("post_exception", "message").format(exp, format_exc()), ) # rmtree(path.join(app.config['locations']['tmp'], tmp_dir), ignore_errors=True) return col_sent.insert_one( { "date": datetime.now(), "image": media.id, "filename": media.filename, "channel": app.config["posting"]["channel"], "caption": None if (submitted is None or submitted["caption"] is None) else submitted["caption"].strip(), } ) func_patch = photo_patch if func is photo_find else video_patch await func_patch(id=media.id, client=client, caption="sent") rmtree(path.join(app.config["locations"]["tmp"], tmp_dir), ignore_errors=True) logger.info( app._("post_sent", "console").format( media.id, str(app.config["posting"]["channel"]), caption.replace("\n", "%n"), str(app.config["posting"]["silent"]), ) ) except Exception as exp: logger.error(app._("post_exception", "console").format(str(exp), format_exc())) if app.config["reports"]["error"]: await app.send_message( app.owner, app._("post_exception", "message").format(exp, format_exc()), ) try: rmtree( path.join(app.config["locations"]["tmp"], tmp_dir), ignore_errors=True ) except: pass