diff options
-rw-r--r-- | CONTRIBUTING.rst | 3 | ||||
-rw-r--r-- | Makefile | 84 | ||||
-rw-r--r-- | README.rst | 23 | ||||
-rwxr-xr-x | ast2json/imachine2json.py | 19 | ||||
-rwxr-xr-x | ast2json/rpyc2json.py | 5 | ||||
-rwxr-xr-x | ast2json/strings2json.py | 22 | ||||
-rwxr-xr-x | configure | 26 | ||||
-rwxr-xr-x | configure.py | 77 | ||||
-rw-r--r-- | www/js/html5ks.js | 10 |
9 files changed, 191 insertions, 78 deletions
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000..5142d5d --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,3 @@ +Check Bugzilla for things that need to be done. https://bugzilla.happinessforme.com/buglist.cgi?cmdtype=runnamed&namedcmd=Open+HTML5KS+bugs + +See docs/ for the obvious. @@ -39,53 +39,40 @@ www/js/lib/when.js: when export PYTHON=python2; cd when && $(NPM) update && $(NPM) run browserify-debug # === JSON === -ORPYC := ast2json/imachine.rpyc ast2json/imachine_replay.rpyc \ - ast2json/ui-strings.rpyc ast2json/ui-strings_FR.rpyc -OJSON := $(ORPYC:ast2json/%.rpyc=www/json/%.json) - -SRPYC := ast2json/script-a1-friday_FR.rpyc ast2json/script-a1-friday.rpyc \ - ast2json/script-a1-monday_FR.rpyc ast2json/script-a1-monday.rpyc \ - ast2json/script-a1-saturday_FR.rpyc ast2json/script-a1-saturday.rpyc \ - ast2json/script-a1-sunday_FR.rpyc ast2json/script-a1-sunday.rpyc \ - ast2json/script-a1-thursday_FR.rpyc ast2json/script-a1-thursday.rpyc \ - ast2json/script-a1-tuesday_FR.rpyc ast2json/script-a1-tuesday.rpyc \ - ast2json/script-a1-wednesday_FR.rpyc ast2json/script-a1-wednesday.rpyc \ - ast2json/script-a2-emi_FR.rpyc ast2json/script-a2-emi.rpyc \ - ast2json/script-a2-hanako_FR.rpyc ast2json/script-a2-hanako.rpyc \ - ast2json/script-a2-lilly_FR.rpyc ast2json/script-a2-lilly.rpyc \ - ast2json/script-a2-rin_FR.rpyc ast2json/script-a2-rin.rpyc \ - ast2json/script-a2-shizune_FR.rpyc ast2json/script-a2-shizune.rpyc \ - ast2json/script-a3-emi_FR.rpyc ast2json/script-a3-emi.rpyc \ - ast2json/script-a3-hanako_FR.rpyc ast2json/script-a3-hanako.rpyc \ - ast2json/script-a3-lilly_FR.rpyc ast2json/script-a3-lilly.rpyc \ - ast2json/script-a3-rin_FR.rpyc ast2json/script-a3-rin.rpyc \ - ast2json/script-a3-shizune_FR.rpyc ast2json/script-a3-shizune.rpyc \ - ast2json/script-a4-emi_FR.rpyc ast2json/script-a4-emi.rpyc \ - ast2json/script-a4-hanako_FR.rpyc ast2json/script-a4-hanako.rpyc \ - ast2json/script-a4-lilly_FR.rpyc ast2json/script-a4-lilly.rpyc \ - ast2json/script-a4-rin_FR.rpyc ast2json/script-a4-rin.rpyc \ - ast2json/script-a4-shizune_FR.rpyc ast2json/script-a4-shizune.rpyc +IRPYC := ast2json/imachine.rpyc ast2json/imachine_replay.rpyc +IJSON := $(IRPYC:ast2json/%.rpyc=www/json/%.json) + +URPYC := ast2json/ui-strings.rpyc ast2json/ui-strings_FR.rpyc +UJSON := $(URPYC:ast2json/%.rpyc=www/json/%.json) + +SRPYC := $(wildcard ast2json/script-a*.rpyc) JSONI := $(SRPYC:%.rpyc=%.json.i) SJSON := $(SRPYC:ast2json/%.rpyc=www/json/%.json) -JSON := $(OJSON) $(SJSON) +JSON := $(IJSON) $(UJSON) $(SJSON) JSONGZ := $(JSON:=.gz) AJSON := $(JSON) $(JSONGZ) -# FIXME json: $(AJSON) %.json.i: ast2json/rpyc2json.py %.rpyc $^ $@ -www/json/script-%.json: ast2json/script2json.py ast2json/script-%.json.i +$(SJSON): www/json/%.json: ast2json/script2json.py ast2json/%.json.i + $^ $@ + +$(UJSON): www/json/%.json: ast2json/strings2json.py ast2json/%.json.i $^ $@ -$(OJSON): www/json/%.json: ast2json/rpyc2json.py ast2json/%.rpyc +$(IJSON): www/json/%.json: ast2json/imachine2json.py ast2json/%.json.i $^ $@ %.json.gz: %.json +ifdef DEFLUFF + $(GZIP) -c $< | $(DEFLUFF) > $@ +else $(GZIP) -c $< > $@ +endif touch $< $@ # === VIDEO === @@ -140,38 +127,11 @@ PNG := $(shell find www/dump -name '*.png' ! -name 'ctc_strip.png') JPG := $(shell find www/dump -name '*.jpg') WEBP := $(PNG:.png=.webp) $(JPG:.jpg=.webp) CTC_ANIM_SRC := www/dump/ui/ctc_strip.png -CTC_ANIM_MORE_TMP := www/dump/ui/ctc_strip-1.png \ - www/dump/ui/ctc_strip-2.png www/dump/ui/ctc_strip-3.png \ - www/dump/ui/ctc_strip-4.png www/dump/ui/ctc_strip-5.png \ - www/dump/ui/ctc_strip-6.png www/dump/ui/ctc_strip-7.png \ - www/dump/ui/ctc_strip-8.png www/dump/ui/ctc_strip-9.png \ - www/dump/ui/ctc_strip-10.png www/dump/ui/ctc_strip-11.png \ - www/dump/ui/ctc_strip-12.png www/dump/ui/ctc_strip-13.png \ - www/dump/ui/ctc_strip-14.png www/dump/ui/ctc_strip-15.png \ - www/dump/ui/ctc_strip-16.png www/dump/ui/ctc_strip-17.png \ - www/dump/ui/ctc_strip-18.png www/dump/ui/ctc_strip-19.png \ - www/dump/ui/ctc_strip-20.png www/dump/ui/ctc_strip-21.png \ - www/dump/ui/ctc_strip-22.png www/dump/ui/ctc_strip-23.png \ - www/dump/ui/ctc_strip-24.png www/dump/ui/ctc_strip-25.png \ - www/dump/ui/ctc_strip-26.png www/dump/ui/ctc_strip-27.png \ - www/dump/ui/ctc_strip-28.png www/dump/ui/ctc_strip-29.png \ - www/dump/ui/ctc_strip-30.png www/dump/ui/ctc_strip-31.png \ - www/dump/ui/ctc_strip-32.png www/dump/ui/ctc_strip-33.png \ - www/dump/ui/ctc_strip-34.png www/dump/ui/ctc_strip-35.png \ - www/dump/ui/ctc_strip-36.png www/dump/ui/ctc_strip-37.png \ - www/dump/ui/ctc_strip-38.png www/dump/ui/ctc_strip-39.png \ - www/dump/ui/ctc_strip-40.png www/dump/ui/ctc_strip-41.png \ - www/dump/ui/ctc_strip-42.png www/dump/ui/ctc_strip-43.png \ - www/dump/ui/ctc_strip-44.png www/dump/ui/ctc_strip-45.png \ - www/dump/ui/ctc_strip-46.png www/dump/ui/ctc_strip-47.png \ - www/dump/ui/ctc_strip-48.png www/dump/ui/ctc_strip-49.png \ - www/dump/ui/ctc_strip-50.png www/dump/ui/ctc_strip-51.png \ - www/dump/ui/ctc_strip-52.png www/dump/ui/ctc_strip-53.png \ - www/dump/ui/ctc_strip-54.png www/dump/ui/ctc_strip-55.png \ - www/dump/ui/ctc_strip-56.png www/dump/ui/ctc_strip-57.png \ - www/dump/ui/ctc_strip-58.png www/dump/ui/ctc_strip-59.png \ - www/dump/ui/ctc_strip-60.png www/dump/ui/ctc_strip-61.png \ - www/dump/ui/ctc_strip-62.png www/dump/ui/ctc_strip-63.png +CTC_ANIM_MORE_TMP := $(foreach n, 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 + 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 + 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 + 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 + 63, www/dump/ui/ctc_strip-$(n).png) CTC_ANIM_TMP := www/dump/ui/ctc_strip-0.png $(CTC_ANIM_MORE_TMP) CTC_ANIM_TMP_WEBP := $(CTC_ANIM_TMP:%.png=%.webp) CTC_ANIM_TMP_ALL := $(CTC_ANIM_TMP) $(CTC_ANIM_TMP_WEBP) @@ -19,18 +19,19 @@ Requirements - Katawa Shoujo (obviously) - Firefox/Chrome/a sensible browser (i.e. not IE) - a shell (Bash, dash, zsh, etc) -- GNU make 3.82 or greater -- ffmpeg with fdk-aac, libopus, libtheora, libvpx-vp9, libx264 (preferably git HEAD) +- GNU make 3.82 or greater (see `Makefile`_ section) +- ffmpeg (preferably git HEAD) with fdk-aac, libopus, libtheora, libvpx-vp9, libx264 - for full list, see ``configure`` or ``.travis.sh`` - cwebp and webpmux from libwebp - convert from ImageMagick - apngasm - Node.js, npm for uglifyjs +- Python 3 Recommended ''''''''''' - DeflOpt - defluff -- inotify-tools (for ``make watch``) +- inotify-tools (for ``make dev``) - jpegmini - jpegrescan - jpegtran @@ -61,18 +62,26 @@ Alternatively, specific conversions can be disabled by passing --disable-convers See ``./configure --help`` for more information. Reducing disk usage -------------------- +=================== Run ``make space``. Warning: This will remove source files from dump. ``make`` will continue to work (i.e. make new files as appropriate) but will not re-make converted files. Contributing ------------- +============ -Check Bugzilla for things that need to be done. https://bugzilla.happinessforme.com/buglist.cgi?cmdtype=runnamed&namedcmd=Open+HTML5KS+bugs +See ``CONTRIBUTING.rst``. -See docs/ for the obvious. +Makefile +======== Run ``make dev`` to automatically start nginx and re-make when changes are made. +GNU make is required since I do not really want to write a script to output a Makefile. +I refuse to use autoconf; moreover, it isn't even relevant to this program, being designed for use with C/C++ projects. + +Make 3.82 is required since this version sorts rules differently; versions of make prior to this one will not properly build www/dump/ctc_strip-0.png, resulting in errors building ctc_anim.png and ctc_anim-*.webp. +If you must use a version before that one (e.g. you are stuck on Ubuntu 12.04), manually building that file according to the Makefile should resolve the error. +Patches to fix this are welcome. + .. _`Katawa Shoujo`: http://www.katawa-shoujo.com/ diff --git a/ast2json/imachine2json.py b/ast2json/imachine2json.py new file mode 100755 index 0000000..db1878c --- /dev/null +++ b/ast2json/imachine2json.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +import json +import sys + +def imachine2json(ast): + ret = {} + if ast[0]['_type'] != 'Label': + raise TypeError('obj does not start with Label, wrong file?') + for label in ast: + if label['parameters'] is not None or label['hide']: + raise NotImplementedError() + ret[label['name']] = label + return ret + +with open(sys.argv[1], 'r') as f: + output = imachine2json(json.load(f)) + +json.dump(output, open(sys.argv[2], 'w'), separators=(',', ':')) diff --git a/ast2json/rpyc2json.py b/ast2json/rpyc2json.py index 2caf53e..1bf9b73 100755 --- a/ast2json/rpyc2json.py +++ b/ast2json/rpyc2json.py @@ -67,7 +67,10 @@ def get_value(attr_value): if isinstance(attr_value, renpy.ast.Node): return node2json(attr_value) if isinstance(attr_value, renpy.ast.PyCode): - return ast2json.str2json(attr_value.source) + return { + "source": attr_value.source, + "ast": ast2json.str2json(attr_value.source) + } if isinstance(attr_value, renpy.ast.ArgumentInfo): return list(map(lambda x: getattr(attr_value, x), ["arguments", "extrapos", "extrakw"])) if isinstance(attr_value, renpy.atl.RawBlock): diff --git a/ast2json/strings2json.py b/ast2json/strings2json.py new file mode 100755 index 0000000..0736a10 --- /dev/null +++ b/ast2json/strings2json.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +import json +import sys + +def strings2json(ast): + ret = {} + if ast[0]['_type'] != 'Init': raise TypeError('obj does not start with Init, wrong file?') + for string in ast[0]['block'][0]['code']['ast']['body'][1:]: + target = string['targets'][0] + if target['_type'] == 'Attribute': + name = string['targets'][0]['attr'] + value = string['value'] + vtype = value['_type'] + if vtype == 'Str': + ret[name] = value['s'] + return ret + +with open(sys.argv[1], 'r') as f: + output = strings2json(json.load(f)) + +json.dump(output, open(sys.argv[2], 'w'), separators=(',', ':')) @@ -1,11 +1,11 @@ #!/bin/bash checking() { - printf "checking for %s... " "$1" >&2 + printf "checking %s... " "$1" >&2 } check() { - checking "$1" + checking "for $1" var="${VAR:-${1^^}}" cmd="${!var}" : ${cmd:=${1}} @@ -15,16 +15,19 @@ check() { get=$(command -v "${cmd}") e=$? if [[ -n "$get" ]]; then + declare -g "$var=$get" + echo ${get} if [[ -z "$NO_RUN" ]]; then + checking "${get} usability" ${get} -h >/dev/null 2>&1 e=$? if (( $e )); then echo unusable, returned $e return $e + else + echo yes fi fi - declare -g "$var=$get" - echo ${get} # intentionally stripping whitespace echo ${var} := ${get} ${varflags} >> "${OUT}" || exit 1 else @@ -39,7 +42,7 @@ rcheck() { fcheck() { for f in $3; do - checking "$f $1 support in ffmpeg" + checking "for $f $1 support in ffmpeg" if grep -Eq "^ $2 $f " <<< "$4"; then echo yes else @@ -49,6 +52,19 @@ fcheck() { done } +echeck() { + checking "for $2" + if [ "$1" "$2" ]; then + echo found + else + echo "$2 is missing; make sure you have $3" >&2 + exit 1 + fi +} + +echeck -f ast2json/script-a1-monday.rpyc "copied the rpyc files" +echeck -d www/dump "you have extracted the rpa" + OUT=Makefile.inc > "${OUT}" || exit 1 diff --git a/configure.py b/configure.py new file mode 100755 index 0000000..291ce68 --- /dev/null +++ b/configure.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 + +import os +import re +import shlex +import shutil +import subprocess +from sys import stderr + +cmds = {} + +class CheckError(Exception): + pass + +def checking(thing): + stderr.write("checking %s... " % thing) + stderr.flush() + +def check(name, flags=[], optional=False, var=None, run=True): + checking("for %s" % name) + var = var or name.upper() + split = shlex.split(os.getenv(var) or name) + exe = shutil.which(split[0]) + if not exe: + stderr.write("not found\n") + if not optional: + raise CheckError() + stderr.write("%s\n" % exe) + cmd = [exe] + split[1:] + flags + shlex.split(os.getenv(var + "FLAGS") or "") + if run: + checking("%s usability" % exe) + try: + subprocess.check_call(cmd + ["-h"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) + stderr.write("yes\n") + except subprocess.CalledProcessError as e: + raise CheckError() from e + + cmds[var] = cmd + return cmd + +def run_ffmpeg(arg): + return subprocess.check_output(ffmpeg + [arg], stderr=subprocess.STDOUT).decode('utf-8') + +def ffmpeg_check(name, regex, checks, output): + for check in checks: + checking("if %s supports %s %s" % (ffmpeg[0], name, check)) + + if re.search("\n %s %s " % (regex, check), output): + stderr.write("yes\n") + else: + stderr.write("no\n") + raise CheckError() + +try: + check("zopfli", var="GZIP") +except CheckError: + check("gzip", ["-9"]) + +check("apngasm", run=False) +check("convert") +check("cwebp", ["-quiet", "-alpha_cleanup", "-m", "6"]) +ffmpeg = check("ffmpeg", ["-v", "warning", "-y"], run=False) +ffmpeg_formats = run_ffmpeg("-formats") +ffmpeg_check("demuxing", "D.", ["matroska,webm", "ogg", "wav", "yuv4mpegpipe"], ffmpeg_formats) +ffmpeg_check("muxing", ".E", ["ipod", "mp4", "ogg", "wav", "webm", "yuv4mpegpipe"], ffmpeg_formats) +ffmpeg_check("decoding", ".{6}", ["mpeg4", "rawvideo", "pcm_s16le", "vorbis"], run_ffmpeg("-decoders")) +ffmpeg_check("encoding", ".{6}", ["libx264", "rawvideo", "libtheora", "libvpx", "libvpx-vp9", "libfdk_aac", "libopus", "pcm_s16le"], run_ffmpeg("-encoders")) +check("npm", ["--quiet"]) +check("webpmux") +check("defluff", optional=True, run=False) +check("pngquant", optional=True) +check("zopflipng", optional=True) + +stderr.write("creating Makefile.inc\n") + +with open("Makefile.inc", "w") as f: + f.write(''.join('%s := %s\n' % (k, subprocess.list2cmdline(cmds[k])) for k in cmds)) diff --git a/www/js/html5ks.js b/www/js/html5ks.js index 916426c..0a8eff3 100644 --- a/www/js/html5ks.js +++ b/www/js/html5ks.js @@ -209,9 +209,13 @@ window.html5ks = { } else { xhr.open("GET", "json/" + name + ".json"); xhr.onload = function () { - var d = JSON.parse(xhr.responseText); - html5ks.data[name] = d; - deferred.resolve(d); + if (xhr.status === 200) { + var d = JSON.parse(xhr.responseText); + html5ks.data[name] = d; + deferred.resolve(d); + } else { + xhr.onerror(); + } }; xhr.onerror = function () { deferred.reject(); |