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_JS := $(patsubst res/%.js,public/%.js,$(wildcard res/*.js))
ALL_SVG := $(patsubst res/%.svg,public/%.svg,$(wildcard res/*.svg))
ALL_TEMPLATES := $(wildcard res/html/*.html)
all: public/index.html
@ -17,9 +18,7 @@ svg: $(ALL_SVG)
public:
mkdir public
public/index.html: static public public/audios \
res/index.html res/page.html \
res/song.html res/song_li.html res/song_redir.html
public/index.html: static public public/audios $(ALL_TEMPLATES)
python3 src/latex_scanner.py --latex latex/cancionero.tex --audios audios
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;
transition-duration: @transition;
}
&.hasChords {
&.noChords {
background-color: @nochordscolor;
&:hover {
color: @text-hover;
@ -30,7 +30,7 @@
}
}
}
span.hasChords {
span.noChords {
background-color: @nochordscolor;
padding: 0.3em 0.4em;
border-radius: @border-radius;

View file

@ -6,6 +6,9 @@ h1 {
width: max-content;
max-width: 100%;
text-align: center;
> a, > a:hover, > a:active, > a:visited {
color: @title;
}
}
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.path import isfile, join
from song_types import Audio
from model import Audio
import re
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 urllib.parse
import os
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):
if not os.path.exists(path):
@ -31,14 +32,6 @@ def extra_put(extra, index, the_type, data=None):
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:
def __init__(self, latex_file, audio_dir):
self.index = 1
@ -235,35 +228,28 @@ class SongLoader:
continue
current_verse.add_line(Line(text, extras))
def print_index(self, index_file="index.html"):
self.songs = sorted(self.songs, key=lambda s: s.number)
song_list = join_list([index_per_song_template.format(
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)
def print_index(self, index_file, dj_engine):
songs = sorted(self.songs, key=lambda s: s.number)
html = dj_engine.get_template("index.html").render(Context({'songs': songs}))
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="."):
for song in self.songs:
num_dir = join(directory, "%03d" % (song.number))
mkdir(num_dir)
with open(join(num_dir, "index.html"), 'w') as f:
f.write(song_redir_template.format(url=urllib.parse.quote("../" + song.get_url())))
song_dir = join(directory, song.get_url())
mkdir(song_dir)
with open(join(song_dir, "index.html"), 'w') as f:
f.write(page_template.format(css=song_css, main=str(song)))
def print_song(self, song, directory, dj_engine):
context = Context({'song': song})
num_dir = join(directory, "%03d" % (song.number))
mkdir(num_dir)
with open(join(num_dir, "index.html"), 'w') as f:
f.write(dj_engine.get_template("song_redir.html").render(context))
song_dir = join(directory, song.url())
mkdir(song_dir)
with open(join(song_dir, "index.html"), 'w') as f:
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)
self.print_songs(output_dir)
self.print_index(join(output_dir, "index.html"))
for song in self.songs:
self.print_song(song, output_dir, dj_engine)
self.print_index(join(output_dir, "index.html"), dj_engine)
def parse_args():
@ -277,4 +263,6 @@ def parse_args():
if __name__ == '__main__':
args = parse_args()
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, "")
def readfile(file):
with open(file, 'r') as f:
return join_list(f.readlines(), '')
locale.setlocale(locale.LC_ALL, "es_ES.UTF-8")
song_template = readfile("res/song.html")
class Song:
@ -32,17 +26,7 @@ class Song:
self.category = category
def __str__(self):
return song_template.format(
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)
return self.name
def set_capo(self, capo):
self.capo = capo
@ -55,7 +39,7 @@ class Song:
assert isinstance(verse, Verse)
self.verses.append(verse)
def get_url(self):
def url(self):
return "%03d %s" % (self.number, self.name.replace("¿", "").replace("?", ""))
def chorded(self):
@ -69,13 +53,10 @@ class Verse:
def __init__(self, is_chorus=False):
self.is_chorus = is_chorus
self.lines = []
self.kind = "chorus" if is_chorus else "verse"
def __str__(self):
return """
<div class="%s">
%s
</div>
""" % ("chorus" if self.is_chorus else "verse", join_list([str(l) for l in self.lines], "\n<br>\n"))
return join_list(self.lines, " ")
def add_line(self, line):
assert isinstance(line, Line)
@ -99,15 +80,11 @@ class Line:
self.lyric_arr = []
self.build()
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):
assert len(self.chord_arr) == len(self.lyric_arr)
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='')
return self.text
def add_chord(self, index, chord):
self.add_item(index, "chord", chord)
@ -172,8 +149,7 @@ class Line:
self.lyric_arr.append(Line.ECHO_BEGIN if inside_echo else '')
mid = True
self.lyric_arr[-1] += self.text[i]
for i in range(len(self.lyric_arr)):
self.lyric_arr[i] = re.sub(r"(^ | $)", "&nbsp;", self.lyric_arr[i])
self.lyric_arr = [re.sub(r"(^ | $)", "&nbsp;", l) for l in self.lyric_arr]
def remove_brackets(self):
self.lyric_arr = [l.replace('}', '').replace('{', '') for l in self.lyric_arr]
@ -186,6 +162,10 @@ class Line:
return False
def chord_eng2lat(text):
return Chord.CHORDS_LAT[Chord.ENG_INDEX[text]]
class Chord:
N_CHORDS = 12
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):
self.text = text
self.chords = []
self.items = []
self.base_transpose = base_transpose
ignore = False
for i, char in enumerate(text):
@ -203,21 +183,15 @@ class Chord:
continue
if "A" <= char <= "G":
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
else:
self.chords.append({'text': char, 'chord': True})
self.items.append({'text': chord_eng2lat(char), 'chord': True})
else:
self.chords.append({'text': char, 'chord': False})
self.items.append({'text': char, 'chord': False})
def __str__(self):
res = ""
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
return self.text
class Audio:
@ -228,11 +202,4 @@ class Audio:
self.audio_file = audio_file
def __str__(self):
return """
<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)
return self.audio_file