Convert Python templates to django template engine

This commit is contained in:
Carlos Galindo 2020-12-24 16:17:13 +01:00
parent 7f52ff6b6c
commit fc90400f8f
18 changed files with 225 additions and 196 deletions

View file

@ -3,6 +3,7 @@
ALL_CSS := $(patsubst res/%.less,public/%.css,$(wildcard res/*.less)) ALL_CSS := $(patsubst res/%.less,public/%.css,$(wildcard res/*.less))
ALL_JS := $(patsubst res/%.js,public/%.js,$(wildcard res/*.js)) ALL_JS := $(patsubst res/%.js,public/%.js,$(wildcard res/*.js))
ALL_SVG := $(patsubst res/%.svg,public/%.svg,$(wildcard res/*.svg)) ALL_SVG := $(patsubst res/%.svg,public/%.svg,$(wildcard res/*.svg))
ALL_TEMPLATES := $(wildcard res/html/*.html)
all: public/index.html all: public/index.html
@ -17,9 +18,7 @@ svg: $(ALL_SVG)
public: public:
mkdir public mkdir public
public/index.html: static public public/audios \ public/index.html: static public public/audios $(ALL_TEMPLATES)
res/index.html res/page.html \
res/song.html res/song_li.html res/song_redir.html
python3 src/latex_scanner.py --latex latex/cancionero.tex --audios audios python3 src/latex_scanner.py --latex latex/cancionero.tex --audios audios
public/audios: audios public public/audios: audios public

6
res/html/footer.html Normal file
View file

@ -0,0 +1,6 @@
<footer>
<p>
&copy; 2020 Carlos Galindo, Parroquia San Leandro
<a href="https://gitlab.com/parroquia-san-leandro/cancionero-web"><span>Código fuente</span></a>
</p>
</footer>

7
res/html/head.html Normal file
View file

@ -0,0 +1,7 @@
<meta charset="UTF-8">
<title>Cancionero - Parroquia San Leandro</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="{{ path|urlencode }}/main.css"/>
{% if specific_css %}
<link rel="stylesheet" type="text/css" href="{{ path|urlencode }}/{{ specific_css|urlencode }}"/>
{% endif %}

10
res/html/header.html Normal file
View file

@ -0,0 +1,10 @@
<header>
<h1><a href="{{ path }}">Cancionero San Leandro</a></h1>
<nav class="nav">
<ul>
<li><a href="https://sanleandro-obispo.net/"><span>Parroquia San Leandro</span></a></li>
<li><a href="https://nube.sanleandro-obispo.net/s/X23Jzz5A6dpCfr2"><span>Grabaciones</span></a></li>
<li><a href="https://sanleandro-obispo.net/cancionero/"><span>Cancionero en PDF</span></a></li>
</ul>
</nav>
</header>

25
res/html/index.html Normal file
View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="es">
<head>
{% include "head.html" with path="." only %}
<link rel="stylesheet" type="text/css" href="index.css"/>
</head>
<body>
{% include "header.html" with path="." %}
<h2>Índice</h2>
Las canciones sin acordes están marcadas en <span class="noChords">rojo</span>.
<ol class="songs">
{% for song in songs %}
<a href="{{ song.url }}">
<li {% if not song.chorded %}class="noChords"{% endif %}>
<span class="number">{{ song.number }}.</span>
{{ song.name }}
{% if song.author %} por {{ song.author }} {% endif %}
{% if song.origin %} basado en {{ song.origin }} {% endif %}
</li>
</a>
{% endfor %}
</ol>
{% include "footer.html" %}
</body>
</html>

110
res/html/song.html Normal file
View file

@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="es">
<head>
{% include "head.html" with path=".." only %}
<link rel="stylesheet" type="text/css" href="../song.css"/>
<script async src="../transpose.js"></script>
<script async src="../sizes.js"></script>
</head>
<body>
{% include "header.html" with path=".." %}
<div class="song">
<h2>{{ song.name}}</h2>
{% if song.author %}
<div>Autor: {{ song.author }}</div>
{% endif %}
{% if song.origin %}
<div>Basada en: {{ song.origin }}</div>
{% endif %}
<h3>Ajustes</h3>
<div>
<label>Cambiar tamaño de letra </label>
<button class="small" onclick="size(-1)">-</button>
<button class="small" onclick="size(0)">Reset</button>
<button class="small" onclick="size(+1)">+</button>
</div>
{% if song.chorded %}
<div>
<label>Transponer acordes </label>
<button class="small" onclick="transposeAdd(-2)">-2</button>
<button class="small" onclick="transposeAdd(-1)">-1</button>
<select id="transposeSelect" disabled>
<option onclick="transpose(-6)">-6</option>
<option onclick="transpose(-5)">-5</option>
<option onclick="transpose(-4)">-4</option>
<option onclick="transpose(-3)">-3</option>
<option onclick="transpose(-2)">-2</option>
<option onclick="transpose(-1)">-1</option>
<option onclick="transpose(0)" selected="selected">0</option>
<option onclick="transpose(1)">1</option>
<option onclick="transpose(2)">2</option>
<option onclick="transpose(3)">3</option>
<option onclick="transpose(4)">4</option>
<option onclick="transpose(5)">5</option>
<option onclick="transpose(6)">6</option>
</select>
<button class="small" onclick="transposeAdd(1)">+1</button>
<button class="small" onclick="transposeAdd(2)">+2</button>
<button onclick="transpose(0)">Reset</button>
</div>
{% endif %}
{% if song.capo != 0 %}
<div>
<span class="capo">Tono original: Cejilla {{ song.capo }}</span>
<button style="margin-left: 0.5em;" onclick="transpose({{ song.capo}})">Transponer para quitarla</button>
</div>
{% endif %}
<h3>Canción</h3>
<div id="wholeSongDiv">
{% for verse in song.verses %}
<div class="{{ verse.kind }}">
{% for line in verse.lines %}
{% spaceless %}
{% for chord, lyric in line.zipped_arr %}
<table class="chordedline">
<tr class="chord">
<td rowspan="{{ chord.rowspan|default:'1' }}">
{% if chord.class %}
<span class="{{ chord.class }}"></span>
{% endif %}
{% for c in chord.chord.items %}
{% if c.chord %}
<span class="c">{{ c.text|safe }}</span>
{% else %}
<span>{{ c.text|safe }}</span>
{% endif %}
{% endfor %}
</td>
</tr>
<tr class="lyric">
<td>
{% if 'rowspan' not in chord %}
<span>{{ lyric|safe }}</span>
{% endif %}
</td>
</tr>
</table>
{% endfor %}
{% if not forloop.last %} <br/> {% endif %}
{% endspaceless %}
{% endfor %}
</div>
{% endfor %}
</div>
{% for audio in audios %}
{% if forloop.first %}
<h3>Audios</h3>
{% endif %}
<div>
Audio del {{ audio.date_text }} <a href="{{ audio.audio_file|urlencode }}"><span>Descargar</span></a>
<audio controls style='width: 100%%;'>
<source src='{{ audio.audio_file|urlencode }}' type='audio/mpeg'/>
</audio>
</div>
{% endfor %}
<a href="https://gitlab.com/parroquia-san-leandro/cancionero-25/blob/master/{{ song.latex_file|urlencode }}"><span>Ver archivo original (LaTeX)</span></a>
<a href="../"><span>Índice</span></a>
</div>
{% include "footer.html" %}
</body>
</html>

12
res/html/song_redir.html Normal file
View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="es">
<head>
{% include "head.html" with path=".." only %}
<meta http-equiv="refresh" content="0; url = ../{{ song.url|urlencode }}">
</head>
<body>
{% include "header.html" with path=".." %}
<a href="../{{ song.url|urlencode }}">Redirigiendo a la canción, haz click aquí si no sucede de forma automática.</a>
{% include "footer.html" %}
</body>
</html>

View file

@ -1,5 +0,0 @@
<h2>Índice</h2>
<ol class="songs">
Las canciones sin acordes están marcadas en <span class="hasChords">rojo</span>.
{list_content}
</ol>

View file

@ -20,7 +20,7 @@
background-color: @secondary-hover; background-color: @secondary-hover;
transition-duration: @transition; transition-duration: @transition;
} }
&.hasChords { &.noChords {
background-color: @nochordscolor; background-color: @nochordscolor;
&:hover { &:hover {
color: @text-hover; color: @text-hover;
@ -30,7 +30,7 @@
} }
} }
} }
span.hasChords { span.noChords {
background-color: @nochordscolor; background-color: @nochordscolor;
padding: 0.3em 0.4em; padding: 0.3em 0.4em;
border-radius: @border-radius; border-radius: @border-radius;

View file

@ -6,6 +6,9 @@ h1 {
width: max-content; width: max-content;
max-width: 100%; max-width: 100%;
text-align: center; text-align: center;
> a, > a:hover, > a:active, > a:visited {
color: @title;
}
} }
h2, h3 { h2, h3 {

View file

@ -1,30 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cancionero - Parroquia San Leandro</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
{css}
</head>
<body>
<header>
<h1>Cancionero San Leandro</h1>
<nav class="nav">
<ul>
<li><a href="https://sanleandro-obispo.net/"><span>Parroquia San Leandro</span></a></li>
<li><a href="https://nube.sanleandro-obispo.net/s/X23Jzz5A6dpCfr2"><span>Grabaciones</span></a></li>
<li><a href="https://sanleandro-obispo.net/cancionero/"><span>Cancionero en PDF</span></a></li>
</ul>
</nav>
</header>
<main>
{main}
</main>
<footer>
<p>
&copy; 2020 Carlos Galindo, Parroquia San Leandro
<a href="https://gitlab.com/parroquia-san-leandro/cancionero-web"><span>Código fuente</span></a>
</p>
</footer>
</body>
</html>

View file

@ -1,48 +0,0 @@
<div class="song">
<script async src="../transpose.js"></script>
<script async src="../sizes.js"></script>
<h2>{name}</h2>
{author}
{origin}
<h3>Ajustes</h3>
<div>
<label>Cambiar tamaño de letra </label>
<button class="small" onclick="size(-1)">-</button>
<button class="small" onclick="size(0)">Reset</button>
<button class="small" onclick="size(+1)">+</button>
</div>
<div>
<label>Transponer acordes </label>
<button class="small" onclick="transposeAdd(-2)">-2</button>
<button class="small" onclick="transposeAdd(-1)">-1</button>
<select id="transposeSelect" disabled>
<option onclick="transpose(-6)">-6</option>
<option onclick="transpose(-5)">-5</option>
<option onclick="transpose(-4)">-4</option>
<option onclick="transpose(-3)">-3</option>
<option onclick="transpose(-2)">-2</option>
<option onclick="transpose(-1)">-1</option>
<option onclick="transpose(0)" selected="selected">0</option>
<option onclick="transpose(1)">1</option>
<option onclick="transpose(2)">2</option>
<option onclick="transpose(3)">3</option>
<option onclick="transpose(4)">4</option>
<option onclick="transpose(5)">5</option>
<option onclick="transpose(6)">6</option>
</select>
<button class="small" onclick="transposeAdd(1)">+1</button>
<button class="small" onclick="transposeAdd(2)">+2</button>
<button onclick="transpose(0)">Reset</button>
</div>
{capo_settings}
<h3>Canción</h3>
<div id="wholeSongDiv">
{song_html}
</div>
<div>
{audios_header}
{audios_html}
</div>
<a href="https://gitlab.com/parroquia-san-leandro/cancionero-25/blob/master/{latex_file}"><span>Ver archivo original (LaTeX)</span></a>
<a href="../"><span>Atrás</span></a>
</div>

View file

@ -1,6 +0,0 @@
<a href="{url}">
<li {li_class}>
<span class="number">{number}.</span>
{name}{author}{origin}
</li>
</a>

View file

@ -1,9 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="0; url = {url}">
</head>
<body>
<a href="{url}">Redirigiendo a la canción, haz click aquí si no sucede de forma automática.</a>
</body>
</html>

0
src/__init__.py Normal file
View file

View file

@ -1,6 +1,6 @@
from os import listdir from os import listdir
from os.path import isfile, join from os.path import isfile, join
from song_types import Audio from model import Audio
import re import re
from datetime import datetime from datetime import datetime

View file

@ -1,14 +1,15 @@
from song_types import Chord, Line, Song, Verse
from song_types import readfile, join_list
from audio_scanner import find_audios
from os.path import join
from pathlib import Path
import shutil
import argparse import argparse
import urllib.parse
import os import os
import re import re
import shutil
from django.conf import settings
from django.template import Engine, Context
from os.path import join
from pathlib import Path
from audio_scanner import find_audios
from model import Chord, Line, Song, Verse
def mkdir(path): def mkdir(path):
if not os.path.exists(path): if not os.path.exists(path):
@ -31,14 +32,6 @@ def extra_put(extra, index, the_type, data=None):
extra[index].append(payload) extra[index].append(payload)
page_template = readfile("res/page.html")
index_template = readfile("res/index.html")
index_per_song_template = readfile("res/song_li.html")
song_redir_template = readfile("res/song_redir.html")
index_css = '<link rel="stylesheet" href="main.css">\n\t<link rel="stylesheet" href="index.css">'
song_css = '<link rel="stylesheet" href="../song.css">\n\t<link rel="stylesheet" href="../main.css">'
class SongLoader: class SongLoader:
def __init__(self, latex_file, audio_dir): def __init__(self, latex_file, audio_dir):
self.index = 1 self.index = 1
@ -235,35 +228,28 @@ class SongLoader:
continue continue
current_verse.add_line(Line(text, extras)) current_verse.add_line(Line(text, extras))
def print_index(self, index_file="index.html"): def print_index(self, index_file, dj_engine):
self.songs = sorted(self.songs, key=lambda s: s.number) songs = sorted(self.songs, key=lambda s: s.number)
song_list = join_list([index_per_song_template.format( html = dj_engine.get_template("index.html").render(Context({'songs': songs}))
url=s.get_url(),
li_class=' class="hasChords"' if not s.chorded() else '',
number=s.number,
name=s.name,
author=" por %s " % s.author if s.author else "",
origin=" basado en %s " % s.origin if s.origin else "")
for s in self.songs])
body = index_template.format(list_content=song_list)
with open(index_file, 'w') as f: with open(index_file, 'w') as f:
f.write(page_template.format(css=index_css, main=body)) f.write(html)
def print_songs(self, directory="."): def print_song(self, song, directory, dj_engine):
for song in self.songs: context = Context({'song': song})
num_dir = join(directory, "%03d" % (song.number)) num_dir = join(directory, "%03d" % (song.number))
mkdir(num_dir) mkdir(num_dir)
with open(join(num_dir, "index.html"), 'w') as f: with open(join(num_dir, "index.html"), 'w') as f:
f.write(song_redir_template.format(url=urllib.parse.quote("../" + song.get_url()))) f.write(dj_engine.get_template("song_redir.html").render(context))
song_dir = join(directory, song.get_url()) song_dir = join(directory, song.url())
mkdir(song_dir) mkdir(song_dir)
with open(join(song_dir, "index.html"), 'w') as f: with open(join(song_dir, "index.html"), 'w') as f:
f.write(page_template.format(css=song_css, main=str(song))) f.write(dj_engine.get_template("song.html").render(context))
def generate_html(self, output_dir): def generate_html(self, output_dir, dj_engine):
mkdir(output_dir) mkdir(output_dir)
self.print_songs(output_dir) for song in self.songs:
self.print_index(join(output_dir, "index.html")) self.print_song(song, output_dir, dj_engine)
self.print_index(join(output_dir, "index.html"), dj_engine)
def parse_args(): def parse_args():
@ -277,4 +263,6 @@ def parse_args():
if __name__ == '__main__': if __name__ == '__main__':
args = parse_args() args = parse_args()
loader = SongLoader(args.latex[0], args.audios[0]) loader = SongLoader(args.latex[0], args.audios[0])
loader.generate_html(args.output_dir[0]) settings.configure(USE_TZ=False, USE_I18N=False)
e = Engine(dirs=["res/html/"])
loader.generate_html(args.output_dir[0], e)

View file

@ -8,13 +8,7 @@ def join_list(the_list, separator="\n"):
return ft.reduce(lambda x, y: x + (separator if x else "") + str(y), the_list, "") return ft.reduce(lambda x, y: x + (separator if x else "") + str(y), the_list, "")
def readfile(file):
with open(file, 'r') as f:
return join_list(f.readlines(), '')
locale.setlocale(locale.LC_ALL, "es_ES.UTF-8") locale.setlocale(locale.LC_ALL, "es_ES.UTF-8")
song_template = readfile("res/song.html")
class Song: class Song:
@ -32,17 +26,7 @@ class Song:
self.category = category self.category = category
def __str__(self): def __str__(self):
return song_template.format( return self.name
name=self.name,
author="<div>Autor: %s</div>" % self.author if self.author else "",
origin="<div>Basada en: %s</div>" % self.origin if self.origin else "",
capo_settings="""<div><span class="capo">Tono original: Cejilla {s.capo}</span>
<button style="margin-left: 0.5em;" onclick="transpose({s.capo})">Transponer para quitarla</button></div>"""
.format(s=self) if self.capo != 0 else "",
song_html=join_list(self.verses),
audios_header="<h3>Audios</h3>" if len(self.audios) > 0 else "",
audios_html=join_list(self.audios),
latex_file=self.latex_file)
def set_capo(self, capo): def set_capo(self, capo):
self.capo = capo self.capo = capo
@ -55,7 +39,7 @@ class Song:
assert isinstance(verse, Verse) assert isinstance(verse, Verse)
self.verses.append(verse) self.verses.append(verse)
def get_url(self): def url(self):
return "%03d %s" % (self.number, self.name.replace("¿", "").replace("?", "")) return "%03d %s" % (self.number, self.name.replace("¿", "").replace("?", ""))
def chorded(self): def chorded(self):
@ -69,13 +53,10 @@ class Verse:
def __init__(self, is_chorus=False): def __init__(self, is_chorus=False):
self.is_chorus = is_chorus self.is_chorus = is_chorus
self.lines = [] self.lines = []
self.kind = "chorus" if is_chorus else "verse"
def __str__(self): def __str__(self):
return """ return join_list(self.lines, " ")
<div class="%s">
%s
</div>
""" % ("chorus" if self.is_chorus else "verse", join_list([str(l) for l in self.lines], "\n<br>\n"))
def add_line(self, line): def add_line(self, line):
assert isinstance(line, Line) assert isinstance(line, Line)
@ -99,15 +80,11 @@ class Line:
self.lyric_arr = [] self.lyric_arr = []
self.build() self.build()
self.remove_brackets() self.remove_brackets()
assert len(self.chord_arr) == len(self.lyric_arr)
self.zipped_arr = zip(self.chord_arr, self.lyric_arr)
def __str__(self): def __str__(self):
assert len(self.chord_arr) == len(self.lyric_arr) return self.text
return join_list(["""<table class="chordedline"><tr class="chord"><td rowspan="%s">%s%s</td></tr>%s</table>"""
% (self.chord_arr[i]["rowspan"] if "rowspan" in self.chord_arr[i] else 1,
'<span class="%s"></span>' % self.chord_arr[i]["class"] if "class" in self.chord_arr[i] else "",
self.chord_arr[i]["chord"] if "chord" in self.chord_arr[i] else "",
'<tr class="lyric"><td>%s</td></tr>' % self.lyric_arr[i] if "rowspan" not in self.chord_arr[i] else ''
) for i in range(len(self.chord_arr))], separator='')
def add_chord(self, index, chord): def add_chord(self, index, chord):
self.add_item(index, "chord", chord) self.add_item(index, "chord", chord)
@ -172,8 +149,7 @@ class Line:
self.lyric_arr.append(Line.ECHO_BEGIN if inside_echo else '') self.lyric_arr.append(Line.ECHO_BEGIN if inside_echo else '')
mid = True mid = True
self.lyric_arr[-1] += self.text[i] self.lyric_arr[-1] += self.text[i]
for i in range(len(self.lyric_arr)): self.lyric_arr = [re.sub(r"(^ | $)", "&nbsp;", l) for l in self.lyric_arr]
self.lyric_arr[i] = re.sub(r"(^ | $)", "&nbsp;", self.lyric_arr[i])
def remove_brackets(self): def remove_brackets(self):
self.lyric_arr = [l.replace('}', '').replace('{', '') for l in self.lyric_arr] self.lyric_arr = [l.replace('}', '').replace('{', '') for l in self.lyric_arr]
@ -186,6 +162,10 @@ class Line:
return False return False
def chord_eng2lat(text):
return Chord.CHORDS_LAT[Chord.ENG_INDEX[text]]
class Chord: class Chord:
N_CHORDS = 12 N_CHORDS = 12
CHORDS_LAT = ['Do', 'Do#', 'Re', 'Re#', 'Mi', 'Fa', 'Fa#', 'Sol', 'Sol#', 'La', 'Sib', 'Si'] CHORDS_LAT = ['Do', 'Do#', 'Re', 'Re#', 'Mi', 'Fa', 'Fa#', 'Sol', 'Sol#', 'La', 'Sib', 'Si']
@ -194,7 +174,7 @@ class Chord:
def __init__(self, text, base_transpose=0): def __init__(self, text, base_transpose=0):
self.text = text self.text = text
self.chords = [] self.items = []
self.base_transpose = base_transpose self.base_transpose = base_transpose
ignore = False ignore = False
for i, char in enumerate(text): for i, char in enumerate(text):
@ -203,21 +183,15 @@ class Chord:
continue continue
if "A" <= char <= "G": if "A" <= char <= "G":
if len(text) > i + 1 and (text[i + 1] == "#" or text[i + 1] == "&"): if len(text) > i + 1 and (text[i + 1] == "#" or text[i + 1] == "&"):
self.chords.append({'text': char + text[i + 1], 'chord': True}) self.items.append({'text': chord_eng2lat(char + text[i + 1]), 'chord': True})
ignore = True ignore = True
else: else:
self.chords.append({'text': char, 'chord': True}) self.items.append({'text': chord_eng2lat(char), 'chord': True})
else: else:
self.chords.append({'text': char, 'chord': False}) self.items.append({'text': char, 'chord': False})
def __str__(self): def __str__(self):
res = "" return self.text
for c in self.chords:
if c['chord']:
res += "<span class='c'>%s</span>" % Chord.CHORDS_LAT[Chord.ENG_INDEX[c['text']]]
else:
res += c['text']
return res
class Audio: class Audio:
@ -228,11 +202,4 @@ class Audio:
self.audio_file = audio_file self.audio_file = audio_file
def __str__(self): def __str__(self):
return """ return self.audio_file
<div>
Audio del %s <a href="%s"><span>Descargar</span></a>
<audio controls style='width: 100%%;'>
<source src='%s' type='audio/mpeg'/>
</audio>
</div>
""" % (self.date_text, self.audio_file, self.audio_file)