2121import pandas as pd
2222import numpy as np
2323import gzip
24+ import re
2425from astropy .io import fits
2526
2627import matplotlib .pyplot as plt
3132COLORS_ZTF = {1 : "#15284F" , 2 : "#F5622E" }
3233
3334
35+ def escape (text ):
36+ """Escapes the text as needed for MarkdownV2 parse_mode
37+
38+ Parameters
39+ ----------
40+ text : Text to escape
41+
42+ Returns
43+ -------
44+ result : str
45+ """
46+ return re .sub (r'[_*[\]()~>#\+\-=|{}.!]' , lambda x : '\\ ' + x .group (), text )
47+
48+
3449def status_check (res , header , sleep = 8 , timeout = 25 ):
3550 """Checks whether the request was successful.
3651
@@ -86,7 +101,7 @@ def send_simple_text_tg(text, channel_id, timeout=25):
86101 status_check (res , header = channel_id )
87102
88103
89- def msg_handler_tg (tg_data , channel_id , init_msg , timeout = 25 ):
104+ def msg_handler_tg (tg_data , channel_id , init_msg = None , timeout = 25 , sleep_seconds = 10 , parse_mode = "markdown" ):
90105 """Send `tg_data` to a telegram channel
91106
92107 Notes
@@ -100,14 +115,19 @@ def msg_handler_tg(tg_data, channel_id, init_msg, timeout=25):
100115 Content of the tuple:
101116 text_data : str
102117 Notification text
103- cutout : BytesIO stream
104- cutout image in png format
118+ cutout : BytesIO stream or str
119+ cutout image in png format, image url, or a list of these
105120 curve : BytesIO stream
106121 light curve picture
107122 channel_id: string
108123 Channel id in Telegram
109124 init_msg: str
110125 Initial message
126+ timeout: int
127+ Timeout when sending message. Default is 25 seconds.
128+ sleep_seconds: int
129+ How many seconds to sleep between two messages to avoid
130+ code 429 from the Telegram API. Default is 10 seconds.
111131
112132 Returns
113133 -------
@@ -117,29 +137,48 @@ def msg_handler_tg(tg_data, channel_id, init_msg, timeout=25):
117137 url += os .environ ["FINK_TG_TOKEN" ]
118138 method = url + "/sendMediaGroup"
119139
120- if init_msg != "" :
121- send_simple_text_tg (init_msg , channel_id , timeout = 25 )
140+ files = {}
141+ media = []
142+
143+ def add (data , text = None , parse_mode = parse_mode ):
144+ # TODO: handle text-only messages?
145+ item = {
146+ "type" : "photo" ,
147+ }
148+
149+ if isinstance (data , str ):
150+ item ["media" ] = data
151+ elif data is not None :
152+ fname = "file{}" .format (len (files ))
153+ files [fname ] = data
154+ item ["media" ] = "attach://{}" .format (fname )
155+
156+ if text is not None :
157+ item ["caption" ] = text
158+ item ["parse_mode" ] = parse_mode
159+
160+ media .append (item )
161+
162+ if init_msg :
163+ send_simple_text_tg (init_msg , channel_id , timeout = timeout )
122164 for text_data , cutout , curve in tg_data :
123- files = {"first" : curve }
124- media = [
125- {
126- "type" : "photo" ,
127- "media" : "attach://first" ,
128- "caption" : text_data ,
129- "parse_mode" : "markdown" ,
130- }
131- ]
132- if cutout is not None :
133- files .update ({"second" : cutout })
134- media .append ({"type" : "photo" , "media" : "attach://second" })
165+ if curve is not None :
166+ add (curve , text_data )
167+
168+ if isinstance (cutout , list ):
169+ for c in cutout :
170+ add (c )
171+ else :
172+ add (cutout )
173+
135174 res = requests .post (
136175 method ,
137176 params = {"chat_id" : channel_id , "media" : str (media ).replace ("'" , '"' )},
138177 files = files ,
139178 timeout = timeout ,
140179 )
141180 status_check (res , header = channel_id )
142- time .sleep (10 )
181+ time .sleep (sleep_seconds )
143182
144183
145184def msg_handler_tg_cutouts (tg_data , channel_id , init_msg , timeout = 25 , sleep_seconds = 10 ):
0 commit comments