11# Classes and methods for interacting with turbowarp placeholder (https://share.turbowarp.org/)
22import re
3- import json
43import bs4
54
65from dataclasses import dataclass
76from typing_extensions import Optional
87from bs4 import BeautifulSoup
98
109from scratchattach .site import session
10+ from scratchattach .site .typed_dicts import PlaceholderProjectDataDict
1111from scratchattach .utils .requests import requests
1212from 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
0 commit comments