Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge main into sa-selenium #305

Open
wants to merge 119 commits into
base: sa-selenium
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
3960e9c
fixed image in pypi info page
TimMcCool Nov 9, 2024
645606a
Added create_studio and did a little with exceptions. - ConnectionErr…
FAReTek1 Nov 9, 2024
07a69c2
typo
FAReTek1 Nov 9, 2024
f9922af
A ton of UNTESTED docstrings
FAReTek1 Nov 9, 2024
253f88a
Merge remote-tracking branch 'origin/main'
FAReTek1 Nov 9, 2024
92344ed
More UNTESTED type hints
FAReTek1 Nov 9, 2024
4e23734
More UNTESTED type hints
FAReTek1 Nov 9, 2024
8a53174
More UNTESTED type hints
FAReTek1 Nov 9, 2024
49c25bb
Fix typo in cloud_server.py
The-Arx Nov 12, 2024
6cb631f
Added (smart) translation api
FAReTek1 Nov 12, 2024
9ca8008
Added (smart) translation api
FAReTek1 Nov 12, 2024
69e697f
Merge pull request #2 from TimMcCool/main
FAReTek1 Nov 12, 2024
f3ce6a2
Added tts api
FAReTek1 Nov 13, 2024
47b0257
Merge remote-tracking branch 'origin/main'
FAReTek1 Nov 13, 2024
b7a3249
Added tts api
FAReTek1 Nov 13, 2024
2b93c18
added an enum i guess?
FAReTek1 Nov 13, 2024
1a9e4d8
added an enum i guess?
FAReTek1 Nov 13, 2024
765b068
using languages enum now + kitten improvement
FAReTek1 Nov 16, 2024
f91178d
using languages enum now + kitten improvement
FAReTek1 Nov 16, 2024
dbe7c32
more classroom stuff. lets you actually edit title, description and s…
FAReTek1 Nov 18, 2024
7434255
classroom alerts, simplified code for wiwo/bio setting
FAReTek1 Nov 18, 2024
1904ee1
added setting pfp! wow that was confusing! bruh
FAReTek1 Nov 18, 2024
680640e
find ended classes, reopen/close classes & set thumbnail
FAReTek1 Nov 18, 2024
0ee943a
activity for classes. private activity is in a weird non-normalised f…
FAReTek1 Nov 18, 2024
c569235
added more parameters for the functions
FAReTek1 Nov 18, 2024
a2b87ef
register by class token
FAReTek1 Nov 18, 2024
51d3422
smarter language evaluation in translate function. some credit to the…
FAReTek1 Nov 20, 2024
cec1a12
dataclasses = conciseness & clean
FAReTek1 Nov 20, 2024
a5c48a0
docstrings and removing use of kwarg for all_of
FAReTek1 Nov 20, 2024
b6c565e
smarter language evaluation in translate function. some credit to the…
FAReTek1 Nov 20, 2024
e3c4769
dataclasses = conciseness & clean
FAReTek1 Nov 20, 2024
8690df1
docstrings and removing use of kwarg for all_of
FAReTek1 Nov 20, 2024
6ce4ff7
merge tts chinese with translate versions, same with portuguese (not …
FAReTek1 Nov 20, 2024
3e9f72e
merge tts chinese with translate versions, same with portuguese (not …
FAReTek1 Nov 20, 2024
a6c6168
using enums for tts genders asw + enum wrapper with finding by multip…
FAReTek1 Nov 20, 2024
6e92961
using enums for tts genders asw + enum wrapper with finding by multip…
FAReTek1 Nov 20, 2024
7d71d96
make sure language has code for translation
FAReTek1 Nov 20, 2024
2104d00
make sure language has code for translation
FAReTek1 Nov 20, 2024
9ec03bc
1 docstring
FAReTek1 Nov 21, 2024
24c7f1f
1 docstring
FAReTek1 Nov 21, 2024
d0f9356
removed json.dumps, using json in requests.post instead
FAReTek1 Nov 21, 2024
a5d1942
Merge pull request #4 from TimMcCool/main
FAReTek1 Nov 21, 2024
7752050
added support for closed classes using bs4
FAReTek1 Nov 21, 2024
9f8f727
studio adding and code simplification
FAReTek1 Nov 21, 2024
7af67a9
project attrs (no sprites yet)
FAReTek1 Nov 23, 2024
647cee2
sprites with everything but blocks (comments will need to be attached…
FAReTek1 Nov 23, 2024
860c111
prims are better now
FAReTek1 Nov 23, 2024
f488191
vlb prims have a vlb value, not a name/id
FAReTek1 Nov 23, 2024
491297b
renamed some base classes
FAReTek1 Nov 23, 2024
2d1e0f9
platform dataclass + global var searching
FAReTek1 Nov 24, 2024
6a8f040
starting to add blocks
FAReTek1 Nov 24, 2024
1ab0fed
added mutations
FAReTek1 Nov 24, 2024
0aa48ec
fixed mutation arg defaulting and added local globals (for importing …
FAReTek1 Nov 24, 2024
cdd5d99
fields
FAReTek1 Nov 24, 2024
faccac4
inputs
FAReTek1 Nov 24, 2024
9b19ae7
minor meta edit
FAReTek1 Nov 24, 2024
0841332
exporting projects (my ide is supper laggy rn bruh)
FAReTek1 Nov 25, 2024
7b00168
no need for shutil
FAReTek1 Nov 26, 2024
1fe2602
need to add mutation json
FAReTek1 Nov 26, 2024
802b2aa
mutation json
FAReTek1 Nov 26, 2024
ed228a7
mutation json update (not done)
FAReTek1 Nov 26, 2024
6025639
fixed mutations
FAReTek1 Nov 26, 2024
1bebf64
functions for systematically making new ids. will need to make specia…
FAReTek1 Nov 27, 2024
016cfe8
copy -> dcopy, minor change
FAReTek1 Nov 27, 2024
0f79f34
sprite exportation
FAReTek1 Nov 28, 2024
1f42a88
Merge pull request #283 from The-Arx/main
TheCommCraft Dec 2, 2024
c3614ea
Added misc features + todo list
FAReTek1 Dec 8, 2024
ba029ba
Loading scripts from backpack + other backpack cleanup
FAReTek1 Dec 8, 2024
88ca79e
clarification
FAReTek1 Dec 8, 2024
3a91227
twconfig
FAReTek1 Dec 8, 2024
c9260e2
import twconfig
FAReTek1 Dec 8, 2024
197c01b
stack types + can next
FAReTek1 Dec 9, 2024
c9e8d18
added check in classroom.py for nonexistent classes
FAReTek1 Dec 9, 2024
3a7e606
docstring
FAReTek1 Dec 10, 2024
6e8d21c
lots of new stuff for blocks
FAReTek1 Dec 12, 2024
19e910e
duplicating chains attach chain etc
FAReTek1 Dec 12, 2024
3d3a7be
more block stuffies :D
FAReTek1 Dec 12, 2024
f6da6f3
more block featuresssssss
FAReTek1 Dec 13, 2024
4209a8c
bugfix with comments and ids
FAReTek1 Dec 14, 2024
2a2960d
tw block detection
FAReTek1 Dec 14, 2024
b553d49
argument types
FAReTek1 Dec 14, 2024
f0f8a99
with statements with sprites to reduce the add_block calls needed. pr…
FAReTek1 Dec 15, 2024
83f9346
better singleton implementation
FAReTek1 Dec 15, 2024
1aa7bca
Merge pull request #285 from FAReTek1/translate
TimMcCool Dec 20, 2024
2b01dae
adds reset link send (maybe review this)
FAReTek1 Dec 20, 2024
fab2cb7
Merge branch 'main' into classes
FAReTek1 Dec 21, 2024
0a03800
class build rate limit
FAReTek1 Dec 21, 2024
8fa2f06
Merge remote-tracking branch 'origin/classes' into classes
FAReTek1 Dec 21, 2024
6b02a74
Merge branch 'main' into sbeditor
FAReTek1 Dec 21, 2024
569d9ec
fix old type hints + add from future import annotations to top of all…
FAReTek1 Dec 21, 2024
0064dba
reset email thing
FAReTek1 Dec 21, 2024
2254b82
remove email thing since i moved it
FAReTek1 Dec 21, 2024
84ef9d9
Merge remote-tracking branch 'origin/sbeditor' into sbeditor
FAReTek1 Dec 21, 2024
9c2f6c4
various basic scratchtools endpoints
FAReTek1 Dec 21, 2024
9b63c3e
get emoji status
FAReTek1 Dec 21, 2024
decbf69
get pinned comment
FAReTek1 Dec 21, 2024
0daab14
ctrl alt l (reformat)
FAReTek1 Dec 21, 2024
3cf71e7
.
TimMcCool Dec 21, 2024
136f4f9
Merge branch 'main' of https://github.com/TimMcCool/scratchattach
TimMcCool Dec 21, 2024
722e170
fixed small typo
TimMcCool Dec 21, 2024
bbd83e1
.
TimMcCool Dec 22, 2024
17ac00f
.
TimMcCool Dec 22, 2024
52853ce
.
TimMcCool Dec 22, 2024
24d2f0e
Merge branch 'main' into sbeditor
FAReTek1 Dec 22, 2024
c0f2ee8
actually parse private class activity (analyzed html/js to do so)
FAReTek1 Dec 23, 2024
220c703
moved json activity parser to activity method
FAReTek1 Dec 23, 2024
f349826
using datetime_created because it is more applicable??
FAReTek1 Dec 23, 2024
66f3782
add datetime_created as attribute for hinting
FAReTek1 Dec 23, 2024
665109b
Merge remote-tracking branch 'origin/sbeditor' into sbeditor
FAReTek1 Dec 24, 2024
b0e429e
folder support and some new find methods + a few type hints
FAReTek1 Dec 24, 2024
ae1002a
Merge branch 'main' into classes
FAReTek1 Dec 24, 2024
59a8008
line break
FAReTek1 Dec 24, 2024
4ba9ed0
fix files param
FAReTek1 Dec 24, 2024
9432bb1
Merge pr #294 from FAReTek1/classes (if there are weird bugs maybe lo…
FAReTek1 Dec 24, 2024
add93f7
Merge branch 'main' into sbeditor
FAReTek1 Dec 24, 2024
e829df8
rename yesnt
FAReTek1 Dec 24, 2024
9fe3d68
Merge remote-tracking branch 'origin/sbeditor' into sbeditor
FAReTek1 Dec 24, 2024
bcae33b
Merge pull request #295 from FAReTek1/sbeditor
FAReTek1 Dec 24, 2024
3987c6f
Update session.py
TheCommCraft Jan 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ scratchattach/test.py
scratchattach.code-workspace
**/.DS_Store
setup.py
setup.py
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 2.1.7

- Fixed self-hosting TW cloud ws servers feature
- Added sa.translate and sa.text2speech functions

# 2.0.6

Cloud variables: Stability improvement
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The library allows setting cloud variables, following users, updating your profi
so much more! Additionally, it provides frameworks that simplify sending data through cloud variables.

<p align="left" style="margin:10px">
<img width="160" src="https://github.com/TimMcCool/scratchattach/blob/main/logos/logo.svg">
<img width="160" src="https://raw.githubusercontent.com/TimMcCool/scratchattach/refs/heads/main/logos/logo.svg">

[![PyPI status](https://img.shields.io/pypi/status/scratchattach.svg)](https://pypi.python.org/pypi/scratchattach/)
[![PyPI download month](https://img.shields.io/pypi/dm/scratchattach.svg)](https://pypi.python.org/pypi/scratchattach/)
Expand Down
3 changes: 3 additions & 0 deletions scratchattach/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from .other.other_apis import *
from .other.project_json_capabilities import ProjectBody, get_empty_project_pb, get_pb_from_dict, read_sb3_file, download_asset
from .utils.encoder import Encoding
from .utils.enums import Languages, TTSVoices

from .site.activity import Activity
from .site.backpack_asset import BackpackAsset
Expand All @@ -22,3 +23,5 @@
from .site.classroom import Classroom, get_classroom
from .site.user import User, get_user
from .site._base import BaseSiteComponent

from . import editor
86 changes: 46 additions & 40 deletions scratchattach/cloud/_base.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,62 @@
from abc import ABC, abstractmethod
from __future__ import annotations

import websocket
import json
import ssl
import time
from ..utils import exceptions
import warnings
from abc import ABC

import websocket

from ..eventhandlers import cloud_recorder
import ssl
from ..utils import exceptions

class BaseCloud(ABC):

class BaseCloud(ABC):
"""
Base class for a project's cloud variables. Represents a cloud.

When inheriting from this class, the __init__ function of the inherited class ...

When inheriting from this class, the __init__ function of the inherited class:
- must first call the constructor of the super class: super().__init__()

- must then set some attributes

Attributes that must be specified in the __init__ function a class inheriting from this one:
project_id: Project id of the cloud variables

:self.project_id: Project id of the cloud variables

:self.cloud_host: URL of the websocket server ("wss://..." or "ws://...")
cloud_host: URL of the websocket server ("wss://..." or "ws://...")

Attributes that can, but don't have to be specified in the __init__ function:

:self._session: Either None or a site.session.Session object. Defaults to None.
_session: Either None or a site.session.Session object. Defaults to None.

:self.ws_shortterm_ratelimit: The wait time between cloud variable sets. Defaults to 0.1
ws_shortterm_ratelimit: The wait time between cloud variable sets. Defaults to 0.1

:self.ws_longterm_ratelimit: The amount of cloud variable set that can be performed long-term without ever getting ratelimited
ws_longterm_ratelimit: The amount of cloud variable set that can be performed long-term without ever getting ratelimited

:self.allow_non_numeric: Whether non-numeric cloud variable values are allowed. Defaults to False
allow_non_numeric: Whether non-numeric cloud variable values are allowed. Defaults to False

:self.length_limit: Length limit for cloud variable values. Defaults to 100000
length_limit: Length limit for cloud variable values. Defaults to 100000

:self.username: The username to send during handshake. Defaults to "scratchattach"
username: The username to send during handshake. Defaults to "scratchattach"

:self.header: The header to send. Defaults to None
header: The header to send. Defaults to None

:self.cookie: The cookie to send. Defaults to None
cookie: The cookie to send. Defaults to None

:self.origin: The origin to send. Defaults to None
origin: The origin to send. Defaults to None

:self.print_connect_messages: Whether to print a message on every connect to the cloud server. Defaults to False.
print_connect_messages: Whether to print a message on every connect to the cloud server. Defaults to False.
"""

def __init__(self):

def __init__(self, *, _session=None):

# Required internal attributes that every object representing a cloud needs to have (no matter what cloud is represented):
self._session = None
self._session = _session
self.active_connection = False #whether a connection to a cloud variable server is currently established

self.websocket = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE})
self.recorder = None # A CloudRecorder object that records cloud activity for the values to be retrieved later will be saved in this attribute as soon as .get_var is called
self.recorder = None # A CloudRecorder object that records cloud activity for the values to be retrieved later,
# which will be saved in this attribute as soon as .get_var is called
self.first_var_set = 0
self.last_var_set = 0
self.var_stets_since_first = 0
Expand All @@ -63,7 +65,8 @@ def __init__(self):
# (These attributes can be specifically in the constructors of classes inheriting from this base class)
self.ws_shortterm_ratelimit = 0.06667
self.ws_longterm_ratelimit = 0.1
self.ws_timeout = 3 # Timeout for send operations (after the timeout, the connection will be renewed and the operation will be retried 3 times)
self.ws_timeout = 3 # Timeout for send operations (after the timeout,
# the connection will be renewed and the operation will be retried 3 times)
self.allow_non_numeric = False
self.length_limit = 100000
self.username = "scratchattach"
Expand Down Expand Up @@ -100,7 +103,7 @@ def _send_packet(self, packet):
self.websocket.send(json.dumps(packet) + "\n")
except Exception:
self.active_connection = False
raise exceptions.ConnectionError(f"Sending packet failed three times in a row: {packet}")
raise exceptions.CloudConnectionError(f"Sending packet failed three times in a row: {packet}")

def _send_packet_list(self, packet_list):
packet_string = "".join([json.dumps(packet) + "\n" for packet in packet_list])
Expand All @@ -126,7 +129,8 @@ def _send_packet_list(self, packet_list):
self.websocket.send(packet_string)
except Exception:
self.active_connection = False
raise exceptions.ConnectionError(f"Sending packet list failed four times in a row: {packet_list}")
raise exceptions.CloudConnectionError(
f"Sending packet list failed four times in a row: {packet_list}")

def _handshake(self):
packet = {"method": "handshake", "user": self.username, "project_id": self.project_id}
Expand All @@ -139,8 +143,8 @@ def connect(self):
cookie=self.cookie,
origin=self.origin,
enable_multithread=True,
timeout = self.ws_timeout,
header = self.header
timeout=self.ws_timeout,
header=self.header
)
self._handshake()
self.active_connection = True
Expand All @@ -166,29 +170,29 @@ def _assert_valid_value(self, value):
if not (value in [True, False, float('inf'), -float('inf')]):
value = str(value)
if len(value) > self.length_limit:
raise(exceptions.InvalidCloudValue(
raise (exceptions.InvalidCloudValue(
f"Value exceeds length limit: {str(value)}"
))
if not self.allow_non_numeric:
x = value.replace(".", "")
x = x.replace("-", "")
if not (x.isnumeric() or x == ""):
raise(exceptions.InvalidCloudValue(
raise (exceptions.InvalidCloudValue(
"Value not numeric"
))

def _enforce_ratelimit(self, *, n):
# n is the amount of variables being set
if (time.time() - self.first_var_set) / (self.var_stets_since_first+1) > self.ws_longterm_ratelimit: # if the average delay between cloud variable sets has been bigger than the long-term rate-limit, cloud variables can be set fast (wait time smaller than long-term rate limit) again
if (time.time() - self.first_var_set) / (
self.var_stets_since_first + 1) > self.ws_longterm_ratelimit: # if the average delay between cloud variable sets has been bigger than the long-term rate-limit, cloud variables can be set fast (wait time smaller than long-term rate limit) again
self.var_stets_since_first = 0
self.first_var_set = time.time()

wait_time = self.ws_shortterm_ratelimit * n
if time.time() - self.first_var_set > 25: # if cloud variables have been continously set fast (wait time smaller than long-term rate limit) for 25 seconds, they should be set slow now (wait time = long-term rate limit) to avoid getting rate-limited
if time.time() - self.first_var_set > 25: # if cloud variables have been continously set fast (wait time smaller than long-term rate limit) for 25 seconds, they should be set slow now (wait time = long-term rate limit) to avoid getting rate-limited
wait_time = self.ws_longterm_ratelimit * n
while self.last_var_set + wait_time >= time.time():
time.sleep(0.001)


def set_var(self, variable, value):
"""
Expand Down Expand Up @@ -231,7 +235,7 @@ def set_vars(self, var_value_dict, *, intelligent_waits=True):
self.connect()
if intelligent_waits:
self._enforce_ratelimit(n=len(list(var_value_dict.keys())))

self.var_stets_since_first += len(list(var_value_dict.keys()))

packet_list = []
Expand All @@ -256,7 +260,7 @@ def get_var(self, var, *, recorder_initial_values={}):
self.recorder = cloud_recorder.CloudRecorder(self, initial_values=recorder_initial_values)
self.recorder.start()
start_time = time.time()
while not (self.recorder.cloud_values != {} or start_time < time.time() -5):
while not (self.recorder.cloud_values != {} or start_time < time.time() - 5):
time.sleep(0.01)
return self.recorder.get_var(var)

Expand All @@ -265,17 +269,19 @@ def get_all_vars(self, *, recorder_initial_values={}):
self.recorder = cloud_recorder.CloudRecorder(self, initial_values=recorder_initial_values)
self.recorder.start()
start_time = time.time()
while not (self.recorder.cloud_values != {} or start_time < time.time() -5):
while not (self.recorder.cloud_values != {} or start_time < time.time() - 5):
time.sleep(0.01)
return self.recorder.get_all_vars()

def events(self):
from ..eventhandlers.cloud_events import CloudEvents
return CloudEvents(self)

def requests(self, *, no_packet_loss=False, used_cloud_vars=["1", "2", "3", "4", "5", "6", "7", "8", "9"], respond_order="receive"):
def requests(self, *, no_packet_loss=False, used_cloud_vars=["1", "2", "3", "4", "5", "6", "7", "8", "9"],
respond_order="receive"):
from ..eventhandlers.cloud_requests import CloudRequests
return CloudRequests(self, used_cloud_vars=used_cloud_vars, no_packet_loss=no_packet_loss, respond_order=respond_order)
return CloudRequests(self, used_cloud_vars=used_cloud_vars, no_packet_loss=no_packet_loss,
respond_order=respond_order)

def storage(self, *, no_packet_loss=False, used_cloud_vars=["1", "2", "3", "4", "5", "6", "7", "8", "9"]):
from ..eventhandlers.cloud_storage import CloudStorage
Expand Down
9 changes: 6 additions & 3 deletions scratchattach/cloud/cloud.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""v2 ready: ScratchCloud, TwCloud and CustomCloud classes"""

from __future__ import annotations

from ._base import BaseCloud
from typing import Type
from ..utils.requests import Requests as requests
from ..utils import exceptions, commons
from ..site import cloud_activity

class ScratchCloud(BaseCloud):

class ScratchCloud(BaseCloud):
def __init__(self, *, project_id, _session=None):
super().__init__()

Expand Down Expand Up @@ -91,9 +93,10 @@ def events(self, *, use_logs=False):
else:
return super().events()

class TwCloud(BaseCloud):

def __init__(self, *, project_id, cloud_host="wss://clouddata.turbowarp.org", purpose="", contact=""):
class TwCloud(BaseCloud):
def __init__(self, *, project_id, cloud_host="wss://clouddata.turbowarp.org", purpose="", contact="",
_session=None):
super().__init__()

self.project_id = project_id
Expand Down
21 changes: 21 additions & 0 deletions scratchattach/editor/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
scratchattach.editor (sbeditor v2) - a library for all things sb3
"""

from .asset import Asset, Costume, Sound
from .project import Project
from .extension import Extensions, Extension
from .mutation import Mutation, Argument, parse_proc_code
from .meta import Meta, set_meta_platform
from .sprite import Sprite
from .block import Block
from .prim import Prim, PrimTypes
from .backpack_json import load_script as load_script_from_backpack
from .twconfig import TWConfig, is_valid_twconfig
from .inputs import Input, ShadowStatuses
from .field import Field
from .vlb import Variable, List, Broadcast
from .comment import Comment
from .monitor import Monitor

from .build_defaulting import add_chain, add_comment, add_block
Loading