repos
/
irgramd
/ annotate_shade
Update year in copyright notices
Annotate for file utils.py
2022-02-20 E.
1
# irgramd: IRC-Telegram gateway
01:25:27 '
2
# utils.py: Helper functions
'
3
#
'
4
# Copyright (c) 2019 Peter Bui <pbui@bx612.space>
2026-06-21 E.
5
# Copyright (c) 2020-2026 E. Bosch <presidev@AT@gmail.com>
2022-02-20 E.
6
#
01:25:27 '
7
# Use of this source code is governed by a MIT style license that
'
8
# can be found in the LICENSE file included in this project.
2020-11-19 E.
9
19:41:24 '
10
import itertools
2022-01-24 E.
11
import textwrap
2022-01-30 E.
12
import re
2022-03-19 E.
13
import datetime
2023-05-06 E.
14
import zoneinfo
2023-04-15 E.
15
import difflib
2023-12-20 E.
16
import logging
2026-05-30 E.
17
import random
2020-11-19 E.
18
2022-02-09 E.
19
# Constants
21:58:31 '
20
2026-05-30 E.
21
FILENAME_INVALID_CHARS = re.compile('[\0-\x1F/{}<>"\'\\|*&#%?\x7F]')
2022-02-19 E.
22
SIMPLE_URL = re.compile('http(|s)://[^ ]+')
2022-02-09 E.
23
2024-11-02 E.
24
from include import MAX_LINE
19:20:45 '
25
2020-11-19 E.
26
# Utilities
19:41:24 '
27
2023-06-22 E.
28
class command:
19:57:16 '
29
async def parse_command(self, line, nick):
2023-06-25 E.
30
command = line.partition(' ')[0].lower()
2023-06-22 E.
31
self.tmp_ircnick = nick
19:57:16 '
32
if command in self.commands.keys():
2023-06-25 E.
33
handler, min_args, max_args, maxsplit = self.commands[command]
22:17:22 '
34
words = line.split(maxsplit=maxsplit)[1:]
2023-06-22 E.
35
num_words = len(words)
19:57:16 '
36
if num_words < min_args or num_words > max_args:
'
37
reply = ('Wrong number of arguments',)
'
38
else:
'
39
reply = await handler(*words)
'
40
else:
'
41
reply = ('Unknown command',)
'
42
'
43
return reply
'
44
2023-06-25 E.
45
class HELP:
22:17:22 '
46
desc = 1
'
47
brief = 2
'
48
2024-08-30 E.
49
class LOGL:
17:00:53 '
50
debug = False
'
51
2020-11-19 E.
52
def chunks(iterable, n, fillvalue=None):
19:41:24 '
53
''' Return iterable consisting of a sequence of n-length chunks '''
'
54
args = [iter(iterable)] * n
'
55
return itertools.zip_longest(*args, fillvalue=fillvalue)
2021-02-21 E.
56
00:12:58 '
57
def set_replace(set, item, new_item):
'
58
if item in set:
'
59
set.remove(item)
'
60
set.add(new_item)
2022-01-24 E.
61
21:35:55 '
62
def get_continued(items, mark, length):
'
63
# Add "continued" mark to lines, except last one
'
64
return (x + mark if n != length else x for n, x in enumerate(items, start=1))
'
65
'
66
def split_lines(message):
'
67
messages_limited = []
2024-11-02 E.
68
wr = textwrap.TextWrapper(width=MAX_LINE)
2022-01-24 E.
69
21:35:55 '
70
# Split when Telegram original message has breaks
'
71
messages = message.splitlines()
'
72
lm = len(messages)
'
73
if lm > 1:
'
74
# Add "continued line" mark (\) for lines that belong to the same message
'
75
# (split previously)
'
76
messages = get_continued(messages, ' \\', lm)
'
77
for m in messages:
'
78
wrapped = wr.wrap(text=m)
'
79
lw = len(wrapped)
'
80
if lw > 1:
'
81
# Add double "continued line" mark (\\) for lines that belong to the same message
'
82
# and have been wrapped to not exceed IRC limits
'
83
messages_limited += get_continued(wrapped, ' \\\\', lw)
'
84
else:
'
85
messages_limited += wrapped
'
86
del wr
'
87
return messages_limited
2022-01-30 E.
88
00:29:08 '
89
def sanitize_filename(fn):
2026-05-30 E.
90
def hexize(m):
22:26:34 '
91
return '-{:x}-'.format(ord(m.group(0)))
'
92
'
93
new_fn = FILENAME_INVALID_CHARS.sub(hexize, fn)
'
94
return new_fn.lstrip('-').replace(' ','_')
2022-02-08 E.
95
2023-12-17 E.
96
def add_filename(filename, add):
01:49:18 '
97
if add:
'
98
aux = filename.rsplit('.', 1)
'
99
name = aux[0]
2026-05-30 E.
100
last_dot = '.'
2024-04-27 E.
101
try:
22:28:22 '
102
ext = aux[1]
'
103
except:
'
104
ext = ''
2026-05-30 E.
105
last_dot = ''
20:25:32 '
106
return '{}-{}{}{}'.format(name, add, last_dot, ext)
2023-12-17 E.
107
else:
01:49:18 '
108
return filename
'
109
2022-02-08 E.
110
def remove_slash(url):
01:04:55 '
111
return url[:-1] if url[-1:] == '/' else url
'
112
'
113
def remove_http_s(url):
'
114
if url[:8] == 'https://':
'
115
surl = url[8:]
'
116
elif url[:7] == 'http://':
'
117
surl = url[7:]
'
118
else:
'
119
surl = url
'
120
return remove_slash(surl)
2022-02-09 E.
121
2022-02-19 E.
122
def is_url_equiv(url1, url2):
01:10:00 '
123
if url1 and url2:
'
124
return url1 == url2 or remove_slash(remove_http_s(url1)) == remove_slash(remove_http_s(url2))
'
125
else:
'
126
return False
'
127
'
128
def extract_url(text):
'
129
url = SIMPLE_URL.search(text)
'
130
return url.group() if url else None
'
131
2022-02-09 E.
132
def get_human_size(size):
22:52:06 '
133
human_units = ('', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
'
134
'
135
def get_human_size_values(size, unit_pos=0):
'
136
aux = size / 1024.0
'
137
if aux > 1: return get_human_size_values(aux, unit_pos + 1)
'
138
else: return size, human_units[unit_pos]
'
139
'
140
if size <= 1237940039285380274899124224: # 1024Y
'
141
num, unit = get_human_size_values(size)
'
142
else:
'
143
num = size / 1208925819614629174706176 # 1Y
'
144
unit = 'Y'
'
145
'
146
fs = '{:.1f}{}' if num < 10 else '{:.0f}{}'
'
147
'
148
return fs.format(num, unit)
'
149
'
150
def get_human_duration(duration):
'
151
res = ''
'
152
x, s = divmod(duration, 60)
'
153
h, m = divmod(x, 60)
'
154
'
155
if h > 0: res = str(h) + 'h'
'
156
if m > 0: res += str(m) + 'm'
2023-12-14 E.
157
if s > 0 or duration < 60: res += str(s) + 's'
2022-02-09 E.
158
return res
2022-03-19 E.
159
2023-05-07 E.
160
def compact_date(date, tz):
2024-08-29 E.
161
delta = current_date() - date
2023-05-07 E.
162
date_local = date.astimezone(zoneinfo.ZoneInfo(tz))
2022-03-19 E.
163
22:26:56 '
164
if delta.days < 1:
2023-05-07 E.
165
compact_date = date_local.strftime('%H:%M')
2023-03-19 E.
166
elif delta.days < 365:
2023-05-07 E.
167
compact_date = date_local.strftime('%d-%b')
2022-03-19 E.
168
else:
2023-05-07 E.
169
compact_date = date_local.strftime('%Y')
2022-03-19 E.
170
22:26:56 '
171
return compact_date
2023-04-15 E.
172
2024-08-29 E.
173
def current_date():
23:58:06 '
174
return datetime.datetime.now(datetime.timezone.utc)
'
175
2023-04-15 E.
176
def get_highlighted(a, b):
23:13:07 '
177
awl = len(a.split())
'
178
bwl = len(b.split())
'
179
delta_size = abs(awl - bwl)
'
180
highlighted = True
'
181
'
182
if not a:
'
183
res = '> {}'.format(b)
'
184
elif delta_size > 5:
'
185
res = b
'
186
highlighted = False
'
187
else:
'
188
al = a.split(' ')
'
189
bl = b.split(' ')
'
190
diff = difflib.ndiff(al, bl)
'
191
ld = list(diff)
'
192
res = ''
'
193
d = ''
'
194
eq = 0
'
195
'
196
for i in ld:
'
197
if i == '- ' or i[0] == '?':
'
198
continue
'
199
elif i == ' ' or i == '+ ':
'
200
res += ' '
'
201
continue
2023-05-07 E.
202
# deletion of words
2023-04-15 E.
203
elif i[0] == '-':
2023-05-07 E.
204
res += '-{}- '.format(i[2:])
00:24:08 '
205
# addition of words
2023-04-15 E.
206
elif i[0] == '+':
2023-11-18 E.
207
res += '+{}+ '.format(i[2:])
2023-04-15 E.
208
else:
23:13:07 '
209
res += '{} '.format(i[2:])
'
210
eq += 1
'
211
'
212
delta_eq = bwl - eq
'
213
if delta_eq > 3:
'
214
res = b
'
215
highlighted = False
'
216
'
217
return res, highlighted
2023-04-26 E.
218
18:45:17 '
219
def fix_braces(text):
'
220
# Remove braces not closed, if the text was truncated
'
221
if text.endswith(' {...'):
'
222
subtext = text[:-5]
'
223
if not '{}' in subtext:
'
224
return '{}...'.format(subtext)
'
225
return text
2023-05-06 E.
226
23:31:34 '
227
def format_timestamp(format, tz, date):
'
228
date_local = date.astimezone(zoneinfo.ZoneInfo(tz))
'
229
return date_local.strftime(format)
2023-12-20 E.
230
00:50:56 '
231
def parse_loglevel(level):
'
232
levelu = level.upper()
2024-08-30 E.
233
if levelu == 'DEBUG':
17:00:53 '
234
LOGL.debug = True
2023-12-20 E.
235
if levelu == 'NONE':
00:50:56 '
236
l = None
'
237
elif levelu in ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'):
'
238
l = getattr(logging, levelu)
'
239
else:
'
240
l = False
'
241
return l
2024-08-24 E.
242
23:21:01 '
243
def pretty(object):
2024-08-30 E.
244
return object.stringify() if LOGL.debug and object else object
2026-05-30 E.
245
19:33:57 '
246
class token:
'
247
def __init__(self, alpha):
'
248
self.alpha = alpha
'
249
self.long_alpha = len(alpha)
'
250
'
251
def gen_token(self, long_token):
'
252
if long_token == 1:
'
253
return self.alpha[random.randrange(self.long_alpha)]
'
254
else:
'
255
aux = self.gen_token(long_token - 1)
'
256
return aux + self.alpha[random.randrange(self.long_alpha)]