Skip to content

Commit ad2d410

Browse files
committed
fix: use hjson instead of regex mess
This is not a required dependency. If you want to use it, install it separately
1 parent 7241ea9 commit ad2d410

2 files changed

Lines changed: 30 additions & 21 deletions

File tree

scratchattach/site/placeholder.py

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# Classes and methods for interacting with turbowarp placeholder (https://share.turbowarp.org/)
22
import re
3-
import json
43
import bs4
54

65
from dataclasses import dataclass
76
from typing_extensions import Optional
87
from bs4 import BeautifulSoup
98

109
from scratchattach.site import session
10+
from scratchattach.site.typed_dicts import PlaceholderProjectDataDict
1111
from scratchattach.utils.requests import requests
1212
from scratchattach import editor
1313

@@ -18,17 +18,22 @@ class PlaceholderProject:
1818
title: Optional[str] = None
1919
description: Optional[str] = None
2020
md5exts_to_sha256: Optional[dict[str, str]] = None
21+
admin_ownership_token: Optional[str] = None # guessing it's a str
2122

2223
_session: Optional[session.Session] = None
2324

2425
def get_json(self):
2526
with requests.no_error_handling():
2627
return requests.get(f"https://share.turbowarp.org/api/projects/{self.id}").json()
2728

28-
def update_by_html(self):
29+
def update_by_html(self) -> None:
2930
"""
30-
Scrape JS to update the project. Hopefully this will not be necessary in the future, as it is very error-prone.
31+
Scrape JS to update the project. Requires hjson
3132
"""
33+
try:
34+
import hjson # type: ignore
35+
except ImportError as e:
36+
raise ImportError("Please use pip install hjson if you want to use placeholder projects!") from e
3237

3338
with requests.no_error_handling():
3439
resp = requests.get(f"https://share.turbowarp.org/projects/{self.id}")
@@ -41,24 +46,16 @@ def update_by_html(self):
4146
if raw_data := re.search("const data = \\[.*\"data\":{metadata:{.*},md5extsToSha256:.*];", str(script.contents[0])):
4247
data = raw_data.group().removeprefix("const data = ").removesuffix(";")
4348
# this data is NOT json. Therefore, we can't just JSON.parse it.
44-
# it's actually native JavaScript, but we can extract the information in a really flimsy way using regex
45-
# This flimsy method would probably break with bad input, so maybe, instead, a request should be made to GarboMuffin.
46-
# If you want full JS support, use an automated browser.
47-
print(data)
48-
49-
# get title
50-
pf, sf = 'metadata:{title:"', '",description'
51-
if group := re.search(pf+'.*?'+sf, data).group():
52-
self.title = json.loads('"' + group.removeprefix(pf).removesuffix(sf) + '"')
53-
54-
# Get description. It is probably very easy to break this regex
55-
pf, sf = 'description:"', '"},'
56-
if group := re.search(pf+'.*?'+sf, data).group():
57-
self.description = json.loads('"' + group.removeprefix(pf).removesuffix(sf) + '"')
58-
59-
pf, sf = 'md5extsToSha256:{', '},'
60-
if group := re.search(pf+'.*?'+sf, data).group():
61-
self.md5exts_to_sha256 = json.loads('{' + group.removeprefix(pf).removesuffix(sf) + '}')
49+
# it's actually native JavaScript, but we can extract the information in a relatively stable way using hjson
50+
# maybe, instead, a request should be made to GarboMuffin.
51+
data = hjson.loads(data)
52+
# i am unsure if the other data here is of any use. It may be artifacts coming from svelte
53+
parsed_data: PlaceholderProjectDataDict = data[1]["data"]
54+
55+
self.title = parsed_data["metadata"]["title"]
56+
self.description = parsed_data["metadata"]["description"]
57+
self.md5exts_to_sha256 = dict(parsed_data["md5extsToSha256"])
58+
self.admin_ownership_token = parsed_data["adminOwnershipToken"]
6259

6360
break
6461

scratchattach/site/typed_dicts.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
from typing_extensions import OrderedDict
4+
35
from scratchattach.cloud import _base
46
from typing import TypedDict, Union, Optional, Required, NotRequired
57

@@ -124,3 +126,13 @@ class StudioRoleDict(TypedDict):
124126
curator: bool
125127
invited: bool
126128
following: bool
129+
130+
class PlaceholderProjectDataMetadataDict(TypedDict):
131+
title: str
132+
description: str
133+
134+
# https://github.com/GarboMuffin/placeholder/blob/e1e98953342a40abbd626a111f621711f74e783b/src/routes/projects/%5Bproject%5D/%2Bpage.server.ts#L19
135+
class PlaceholderProjectDataDict(TypedDict):
136+
metadata: PlaceholderProjectDataMetadataDict
137+
md5extsToSha256: OrderedDict[str, str]
138+
adminOwnershipToken: Optional[str]

0 commit comments

Comments
 (0)