100 lines
2.9 KiB
Python
Executable File
100 lines
2.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import argparse
|
|
import gzip
|
|
import html.parser
|
|
import logging
|
|
import re
|
|
import subprocess
|
|
import urllib.request
|
|
|
|
## The URL of a dndbeyond character which won't be deleted
|
|
DND_BEYOND_CHARACTER_URL = "https://www.dndbeyond.com/characters/147022047"
|
|
|
|
## Regex to find the matching JS file
|
|
MAIN_JS_RE = re.compile(r"https://media\.dndbeyond\.com\/character-app.*main.*\.js")
|
|
|
|
## Path to sourcemapper bin
|
|
SOURCEMAPPER_BIN = "/home/prometheus/go/bin/sourcemapper"
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Utility for scanning and converting videos."
|
|
)
|
|
parser.add_argument(
|
|
"-u",
|
|
"--character-url",
|
|
default=DND_BEYOND_CHARACTER_URL,
|
|
help="URL of the dndbeyond character to grab the source from.",
|
|
)
|
|
parser.add_argument(
|
|
"-v", "--verbose", action="store_true", help="Enable verbose logging"
|
|
)
|
|
parser.add_argument(
|
|
"-q", "--quiet", action="store_true", help="Only display errors"
|
|
)
|
|
args = parser.parse_args()
|
|
if args.verbose:
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
elif args.quiet:
|
|
logging.basicConfig(level=logging.ERROR)
|
|
else:
|
|
logging.basicConfig(level=logging.INFO)
|
|
char_data = download_character()
|
|
parser = MainJSExtractor()
|
|
parser.feed(char_data.decode("utf-8"))
|
|
print(f"Found URL: {parser.js_url}")
|
|
subprocess.check_call(
|
|
[
|
|
SOURCEMAPPER_BIN,
|
|
"-output",
|
|
"ddb_main",
|
|
"-jsurl",
|
|
parser.js_url,
|
|
]
|
|
)
|
|
|
|
|
|
def download_character() -> bytes:
|
|
try:
|
|
req = urllib.request.Request(
|
|
DND_BEYOND_CHARACTER_URL,
|
|
headers={
|
|
"user-agent": "Mozilla/5.0",
|
|
"authority": "www.dndbeyond.com",
|
|
"cache-control": "max-age=0",
|
|
"upgrade-insecure-requests": "1",
|
|
"sec-fetch-user": "?1",
|
|
"accept": "text/json",
|
|
"sec-fetch-site": "none",
|
|
"sec-fetch-mode": "navigate",
|
|
"accept-encoding": "gzip, deflate, br",
|
|
"accept-language": "en-US,en;q=0.9",
|
|
},
|
|
)
|
|
with urllib.request.urlopen(req) as resp:
|
|
if resp.info().get("Content-Encoding") == "gzip":
|
|
return gzip.decompress(resp.read())
|
|
else:
|
|
return resp.read()
|
|
except Exception:
|
|
logging.exception(f"Failed to load the character")
|
|
|
|
|
|
class MainJSExtractor(html.parser.HTMLParser):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.js_url = None
|
|
|
|
def handle_starttag(self, tag, attrs):
|
|
if tag == "script":
|
|
for attr_name, attr_val in attrs:
|
|
if attr_name == "src":
|
|
m = MAIN_JS_RE.match(attr_val)
|
|
if m is not None:
|
|
self.js_url = attr_val
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|