1
- import logging
2
1
import re
2
+ from base64 import b64decode
3
3
from datetime import datetime , timedelta
4
4
from enum import Enum
5
+ from io import BytesIO
5
6
from typing import Optional
6
7
7
8
import pytz
9
+ from PIL import Image as pil_image
8
10
from markdown import markdown
9
11
from maubot import Plugin
10
12
from maubot .matrix import MaubotMessageEvent
13
+ from mautrix .crypto .attachments import encrypt_attachment
11
14
from mautrix .errors .request import MForbidden
12
15
from mautrix .types import TextMessageEventContent , Format , MessageType , RoomID , PaginationDirection , \
13
- MessageEventContent , EventID
16
+ MessageEventContent , EventID , MediaMessageEventContent , ImageInfo , EventType , ThumbnailInfo
14
17
15
18
from .db import LifetimeEnd
16
19
17
20
21
+ class Image :
22
+ content : str
23
+ content_type : str
24
+ name : str
25
+ thumbnail_size : int
26
+
27
+ def __init__ (self , content : str , content_type : str , name : str , thumbnail_size : int ):
28
+ self .content = content
29
+ self .content_type = content_type
30
+ self .name = name
31
+ self .thumbnail_size = thumbnail_size
32
+
33
+
18
34
class RoomPosterType (Enum ):
19
35
MESSAGE = 1
20
36
EDIT = 2
21
37
REDACTION = 3
22
38
REACTION = 4
39
+ IMAGE = 5
23
40
24
41
@classmethod
25
42
def get_type_from_str (cls , mtype : str ):
@@ -28,7 +45,8 @@ def get_type_from_str(cls, mtype: str):
28
45
"message" : RoomPosterType .MESSAGE ,
29
46
"redaction" : RoomPosterType .REDACTION ,
30
47
"edit" : RoomPosterType .EDIT ,
31
- "reaction" : RoomPosterType .REACTION
48
+ "reaction" : RoomPosterType .REACTION ,
49
+ "image" : RoomPosterType .IMAGE
32
50
}
33
51
return type_switcher .get (mtype )
34
52
@@ -43,22 +61,23 @@ class RoomPoster:
43
61
lifetime : int
44
62
45
63
def __init__ (self , hasswebhook : Plugin , identifier : str , rp_type : RoomPosterType , room_id : str ,
46
- message = "" , callback_url = "" , lifetime = - 1 ):
64
+ image : Optional [ Image ] = None , message = "" , callback_url = "" , lifetime = - 1 ):
47
65
self .rp_type = rp_type
48
66
self .room_id = RoomID (room_id )
49
67
self .hasswebhook = hasswebhook
50
68
self .identifier = identifier
51
69
self .callback_url = callback_url
52
70
self .message = message
53
71
self .lifetime = lifetime
72
+ self .image = image
54
73
55
74
# Send a POST as a callback containing the event_id of the sent message
56
75
async def callback (self , event_id : str ) -> None :
57
76
if self .callback_url :
58
77
await self .hasswebhook .http .post (self .callback_url , json = {'event_id' : event_id })
59
78
60
79
# Switch for each RoomPosterType
61
- async def post_to_room (self ) -> bool :
80
+ async def post_to_room (self ):
62
81
if self .rp_type == RoomPosterType .MESSAGE :
63
82
return await self .post_message ()
64
83
if self .rp_type == RoomPosterType .REDACTION :
@@ -67,10 +86,44 @@ async def post_to_room(self) -> bool:
67
86
return await self .post_edit ()
68
87
if self .rp_type == RoomPosterType .REACTION :
69
88
return await self .post_reaction ()
89
+ if self .rp_type == RoomPosterType .IMAGE :
90
+ return await self .post_image ()
70
91
return False
71
92
93
+ async def post_image (self ) -> str :
94
+ media_event = MediaMessageEventContent (body = self .image .name , msgtype = MessageType .IMAGE )
95
+
96
+ upload_mime = "application/octet-stream"
97
+ bytes_image = b64decode (self .image .content )
98
+ encrypted_image , file = encrypt_attachment (bytes_image )
99
+ file .url = await self .hasswebhook .client .upload_media (encrypted_image , mime_type = upload_mime )
100
+ media_event .file = file
101
+
102
+ img = pil_image .open (BytesIO (bytes_image ))
103
+ image_info = ImageInfo (mimetype = self .image .content_type , height = img .height , width = img .width )
104
+ media_event .info = image_info
105
+
106
+ byt_arr_tn = BytesIO ()
107
+ img .thumbnail ((self .image .thumbnail_size , self .image .thumbnail_size ), pil_image .ANTIALIAS )
108
+ img .save (byt_arr_tn , format = 'PNG' )
109
+
110
+ tn_img = pil_image .open (byt_arr_tn )
111
+ enc_tn , tn_file = encrypt_attachment (byt_arr_tn .getvalue ())
112
+
113
+ image_info .thumbnail_info = ThumbnailInfo (mimetype = "image/png" , height = tn_img .height , width = tn_img .width )
114
+ tn_file .url = await self .hasswebhook .client .upload_media (enc_tn , mime_type = upload_mime )
115
+ image_info .thumbnail_file = tn_file
116
+
117
+ img .close ()
118
+ tn_img .close ()
119
+
120
+ event_id = await self .hasswebhook .client .send_message_event (self .room_id , event_type = EventType .ROOM_MESSAGE ,
121
+ content = media_event )
122
+ await self .callback (event_id )
123
+ return event_id
124
+
72
125
# Send message to room
73
- async def post_message (self ) -> bool :
126
+ async def post_message (self ):
74
127
body = "{message} by {identifier}" .format (
75
128
message = self .message , identifier = self .identifier ) if self .identifier else self .message
76
129
content = TextMessageEventContent (
@@ -87,10 +140,10 @@ async def post_message(self) -> bool:
87
140
end_time = datetime .now (tz = pytz .UTC ) + timedelta (minutes = self .lifetime )
88
141
self .hasswebhook .db .insert (
89
142
LifetimeEnd (end_date = end_time , room_id = self .room_id , event_id = event_id_req ))
143
+ return event_id_req
90
144
except MForbidden :
91
145
self .hasswebhook .log .error ("Wrong Room ID" )
92
146
return False
93
- return True
94
147
95
148
# Redact message
96
149
async def post_redaction (self ) -> bool :
0 commit comments