moonlib 1.0.0__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.
main.py ADDED
@@ -0,0 +1,789 @@
1
+ r"""
2
+ __ __ _ _ _
3
+ | \/ | ___ ___ _ __ | | (_) |__
4
+ | |\/| |/ _ \ / _ \| '_ \| | | | '_ \
5
+ | | | | (_) | (_) | | | | |___| | |_) |
6
+ |_| |_|\___/ \___/|_| |_|_____|_|_.__/
7
+
8
+ ____ __ __ _ ____ _ _
9
+ / __ \| \/ | | | _ \| |_ _ __ _(_)_ __ ___
10
+ / / _` | |\/| | | | |_) | | | | |/ _` | | '_ \/ __|
11
+ | | (_| | | | | |___| __/| | |_| | (_| | | | | \__ \
12
+ \ \__,_|_| |_|_____|_| |_|\__,_|\__, |_|_| |_|___/
13
+ \____/ |___/
14
+
15
+ MoonLib - либа для удобной работы с java классами
16
+ В основном для разрабов и тех кто хочет юзать мои плагины где эта либа нужна
17
+
18
+ Код для своего плагина/либы можно брать, но только с указанием @MLPlugins в __author__
19
+ Например: __author__ = "@username & @MLPlugins"
20
+ При использовании либы в своих плагинах указывать авторство не нужно
21
+
22
+ Также небольшой совет: проверять импорты
23
+ Пример:
24
+ try: from moonlib import Fortune, Browser
25
+ except ImportError:
26
+ # Код для ошибки типа "Требуется установить либу MoonLib для работы плагина"
27
+ # Либо можно юзать fallback с ограниченными функциями
28
+
29
+ Остальное можно почитать в документации: @MLDocumentation
30
+
31
+ Gift dataclass я взял у @binbash_0, и немного отредактировал
32
+
33
+ Если есть вопросы, пиши в лс тгк: @MLPlugins
34
+ Но советую перед этим прочитать документацию чтобы избежать бана за глупый вопрос
35
+ Бан будет за вопросы типа "А как импортировать", "Где тут ваще классы?", и т.п
36
+
37
+ HookRouter класс взял из плагина AntiScam от @binbash_0
38
+
39
+ Некоторый код писал на скорую руку, так что может быть говнокод
40
+ """
41
+
42
+ __id__ = "moonlib"
43
+ __name__ = "MoonLib"
44
+ __description__ = "Мини либа для работы с java классами, и т.д\nВ основном для разрабов плагинов или для тех, кто хочет юзать мои плагины\nДокументация: @MLDocumentation"
45
+ __author__ = "@MLPlugins & @MLDocumentation"
46
+ __version__ = "1.0.1"
47
+ __min_version__ = "12.5.1"
48
+ __priority__ = 1
49
+
50
+ MOONLIB_VERSION = __version__
51
+
52
+ from base_plugin import BasePlugin, HookResult, HookStrategy
53
+ from java import jclass
54
+ from android_utils import (copy_to_clipboard, run_on_ui_thread)
55
+ from android_utils import log as _log
56
+ from client_utils import get_last_fragment, run_on_queue
57
+ from dataclasses import dataclass
58
+ from ui.settings import (
59
+ Header,
60
+ Switch,
61
+ Custom
62
+ )
63
+ from ui.alert import AlertDialogBuilder
64
+ from ui.bulletin import BulletinHelper
65
+ from typing import (
66
+ Any,
67
+ Union,
68
+ List,
69
+ )
70
+ from typing_extensions import deprecated
71
+ from file_utils import (get_cache_dir, list_dir, get_plugins_dir)
72
+
73
+ from decimal import(Decimal, getcontext)
74
+
75
+ getcontext().prec = 2
76
+
77
+ import threading
78
+ import pathlib
79
+ import subprocess
80
+ import requests
81
+ import functools
82
+ import os
83
+ import shutil
84
+ import json
85
+
86
+ def find_class(c: str) -> Any:
87
+ loader = jclass("org.telegram.messenger.ApplicationLoader")
88
+ ctx = loader.applicationContext
89
+ cl = loader.getClassLoader()
90
+ if (
91
+ loader and
92
+ ctx and
93
+ cl
94
+ ): return cl.loadClass(c)
95
+ return None
96
+
97
+ @deprecated("useless")
98
+ def _get_tg_classes() -> dict:
99
+ tg = {
100
+ "browser.Browser": jclass("org.telegram.messenger.browser.Browser"),
101
+ "ApplicationLoader": jclass("org.telegram.messenger.ApplicationLoader"),
102
+ "tgnet.TLRPC": jclass("org.telegram.tgnet.TLRPC"),
103
+ "AndroidUtilities": jclass("org.telegram.messenger.AndroidUtilities"),
104
+ "LocaleController": jclass("org.telegram.messenger.LocaleController")
105
+ }
106
+ return tg
107
+
108
+ @deprecated("useless")
109
+ def _get_java_classes() -> dict:
110
+ java = {
111
+ "util.ArrayList": jclass("java.util.ArrayList"),
112
+ "lang.String": jclass("java.lang.String"),
113
+ "security.SecureRandom": jclass("java.security.SecureRandom"),
114
+ "util.Locale": jclass("java.util.Locale")
115
+ }
116
+ return java
117
+
118
+ @deprecated("useless")
119
+ def _get_android_classes() -> dict:
120
+ android = {
121
+ "os.VibrationEffect": jclass("android.os.VibrationEffect"),
122
+ "os.Process": jclass("android.os.Process"),
123
+ "widget.TextView": jclass("android.widget.TextView"),
124
+ "widget.LinearLayout": jclass("android.widget.LinearLayout"),
125
+ "media.AudioManager": jclass("android.media.AudioManager"),
126
+ "media.ToneGenerator": jclass("android.media.ToneGenerator"),
127
+ "view.WindowManager": jclass("android.view.WindowManager"),
128
+ "webkit.WebView": jclass("android.webkit.WebView"),
129
+ "webkit.WebViewClient": jclass("android.webkit.WebViewClient")
130
+ }
131
+ return android
132
+
133
+ @deprecated("useless")
134
+ def _err(msg: str):
135
+ android = _get_android_classes()
136
+ process = android["os.Process"]
137
+ pid = process.myPid()
138
+ copy_to_clipboard(msg)
139
+ process.killProcess(pid)
140
+
141
+ @deprecated("useless")
142
+ def err(msg: str):
143
+ if msg: _err(msg)
144
+
145
+ def _xor(_str: str, key: int) -> str:
146
+ xor_str = ""
147
+ for char in _str: xor_str += "".join(chr(ord(char) ^ key))
148
+ return xor_str
149
+
150
+ @deprecated("useless")
151
+ def _get_ctx() -> Any:
152
+ tg = _get_tg_classes()
153
+ loader = tg["ApplicationLoader"]
154
+ ctx = loader.applicationContext
155
+ return ctx
156
+
157
+ def _settings_label(text: str) -> Any:
158
+ ctx = _get_ctx()
159
+ android = _get_android_classes()
160
+ _text_view = android["widget.TextView"]
161
+ textView = _text_view(ctx)
162
+ textView.setText(text)
163
+ _label = Custom(view=textView)
164
+ return _label
165
+
166
+ def _find_su() -> str:
167
+ su_dir = [
168
+ "/bin",
169
+ "/sbin",
170
+ "/system/bin",
171
+ "/vendor/bin"
172
+ ]
173
+ _su_dir = ""
174
+ for _dir in su_dir:
175
+ file = pathlib.Path(f"{_dir}/su")
176
+ if file.exists(): _su_dir = f"{_dir}/su"
177
+ return _su_dir
178
+
179
+ def _create_text(text: list) -> str:
180
+ _text = ""
181
+ for line in text:
182
+ _text += line
183
+ index = text.index(_text)
184
+ length = text.__len__()
185
+ if length is not index: _text += "\n"
186
+ return _text
187
+
188
+ @dataclass
189
+ class Point:
190
+ x: int
191
+ y: int
192
+
193
+ @dataclass
194
+ class Size:
195
+ width: int
196
+ height: int
197
+
198
+ @dataclass
199
+ class Output:
200
+ stdout: str
201
+ stderr: str
202
+
203
+ @dataclass
204
+ class Gift:
205
+ _id: int
206
+ price: int
207
+ sticker: int
208
+
209
+ @deprecated("TaskManager дает больше контроля и ленивый запуск, в отличии от PartRun")
210
+ class PartRun:
211
+ def __init__(self, init, start, main, _continue, end):
212
+ self.init = init
213
+ self.start = start
214
+ self.main = main
215
+ self._continue = _continue
216
+ self.end = end
217
+ self.init()
218
+ self.start()
219
+ self.main()
220
+ self._continue()
221
+ self.end()
222
+
223
+ # Хз зачем, пусть будет...
224
+ # Все таки помечу как deprecated
225
+ @deprecated("TaskManager дает больше контроля и ленивый запуск, в отличии от LoadClass")
226
+ class LoadClass:
227
+ def __init__(self, load, unload):
228
+ self.load = load
229
+ self.unload = unload
230
+ def _load(self): self.load()
231
+ def _unload(self): self.unload()
232
+
233
+ """
234
+ Использование TaskManager:
235
+ manager = TaskManager()
236
+
237
+ @manager.Task("foo")
238
+ def foo(): print("bar")
239
+
240
+ @manager.Task("bar")
241
+ def bar(): print("foo")
242
+
243
+ manager.Run("foo")
244
+ manager.Run("bar")
245
+
246
+ # Тута запуск задач по порядку создания
247
+ manager.RunAll()
248
+ """
249
+ class TaskManager:
250
+ def __init__(self): self.tasks = {}
251
+ def Task(self, name: str):
252
+ def decorator(function):
253
+ self.tasks[name] = {"function": function}
254
+ return function
255
+ return decorator
256
+ def Run(self, name: str):
257
+ task = self.tasks.get(name)
258
+ if task:
259
+ function = task.get("function")
260
+ if function: function()
261
+ def RunAll(self):
262
+ for name in self.tasks:
263
+ task = self.tasks.get(name)
264
+ if task:
265
+ function = task.get("function")
266
+ if function: function()
267
+
268
+ # В отличии от класса в других моих плагинах, тута я поменял получение сервиса, должно работать везде
269
+ class VibBlink:
270
+ def vib(self):
271
+ ctx = _get_ctx()
272
+ android = _get_android_classes()
273
+ vibration = ctx.getSystemService(ctx.VIBRATOR_SERVICE)
274
+ if vibration:
275
+ try:
276
+ effect = android["os.VibrationEffect"]
277
+ vibration.vibrate(effect.createOneShot(1000, 500))
278
+ except:
279
+ vibration.vibrate(1000)
280
+ def blink(self):
281
+ thread = threading.Thread(target=self.vib, daemon=True)
282
+ thread.start()
283
+
284
+ class File:
285
+ @staticmethod
286
+ def Read(path: str, encoding: str) -> str:
287
+ with open(path, "r", encoding=encoding) as file:
288
+ data = file.read()
289
+ return data
290
+ @staticmethod
291
+ def Write(path: str, encoding: str, data: str):
292
+ with open(path, "w", encoding=encoding) as file:
293
+ file.write(data)
294
+ @staticmethod
295
+ def Exists(path: str) -> bool:
296
+ file = pathlib.Path(path)
297
+ return file.exists()
298
+ @staticmethod
299
+ def ReadLine(path: str, encoding: str) -> Any:
300
+ with open(path, "r", encoding=encoding) as file:
301
+ for line in file.readlines(): yield line
302
+
303
+ class TelegramBrowser:
304
+ browser = None
305
+ context = None
306
+
307
+ def OpenUrl(self, url: str):
308
+ tg = _get_tg_classes()
309
+ self.browser = tg["browser.Browser"]
310
+ self.context = _get_ctx()
311
+ self.browser.openUrl(self.context, url)
312
+
313
+ class FileDownload:
314
+ @staticmethod
315
+ def Download(url: str, path: str):
316
+ response = requests.get(url, timeout=30)
317
+ response.raise_for_status()
318
+
319
+ with open(path, "wb") as file:
320
+ file.write(response.content)
321
+
322
+ def _get_args(text: str) -> list:
323
+ args = text.split(" ")
324
+ return args
325
+
326
+ def _get_args_str(text: str) -> str:
327
+ space_index = text.find(" ")
328
+ if space_index is -1: return ""
329
+ args = text[space_index + 1:].strip()
330
+ return args
331
+
332
+ def log(prefix: str, msg: str):
333
+ _str = f"[{prefix}] {msg}"
334
+ _log(_str)
335
+
336
+ # Не юзайте там, где нужны esc codes, zero, ZWNJ, BOM, и т.д
337
+ def _clear_str(_str: str) -> str:
338
+ string = _str.replace("\0", "") # Zero
339
+ string = string.replace("\x00", "") # Zero
340
+ string = string.replace("\a", "") # Beep
341
+ string = string.replace("\u200C", "") # ZWNJ
342
+ string = string.replace("\r", "") # Это уже конвертация DOS в UNIX, но похуй
343
+ string = string.replace("\b", "") # Backspace
344
+ string = string.replace("\xEF\xBB\xBF", "") # BOM
345
+ return string
346
+
347
+ class Fortune:
348
+ def parse_fortunes(self, path: str) -> list:
349
+ file = File()
350
+ data = file.Read(path, "UTF-8")
351
+ fortunes = self.parse_fortunes_with_data(data)
352
+ return fortunes
353
+ def parse_fortunes_with_data(self, data: str) -> list:
354
+ fortunes = []
355
+ lines = []
356
+ _data = _clear_str(data)
357
+
358
+ for line in _data.splitlines():
359
+ if line.strip() is "%":
360
+ if lines:
361
+ fortune = "\n".join(lines).strip()
362
+ fortunes.append(fortune)
363
+ lines = []
364
+ else: lines.append(line)
365
+ return fortunes
366
+
367
+ @deprecated("useless")
368
+ def _get_activity() -> Any:
369
+ ctx = _get_ctx()
370
+ fragment = ctx.get("fragment") or get_last_fragment()
371
+ activity = fragment.getParentActivity()
372
+ return activity
373
+
374
+ @deprecated("not working")
375
+ def _alert_dialog(title: str, msg: str, positive_str: str, negative_str: str, on_positive_click, on_negative_click):
376
+ activity = _get_activity()
377
+ builder = AlertDialogBuilder(activity)
378
+ builder.set_title(title)
379
+ builder.set_message(msg)
380
+ builder.set_positive_button(positive_str, on_positive_click)
381
+ builder.set_negative_button(negative_str, on_negative_click)
382
+ builder.create()
383
+ builder.set_cancelable(True)
384
+ builder.show()
385
+
386
+ class Subprocess:
387
+ @staticmethod
388
+ def Run(args: list) -> Output:
389
+ output = Output(stdout="", stderr="")
390
+ if args:
391
+ process = subprocess.run(args, text=True, capture_output=True)
392
+ output = Output(stdout=process.stdout, stderr=process.stderr)
393
+ return output
394
+ @staticmethod
395
+ def ShellRun(cmd: str) -> Output:
396
+ output = Output(stdout="", stderr="")
397
+ if cmd:
398
+ process = subprocess.run(cmd, text=True, capture_output=True, shell=True)
399
+ output = Output(stdout=process.stdout, stderr=process.stderr)
400
+ return output
401
+
402
+ @dataclass
403
+ class Command:
404
+ name: str
405
+ command: str
406
+ prefix: str
407
+ function: Any
408
+
409
+ class PhysicsUtils:
410
+ CELSIUS = 0x0000
411
+ KELVIN = 0x1FFF
412
+
413
+ def __init__(self):
414
+ getcontext().prec = 2
415
+
416
+ # address - адрес к единице измерения в которую нужно конвертировать
417
+ # В классе есть константы с адресами
418
+ def convert(self, address: int, value: Decimal) -> Decimal:
419
+ _value: Decimal = value
420
+ match address:
421
+ case self.CELSIUS: _value -= Decimal("273.15")
422
+ case self.KELVIN: _value += Decimal("273.15")
423
+ return _value
424
+
425
+ # HookRouter взял из плагина AntiScam от @binbash_0
426
+ class HookRouter:
427
+ def __init__(self):
428
+ self.handlers = {}
429
+
430
+ def hook(self, name: Union[str, List[str]]):
431
+ names = frozenset([name] if isinstance(name, str) else name)
432
+
433
+ def decorator(func):
434
+ @functools.wraps(func)
435
+ def wrapper(calling_name, *args, **kwargs):
436
+ if calling_name not in names:
437
+ return HookResult(strategy=HookStrategy.DEFAULT)
438
+ return func(*args, **kwargs)
439
+
440
+ for n in names:
441
+ self.handlers.setdefault(n, []).append(wrapper)
442
+ return func
443
+
444
+ return decorator
445
+
446
+ def _stop_plugin(_id: str):
447
+ def stop():
448
+ PluginsController = find_class("com.exteragram.messenger.plugins.PluginsController")
449
+ instance = PluginsController.getInstance()
450
+ plugin = instance.plugins.get(_id)
451
+ plugin.setEnabled(False)
452
+ run_on_queue(stop, delay=50)
453
+
454
+ class JavaExceptions:
455
+ def __init__(self):
456
+ self.JavaException = jclass("java.lang.Exception")
457
+ self.RuntimeException = jclass("java.lang.RuntimeException")
458
+ self.SecurityException = jclass("java.lang.SecurityException")
459
+ self.IllegalStateException = jclass("java.lang.IllegalStateException")
460
+ self.NullPointerException = jclass("java.lang.NullPointerException")
461
+ self.AccessViolationException = jclass("java.lang.AccessViolationException")
462
+ self.IllegalArgumentException = jclass("java.lang.IllegalArgumentException")
463
+ self.IOException = jclass("java.lang.IOException")
464
+ self.SocketException = jclass("java.lang.SocketException")
465
+ self.ConnectException = jclass("java.lang.ConnectException")
466
+ not_exceptions_1 = not self.JavaException and not self.RuntimeException
467
+ not_exceptions_2 = not self.SecurityException and not self.IllegalStateException
468
+ not_exceptions_3 = not self.NullPointerException and not self.AccessViolationException
469
+ not_exceptions_4 = not self.IllegalArgumentException and not self.IOException
470
+ not_exceptions_5 = not self.SocketException and not self.ConnectException
471
+ not_exceptions = (
472
+ not_exceptions_1 and
473
+ not_exceptions_2 and
474
+ not_exceptions_3 and
475
+ not_exceptions_4 and
476
+ not_exceptions_5
477
+ )
478
+ if (not_exceptions): _stop_plugin(__id__)
479
+ self.exceptions = {"java.lang.Exception": self.JavaException}
480
+ self.exceptions["java.lang.RuntimeException"], self.exceptions["java.lang.SecurityException"], self.exceptions["java.lang.IllegalStateException"], self.exceptions["java.lang.NullPointerException"], self.exceptions["java.lang.AccessViolationException"], self.exceptions["java.lang.IllegalArgumentException"], self.exceptions["java.lang.IOException"], self.exceptions["java.lang.SocketException"], self.exceptions["java.lang.ConnectException"] = (
481
+ self.RuntimeException,
482
+ self.SecurityException,
483
+ self.IllegalStateException,
484
+ self.NullPointerException,
485
+ self.AccessViolationException,
486
+ self.IllegalArgumentException,
487
+ self.IOException,
488
+ self.SocketException,
489
+ self.ConnectException
490
+ )
491
+ def _java_raise(self, exception: str):
492
+ _exception = self.exceptions.get(exception)
493
+ if _exception: raise _exception()
494
+ def _get_exception(self, exception: str) -> Any:
495
+ _exception = self.exceptions.get(exception)
496
+ return _exception
497
+
498
+ class AdvancedBulletinHelper(BulletinHelper):
499
+ def __init__(self):
500
+ self.INFO = 0x1000
501
+ self.ERROR = 0xFFFF
502
+ self.SUCCESS = 0x0000
503
+ # show функция только для info, error, success
504
+ # Для button юзаем show_with_button из ориг BulletinHelper
505
+ def show(self, msg: str, status: int):
506
+ bulletin = BulletinHelper.show_info # Будет show_info как fallback
507
+ match status:
508
+ case self.ERROR: bulletin = BulletinHelper.show_error
509
+ case self.SUCCESS: bulletin = BulletinHelper.show_success
510
+ run_on_ui_thread(lambda: bulletin(msg))
511
+
512
+ class Return:
513
+ @staticmethod
514
+ def _range(r: list) -> Any:
515
+ for i in r: yield i
516
+ @staticmethod
517
+ def _count(c: int) -> Any:
518
+ for i in range(c): yield i
519
+ @staticmethod
520
+ def _strings(sl: list[str]) -> Any:
521
+ for s in sl: yield s
522
+
523
+ class ListImport:
524
+ def _clear_modules_str(self, modules: str) -> str:
525
+ _modules = _clear_str(modules)
526
+ _modules = _modules.replace(" ", "")
527
+ _modules = _modules.replace("\n", "")
528
+ return _modules
529
+ def _import(self, modules: str) -> list:
530
+ _modules = self._clear_modules_str(modules)
531
+ _modules_list = []
532
+ if _modules:
533
+ index = _modules.find(",")
534
+ if index is not -1:
535
+ _names = _modules.split(",")
536
+ if _names:
537
+ for module in _names: _modules_list.append(module)
538
+ return _modules_list
539
+
540
+ def _clear_cache():
541
+ cache_dir = get_cache_dir()
542
+ if cache_dir:
543
+ shutil.rmtree(cache_dir, ignore_errors=True)
544
+ os.mkdir(cache_dir)
545
+
546
+ # Сразу говорю, это не получение директории, а получение самих плагинов
547
+ def _get_plugins() -> list:
548
+ plugins_dir = get_plugins_dir()
549
+ plugins = []
550
+ if plugins_dir: plugins = list_dir(path=plugins_dir, extensions=[".py", ".plugin"])
551
+ return plugins
552
+
553
+ @deprecated("AndroidUtilities.getPropertyString")
554
+ def _verify_getprop_string(s: str) -> bool:
555
+ deny_chars = [
556
+ "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "=", "+", "/", "\\",
557
+ "?", ",", "\"", "'", "|", "<", ">"
558
+ ]
559
+
560
+ status = []
561
+ _last_status = True
562
+
563
+ for char in deny_chars:
564
+ status.append(not s.__contains__(char))
565
+
566
+ for _status in status:
567
+ if not _status:
568
+ _last_status = False
569
+ break
570
+
571
+ return _last_status
572
+
573
+ @deprecated("Используйте AndroidUtilities.getPropertyString")
574
+ class AndroidUtils:
575
+ @staticmethod
576
+ def getprop(s: str) -> dict:
577
+ if _verify_getprop_string(s):
578
+ output = Subprocess.Run(["getprop", s])
579
+ _output = {
580
+ "stdout": output.stdout,
581
+ "stderr": output.stderr
582
+ }
583
+ return _output
584
+ output = {
585
+ "stdout": None,
586
+ "stderr": None
587
+ }
588
+ return output
589
+
590
+ class LocaleManager:
591
+ def __init__(self, strings: dict): self.strings = strings
592
+ def _get_lang(self) -> str:
593
+ java = _get_java_classes()
594
+ Locale = java.get("util.Locale")
595
+ default = Locale.getDefault()
596
+ lang = default.getLanguage()
597
+ return lang
598
+ def _get_string(self, lang: str, _str_id: str) -> str:
599
+ string = self.strings[lang][_str_id]
600
+ return string
601
+ def get_string(self, _str_id: str) -> str:
602
+ lang = self._get_lang()
603
+ string = self._get_string(lang, _str_id)
604
+ return string
605
+
606
+ # Тута базовый интерпритатор Forth
607
+ class Forth:
608
+ def __init__(self):
609
+ self.stack = []
610
+ self.words = {
611
+ ".": lambda: _log(self.stack.pop()),
612
+ "+": lambda: self.stack.append(self.stack.pop() + self.stack.pop()),
613
+ "-": lambda: self.stack.append(-self.stack.pop() + self.stack.pop()),
614
+ "*": lambda: self.stack.append(self.stack.pop() * self.stack.pop()),
615
+ "/": lambda: self.stack.append(1 // self.stack.pop() * self.stack.pop()),
616
+ "drop": lambda: self.stack.pop(),
617
+ "swap": lambda: (self.stack.append(self.stack.pop(-2)), self.stack.pop(-2)),
618
+ "dup": lambda: self.stack.append(self.stack[-1])
619
+ }
620
+
621
+ def _exec(self, code: str):
622
+ _code = code.lower()
623
+
624
+ for i in _code.split():
625
+ if i in self.words:
626
+ self.words[i]()
627
+ else:
628
+ try:
629
+ self.stack.append(int(i))
630
+ except Exception:
631
+ self.stack.append(i)
632
+
633
+ class Const:
634
+ def __setattr__(self, name: str, value: Any):
635
+ if name in self.__dict__:
636
+ raise Exception("const")
637
+ super().__setattr__(name, value)
638
+
639
+ class JSONError(Exception):
640
+ ...
641
+
642
+ class TrueString(str):
643
+ def __bool__(self):
644
+ return True
645
+
646
+ class FalseString(str):
647
+ def __bool__(self):
648
+ return False
649
+
650
+ # :)
651
+ class String(TrueString):
652
+ pass
653
+
654
+ class MoonLib(BasePlugin):
655
+ vib_blink = None
656
+ path = None
657
+ data = """
658
+ DON'T TOUCH THIS FILE
659
+
660
+ This is file created for check plugin new install
661
+
662
+ By MLevankov
663
+ """
664
+
665
+ def __init__(self):
666
+ super().__init__()
667
+
668
+ self.log = _log
669
+ self.versions = None
670
+ self.changes = None
671
+ def on_plugin_load(self):
672
+ self.log("[MoonLib] Plugin is successfully loaded")
673
+ self.add_on_send_message_hook()
674
+ self.log("[MoonLib] Message hook is successfully added")
675
+ ctx = _get_ctx()
676
+ self.path = f"{ctx.getFilesDir().getAbsolutePath()}/moonlib.txt"
677
+ new_install = self.is_new_install()
678
+ if new_install:
679
+ self.vib_blink = VibBlink()
680
+ self.vib_blink.blink()
681
+ self.log("[MoonLib] Vibrator is successfully called")
682
+ file = File()
683
+ file.Write(self.path, "UTF-8", self.data)
684
+ self.log("[MoonLib] File is successfully created")
685
+
686
+ def on_plugin_unload(self):
687
+ self.log("[MoonLib] Plugin is successfully unloaded")
688
+
689
+ def on_send_message_hook(self, account: int, params: Any) -> HookResult:
690
+ if params.message is ".moon":
691
+ self.vib_blink = VibBlink()
692
+ self.vib_blink.blink()
693
+ params.message = "By MLevankov :3"
694
+ return HookResult(strategy=HookStrategy.MODIFY, params=params)
695
+
696
+ def is_new_install(self) -> bool:
697
+ if File.Exists(self.path):
698
+ file_data = File.Read(self.path, "UTF-8")
699
+ if file_data is self.data:
700
+ return False
701
+ return False
702
+ return True
703
+
704
+ def create_settings(self) -> List[Any]:
705
+ # Ласт этап инициализации будет перед созданием настроек
706
+ self._end_initialization()
707
+
708
+ settings = [
709
+ Header(text="Настройки"),
710
+ Switch(key="enable_moon_command", text="Включить команду .moon", default=True)
711
+ ]
712
+ return settings
713
+
714
+ def _end_initialization(self):
715
+ def download():
716
+ try:
717
+ response = requests.get(
718
+ "https://github.com/MLevankov/moonlib/raw/refs/heads/master/changelog.json",
719
+ timeout=60
720
+ )
721
+ response.raise_for_status()
722
+ path = f"{self._get_absolute_path()}/changelog.json"
723
+
724
+ with open(path, "wb") as file:
725
+ file.write(response.content)
726
+
727
+ with open(path, "r", encoding="UTF-8") as file:
728
+ changelog = json.load(file)
729
+ if isinstance(changelog, dict):
730
+ self.versions = changelog.get("versions")
731
+ self.changes = changelog.get("changes")
732
+
733
+ if (
734
+ self.versions and
735
+ self.changes
736
+ ):
737
+ self._changelog()
738
+ else:
739
+ raise JSONError("version && changes == none")
740
+ except Exception as ex:
741
+ self.log(f"[MoonLib] {ex}")
742
+
743
+ thread = threading.Thread(target=download, daemon=True)
744
+ thread.start()
745
+
746
+ def _get_absolute_path(self) -> str:
747
+ ctx = _get_ctx()
748
+ return ctx.getFilesDir().getAbsolutePath()
749
+
750
+ def _changelog(self):
751
+ from base_plugin import(
752
+ MenuItemData,
753
+ MenuItemType
754
+ )
755
+
756
+ self.add_menu_item(
757
+ MenuItemData(
758
+ menu_type=MenuItemType.DRAWER_MENU,
759
+ text="MoonLib ChangeLog",
760
+ on_click=self._show_changelog
761
+ )
762
+ )
763
+
764
+ from typing import Dict
765
+
766
+ def _show_changelog(self, context: Dict[str, Any]):
767
+ activity = get_last_fragment().getParentActivity()
768
+
769
+ builder = AlertDialogBuilder(activity)
770
+
771
+ msg = f"""
772
+ Изменения в либе:
773
+ Версии: {self.versions}
774
+ {self.changes}
775
+ """
776
+
777
+ def on_positive_click(bld: AlertDialogBuilder, which: int):
778
+ bld.dismiss()
779
+
780
+ def on_negative_click(bld: AlertDialogBuilder, which: int):
781
+ bld.dismiss()
782
+
783
+ builder.set_title("ChangeLog")
784
+ builder.set_message(msg)
785
+ builder.set_positive_button("OK", on_positive_click)
786
+ builder.set_negative_button("Cancel", on_negative_click)
787
+ builder.create()
788
+ builder.set_cancelable(True)
789
+ builder.show()
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: moonlib
3
+ Version: 1.0.0
4
+ Summary: Мини либа для работы с java классами, и т.д
5
+ Author: @MLPlugins
6
+ License: @MoonLicence
7
+ License-File: LICENCE
8
+ Dynamic: author
9
+ Dynamic: license
10
+ Dynamic: license-file
11
+ Dynamic: summary
@@ -0,0 +1,6 @@
1
+ main.py,sha256=5sOmlQ3liTqpOZW5umEuyJACMd4lv_EZrXTBTWyILhs,26856
2
+ moonlib-1.0.0.dist-info/licenses/LICENCE,sha256=2QA-eWMIwR12hsp2O2S_b1sSyVlNBDWavUgvGPKqO1g,13
3
+ moonlib-1.0.0.dist-info/METADATA,sha256=CVRja6xq6Y6vlNV-dMiMET5mAwpEI-YkB_PHgFcJT6Y,268
4
+ moonlib-1.0.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
5
+ moonlib-1.0.0.dist-info/top_level.txt,sha256=ZAMgPdWghn6xTRBO6Kc3ML1y3ZrZLnjZlqbboKXc_AE,5
6
+ moonlib-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ @MoonLicence
@@ -0,0 +1 @@
1
+ main