WIP: Video support

This commit is contained in:
Profitroll 2023-06-22 15:17:44 +02:00
parent 070acb474d
commit f29c1e7ae6
Signed by: profitroll
GPG Key ID: FA35CAB49DACD3B2
6 changed files with 144 additions and 56 deletions

View File

@ -8,11 +8,13 @@ from shutil import rmtree
from time import time from time import time
from traceback import format_exc from traceback import format_exc
from typing import List, Tuple, Union from typing import List, Tuple, Union
import aiofiles
import pyrogram import pyrogram
from aiohttp import ClientSession from aiohttp import ClientSession
from bson import ObjectId from bson import ObjectId
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from classes.enums.submission_types import SubmissionType
from libbot import json_read, json_write from libbot import json_read, json_write
from libbot.i18n import BotLocale from libbot.i18n import BotLocale
from libbot.i18n.sync import _ from libbot.i18n.sync import _
@ -43,10 +45,14 @@ from classes.exceptions import (
) )
from classes.pyrocommand import PyroCommand from classes.pyrocommand import PyroCommand
from modules.api_client import ( from modules.api_client import (
BodyPhotoUploadAlbumsAlbumPhotosPost, BodyPhotoUpload,
BodyVideoUpload,
File, File,
Photo,
Video,
client, client,
photo_upload, photo_upload,
video_upload,
) )
from modules.database import col_submitted from modules.database import col_submitted
from modules.http_client import http_session from modules.http_client import http_session
@ -398,7 +404,7 @@ class PyroClient(Client):
language_code=command_set.language_code, language_code=command_set.language_code,
) )
async def submit_photo( async def submit_media(
self, id: str self, id: str
) -> Tuple[Union[Message, None], Union[str, None]]: ) -> Tuple[Union[Message, None], Union[str, None]]:
db_entry = col_submitted.find_one({"_id": ObjectId(id)}) db_entry = col_submitted.find_one({"_id": ObjectId(id)})
@ -431,24 +437,47 @@ class PyroClient(Client):
db_entry["user"], db_entry["telegram"]["msg_id"] db_entry["user"], db_entry["telegram"]["msg_id"]
) )
with open(str(filepath), "rb") as fh: async with aiofiles.open(str(filepath), "rb") as fh:
photo_bytes = BytesIO(fh.read()) media_bytes = BytesIO(await fh.read())
try: try:
response = await photo_upload( if db_entry["type"] == SubmissionType.PHOTO.value:
self.config["posting"]["api"]["album"], response = await photo_upload(
client=client, self.config["posting"]["api"]["album"],
multipart_data=BodyPhotoUploadAlbumsAlbumPhotosPost( client=client,
File(photo_bytes, filepath.name, "image/jpeg") multipart_data=BodyPhotoUpload(
), File(media_bytes, filepath.name, "image/jpeg")
ignore_duplicates=self.config["submission"]["allow_duplicates"], ),
compress=False, ignore_duplicates=self.config["submission"]["allow_duplicates"],
caption="queue", compress=False,
) caption="queue",
)
elif db_entry["type"] == SubmissionType.VIDEO.value:
response = await video_upload(
self.config["posting"]["api"]["album"],
client=client,
multipart_data=BodyVideoUpload(
File(media_bytes, filepath.name, "video/*")
),
caption="queue",
)
elif db_entry["type"] == SubmissionType.ANIMATION.value:
response = await video_upload(
self.config["posting"]["api"]["album"],
client=client,
multipart_data=BodyVideoUpload(
File(media_bytes, filepath.name, "video/*")
),
caption="queue",
)
except UnexpectedStatus: except UnexpectedStatus:
raise SubmissionUnsupportedError(str(filepath)) raise SubmissionUnsupportedError(str(filepath))
response_dict = loads(response.content.decode("utf-8")) response_dict = (
{}
if not hasattr(response, "content")
else loads(response.content.decode("utf-8"))
)
if "duplicates" in response_dict and len(response_dict["duplicates"]) > 0: if "duplicates" in response_dict and len(response_dict["duplicates"]) > 0:
duplicates = [] duplicates = []
@ -480,7 +509,10 @@ class PyroClient(Client):
except (FileNotFoundError, NotADirectoryError): except (FileNotFoundError, NotADirectoryError):
logger.error("Could not delete '%s' on submission accepted", filepath) logger.error("Could not delete '%s' on submission accepted", filepath)
return submission, response.parsed.id return (
submission,
response.id if not hasattr(response, "parsed") else response.parsed.id,
)
async def ban_user(self, id: int) -> None: async def ban_user(self, id: int) -> None:
pass pass

View File

@ -56,6 +56,11 @@
"ignore_admins": true, "ignore_admins": true,
"text": "#submitted" "text": "#submitted"
}, },
"types": {
"photo": true,
"video": false,
"animation": false
},
"extensions": { "extensions": {
"photo": [ "photo": [
"jpg", "jpg",

View File

@ -35,14 +35,26 @@ from photosapi_client.api.default.user_me_users_me_get import sync as user_me
from photosapi_client.api.default.video_find_albums_album_videos_get import ( from photosapi_client.api.default.video_find_albums_album_videos_get import (
asyncio as video_find, asyncio as video_find,
) )
from photosapi_client.api.default.video_get_videos_id_get import asyncio as video_get
from photosapi_client.api.default.video_patch_videos_id_patch import (
asyncio as video_patch,
)
from photosapi_client.api.default.video_upload_albums_album_videos_post import (
asyncio as video_upload,
)
from photosapi_client.models.body_login_for_access_token_token_post import ( from photosapi_client.models.body_login_for_access_token_token_post import (
BodyLoginForAccessTokenTokenPost, BodyLoginForAccessTokenTokenPost,
) )
from photosapi_client.models.body_photo_upload_albums_album_photos_post import ( from photosapi_client.models.body_photo_upload_albums_album_photos_post import (
BodyPhotoUploadAlbumsAlbumPhotosPost, BodyPhotoUploadAlbumsAlbumPhotosPost as BodyPhotoUpload,
)
from photosapi_client.models.body_video_upload_albums_album_videos_post import (
BodyVideoUploadAlbumsAlbumVideosPost as BodyVideoUpload,
) )
from photosapi_client.models.http_validation_error import HTTPValidationError from photosapi_client.models.http_validation_error import HTTPValidationError
from photosapi_client.models.photo import Photo
from photosapi_client.models.token import Token from photosapi_client.models.token import Token
from photosapi_client.models.video import Video
from photosapi_client.types import File from photosapi_client.types import File
from modules.http_client import http_session from modules.http_client import http_session

View File

@ -3,7 +3,7 @@ from datetime import datetime
from os import makedirs, path from os import makedirs, path
from random import choice from random import choice
from shutil import rmtree from shutil import rmtree
from traceback import format_exc from traceback import format_exc, print_exc
from uuid import uuid4 from uuid import uuid4
import aiofiles import aiofiles
@ -12,7 +12,16 @@ from photosapi_client.errors import UnexpectedStatus
from PIL import Image from PIL import Image
from pyrogram.client import Client from pyrogram.client import Client
from modules.api_client import authorize, client, photo_find, photo_patch 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 from modules.database import col_sent, col_submitted
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -30,9 +39,19 @@ async def send_content(app: Client, http_session: ClientSession) -> None:
return return
try: try:
pic = choice( 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 photo_find( await func(
album=app.config["posting"]["api"]["album"], album=app.config["posting"]["api"]["album"],
caption="queue", caption="queue",
page_size=app.config["posting"]["page_size"], page_size=app.config["posting"]["page_size"],
@ -56,41 +75,48 @@ async def send_content(app: Client, http_session: ClientSession) -> None:
) )
return return
response = await http_session.get( try:
f"{app.config['posting']['api']['address']}/photos/{pic.id}", if func is photo_find:
headers={"Authorization": f"Bearer {token}"}, response = await photo_get(id=media.id, client=client)
) else:
response = await video_get(id=media.id, client=client)
if response.status != 200: except Exception as exp:
print_exc()
logger.warning( logger.warning(
app._("post_invalid_pic", "console").format( "Media is invalid: %s",
response.status, str(await response.json()) exp
) # app._("post_invalid_pic", "console").format(
# response.status, str(await response.json())
# )
) )
if app.config["reports"]["error"]: if app.config["reports"]["error"]:
await app.send_message( await app.send_message(app.owner, f"Media is invalid: {exp}")
app.owner, return
app._("post_invalid_pic", "message").format( # await app.send_message(
response.status, await response.json() # app.owner,
), # app._("post_invalid_pic", "message").format(
) # response.status, await response.json()
# ),
# )
tmp_dir = str(uuid4()) tmp_dir = str(uuid4())
makedirs(path.join(app.config["locations"]["tmp"], tmp_dir), exist_ok=True) makedirs(path.join(app.config["locations"]["tmp"], tmp_dir), exist_ok=True)
tmp_path = path.join(tmp_dir, pic.filename) tmp_path = path.join(tmp_dir, media.filename)
async with aiofiles.open( async with aiofiles.open(
path.join(app.config["locations"]["tmp"], tmp_path), "wb" path.join(app.config["locations"]["tmp"], tmp_path), "wb"
) as out_file: ) as out_file:
await out_file.write(await response.read()) await out_file.write(response.payload.read())
logger.info( logger.info(
f"Candidate {pic.filename} ({pic.id}) is {path.getsize(path.join(app.config['locations']['tmp'], tmp_path))} bytes big", 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: 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)) image = Image.open(path.join(app.config["locations"]["tmp"], tmp_path))
width, height = image.size width, height = image.size
image = image.resize((int(width / 2), int(height / 2)), Image.ANTIALIAS) image = image.resize((int(width / 2), int(height / 2)), Image.ANTIALIAS)
@ -110,7 +136,9 @@ async def send_content(app: Client, http_session: ClientSession) -> None:
) )
image.close() image.close()
if path.getsize(path.join(app.config["locations"]["tmp"], tmp_path)) > 5242880: if (
path.getsize(path.join(app.config["locations"]["tmp"], tmp_path)) > 5242880
) and func is photo_find:
rmtree( rmtree(
path.join(app.config["locations"]["tmp"], tmp_dir), ignore_errors=True path.join(app.config["locations"]["tmp"], tmp_dir), ignore_errors=True
) )
@ -118,7 +146,7 @@ async def send_content(app: Client, http_session: ClientSession) -> None:
del response del response
submitted = col_submitted.find_one({"temp.file": pic.filename}) submitted = col_submitted.find_one({"temp.file": media.filename})
if submitted is not None and submitted["caption"] is not None: if submitted is not None and submitted["caption"] is not None:
caption = submitted["caption"].strip() caption = submitted["caption"].strip()
@ -150,14 +178,24 @@ async def send_content(app: Client, http_session: ClientSession) -> None:
caption = caption caption = caption
try: try:
sent = await app.send_photo( if func is photo_find:
app.config["posting"]["channel"], sent = await app.send_photo(
path.join(app.config["locations"]["tmp"], tmp_path), app.config["posting"]["channel"],
caption=caption, path.join(app.config["locations"]["tmp"], tmp_path),
disable_notification=app.config["posting"]["silent"], 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: except Exception as exp:
logger.error(f"Could not send image {pic.filename} ({pic.id}) due to {exp}") logger.error(
f"Could not send media {media.filename} ({media.id}) due to {exp}"
)
if app.config["reports"]["error"]: if app.config["reports"]["error"]:
await app.send_message( await app.send_message(
app.owner, app.owner,
@ -169,8 +207,8 @@ async def send_content(app: Client, http_session: ClientSession) -> None:
col_sent.insert_one( col_sent.insert_one(
{ {
"date": datetime.now(), "date": datetime.now(),
"image": pic.id, "image": media.id,
"filename": pic.filename, "filename": media.filename,
"channel": app.config["posting"]["channel"], "channel": app.config["posting"]["channel"],
"caption": None "caption": None
if (submitted is None or submitted["caption"] is None) if (submitted is None or submitted["caption"] is None)
@ -178,13 +216,14 @@ async def send_content(app: Client, http_session: ClientSession) -> None:
} }
) )
await photo_patch(id=pic.id, client=client, caption="sent") 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) rmtree(path.join(app.config["locations"]["tmp"], tmp_dir), ignore_errors=True)
logger.info( logger.info(
app._("post_sent", "console").format( app._("post_sent", "console").format(
pic.id, media.id,
str(app.config["posting"]["channel"]), str(app.config["posting"]["channel"]),
caption.replace("\n", "%n"), caption.replace("\n", "%n"),
str(app.config["posting"]["silent"]), str(app.config["posting"]["silent"]),

View File

@ -18,7 +18,7 @@ from ujson import loads
from classes.pyroclient import PyroClient from classes.pyroclient import PyroClient
from modules.api_client import ( from modules.api_client import (
BodyPhotoUploadAlbumsAlbumPhotosPost, BodyPhotoUpload,
File, File,
client, client,
photo_delete, photo_delete,
@ -158,7 +158,7 @@ async def cmd_import(app: PyroClient, msg: Message):
uploaded = await photo_upload( uploaded = await photo_upload(
app.config["posting"]["api"]["album"], app.config["posting"]["api"]["album"],
client=client, client=client,
multipart_data=BodyPhotoUploadAlbumsAlbumPhotosPost( multipart_data=BodyPhotoUpload(
File(photo_bytes, Path(filename).name, "image/jpeg") File(photo_bytes, Path(filename).name, "image/jpeg")
), ),
ignore_duplicates=app.config["submission"]["allow_duplicates"], ignore_duplicates=app.config["submission"]["allow_duplicates"],

View File

@ -215,7 +215,7 @@ async def get_submission(app: PyroClient, msg: Message):
and app.config["submission"]["require_confirmation"]["admins"] is False and app.config["submission"]["require_confirmation"]["admins"] is False
): ):
try: try:
submitted = await app.submit_photo(str(inserted.inserted_id)) submitted = await app.submit_media(str(inserted.inserted_id))
await msg.reply_text( await msg.reply_text(
app._("sub_yes_auto", "message", locale=user_locale), app._("sub_yes_auto", "message", locale=user_locale),
disable_notification=True, disable_notification=True,