Update to telethon 1.8. Fixes #334

This commit is contained in:
Tulir Asokan
2019-06-20 21:42:22 +03:00
parent 070601689a
commit 5fba658c66
5 changed files with 96 additions and 41 deletions
+1 -1
View File
@@ -309,7 +309,7 @@ class AbstractUser(ABC):
if await puppet.update_displayname(self, update):
puppet.save()
elif isinstance(update, UpdateUserPhoto):
if await puppet.update_avatar(self, update.photo.photo_big):
if await puppet.update_avatar(self, update.photo):
puppet.save()
else:
self.log.warning("Unexpected other user info update: %s", update)
+58 -28
View File
@@ -47,13 +47,13 @@ from telethon.errors import (ChatAdminRequiredError, ChatNotModifiedError, Photo
PhotoInvalidDimensionsError, PhotoSaveFileInvalidError)
from telethon.tl.patched import Message, MessageService
from telethon.tl.types import (
Channel, ChatAdminRights, ChatBannedRights, ChannelFull, ChannelParticipantAdmin,
Channel, ChatAdminRights, ChatBannedRights, ChannelFull, ChannelParticipantAdmin, Document,
ChannelParticipantCreator, ChannelParticipantsRecent, ChannelParticipantsSearch, Chat,
ChatFull, ChatInviteEmpty, ChatParticipantAdmin, ChatParticipantCreator, ChatPhoto, Poll,
DocumentAttributeFilename, DocumentAttributeImageSize, DocumentAttributeSticker,
DocumentAttributeVideo, FileLocation, GeoPoint, InputChannel, InputChatUploadedPhoto,
DocumentAttributeFilename, DocumentAttributeImageSize, DocumentAttributeSticker, PhotoEmpty,
DocumentAttributeVideo, GeoPoint, InputChannel, InputChatUploadedPhoto, InputPhotoFileLocation,
InputPeerChannel, InputPeerChat, InputPeerUser, InputUser, InputUserSelf, MessageMediaPoll,
MessageActionChannelCreate, MessageActionChatAddUser, MessageActionChatCreate,
MessageActionChannelCreate, MessageActionChatAddUser, MessageActionChatCreate, ChatPhotoEmpty,
MessageActionChatDeletePhoto, MessageActionChatDeleteUser, MessageActionChatEditPhoto,
MessageActionChatEditTitle, MessageActionChatJoinedByLink, MessageActionChatMigrateTo,
MessageActionPinMessage, MessageActionGameScore, MessageMediaContact, MessageMediaDocument,
@@ -63,7 +63,7 @@ from telethon.tl.types import (
TypeDocumentAttribute, TypeInputPeer, TypeMessageAction, TypeMessageEntity, TypePeer,
TypePhotoSize, TypeUpdates, TypeUser, PhotoSize, TypeUserFull, UpdateChatUserTyping,
UpdateNewChannelMessage, UpdateNewMessage, UpdateUserTyping, User, UserFull, MessageEntityPre,
InputMediaUploadedDocument)
InputMediaUploadedDocument, InputPeerPhotoFileLocation)
from mautrix_appservice import MatrixRequestError, IntentError, AppService, IntentAPI
from .types import MatrixEventID, MatrixRoomID, MatrixUserID, TelegramID
@@ -575,7 +575,7 @@ class Portal:
changed = await self.update_title(entity.title) or changed
if isinstance(entity.photo, ChatPhoto):
changed = await self.update_avatar(user, entity.photo.photo_big) or changed
changed = await self.update_avatar(user, entity.photo) or changed
if changed:
self.save()
@@ -616,12 +616,21 @@ class Portal:
return False
@staticmethod
def _get_largest_photo_size(photo: Union[Photo, List[TypePhotoSize]]
) -> Optional[TypePhotoSize]:
def _get_largest_photo_size(photo: Union[Photo, Document]
) -> Tuple[Optional[InputPhotoFileLocation],
Optional[TypePhotoSize]]:
if not photo:
return None
return max(photo.sizes if isinstance(photo, Photo) else photo, key=(lambda photo2: (
len(photo2.bytes) if not isinstance(photo2, PhotoSize) else photo2.size)))
return None, None
largest = max(photo.sizes if isinstance(photo, Photo) else photo.thumbs,
key=(lambda photo2: (len(photo2.bytes)
if not isinstance(photo2, PhotoSize)
else photo2.size)))
return InputPhotoFileLocation(
id=photo.id,
access_hash=photo.access_hash,
file_reference=photo.file_reference,
thumb_size=largest.type,
), largest
async def remove_avatar(self, _: 'AbstractUser', save: bool = False) -> None:
await self.main_intent.set_room_avatar(self.mxid, None)
@@ -629,11 +638,33 @@ class Portal:
if save:
self.save()
async def update_avatar(self, user: 'AbstractUser', photo: FileLocation,
async def update_avatar(self, user: 'AbstractUser',
photo: Union[ChatPhoto, ChatPhotoEmpty, Photo, PhotoEmpty],
save: bool = False) -> bool:
photo_id = f"{photo.volume_id}-{photo.local_id}"
if isinstance(photo, ChatPhoto):
loc = InputPeerPhotoFileLocation(
peer=await self.get_input_entity(user),
local_id=photo.photo_big.local_id,
volume_id=photo.photo_big.volume_id,
big=True
)
photo_id = f"{loc.volume_id}-{loc.local_id}"
elif isinstance(photo, Photo):
loc, largest = self._get_largest_photo_size(photo)
photo_id = f"{largest.location.volume_id}-{largest.location.local_id}"
elif isinstance(photo, (ChatPhotoEmpty, PhotoEmpty)):
photo_id = ""
loc = None
else:
raise ValueError(f"Unknown photo type {type(photo)}")
if self.photo_id != photo_id:
file = await util.transfer_file_to_matrix(user.client, self.main_intent, photo)
if not photo_id:
await self.main_intent.set_room_avatar(self.mxid, "")
self.photo_id = ""
if save:
self.save()
return True
file = await util.transfer_file_to_matrix(user.client, self.main_intent, loc)
if file:
await self.main_intent.set_room_avatar(self.mxid, file.mxc)
self.photo_id = photo_id
@@ -1212,8 +1243,8 @@ class Portal:
and isinstance(update.message, MessageService)
and isinstance(update.message.action, MessageActionChatEditPhoto))
if is_photo_update:
loc = self._get_largest_photo_size(update.message.action.photo).location
self.photo_id = f"{loc.volume_id}-{loc.local_id}"
loc, size = self._get_largest_photo_size(update.message.action.photo)
self.photo_id = f"{size.location.volume_id}-{size.location.local_id}"
self.save()
break
@@ -1368,8 +1399,8 @@ class Portal:
async def handle_telegram_photo(self, source: 'AbstractUser', intent: IntentAPI, evt: Message,
relates_to: Dict = None) -> Optional[Dict]:
largest_size = self._get_largest_photo_size(evt.media.photo)
file = await util.transfer_file_to_matrix(source.client, intent, largest_size.location)
loc, largest_size = self._get_largest_photo_size(evt.media.photo)
file = await util.transfer_file_to_matrix(source.client, intent, loc)
if not file:
return None
if self.get_config("inline_images") and (evt.message
@@ -1429,7 +1460,7 @@ class Portal:
@staticmethod
def _parse_telegram_document_meta(evt: Message, file: DBTelegramFile, attrs: Dict,
thumb: TypePhotoSize) -> Tuple[Dict, str]:
thumb_size: TypePhotoSize) -> Tuple[Dict, str]:
document = evt.media.document
name = evt.message or attrs["name"]
if attrs["is_sticker"]:
@@ -1461,8 +1492,8 @@ class Portal:
info["thumbnail_url"] = file.thumbnail.mxc
info["thumbnail_info"] = {
"mimetype": file.thumbnail.mime_type,
"h": file.thumbnail.height or thumb.h,
"w": file.thumbnail.width or thumb.w,
"h": file.thumbnail.height or thumb_size.h,
"w": file.thumbnail.width or thumb_size.w,
"size": file.thumbnail.size,
}
@@ -1473,16 +1504,16 @@ class Portal:
document = evt.media.document
attrs = self._parse_telegram_document_attributes(document.attributes)
thumb = self._get_largest_photo_size(document.thumbs)
if thumb and not isinstance(thumb, (PhotoSize, PhotoCachedSize)):
self.log.debug(f"Unsupported thumbnail type {type(thumb)}")
thumb_loc, thumb_size = self._get_largest_photo_size(document)
if thumb_size and not isinstance(thumb_size, (PhotoSize, PhotoCachedSize)):
self.log.debug(f"Unsupported thumbnail type {type(thumb_size)}")
thumb = None
file = await util.transfer_file_to_matrix(source.client, intent, document, thumb,
file = await util.transfer_file_to_matrix(source.client, intent, document, thumb_loc,
is_sticker=attrs["is_sticker"])
if not file:
return None
info, name = self._parse_telegram_document_meta(evt, file, attrs, thumb)
info, name = self._parse_telegram_document_meta(evt, file, attrs, thumb_size)
await intent.set_typing(self.mxid, is_typing=False)
@@ -1819,8 +1850,7 @@ class Portal:
if isinstance(action, MessageActionChatEditTitle):
await self.update_title(action.title, save=True)
elif isinstance(action, MessageActionChatEditPhoto):
largest_size = self._get_largest_photo_size(action.photo)
await self.update_avatar(source, largest_size.location, save=True)
await self.update_avatar(source, action.photo, save=True)
elif isinstance(action, MessageActionChatDeletePhoto):
await self.remove_avatar(source, save=True)
elif isinstance(action, MessageActionChatAddUser):
+29 -6
View File
@@ -22,7 +22,8 @@ import asyncio
import logging
import re
from telethon.tl.types import UserProfilePhoto, User, FileLocation, UpdateUserName, PeerUser
from telethon.tl.types import (UserProfilePhoto, User, UpdateUserName, PeerUser, TypeInputPeer,
InputPeerPhotoFileLocation, UserProfilePhotoEmpty)
from mautrix_appservice import AppService, IntentAPI, IntentError, MatrixRequestError
from .types import MatrixUserID, TelegramID
@@ -113,6 +114,9 @@ class Puppet:
match = regex.match(self.displayname)
return match.group(1) or self.displayname
def get_input_entity(self, user: 'AbstractUser') -> Awaitable[TypeInputPeer]:
return user.client.get_input_entity(PeerUser(user_id=self.tgid))
# region Custom puppet management
def _fresh_intent(self) -> IntentAPI:
return (self.az.intent.user(self.custom_mxid, self.access_token)
@@ -348,7 +352,7 @@ class Puppet:
changed = await self.update_displayname(source, info) or changed
if isinstance(info.photo, UserProfilePhoto):
changed = await self.update_avatar(source, info.photo.photo_big) or changed
changed = await self.update_avatar(source, info.photo) or changed
self.is_bot = info.bot
@@ -384,13 +388,32 @@ class Puppet:
return True
return False
async def update_avatar(self, source: 'AbstractUser', photo: FileLocation) -> bool:
async def update_avatar(self, source: 'AbstractUser',
photo: Union[UserProfilePhoto, UserProfilePhotoEmpty]) -> bool:
if self.disable_updates:
return False
photo_id = f"{photo.volume_id}-{photo.local_id}"
if isinstance(photo, UserProfilePhotoEmpty):
photo_id = ""
else:
photo_id = str(photo.photo_id)
if self.photo_id != photo_id:
file = await util.transfer_file_to_matrix(source.client, self.default_mxid_intent,
photo)
if not photo_id:
self.photo_id = ""
try:
await self.default_mxid_intent.set_avatar("")
except MatrixRequestError:
self.log.exception("Failed to set avatar")
self.photo_id = ""
return True
loc = InputPeerPhotoFileLocation(
peer=await self.get_input_entity(source),
local_id=photo.photo_big.local_id,
volume_id=photo.photo_big.volume_id,
big=True
)
file = await util.transfer_file_to_matrix(source.client, self.default_mxid_intent, loc)
if file:
self.photo_id = photo_id
try:
+7 -5
View File
@@ -23,8 +23,9 @@ import asyncio
import magic
from sqlalchemy.exc import IntegrityError, InvalidRequestError
from telethon.tl.types import (Document, FileLocation, InputFileLocation, InputDocumentFileLocation,
TypePhotoSize, PhotoSize, PhotoCachedSize)
from telethon.tl.types import (Document, InputFileLocation, InputDocumentFileLocation,
TypePhotoSize, PhotoSize, PhotoCachedSize, InputPhotoFileLocation,
InputPeerPhotoFileLocation)
from telethon.errors import (AuthBytesInvalidError, AuthKeyInvalidError, LocationInvalidError,
SecurityError)
from mautrix_appservice import IntentAPI
@@ -47,7 +48,8 @@ except ImportError:
log = logging.getLogger("mau.util") # type: logging.Logger
TypeLocation = Union[Document, InputDocumentFileLocation, FileLocation, InputFileLocation]
TypeLocation = Union[Document, InputDocumentFileLocation, InputPeerPhotoFileLocation,
InputFileLocation, InputPhotoFileLocation]
def convert_image(file: bytes, source_mime: str = "image/webp", target_type: str = "png",
@@ -99,9 +101,9 @@ def _read_video_thumbnail(data: bytes, video_ext: str = "mp4", frame_ext: str =
def _location_to_id(location: TypeLocation) -> str:
if isinstance(location, (Document, InputDocumentFileLocation)):
if isinstance(location, (Document, InputDocumentFileLocation, InputPhotoFileLocation)):
return f"{location.id}-{location.access_hash}"
elif isinstance(location, (FileLocation, InputFileLocation)):
elif isinstance(location, (InputFileLocation, InputPeerPhotoFileLocation)):
return f"{location.volume_id}-{location.local_id}"
+1 -1
View File
@@ -38,7 +38,7 @@ setuptools.setup(
"ruamel.yaml>=0.15.35,<0.16",
"future-fstrings>=0.4.2",
"python-magic>=0.4.15,<0.5",
"telethon>=1.5.5,<1.7",
"telethon>=1.7,<1.9",
"telethon-session-sqlalchemy>=0.2.14,<0.3",
],
extras_require=extras,