aboutsummaryrefslogtreecommitdiff
path: root/main.py
diff options
context:
space:
mode:
authorJoris2023-12-27 18:21:37 +0100
committerJoris2023-12-27 18:21:37 +0100
commit98eca7d594960aa616786cbd491b937d50f55499 (patch)
treedb63132d159d09bed2b0a6454c822c2ed95091c6 /main.py
parent57da196f828352b009ca86dca98e352cf09663f3 (diff)
First version with 2 songs
Diffstat (limited to 'main.py')
-rw-r--r--main.py147
1 files changed, 147 insertions, 0 deletions
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..a4494ff
--- /dev/null
+++ b/main.py
@@ -0,0 +1,147 @@
+import string
+
+atom_end = set('()"\'') | set(string.whitespace)
+
+def parse(sexp):
+ stack, i, length = [[]], 0, len(sexp)
+ while i < length:
+ c = sexp[i]
+
+ reading = type(stack[-1])
+ if reading == list:
+ match c:
+ case '(':
+ stack.append([])
+ case ')':
+ stack[-2].append(stack.pop())
+ if stack[-1][0] == ('quote',): stack[-2].append(stack.pop())
+ case '"':
+ stack.append('')
+ case "'":
+ stack.append([('quote',)])
+ case _:
+ if c in string.whitespace:
+ pass
+ else:
+ stack.append((c,))
+ elif reading == str:
+ if c == '"':
+ stack[-2].append(stack.pop())
+ if stack[-1][0] == ('quote',): stack[-2].append(stack.pop())
+ elif c == '\\':
+ i += 1
+ stack[-1] += sexp[i]
+ else:
+ stack[-1] += c
+ elif reading == tuple:
+ if c in atom_end:
+ atom = stack.pop()
+ if atom[0][0].isdigit():
+ stack[-1].append(eval(atom[0]))
+ else:
+ stack[-1].append(atom)
+ if stack[-1][0] == ('quote',):
+ stack[-2].append(stack.pop())
+ continue
+ else:
+ stack[-1] = ((stack[-1][0] + c),)
+ i += 1
+ return stack.pop()
+
+def h(node, attributes, *children):
+ res_attrs = ''
+ if type(attributes) == dict:
+ for key in attributes:
+ res_attrs += f' {key}={attributes[key]}'
+ else:
+ children = [attributes] + list(children)
+
+ res = f'<{node} {res_attrs}>'
+ if type(children) in [tuple, list]:
+ res += ''.join(children)
+ elif type(children) == str:
+ res += children
+
+ res += f'</{node}>'
+ return res
+
+def lines(s: str):
+ return [h('div', x) for x in s.split('\n')]
+
+def chord_line(sexp):
+ res = ''
+ for x in sexp:
+ res += h('td', { 'class': 'g-Chord' }, x[0])
+ return res
+
+def chords(sexp):
+ return h('section',
+ { 'class': 'g-Section' },
+ h('h2', { 'class': 'g-Subtitle' }, 'Accords'),
+ h('table', { 'class': 'g-Chords' }, *[h('tr', {}, chord_line(x)) for x in sexp]))
+
+part_names = {
+ 'intro': 'Intro',
+ 'verse': 'Couplet',
+ 'chorus': 'Refrain',
+ 'interlude': 'Interlude'
+}
+
+def lyrics(sexp):
+ ys = []
+ for x in sexp:
+ match x:
+ case [(name)]:
+ ys.append(h('section',
+ { 'class': 'g-Section' },
+ h('div',
+ { 'class': 'g-Lyrics__Part' },
+ h('h3', part_names[name[0]]))))
+ case [(name), s]:
+ ys.append(h('section',
+ { 'class': 'g-Section' },
+ h('div',
+ { 'class': 'g-Lyrics__Part' },
+ h('h3', part_names[name[0]]),
+ h('div', { 'class': 'g-Lyrics__Paragraph' }, *lines(s)))))
+ return h('section',
+ { 'class': 'g-Section' },
+ h('h2', { 'class': 'g-Subtitle' }, 'Paroles'),
+ h('div', { 'class': 'g-Lyrics' }, *ys))
+
+def sexp_prop(sexp, name):
+ return [x[1:] for x in sexp if x[0][0] == name][0]
+
+# -----------------
+
+with open('ben-e-king-stand-by-me.lisp', 'r') as f:
+ content = f.read()
+
+sexp = parse(content)
+
+title = sexp_prop(sexp, 'title')[0]
+subtitle = sexp_prop(sexp, 'from')[0]
+
+html = f'''
+ <!doctype html>
+ <html lang="fr">
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width">
+ <title>{title} – {subtitle}</title>
+ <link rel="stylesheet" href="main.css">
+ <link rel="icon" href="/icon.png">
+ <script src="/main.js"></script>
+'''
+
+html += h('body',
+ h('section',
+ { 'class': 'g-Section' },
+ h('h1', { 'class': 'g-Title' }, title),
+ h('div', { 'class': 'g-Author' }, subtitle)),
+ chords(sexp_prop(sexp, 'chords')),
+ lyrics(sexp_prop(sexp, 'lyrics')))
+
+with open('ben-e-king-stand-by-me.html', 'w') as f:
+ f.write(html)
+
+print('OK')