Rubka 7.2.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rubka/__init__.py +79 -0
- rubka/adaptorrubka/__init__.py +4 -0
- rubka/adaptorrubka/client/__init__.py +1 -0
- rubka/adaptorrubka/client/client.py +60 -0
- rubka/adaptorrubka/crypto/__init__.py +1 -0
- rubka/adaptorrubka/crypto/crypto.py +82 -0
- rubka/adaptorrubka/enums.py +36 -0
- rubka/adaptorrubka/exceptions.py +22 -0
- rubka/adaptorrubka/methods/__init__.py +1 -0
- rubka/adaptorrubka/methods/methods.py +90 -0
- rubka/adaptorrubka/network/__init__.py +3 -0
- rubka/adaptorrubka/network/helper.py +22 -0
- rubka/adaptorrubka/network/network.py +221 -0
- rubka/adaptorrubka/network/socket.py +31 -0
- rubka/adaptorrubka/sessions/__init__.py +1 -0
- rubka/adaptorrubka/sessions/sessions.py +72 -0
- rubka/adaptorrubka/types/__init__.py +1 -0
- rubka/adaptorrubka/types/socket/__init__.py +1 -0
- rubka/adaptorrubka/types/socket/message.py +187 -0
- rubka/adaptorrubka/utils/__init__.py +2 -0
- rubka/adaptorrubka/utils/configs.py +18 -0
- rubka/adaptorrubka/utils/utils.py +251 -0
- rubka/api.py +1723 -0
- rubka/asynco.py +2541 -0
- rubka/button.py +404 -0
- rubka/config.py +3 -0
- rubka/context.py +1077 -0
- rubka/decorators.py +30 -0
- rubka/exceptions.py +37 -0
- rubka/filters.py +330 -0
- rubka/helpers.py +1461 -0
- rubka/jobs.py +15 -0
- rubka/keyboards.py +16 -0
- rubka/keypad.py +298 -0
- rubka/logger.py +12 -0
- rubka/metadata.py +114 -0
- rubka/rubino.py +1271 -0
- rubka/tv.py +145 -0
- rubka/update.py +1038 -0
- rubka/utils.py +3 -0
- rubka-7.2.8.dist-info/METADATA +1047 -0
- rubka-7.2.8.dist-info/RECORD +45 -0
- rubka-7.2.8.dist-info/WHEEL +5 -0
- rubka-7.2.8.dist-info/entry_points.txt +2 -0
- rubka-7.2.8.dist-info/top_level.txt +1 -0
rubka/jobs.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
import time
|
|
3
|
+
from typing import Callable
|
|
4
|
+
|
|
5
|
+
class Job:
|
|
6
|
+
def __init__(self, delay: int, callback: Callable):
|
|
7
|
+
self.delay = delay
|
|
8
|
+
self.callback = callback
|
|
9
|
+
thread = threading.Thread(target=self.run)
|
|
10
|
+
thread.daemon = True
|
|
11
|
+
thread.start()
|
|
12
|
+
|
|
13
|
+
def run(self):
|
|
14
|
+
time.sleep(self.delay)
|
|
15
|
+
self.callback()
|
rubka/keyboards.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Dict, List
|
|
2
|
+
|
|
3
|
+
def create_simple_keyboard(buttons: List[List[str]]) -> Dict:
|
|
4
|
+
"""
|
|
5
|
+
Create a simple chat keypad (keyboard) structure for Rubika.
|
|
6
|
+
buttons: List of button rows, each row is a list of button texts.
|
|
7
|
+
Example:
|
|
8
|
+
[
|
|
9
|
+
["Button1", "Button2"],
|
|
10
|
+
["Button3"]
|
|
11
|
+
]
|
|
12
|
+
"""
|
|
13
|
+
keyboard = {"rows": []}
|
|
14
|
+
for row in buttons:
|
|
15
|
+
keyboard["rows"].append({"buttons": [{"text": text} for text in row]})
|
|
16
|
+
return keyboard
|
rubka/keypad.py
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
from typing import Dict
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Optional, Union
|
|
4
|
+
from typing import Dict, List, Optional
|
|
5
|
+
|
|
6
|
+
class InlineBuilder:
|
|
7
|
+
def __init__(self):
|
|
8
|
+
self.rows: List[Dict] = []
|
|
9
|
+
|
|
10
|
+
def row(self, *buttons: Dict) -> "InlineBuilder":
|
|
11
|
+
"""
|
|
12
|
+
افزودن یک ردیف دکمه به کیبورد
|
|
13
|
+
حداقل یک دکمه باید داده شود.
|
|
14
|
+
"""
|
|
15
|
+
if not buttons:
|
|
16
|
+
raise ValueError("حداقل یک دکمه باید به row داده شود")
|
|
17
|
+
self.rows.append({"buttons": list(buttons)})
|
|
18
|
+
return self
|
|
19
|
+
|
|
20
|
+
def button_simple(self, id: str, text: str) -> Dict:
|
|
21
|
+
return {"id": id, "type": "Simple", "button_text": text}
|
|
22
|
+
|
|
23
|
+
def button_selection(self, id: str, text: str, selection: Dict) -> Dict:
|
|
24
|
+
"""
|
|
25
|
+
selection: dict با فیلدهای:
|
|
26
|
+
- selection_id (str)
|
|
27
|
+
- search_type (str) [ButtonSelectionSearchEnum: None, Local, Api]
|
|
28
|
+
- get_type (str) [ButtonSelectionGetEnum: Local, Api]
|
|
29
|
+
- items (list of ButtonSelectionItem)
|
|
30
|
+
- is_multi_selection (bool)
|
|
31
|
+
- columns_count (str)
|
|
32
|
+
- title (str)
|
|
33
|
+
"""
|
|
34
|
+
return {
|
|
35
|
+
"id": id,
|
|
36
|
+
"type": "Selection",
|
|
37
|
+
"button_text": text,
|
|
38
|
+
"button_selection": selection
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
def button_calendar(self, id: str, title: str, type_: str,
|
|
42
|
+
default_value: Optional[str] = None,
|
|
43
|
+
min_year: Optional[str] = None,
|
|
44
|
+
max_year: Optional[str] = None) -> Dict:
|
|
45
|
+
"""
|
|
46
|
+
type_: ButtonCalendarTypeEnum = "DatePersian" | "DateGregorian"
|
|
47
|
+
"""
|
|
48
|
+
calendar = {
|
|
49
|
+
"title": title,
|
|
50
|
+
"type": type_,
|
|
51
|
+
}
|
|
52
|
+
if default_value:
|
|
53
|
+
calendar["default_value"] = default_value
|
|
54
|
+
if min_year:
|
|
55
|
+
calendar["min_year"] = min_year
|
|
56
|
+
if max_year:
|
|
57
|
+
calendar["max_year"] = max_year
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
"id": id,
|
|
61
|
+
"type": "Calendar",
|
|
62
|
+
"button_text": title,
|
|
63
|
+
"button_calendar": calendar
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
def button_number_picker(self, id: str, title: str, min_value: str, max_value: str,
|
|
67
|
+
default_value: Optional[str] = None) -> Dict:
|
|
68
|
+
picker = {
|
|
69
|
+
"title": title,
|
|
70
|
+
"min_value": min_value,
|
|
71
|
+
"max_value": max_value,
|
|
72
|
+
}
|
|
73
|
+
if default_value:
|
|
74
|
+
picker["default_value"] = default_value
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
"id": id,
|
|
78
|
+
"type": "NumberPicker",
|
|
79
|
+
"button_text": title,
|
|
80
|
+
"button_number_picker": picker
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
def button_string_picker(self, id: str, title: Optional[str], items: List[str],
|
|
84
|
+
default_value: Optional[str] = None) -> Dict:
|
|
85
|
+
picker = {
|
|
86
|
+
"items": items
|
|
87
|
+
}
|
|
88
|
+
if default_value:
|
|
89
|
+
picker["default_value"] = default_value
|
|
90
|
+
if title:
|
|
91
|
+
picker["title"] = title
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
"id": id,
|
|
95
|
+
"type": "StringPicker",
|
|
96
|
+
"button_text": title if title else "انتخاب",
|
|
97
|
+
"button_string_picker": picker
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
def button_location(self, id: str, type_: str, location_image_url: str,
|
|
101
|
+
default_pointer_location: Optional[Dict] = None,
|
|
102
|
+
default_map_location: Optional[Dict] = None,
|
|
103
|
+
title: Optional[str] = None) -> Dict:
|
|
104
|
+
"""
|
|
105
|
+
type_: ButtonLocationTypeEnum = "Picker" | "View"
|
|
106
|
+
location_image_url: str آدرس عکس دکمه موقعیت
|
|
107
|
+
default_pointer_location و default_map_location هر کدام دیکشنری Location (latitude, longitude)
|
|
108
|
+
"""
|
|
109
|
+
loc = {
|
|
110
|
+
"type": type_,
|
|
111
|
+
"location_image_url": location_image_url,
|
|
112
|
+
}
|
|
113
|
+
if default_pointer_location:
|
|
114
|
+
loc["default_pointer_location"] = default_pointer_location
|
|
115
|
+
if default_map_location:
|
|
116
|
+
loc["default_map_location"] = default_map_location
|
|
117
|
+
if title:
|
|
118
|
+
loc["title"] = title
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
"id": id,
|
|
122
|
+
"type": "Location",
|
|
123
|
+
"button_text": title if title else "موقعیت مکانی",
|
|
124
|
+
"button_location": loc
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
def button_textbox(self, id: str, title: Optional[str],
|
|
128
|
+
type_line: str, type_keypad: str,
|
|
129
|
+
place_holder: Optional[str] = None,
|
|
130
|
+
default_value: Optional[str] = None) -> Dict:
|
|
131
|
+
"""
|
|
132
|
+
type_line: ButtonTextboxTypeLineEnum = "SingleLine" | "MultiLine"
|
|
133
|
+
type_keypad: ButtonTextboxTypeKeypadEnum = "String" | "Number"
|
|
134
|
+
"""
|
|
135
|
+
textbox = {
|
|
136
|
+
"type_line": type_line,
|
|
137
|
+
"type_keypad": type_keypad
|
|
138
|
+
}
|
|
139
|
+
if place_holder:
|
|
140
|
+
textbox["place_holder"] = place_holder
|
|
141
|
+
if default_value:
|
|
142
|
+
textbox["default_value"] = default_value
|
|
143
|
+
if title:
|
|
144
|
+
textbox["title"] = title
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
"id": id,
|
|
148
|
+
"type": "Textbox",
|
|
149
|
+
"button_text": title if title else "متن",
|
|
150
|
+
"button_textbox": textbox
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
def button_payment(self, id: str, title: str, amount: int, description: Optional[str] = None) -> Dict:
|
|
154
|
+
"""
|
|
155
|
+
نمونهای ساده برای دکمه پرداخت (مقدار و توضیح دلخواه)
|
|
156
|
+
"""
|
|
157
|
+
payment = {
|
|
158
|
+
"title": title,
|
|
159
|
+
"amount": amount
|
|
160
|
+
}
|
|
161
|
+
if description:
|
|
162
|
+
payment["description"] = description
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
"id": id,
|
|
166
|
+
"type": "Payment",
|
|
167
|
+
"button_text": title,
|
|
168
|
+
"button_payment": payment
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
def button_camera_image(self, id: str, title: str) -> Dict:
|
|
172
|
+
return {
|
|
173
|
+
"id": id,
|
|
174
|
+
"type": "CameraImage",
|
|
175
|
+
"button_text": title
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
def button_camera_video(self, id: str, title: str) -> Dict:
|
|
179
|
+
return {
|
|
180
|
+
"id": id,
|
|
181
|
+
"type": "CameraVideo",
|
|
182
|
+
"button_text": title
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
def button_gallery_image(self, id: str, title: str) -> Dict:
|
|
186
|
+
return {
|
|
187
|
+
"id": id,
|
|
188
|
+
"type": "GalleryImage",
|
|
189
|
+
"button_text": title
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
def button_gallery_video(self, id: str, title: str) -> Dict:
|
|
193
|
+
return {
|
|
194
|
+
"id": id,
|
|
195
|
+
"type": "GalleryVideo",
|
|
196
|
+
"button_text": title
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
def button_file(self, id: str, title: str) -> Dict:
|
|
200
|
+
return {
|
|
201
|
+
"id": id,
|
|
202
|
+
"type": "File",
|
|
203
|
+
"button_text": title
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
def button_audio(self, id: str, title: str) -> Dict:
|
|
207
|
+
return {
|
|
208
|
+
"id": id,
|
|
209
|
+
"type": "Audio",
|
|
210
|
+
"button_text": title
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
def button_record_audio(self, id: str, title: str) -> Dict:
|
|
214
|
+
return {
|
|
215
|
+
"id": id,
|
|
216
|
+
"type": "RecordAudio",
|
|
217
|
+
"button_text": title
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
def button_my_phone_number(self, id: str, title: str) -> Dict:
|
|
221
|
+
return {
|
|
222
|
+
"id": id,
|
|
223
|
+
"type": "MyPhoneNumber",
|
|
224
|
+
"button_text": title
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
def button_my_location(self, id: str, title: str) -> Dict:
|
|
228
|
+
return {
|
|
229
|
+
"id": id,
|
|
230
|
+
"type": "MyLocation",
|
|
231
|
+
"button_text": title
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
def button_link(self, id: str, title: str, url: str) -> Dict:
|
|
235
|
+
return {
|
|
236
|
+
"id": id,
|
|
237
|
+
"type": "Link",
|
|
238
|
+
"button_text": title,
|
|
239
|
+
"url": url
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
def button_ask_my_phone_number(self, id: str, title: str) -> Dict:
|
|
243
|
+
return {
|
|
244
|
+
"id": id,
|
|
245
|
+
"type": "AskMyPhoneNumber",
|
|
246
|
+
"button_text": title
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
def button_ask_location(self, id: str, title: str) -> Dict:
|
|
250
|
+
return {
|
|
251
|
+
"id": id,
|
|
252
|
+
"type": "AskLocation",
|
|
253
|
+
"button_text": title
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
def button_barcode(self, id: str, title: str) -> Dict:
|
|
257
|
+
return {
|
|
258
|
+
"id": id,
|
|
259
|
+
"type": "Barcode",
|
|
260
|
+
"button_text": title
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
def build(self) -> Dict:
|
|
264
|
+
return {"rows": self.rows}
|
|
265
|
+
|
|
266
|
+
from typing import List, Dict, Optional
|
|
267
|
+
|
|
268
|
+
class ChatKeypadBuilder:
|
|
269
|
+
def __init__(self):
|
|
270
|
+
self.rows: List[Dict[str, List[Dict[str, str]]]] = []
|
|
271
|
+
|
|
272
|
+
def row(self, *buttons: Dict[str, str]) -> "ChatKeypadBuilder":
|
|
273
|
+
"""
|
|
274
|
+
یک ردیف دکمه به کیپد اضافه میکند.
|
|
275
|
+
ورودی: چند دیکشنری که نماینده دکمهها هستند.
|
|
276
|
+
"""
|
|
277
|
+
self.rows.append({"buttons": list(buttons)})
|
|
278
|
+
return self
|
|
279
|
+
|
|
280
|
+
def button(self, id: str, text: str, type: str = "Simple") -> Dict[str, str]:
|
|
281
|
+
"""
|
|
282
|
+
دیکشنری یک دکمه میسازد.
|
|
283
|
+
"""
|
|
284
|
+
return {"id": id, "type": type, "button_text": text}
|
|
285
|
+
|
|
286
|
+
def build(
|
|
287
|
+
self,
|
|
288
|
+
resize_keyboard: bool = True,
|
|
289
|
+
on_time_keyboard: bool = False
|
|
290
|
+
) -> Dict[str, object]:
|
|
291
|
+
"""
|
|
292
|
+
ساختار نهایی chat_keypad را میسازد.
|
|
293
|
+
"""
|
|
294
|
+
return {
|
|
295
|
+
"rows": self.rows,
|
|
296
|
+
"resize_keyboard": resize_keyboard,
|
|
297
|
+
"on_time_keyboard": on_time_keyboard
|
|
298
|
+
}
|
rubka/logger.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
logger = logging.getLogger("rubka")
|
|
4
|
+
logger.setLevel(logging.ERROR)
|
|
5
|
+
|
|
6
|
+
ch = logging.StreamHandler()
|
|
7
|
+
ch.setLevel(logging.ERROR)
|
|
8
|
+
|
|
9
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
10
|
+
ch.setFormatter(formatter)
|
|
11
|
+
|
|
12
|
+
logger.addHandler(ch)
|
rubka/metadata.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Any, Dict, List
|
|
3
|
+
import markdownify
|
|
4
|
+
def _normalize_multiline_quote(text: str) -> str:
|
|
5
|
+
lines = text.splitlines()
|
|
6
|
+
normalized_lines = []
|
|
7
|
+
quote_block = []
|
|
8
|
+
|
|
9
|
+
for line in lines + [""]:
|
|
10
|
+
if line.startswith(">"):quote_block.append(line[1:].strip())
|
|
11
|
+
else:
|
|
12
|
+
if quote_block:
|
|
13
|
+
normalized_lines.append("$" + "\n".join(quote_block) + "$")
|
|
14
|
+
quote_block = []
|
|
15
|
+
normalized_lines.append(line)
|
|
16
|
+
return "\n".join(normalized_lines).strip()
|
|
17
|
+
|
|
18
|
+
class Track_parsed:
|
|
19
|
+
_PATT = re.compile(
|
|
20
|
+
r"(?P<pre>```(?P<pre_c>[\s\S]*?)```)"
|
|
21
|
+
r"|(?P<bold>\*\*(?P<bold_c>.*?)\*\*)"
|
|
22
|
+
r"|(?P<mono>`(?P<mono_c>.*?)`)"
|
|
23
|
+
r"|(?P<italic>__(?P<italic_c>.*?)__)"
|
|
24
|
+
r"|(?P<underline>--(?P<underline_c>.*?)--)"
|
|
25
|
+
r"|(?P<link>\[(?P<link_text>.*?)\]\((?P<link_url>\S+?)\))"
|
|
26
|
+
r"|(?P<quote>\$(?P<quote_c>[\s\S]*?)\$)"
|
|
27
|
+
r"|(?P<quote_md>^>(?P<quote_md_c>.*?)(?:\n|$))"
|
|
28
|
+
r"|(?P<strike>~~(?P<strike_c>.*?)~~)"
|
|
29
|
+
r"|(?P<spoiler>\|\|(?P<spoiler_c>.*?)\|\|)",
|
|
30
|
+
flags=re.DOTALL,
|
|
31
|
+
)
|
|
32
|
+
_TYPE_MAP = {
|
|
33
|
+
"pre": "Pre",
|
|
34
|
+
"bold": "Bold",
|
|
35
|
+
"mono": "Mono",
|
|
36
|
+
"italic": "Italic",
|
|
37
|
+
"underline": "Underline",
|
|
38
|
+
"strike": "Strike",
|
|
39
|
+
"spoiler": "Spoiler",
|
|
40
|
+
"quote": "Quote",
|
|
41
|
+
"quote_md": "Quote",
|
|
42
|
+
"link": "Link",
|
|
43
|
+
"mention": "MentionText",
|
|
44
|
+
}
|
|
45
|
+
@staticmethod
|
|
46
|
+
def _utf16_len_java_style(s: str) -> int:
|
|
47
|
+
return len(s.encode("utf-16-be")) // 2
|
|
48
|
+
@staticmethod
|
|
49
|
+
def _html2md(src: str) -> str:
|
|
50
|
+
src = re.sub(r'<i>(.*?)</i>', r'||\1||', src, flags=re.DOTALL)
|
|
51
|
+
src = re.sub(r'<span class="spoiler">(.*?)</span>', r'||\1||', src, flags=re.DOTALL)
|
|
52
|
+
src = markdownify.markdownify(html=src).strip()
|
|
53
|
+
src = src.replace("@@SPOILER@@", "||")
|
|
54
|
+
return src
|
|
55
|
+
def transcribe(self, src: str, mode: str = "MARKDOWN") -> Dict[str, Any]:
|
|
56
|
+
if mode and mode.upper() == "HTML":
|
|
57
|
+
src = self._html2md(src)
|
|
58
|
+
src = _normalize_multiline_quote(src)
|
|
59
|
+
payload_parts: List[Dict[str, Any]] = []
|
|
60
|
+
normalized_text = src
|
|
61
|
+
byte_offset = 0
|
|
62
|
+
char_offset = 0
|
|
63
|
+
matches = list(self._PATT.finditer(src))
|
|
64
|
+
for m in matches:
|
|
65
|
+
whole = m.group(0)
|
|
66
|
+
start, end = m.span()
|
|
67
|
+
adj_from = self._utf16_len_java_style(src[:start]) - byte_offset
|
|
68
|
+
adj_char_from = start - char_offset
|
|
69
|
+
gname = m.lastgroup
|
|
70
|
+
if not gname:continue
|
|
71
|
+
if gname == "link":
|
|
72
|
+
inner = m.group("link_text") or ""
|
|
73
|
+
link_href = m.group("link_url")
|
|
74
|
+
if link_href.startswith("u0"):gname = "mention"
|
|
75
|
+
else:
|
|
76
|
+
inner = m.group(f"{gname}_c") or ""
|
|
77
|
+
link_href = None
|
|
78
|
+
if gname in ["quote", "quote_md", "bold", "italic", "underline", "spoiler", "strike","mention"]:
|
|
79
|
+
inner_metadata = self.transcribe(inner, mode="MARKDOWN")
|
|
80
|
+
inner = inner_metadata["text"]
|
|
81
|
+
if "metadata" in inner_metadata:
|
|
82
|
+
for part in inner_metadata["metadata"]["meta_data_parts"]:
|
|
83
|
+
part["from_index"] += adj_from
|
|
84
|
+
payload_parts.append(part)
|
|
85
|
+
if inner == "":
|
|
86
|
+
continue
|
|
87
|
+
content_utf16_len = self._utf16_len_java_style(inner)
|
|
88
|
+
part: Dict[str, Any] = {
|
|
89
|
+
"type": self._TYPE_MAP.get(gname, "Unknown"),
|
|
90
|
+
"from_index": adj_from,
|
|
91
|
+
"length": content_utf16_len,
|
|
92
|
+
}
|
|
93
|
+
if gname == "mention":
|
|
94
|
+
part["type"] = "MentionText"
|
|
95
|
+
part["mention_text_user_id"] = link_href
|
|
96
|
+
elif link_href:
|
|
97
|
+
part["type"] = "Link"
|
|
98
|
+
part["link_url"] = link_href
|
|
99
|
+
payload_parts.append(part)
|
|
100
|
+
normalized_text = (
|
|
101
|
+
normalized_text[:adj_char_from] + inner + normalized_text[end - char_offset :]
|
|
102
|
+
)
|
|
103
|
+
byte_offset += self._utf16_len_java_style(whole) - content_utf16_len
|
|
104
|
+
char_offset += (end - start) - len(inner)
|
|
105
|
+
|
|
106
|
+
result: Dict[str, Any] = {"text": normalized_text.strip()}
|
|
107
|
+
if payload_parts:
|
|
108
|
+
result["metadata"] = {"meta_data_parts": payload_parts}
|
|
109
|
+
|
|
110
|
+
return result
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def parse(self, text: str, parse_mode: str = "MARKDOWN") -> Dict[str, Any]:
|
|
114
|
+
return self.transcribe(text, mode=parse_mode)
|