#!/usr/bin/env python3
"""Il Muro del Sanpierino dentro il gioco (Andrea, 31 ottobre): dal dump del muro vero riesumato
(~/Workspaces/misc/spswall) prepara assets/muro/ per la pagina statica del telefonino del Barone.
- messaggi.json: i messaggi veri (soprannome, data, testo), con gli accenti rimessi a posto. Niente email né IP.
Solo quelli del dump (i primi 24, novembre 2007): i 654 ritrovati nella Wayback Machine restano nel muro riesumato
(spswall/archivio/importa.py), fuori dal gioco (Andrea, 31 ottobre).
- img/: solo gli smile usati e le icone della pagina; muro.css è il CSS originale; le due pagine di testo, com'erano.
python3 tools/muro.py [percorso del dump] [cartella www del muro]
"""
import json, re, shutil, sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
SPS = Path.home() / 'Workspaces/misc/spswall'
DUMP = Path(sys.argv[1]) if len(sys.argv) > 1 else SPS / 'db/01-spswall.sql'
WWW = Path(sys.argv[2]) if len(sys.argv) > 2 else SPS / 'www'
OUT = ROOT / 'assets/muro'
# Le icone della pagina, oltre agli smile.
PAGE = ['logo_trasparente_obliquo.gif', 'spacer.gif', 'pagefirst.gif', 'pageback.gif', 'postmessage.gif', 'refresh.gif',
'home.gif', 'pageahead.gif', 'pagelast.gif', 'logomanzolo.jpg']
def rows(sql, table):
"""Le righe di INSERT INTO `table` del dump di phpMyAdmin, come liste di valori."""
m = re.search(r'INSERT INTO `%s` \(([^)]*)\) VALUES\s*(.*?);\n' % table, sql, re.S)
cols = [c.strip(' `') for c in m.group(1).split(',')]
body, out, row, val, i, quoted = m.group(2), [], [], '', 0, False
while i < len(body):
ch = body[i]
if quoted:
if ch == '\\': val += {'n': '\n', 'r': '\r', 't': '\t', '0': ''}.get(body[i + 1], body[i + 1]); i += 2; continue
if ch == "'" and body[i + 1:i + 2] == "'": val += "'"; i += 2; continue
if ch == "'": quoted = False
else: val += ch
elif ch == "'": quoted = True
elif ch == '(': row, val = [], ''
elif ch == ',': row.append(val.strip()); val = ''
elif ch == ')': row.append(val.strip()); out.append(dict(zip(cols, row)))
elif not ch.isspace(): val += ch
i += 1
return out
def fix(text):
"""Il muro scriveva UTF-8 su una connessione latin1: nel dump gli accenti sono «Ã¨». Si rimettono a posto."""
for enc in ('latin1', 'cp1252'):
try: return text.encode(enc).decode('utf8')
except (UnicodeEncodeError, UnicodeDecodeError): pass
return text
def main():
sql = DUMP.read_text('utf8')
smiles = {r['codsml']: r['linksml'] for r in rows(sql, 'tpsmiles')}
# Le immagini prese da fuori (http://...) non si caricano: il vecchio dominio oggi può essere di chiunque.
outside = lambda t: re.sub(r']*src="?http[^>]*>', '', t, flags=re.I)
messages = [{'nick': fix(r['nikute']), 'date': r['datmsg'], 'text': outside(fix(r['desmsg']))} for r in rows(sql, 'tpmsgute')]
messages.sort(key=lambda m: m['date'], reverse=True)
# Gli smile usati: dai messaggi veri e da quelli del gioco (story.closeups.muro_sanpierino.messages).
ours = (ROOT / 'src/story/story.js').read_text('utf8')
used = {code: link for code, link in smiles.items() if code in ours or any(code in m['text'] or code in m['nick'] for m in messages)}
shutil.rmtree(OUT / 'img', ignore_errors=True)
(OUT / 'img').mkdir(parents=True)
pictures = {n for m in messages for n in re.findall(r'src="\./img/([^"]+)"', m['text'] + m['nick'])}
for name in PAGE + sorted(set(used.values()) | pictures):
shutil.copy(WWW / 'imgwall' / name, OUT / 'img' / name)
shutil.copy(WWW / 'class/thewall.css', OUT / 'muro.css')
# Le due pagine di testo, com'erano; in fondo un link per tornare al muro (nel telefonino non c'è il «Indietro»).
for page in ('Responsabilita.htm', 'guida_al_muro_del_sanpierino.htm'):
html = (WWW / page).read_bytes()
back = b'