scratchattach 2.1.15b0__py3-none-any.whl → 3.0.0b0__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.
Files changed (69) hide show
  1. scratchattach/__init__.py +14 -6
  2. scratchattach/__main__.py +93 -0
  3. {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/METADATA +7 -11
  4. scratchattach-3.0.0b0.dist-info/RECORD +8 -0
  5. {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/WHEEL +1 -1
  6. scratchattach-3.0.0b0.dist-info/entry_points.txt +2 -0
  7. scratchattach/cloud/__init__.py +0 -2
  8. scratchattach/cloud/_base.py +0 -458
  9. scratchattach/cloud/cloud.py +0 -183
  10. scratchattach/editor/__init__.py +0 -21
  11. scratchattach/editor/asset.py +0 -253
  12. scratchattach/editor/backpack_json.py +0 -117
  13. scratchattach/editor/base.py +0 -193
  14. scratchattach/editor/block.py +0 -579
  15. scratchattach/editor/blockshape.py +0 -357
  16. scratchattach/editor/build_defaulting.py +0 -51
  17. scratchattach/editor/code_translation/__init__.py +0 -0
  18. scratchattach/editor/code_translation/parse.py +0 -177
  19. scratchattach/editor/comment.py +0 -80
  20. scratchattach/editor/commons.py +0 -273
  21. scratchattach/editor/extension.py +0 -50
  22. scratchattach/editor/field.py +0 -99
  23. scratchattach/editor/inputs.py +0 -135
  24. scratchattach/editor/meta.py +0 -114
  25. scratchattach/editor/monitor.py +0 -183
  26. scratchattach/editor/mutation.py +0 -324
  27. scratchattach/editor/pallete.py +0 -90
  28. scratchattach/editor/prim.py +0 -170
  29. scratchattach/editor/project.py +0 -279
  30. scratchattach/editor/sprite.py +0 -599
  31. scratchattach/editor/twconfig.py +0 -114
  32. scratchattach/editor/vlb.py +0 -134
  33. scratchattach/eventhandlers/__init__.py +0 -0
  34. scratchattach/eventhandlers/_base.py +0 -100
  35. scratchattach/eventhandlers/cloud_events.py +0 -110
  36. scratchattach/eventhandlers/cloud_recorder.py +0 -26
  37. scratchattach/eventhandlers/cloud_requests.py +0 -459
  38. scratchattach/eventhandlers/cloud_server.py +0 -246
  39. scratchattach/eventhandlers/cloud_storage.py +0 -136
  40. scratchattach/eventhandlers/combine.py +0 -30
  41. scratchattach/eventhandlers/filterbot.py +0 -161
  42. scratchattach/eventhandlers/message_events.py +0 -42
  43. scratchattach/other/__init__.py +0 -0
  44. scratchattach/other/other_apis.py +0 -284
  45. scratchattach/other/project_json_capabilities.py +0 -475
  46. scratchattach/site/__init__.py +0 -0
  47. scratchattach/site/_base.py +0 -66
  48. scratchattach/site/activity.py +0 -382
  49. scratchattach/site/alert.py +0 -227
  50. scratchattach/site/backpack_asset.py +0 -118
  51. scratchattach/site/browser_cookie3_stub.py +0 -17
  52. scratchattach/site/browser_cookies.py +0 -61
  53. scratchattach/site/classroom.py +0 -447
  54. scratchattach/site/cloud_activity.py +0 -107
  55. scratchattach/site/comment.py +0 -242
  56. scratchattach/site/forum.py +0 -432
  57. scratchattach/site/project.py +0 -826
  58. scratchattach/site/session.py +0 -1238
  59. scratchattach/site/studio.py +0 -611
  60. scratchattach/site/user.py +0 -956
  61. scratchattach/utils/__init__.py +0 -0
  62. scratchattach/utils/commons.py +0 -255
  63. scratchattach/utils/encoder.py +0 -158
  64. scratchattach/utils/enums.py +0 -236
  65. scratchattach/utils/exceptions.py +0 -243
  66. scratchattach/utils/requests.py +0 -93
  67. scratchattach-2.1.15b0.dist-info/RECORD +0 -66
  68. {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/licenses/LICENSE +0 -0
  69. {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/top_level.txt +0 -0
File without changes
@@ -1,255 +0,0 @@
1
- """v2 ready: Common functions used by various internal modules"""
2
- from __future__ import annotations
3
-
4
- import string
5
-
6
- from typing import Optional, Final, Any, TypeVar, Callable, TYPE_CHECKING, Union
7
- from threading import Event as ManualResetEvent
8
- from threading import Lock
9
-
10
- from . import exceptions
11
- from .requests import requests
12
-
13
- from scratchattach.site import _base
14
-
15
-
16
- headers: Final = {
17
- "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
18
- "(KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36",
19
- "x-csrftoken": "a",
20
- "x-requested-with": "XMLHttpRequest",
21
- "referer": "https://scratch.mit.edu",
22
- }
23
- empty_project_json: Final = {
24
- 'targets': [
25
- {
26
- 'isStage': True,
27
- 'name': 'Stage',
28
- 'variables': {
29
- '`jEk@4|i[#Fk?(8x)AV.-my variable': [
30
- 'my variable',
31
- 0,
32
- ],
33
- },
34
- 'lists': {},
35
- 'broadcasts': {},
36
- 'blocks': {},
37
- 'comments': {},
38
- 'currentCostume': 0,
39
- 'costumes': [
40
- {
41
- 'name': '',
42
- 'bitmapResolution': 1,
43
- 'dataFormat': 'svg',
44
- 'assetId': '14e46ec3e2ba471c2adfe8f119052307',
45
- 'md5ext': '14e46ec3e2ba471c2adfe8f119052307.svg',
46
- 'rotationCenterX': 0,
47
- 'rotationCenterY': 0,
48
- },
49
- ],
50
- 'sounds': [],
51
- 'volume': 100,
52
- 'layerOrder': 0,
53
- 'tempo': 60,
54
- 'videoTransparency': 50,
55
- 'videoState': 'on',
56
- 'textToSpeechLanguage': None,
57
- },
58
- ],
59
- 'monitors': [],
60
- 'extensions': [],
61
- 'meta': {
62
- 'semver': '3.0.0',
63
- 'vm': '2.3.0',
64
- 'agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) '
65
- 'Chrome/124.0.0.0 Safari/537.36',
66
- },
67
- }
68
-
69
-
70
- def api_iterative_data(fetch_func: Callable[[int, int], list], limit: int, offset: int, max_req_limit: int = 40,
71
- unpack: bool = True) -> list:
72
- """
73
- Iteratively gets data by calling fetch_func with a moving offset and a limit.
74
- Once fetch_func returns None, the retrieval is completed.
75
- """
76
- if limit is None:
77
- limit = max_req_limit
78
-
79
- end = offset + limit
80
- api_data = []
81
- for offs in range(offset, end, max_req_limit):
82
- # Mimic actual scratch by only requesting the max amount
83
- data = fetch_func(offs, max_req_limit)
84
- if data is None:
85
- break
86
-
87
- if unpack:
88
- api_data.extend(data)
89
- else:
90
- api_data.append(data)
91
-
92
- if len(data) < max_req_limit:
93
- break
94
-
95
- api_data = api_data[:limit]
96
- return api_data
97
-
98
-
99
- def api_iterative(url: str, *, limit: int, offset: int, max_req_limit: int = 40, add_params: str = "",
100
- _headers: Optional[dict] = None, cookies: Optional[dict] = None):
101
- """
102
- Function for getting data from one of Scratch's iterative JSON API endpoints (like /users/<user>/followers, or /users/<user>/projects)
103
- """
104
- if _headers is None:
105
- _headers = headers.copy()
106
- if cookies is None:
107
- cookies = {}
108
-
109
- if offset < 0:
110
- raise exceptions.BadRequest("offset parameter must be >= 0")
111
- if limit < 0:
112
- raise exceptions.BadRequest("limit parameter must be >= 0")
113
-
114
- def fetch(off: int, lim: int):
115
- """
116
- Performs a single API request
117
- """
118
- resp = requests.get(
119
- f"{url}?limit={lim}&offset={off}{add_params}", headers=_headers, cookies=cookies, timeout=10
120
- ).json()
121
-
122
- if not resp:
123
- return None
124
- if resp == {"code": "BadRequest", "message": ""}:
125
- raise exceptions.BadRequest("The passed arguments are invalid")
126
- return resp
127
-
128
- api_data = api_iterative_data(
129
- fetch, limit, offset, max_req_limit=max_req_limit, unpack=True
130
- )
131
- return api_data
132
-
133
- def _get_object(identificator_name, identificator, __class: type[C], NotFoundException, session=None) -> C:
134
- # Internal function: Generalization of the process ran by get_user, get_studio etc.
135
- # Builds an object of class that is inheriting from BaseSiteComponent
136
- # # Class must inherit from BaseSiteComponent
137
- from scratchattach.site import project
138
- try:
139
- use_class: type = __class
140
- if __class is project.PartialProject:
141
- use_class = project.Project
142
- assert issubclass(use_class, __class)
143
- _object = use_class(**{identificator_name: identificator, "_session": session})
144
- r = _object.update()
145
- if r == "429":
146
- raise exceptions.Response429(
147
- "Your network is blocked or rate-limited by Scratch.\n"
148
- "If you're using an online IDE like replit.com, try running the code on your computer.")
149
- if not r:
150
- # Target is unshared. The cases that this can happen in are hardcoded:
151
- if __class is project.PartialProject: # Case: Target is an unshared project.
152
- _object = project.PartialProject(**{identificator_name: identificator,
153
- "shared": False, "_session": session})
154
- assert isinstance(_object, __class)
155
- return _object
156
- else:
157
- raise NotFoundException
158
- else:
159
- return _object
160
- except KeyError as e:
161
- raise NotFoundException(f"Key error at key {e} when reading API response")
162
- except Exception as e:
163
- raise e
164
-
165
-
166
- def webscrape_count(raw, text_before, text_after, cls: type = int) -> int | Any:
167
- return cls(raw.split(text_before)[1].split(text_after)[0])
168
-
169
-
170
- if TYPE_CHECKING:
171
- C = TypeVar("C", bound=_base.BaseSiteComponent)
172
-
173
- def parse_object_list(raw, __class: type[C], session=None, primary_key="id") -> list[C]:
174
- results = []
175
- for raw_dict in raw:
176
- try:
177
- _obj = __class(**{primary_key: raw_dict[primary_key], "_session": session})
178
- _obj._update_from_dict(raw_dict)
179
- results.append(_obj)
180
- except Exception as e:
181
- print("Warning raised by scratchattach: failed to parse ", raw_dict, "error", e)
182
- return results
183
-
184
-
185
- class LockEvent:
186
- """
187
- Can be waited on and triggered. Not to be confused with threading.Event, which has to be reset.
188
- """
189
- _event: ManualResetEvent
190
- _locks: list[Lock]
191
- _access_locks: Lock
192
- def __init__(self):
193
- self._event = ManualResetEvent()
194
- self._locks = []
195
- self._access_locks = Lock()
196
-
197
- def wait(self, blocking: bool = True, timeout: Optional[Union[int, float]] = None) -> bool:
198
- """
199
- Wait for the event.
200
- """
201
- return self._event.wait(timeout if blocking else 0)
202
-
203
- def trigger(self):
204
- """
205
- Trigger all threads waiting on this event to continue.
206
- """
207
- with self._access_locks:
208
- for lock in self._locks:
209
- try:
210
- lock.release()
211
- except RuntimeError:
212
- pass
213
- self._locks.clear()
214
- self._event.set()
215
- self._event = ManualResetEvent()
216
-
217
- def on(self) -> Lock:
218
- """
219
- Return a lock that will unlock once the event takes place. Return value has to be waited on to wait for the event.
220
- """
221
- lock = Lock()
222
- with self._access_locks:
223
- self._locks.append(lock)
224
- lock.acquire(timeout=0)
225
- return lock
226
-
227
- def get_class_sort_mode(mode: str) -> tuple[str, str]:
228
- """
229
- Returns the sort mode for the given mode for classes only
230
- """
231
- ascsort = ''
232
- descsort = ''
233
-
234
- mode = mode.lower()
235
- if mode == "last created":
236
- pass
237
- elif mode == "students":
238
- descsort = "student_count"
239
- elif mode == "a-z":
240
- ascsort = "title"
241
- elif mode == "z-a":
242
- descsort = "title"
243
-
244
- return ascsort, descsort
245
-
246
-
247
- def b62_decode(s: str):
248
- chars = string.digits + string.ascii_uppercase + string.ascii_lowercase
249
-
250
- ret = 0
251
- for char in s:
252
- ret = ret * 62 + chars.index(char)
253
-
254
- return ret
255
-
@@ -1,158 +0,0 @@
1
- from __future__ import annotations
2
- import math
3
- from . import exceptions
4
-
5
- letters = [
6
- None,
7
- None,
8
- None,
9
- None,
10
- None,
11
- None,
12
- None,
13
- None,
14
- None,
15
- None,
16
- "1",
17
- "2",
18
- "3",
19
- "4",
20
- "5",
21
- "6",
22
- "7",
23
- "8",
24
- "9",
25
- "0",
26
- " ",
27
- "a",
28
- "A",
29
- "b",
30
- "B",
31
- "c",
32
- "C",
33
- "d",
34
- "D",
35
- "e",
36
- "E",
37
- "f",
38
- "F",
39
- "g",
40
- "G",
41
- "h",
42
- "H",
43
- "i",
44
- "I",
45
- "j",
46
- "J",
47
- "k",
48
- "K",
49
- "l",
50
- "L",
51
- "m",
52
- "M",
53
- "n",
54
- "N",
55
- "o",
56
- "O",
57
- "p",
58
- "P",
59
- "q",
60
- "Q",
61
- "r",
62
- "R",
63
- "s",
64
- "S",
65
- "t",
66
- "T",
67
- "u",
68
- "U",
69
- "v",
70
- "V",
71
- "w",
72
- "W",
73
- "x",
74
- "X",
75
- "y",
76
- "Y",
77
- "z",
78
- "Z",
79
- "*",
80
- "/",
81
- ".",
82
- ",",
83
- "!",
84
- '"',
85
- "§",
86
- "$",
87
- "%",
88
- "_",
89
- "-",
90
- "(",
91
- "´",
92
- ")",
93
- "`",
94
- "?",
95
- "new line",
96
- "@",
97
- "#",
98
- "~",
99
- ";",
100
- ":",
101
- "+",
102
- "&",
103
- "|",
104
- "^",
105
- "'"
106
- ]
107
-
108
-
109
- class Encoding:
110
- """
111
- Class that contains tools for encoding / decoding strings. The strings encoded / decoded with these functions can be decoded / encoded with Scratch using this sprite: https://scratch3-assets.1tim.repl.co/Encoder.sprite3
112
- """
113
- @staticmethod
114
- def decode(inp):
115
- """
116
- Args:
117
- inp (str): The encoded input.
118
-
119
- Returns:
120
- str: The decoded output.
121
- """
122
- try:
123
- inp = str(inp)
124
- except Exception:
125
- raise(exceptions.InvalidDecodeInput)
126
- outp = ""
127
- for i in range(0, math.floor(len(inp) / 2)):
128
- letter = letters[int(f"{inp[i*2]}{inp[(i*2)+1]}")]
129
- outp = f"{outp}{letter}"
130
- return outp
131
-
132
- @staticmethod
133
- def encode(inp):
134
- """
135
- Args:
136
- inp (str): The decoded input.
137
-
138
- Returns:
139
- str: The encoded output.
140
- """
141
- inp = str(inp)
142
- outp = ""
143
- for i in inp:
144
- if i in letters:
145
- outp = f"{outp}{letters.index(i)}"
146
- else:
147
- outp += str(letters.index(" "))
148
- return outp
149
-
150
- @staticmethod
151
- def replace_char(old_char, new_char):
152
- """
153
- Replaces a character in the list that the encoder uses to encode / decode values.
154
- You can access this list using `scratchattach.encoder.letters`
155
- """
156
- i = letters.index(old_char)
157
- letters[i] = new_char
158
-
@@ -1,236 +0,0 @@
1
- """
2
- List of supported languages of scratch's translate and text2speech extensions.
3
- Adapted from https://translate-service.scratch.mit.edu/supported?language=en
4
- """
5
- from __future__ import annotations
6
-
7
- from dataclasses import dataclass
8
- from enum import Enum
9
- from typing import Optional, Callable, Iterable
10
-
11
-
12
- @dataclass
13
- class Language:
14
- name: str = None
15
- code: str = None
16
- locales: list[str] = None
17
- tts_locale: str = None
18
- single_gender: bool = None
19
-
20
-
21
- class _EnumWrapper(Enum):
22
- @classmethod
23
- def find(cls, value, by: str, apply_func: Optional[Callable] = None):
24
- """
25
- Finds the enum item with the given attribute that is equal to the given value.
26
- the apply_func will be applied to the attribute of each language object before comparison.
27
-
28
- i.e. Languages.find("ukranian", "name", str.lower) will return the Ukrainian language dataclass object
29
- (even though Ukrainian was spelt lowercase, since str.lower will convert the "Ukrainian" string to lowercase)
30
- """
31
- if apply_func is None:
32
- def apply_func(x):
33
- return x
34
-
35
- for item in cls:
36
- item_obj = item.value
37
-
38
- try:
39
- if by is None:
40
- _val = item_obj
41
- else:
42
- _val = getattr(item_obj, by)
43
-
44
- if apply_func(_val) == value:
45
- return item_obj
46
-
47
- except TypeError:
48
- pass
49
-
50
- @classmethod
51
- def all_of(cls, attr_name: str, apply_func: Optional[Callable] = None) -> Iterable:
52
- """
53
- Returns the list of each listed enum item's specified attribute by "attr_name"
54
-
55
- i.e. Languages.all_of("name") will return a list of names:
56
- ["Albanian", "Amharic", ...]
57
-
58
- The apply_func function will be applied to every list item,
59
- i.e. Languages.all_of("name", str.lower) will return the same except in lowercase:
60
- ["albanian", "amharic", ...]
61
- """
62
- if apply_func is None:
63
- def apply_func(x):
64
- return x
65
-
66
- for item in cls:
67
- item_obj = item.value
68
- attr = getattr(item_obj, attr_name)
69
- try:
70
- yield apply_func(attr)
71
-
72
- except TypeError:
73
- yield attr
74
-
75
- @classmethod
76
- def find_by_attrs(cls, value, bys: list[str], apply_func: Optional[Callable] = None) -> list:
77
- """
78
- Calls the EnumWrapper.by function multiple times until a match is found, using the provided 'by' attribute names
79
- """
80
- for by in bys:
81
- ret = cls.find(value, by, apply_func)
82
- if ret is not None:
83
- return ret
84
-
85
-
86
- class Languages(_EnumWrapper):
87
- Albanian = Language('Albanian', 'sq', None, None, None)
88
- Amharic = Language('Amharic', 'am', None, None, None)
89
- Arabic = Language('Arabic', 'ar', ['ar'], 'arb', True)
90
- Armenian = Language('Armenian', 'hy', None, None, None)
91
- Azerbaijani = Language('Azerbaijani', 'az', None, None, None)
92
- Basque = Language('Basque', 'eu', None, None, None)
93
- Belarusian = Language('Belarusian', 'be', None, None, None)
94
- Bulgarian = Language('Bulgarian', 'bg', None, None, None)
95
- Catalan = Language('Catalan', 'ca', None, None, None)
96
- Chinese_Traditional = Language('Chinese (Traditional)', 'zh-tw', ['zh-cn', 'zh-tw'], 'cmn-CN', True)
97
- Croatian = Language('Croatian', 'hr', None, None, None)
98
- Czech = Language('Czech', 'cs', None, None, None)
99
- Danish = Language('Danish', 'da', ['da'], 'da-DK', False)
100
- Dutch = Language('Dutch', 'nl', ['nl'], 'nl-NL', False)
101
- English = Language('English', 'en', ['en'], 'en-US', False)
102
- Esperanto = Language('Esperanto', 'eo', None, None, None)
103
- Estonian = Language('Estonian', 'et', None, None, None)
104
- Finnish = Language('Finnish', 'fi', None, None, None)
105
- French = Language('French', 'fr', ['fr'], 'fr-FR', False)
106
- Galician = Language('Galician', 'gl', None, None, None)
107
- German = Language('German', 'de', ['de'], 'de-DE', False)
108
- Greek = Language('Greek', 'el', None, None, None)
109
- Haitian_Creole = Language('Haitian Creole', 'ht', None, None, None)
110
- Hindi = Language('Hindi', 'hi', ['hi'], 'hi-IN', True)
111
- Hungarian = Language('Hungarian', 'hu', None, None, None)
112
- Icelandic = Language('Icelandic', 'is', ['is'], 'is-IS', False)
113
- Indonesian = Language('Indonesian', 'id', None, None, None)
114
- Irish = Language('Irish', 'ga', None, None, None)
115
- Italian = Language('Italian', 'it', ['it'], 'it-IT', False)
116
- Japanese = Language('Japanese', 'ja', ['ja', 'ja-hira'], 'ja-JP', False)
117
- Kannada = Language('Kannada', 'kn', None, None, None)
118
- Korean = Language('Korean', 'ko', ['ko'], 'ko-KR', True)
119
- Kurdish_Kurmanji = Language('Kurdish (Kurmanji)', 'ku', None, None, None)
120
- Latin = Language('Latin', 'la', None, None, None)
121
- Latvian = Language('Latvian', 'lv', None, None, None)
122
- Lithuanian = Language('Lithuanian', 'lt', None, None, None)
123
- Macedonian = Language('Macedonian', 'mk', None, None, None)
124
- Malay = Language('Malay', 'ms', None, None, None)
125
- Malayalam = Language('Malayalam', 'ml', None, None, None)
126
- Maltese = Language('Maltese', 'mt', None, None, None)
127
- Maori = Language('Maori', 'mi', None, None, None)
128
- Marathi = Language('Marathi', 'mr', None, None, None)
129
- Mongolian = Language('Mongolian', 'mn', None, None, None)
130
- Myanmar_Burmese = Language('Myanmar (Burmese)', 'my', None, None, None)
131
- Persian = Language('Persian', 'fa', None, None, None)
132
- Polish = Language('Polish', 'pl', ['pl'], 'pl-PL', False)
133
- Portuguese = Language('Portuguese', 'pt', ['pt'], 'pt-PT', False)
134
- Romanian = Language('Romanian', 'ro', ['ro'], 'ro-RO', True)
135
- Russian = Language('Russian', 'ru', ['ru'], 'ru-RU', False)
136
- Scots_Gaelic = Language('Scots Gaelic', 'gd', None, None, None)
137
- Serbian = Language('Serbian', 'sr', None, None, None)
138
- Slovak = Language('Slovak', 'sk', None, None, None)
139
- Slovenian = Language('Slovenian', 'sl', None, None, None)
140
- Spanish = Language('Spanish', 'es', None, None, None)
141
- Swedish = Language('Swedish', 'sv', ['sv'], 'sv-SE', True)
142
- Telugu = Language('Telugu', 'te', None, None, None)
143
- Thai = Language('Thai', 'th', None, None, None)
144
- Turkish = Language('Turkish', 'tr', ['tr'], 'tr-TR', True)
145
- Ukrainian = Language('Ukrainian', 'uk', None, None, None)
146
- Uzbek = Language('Uzbek', 'uz', None, None, None)
147
- Vietnamese = Language('Vietnamese', 'vi', None, None, None)
148
- Welsh = Language('Welsh', 'cy', ['cy'], 'cy-GB', True)
149
- Zulu = Language('Zulu', 'zu', None, None, None)
150
- Hebrew = Language('Hebrew', 'he', None, None, None)
151
- Chinese_Simplified = Language('Chinese (Simplified)', 'zh-cn', ['zh-cn', 'zh-tw'], 'cmn-CN', True)
152
- Mandarin = Chinese_Simplified
153
-
154
- nb_NO = Language(None, None, ['nb', 'nn'], 'nb-NO', True)
155
- pt_BR = Language(None, None, ['pt-br'], 'pt-BR', False)
156
- Brazilian = pt_BR
157
- es_ES = Language(None, None, ['es'], 'es-ES', False)
158
- es_US = Language(None, None, ['es-419'], 'es-US', False)
159
-
160
- @classmethod
161
- def find(cls, value, by: str = "name", apply_func: Optional[Callable] = None) -> Language:
162
- return super().find(value, by, apply_func)
163
-
164
- @classmethod
165
- def all_of(cls, attr_name: str = "name", apply_func: Optional[Callable] = None) -> list:
166
- return super().all_of(attr_name, apply_func)
167
-
168
-
169
- @dataclass
170
- class TTSVoice:
171
- name: str
172
- gender: str
173
- playback_rate: float | int = 1
174
-
175
-
176
- class TTSVoices(_EnumWrapper):
177
- alto = TTSVoice("alto", "female")
178
- # female is functionally equal to alto
179
- female = TTSVoice("female", "female")
180
-
181
- tenor = TTSVoice("tenor", "male")
182
- # male is functionally equal to tenor
183
- male = TTSVoice("male", "male")
184
-
185
- squeak = TTSVoice("squeak", "female", 1.19)
186
- giant = TTSVoice("giant", "male", .84)
187
- kitten = TTSVoice("kitten", "female", 1.41)
188
-
189
- @classmethod
190
- def find(cls, value, by: str = "name", apply_func: Optional[Callable] = None) -> TTSVoice:
191
- return super().find(value, by, apply_func)
192
-
193
- @classmethod
194
- def all_of(cls, attr_name: str = "name", apply_func: Optional[Callable] = None) -> Iterable:
195
- return super().all_of(attr_name, apply_func)
196
-
197
-
198
- @dataclass
199
- class AlertType:
200
- id: int
201
- message: str
202
-
203
-
204
- class AlertTypes(_EnumWrapper):
205
- """
206
- Enum for associating alert type indecies with their messages, for use with the str.format() method.
207
- """
208
- # Reference: https://github.com/TimMcCool/scratchattach/issues/304#issuecomment-2800110811
209
- # NOTE: THE TEXT WITHIN THE BRACES HERE MATTERS! IF YOU WANT TO CHANGE IT, MAKE SURE TO EDIT `site.alert.EducatorAlert`!
210
- ban = AlertType(0, "{username} was banned.")
211
- unban = AlertType(1, "{username} was unbanned.")
212
- excluded_from_homepage = AlertType(2, "{username} was excluded from homepage")
213
- excluded_from_homepage2 = AlertType(3, "{username} was excluded from homepage") # for some reason there are duplicates
214
- notified = AlertType(4, "{username} was notified by a Scratch Administrator. Notification type: {notification_type}") # not sure what notification type is
215
- autoban = AlertType(5, "{username} was banned automatically")
216
- autoremoved = AlertType(6, "{project} by {username} was removed automatically")
217
- project_censored2 = AlertType(7, "{project} by {username} was censored.") # <empty #7>
218
- project_censored = AlertType(20, "{project} by {username} was censored.")
219
- project_uncensored = AlertType(8, "{project} by {username} was uncensored.")
220
- project_reviewed2 = AlertType(9, "{project} by {username} was reviewed by a Scratch Administrator.") # <empty #9>
221
- project_reviewed = AlertType(10, "{project} by {username} was reviewed by a Scratch Administrator.")
222
- project_deleted = AlertType(11, "{project} by {username} was deleted by a Scratch Administrator.")
223
- user_deleted2 = AlertType(12, "{username} was deleted by a Scratch Administrator") # <empty #12>
224
- user_deleted = AlertType(17, "{username} was deleted by a Scratch Administrator")
225
- studio_reviewed2 = AlertType(13, "{studio} was reviewed by a Scratch Administrator.") # <empty #13>
226
- studio_reviewed = AlertType(14, "{studio} was reviewed by a Scratch Administrator.")
227
- studio_deleted = AlertType(15, "{studio} was deleted by a Scratch Administrator.")
228
- email_confirm2 = AlertType(16, "The email address of {username} was confirmed by a Scratch Administrator") # <empty #16>
229
- email_confirm = AlertType(18, "The email address of {username} was confirmed by a Scratch Administrator") # no '.' in HTML
230
- email_unconfirm = AlertType(19, "The email address of {username} was set as not confirmed by a Scratch Administrator")
231
- automute = AlertType(22, "{username} was automatically muted by our comment filters. The comment they tried to post was: {comment}")
232
- default = AlertType(-1, "{username} had an admin action performed.") # default case
233
-
234
- @classmethod
235
- def find(cls, value, by: str = "id", apply_func: Optional[Callable] = None) -> AlertType:
236
- return super().find(value, by, apply_func)