import gzip, io, os, re, shutil, sys, tarfile
out, here = sys.argv[1], sys.argv[2]
only = set(sys.argv[3:])
tree = out + '/tree'
# slug : (id do jogo no Chogan, arquivos extras da pasta do jogo)
GAMES = {
'snooker': ('snooker', []),
'eight-ball-pool': ('eightball', []),
'tower-defence': ('tower-defence', []),
'chess-puzzles': ('chess', ['puzzles.js']),
'hokm': ('hokm', []),
'shelem': ('shelem', []),
'pasur': ('pasur', []),
'gin-rummy': ('ginrummy', []),
'bowling': ('bowling', []),
'darts': ('darts', []),
'button-football': ('football', []),
}
# nome do jogo em pt (a barra de titulo usa name[lang] || name.en)
PT_NAMES = {
'snooker': 'Snooker', 'eight-ball-pool': 'Bola 8', 'tower-defence': 'Defesa de torres', 'chess-puzzles': 'Xadrez',
'hokm': 'Hokm', 'shelem': 'Shelem', 'pasur': 'Pasur', 'gin-rummy': 'Gin Rummy', 'bowling': 'Boliche', 'darts': 'Dardos',
'button-football': 'Futebol de bot\u00e3o',
}
PT_MAPS = {'Dolina': 'Vale', 'Przełęcz': 'Passagem', 'Bagno': 'Pântano', 'Wąż': 'Serpente', 'Zbocze': 'Ladeira', 'Kanion': 'Cânion'}
CSP = ("default-src 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; "
"img-src 'self' data: blob:; font-src 'self'; media-src 'self' blob: data:; connect-src 'self'; "
"worker-src 'self' blob:; base-uri 'none'; form-action 'none'")
def read(p):
return open(p, encoding='utf-8', newline='').read()
def sub1(text, old, new, what):
assert text.count(old) == 1, f'{what}: {text.count(old)} ocorrencias de {old!r}'
return text.replace(old, new)
# ---- lib/chogan.js
lib = read(tree + '/www/lib/chogan.js')
# idioma: o da pagina do site que hospeda (en ou pt-BR); sem ela, o do navegador. Ninguem escolhe idioma dentro do jogo.
lib = sub1(lib, " function deviceLang() {\n try {\n",
" function deviceLang() {\n try {\n"
" try {\n"
" var hl = String(global.parent.document.documentElement.lang || '').toLowerCase();\n"
" if (/^pt\\b|^pt-/.test(hl)) return 'pt';\n"
" if (/^en\\b|^en-/.test(hl)) return 'en';\n"
" } catch (e) { /* pagina de fora de outra origem: vale o idioma do navegador */ }\n", 'deviceLang')
lib = sub1(lib, " if (/^fa\\b|^fa-/.test(l)) return 'fa';\n",
" if (/^fa\\b|^fa-/.test(l)) return 'fa';\n if (/^pt\\b|^pt-/.test(l)) return 'pt';\n", 'deviceLang pt')
lib = sub1(lib, "date: 'pl-PL' }\n ];", "date: 'pl-PL' },\n { code: 'pt', label: 'Portugu\u00eas', dir: 'ltr', tag: 'pt-BR', date: 'pt-BR' }\n ];", 'LOCALES')
assert lib.count("Object.assign({}, DEFAULT_SETTINGS, appStore.get('settings', {}))") == 2
lib = lib.replace("Object.assign({}, DEFAULT_SETTINGS, appStore.get('settings', {}))",
"Object.assign({}, DEFAULT_SETTINGS, appStore.get('settings', {}), { lang: deviceLang() })")
# sem menu do app: a pagina do jogo e sempre "avulsa" (sem botao de voltar nem atalho Esc/Backspace)
lib = sub1(lib, " return { title: d[l] || d.en, sub: d['d' + l] || d.den };\n",
" var ap = l === 'pt' && Chogan.achPt && Chogan.achPt[d.id];\n"
" return ap ? { title: ap[0], sub: ap[1] } : { title: d[l] || d.en, sub: d['d' + l] || d.den };\n", 'achText')
lib = sub1(lib, " return ss(SHORTCUT_KEY) === cfg.id;\n", " return true;\n", 'standalone')
# sem compartilhar resultado, sem pontos da liga
lib = sub1(lib, " if (o.shareText) {\n actions.push({", " if (false && o.shareText) {\n actions.push({", 'share')
lib = sub1(lib, " if (rec.points) {\n", " if (false && rec.points) {\n", 'pontos')
css = read(tree + '/www/lib/chogan.css')
cue = read(tree + '/www/lib/cue.js')
version = read(tree + '/www/version.js')
ptlib = ''
if os.path.exists(here + '/pt/lib.js'):
ptlib = read(here + '/pt/lib.js')
LICENSE = (read(tree + '/LICENSE') + '\n\n--------------------------------------------------------------------------------\n'
'Vazirmatn (fonts/vazirmatn-variable.woff2), SIL Open Font License 1.1: see fonts/OFL.txt\n')
built = []
for slug, (gid, extras) in GAMES.items():
if only and slug not in only:
continue
d = f'{out}/{slug}'
os.makedirs(d + '/lib'); os.makedirs(d + '/fonts')
html = read(f'{tree}/www/games/{gid}/index.html')
html = html.replace('../../lib/', 'lib/').replace('../../version.js', 'version.js')
assert '../' not in ''.join(re.findall(r'(?:src|href)="[^"]*"', html)), slug
html = sub1(html, '\n', '\n\n', slug + ' csp')
ptgame = ''
if os.path.exists(f'{here}/pt/{slug}.js'):
ptgame = read(f'{here}/pt/{slug}.js')
html, n = re.subn(r"( name: \{[^}\n]*pl: '[^']*')( \})", lambda m: m.group(1) + ", pt: '" + PT_NAMES[slug] + "'" + m.group(2), html)
assert n == 1, slug + ' name'
if slug == 'tower-defence':
for pl, pt in PT_MAPS.items():
html = sub1(html, "pl: '" + pl + "' }", "pl: '" + pl + "', pt: '" + pt + "' }", 'mapa ' + pl)
open(d + '/lib/pt.js', 'w', encoding='utf-8', newline='').write(ptlib + ptgame)
html = sub1(html, '\n', '\n\n', slug + ' pt')
open(d + '/index.html', 'w', encoding='utf-8', newline='').write(html)
shutil.copy(f'{tree}/www/games/{gid}/icon.svg', d + '/icon.svg')
for e in extras:
shutil.copy(f'{tree}/www/games/{gid}/{e}', f'{d}/{e}')
open(d + '/lib/chogan.js', 'w', encoding='utf-8', newline='').write(lib)
open(d + '/lib/chogan.css', 'w', encoding='utf-8', newline='').write(css)
if 'lib/cue.js' in html:
open(d + '/lib/cue.js', 'w', encoding='utf-8', newline='').write(cue)
open(d + '/version.js', 'w', encoding='utf-8', newline='').write(version)
shutil.copy(tree + '/www/fonts/vazirmatn-variable.woff2', d + '/fonts/vazirmatn-variable.woff2')
shutil.copy(tree + '/www/fonts/OFL.txt', d + '/fonts/OFL.txt')
open(d + '/LICENSE.txt', 'w', encoding='utf-8', newline='').write(LICENSE)
# tar.gz deterministico: nomes em ordem, dono/data fixos, gzip sem nome nem data
buf = io.BytesIO()
with tarfile.open(fileobj=buf, mode='w', format=tarfile.GNU_FORMAT) as tf:
for root_, dirs, files in os.walk(d):
dirs.sort()
for f in sorted(files):
p = os.path.join(root_, f)
ti = tarfile.TarInfo(slug + '/' + os.path.relpath(p, d))
data = open(p, 'rb').read()
ti.size = len(data); ti.mtime = 0; ti.mode = 0o644; ti.uid = ti.gid = 0; ti.uname = ti.gname = ''
tf.addfile(ti, io.BytesIO(data))
with open(f'{out}/{slug}.tar.gz', 'wb') as raw:
with gzip.GzipFile(filename='', mode='wb', fileobj=raw, mtime=0, compresslevel=9) as gz:
gz.write(buf.getvalue())
built.append(slug)
print('ok:', ' '.join(built))