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))