mirror of
https://gitlab.com/parroquia-san-leandro/cancionero-web.git
synced 2025-04-27 23:55:57 +02:00
initial commit
This commit is contained in:
commit
c8c7eae33c
16 changed files with 835 additions and 0 deletions
269
src/latex_scanner.py
Normal file
269
src/latex_scanner.py
Normal file
|
@ -0,0 +1,269 @@
|
|||
from song_types import *
|
||||
from audio_scanner import find_audios
|
||||
from os.path import join
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
# Note that re.match prepends ^ to the pattern, whereas re.search doesn't
|
||||
|
||||
|
||||
def read_property(text, key):
|
||||
if text is None:
|
||||
return None
|
||||
match = re.search(key + "={(.*?)}", text)
|
||||
return match.group(1) if match else None
|
||||
|
||||
|
||||
def extra_put(extra, index, the_type, data=None):
|
||||
payload = {'type': the_type, 'data': data} if data else {'type': the_type}
|
||||
if index not in extra:
|
||||
extra[index] = []
|
||||
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")
|
||||
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):
|
||||
self.index = 1
|
||||
self.category = None
|
||||
self.categories = []
|
||||
self.songs = []
|
||||
self.scan(latex_file)
|
||||
self.memory = {}
|
||||
|
||||
def scan(self, latex_file):
|
||||
main_file = open(latex_file, 'r')
|
||||
canciones_dir = join(str(Path(latex_file).parent), "canciones")
|
||||
for line in main_file.readlines():
|
||||
# Remove newline
|
||||
if line[-1] == '\n':
|
||||
line = line[:-1]
|
||||
# Remove comments
|
||||
line = re.sub(r"%.*$", "", line)
|
||||
# Read counter and category change (max 1 per line)
|
||||
re_set_counter_match = re.search(r"\\setcounter{songnum}{(\d+)}", line)
|
||||
if re_set_counter_match is not None:
|
||||
self.index = int(re_set_counter_match.group(1))
|
||||
re_chapter_match = re.search(r"\\songchapter{(.*?)}", line)
|
||||
if re_chapter_match is not None:
|
||||
self.category = re_chapter_match.group(1)
|
||||
self.categories.append(self.category)
|
||||
# Traverse into \input commands if path starts w/ 'canciones/'
|
||||
re_input_match = re.search(r"\\input{canciones/(.*?)}", line)
|
||||
if re_input_match is not None:
|
||||
input_file = join(canciones_dir, re_input_match.group(1))
|
||||
if not input_file.endswith(".tex"):
|
||||
input_file += ".tex"
|
||||
self.scan_song_file(input_file)
|
||||
|
||||
def scan_song_file(self, song_file):
|
||||
# Variables
|
||||
ignore = False
|
||||
current_song = None
|
||||
current_verse = None
|
||||
memory = None
|
||||
memorizing = False
|
||||
replay_index = 0
|
||||
transpose = 0
|
||||
|
||||
for line in open(song_file, "r").readlines():
|
||||
# Remove newline
|
||||
if line[-1] == '\n':
|
||||
line = line[:-1]
|
||||
# Remove commends and \brk commands
|
||||
text = re.sub(r"%.*$", "", line)
|
||||
text = re.sub(r"\\brk({})?", '', text)
|
||||
|
||||
extras = {}
|
||||
for i in range(len(text)):
|
||||
beginning = text[:i]
|
||||
remain = text[i:]
|
||||
if re.match(r"\\fi", remain):
|
||||
ignore = False
|
||||
text = beginning + text[i + len("\\fi"):]
|
||||
i -= 1
|
||||
continue
|
||||
if ignore:
|
||||
continue
|
||||
|
||||
# Command lookup
|
||||
re_transpose_match = re.match(r"\\transpose *?{(-?\d+?)}", remain)
|
||||
if re_transpose_match:
|
||||
text = beginning + text[i + len(re_transpose_match.group(0)):]
|
||||
transpose = int(re_transpose_match.group(1))
|
||||
i -= 1
|
||||
continue
|
||||
re_song_begin_match = re.match(r"\\beginsong *?{(.*?)}(\[.*?])?", remain)
|
||||
if re_song_begin_match:
|
||||
text = beginning + text[i + len(re_song_begin_match.group(0)):]
|
||||
if current_song is not None:
|
||||
print("error end-begin song! %s at %s" % (line, song_file))
|
||||
self.songs.append(current_song)
|
||||
self.index += 1
|
||||
current_song = Song(re_song_begin_match.group(1), self.index,
|
||||
author=read_property(re_song_begin_match.group(2), "by"),
|
||||
origin=read_property(re_song_begin_match.group(2), "m"),
|
||||
category=self.category,
|
||||
latex_file=song_file)
|
||||
transpose = 0
|
||||
memory = None
|
||||
memorizing = False
|
||||
replay_index = 0
|
||||
for a in find_audios(self.index):
|
||||
current_song.add_audio(a)
|
||||
i -= 1
|
||||
continue
|
||||
if re.match(r"\\endsong", remain):
|
||||
text = beginning + text[i + len("\\endsong"):]
|
||||
self.songs.append(current_song)
|
||||
current_song = None
|
||||
self.index += 1
|
||||
i -= 1
|
||||
continue
|
||||
re_verse_cmd_match = re.match(r"\\(begin|end)(verse|chorus)", remain)
|
||||
if re_verse_cmd_match:
|
||||
text = beginning + text[i + len(re_verse_cmd_match.group(0)):]
|
||||
is_chorus = re_verse_cmd_match.group(2) == "chorus"
|
||||
if current_song is None:
|
||||
print("verse %s found outside song in %s" % (line, song_file))
|
||||
if re_verse_cmd_match.group(1) == "begin":
|
||||
if current_verse is not None:
|
||||
print("error end-begin verse! %s at %s" % (line, song_file))
|
||||
current_song.add_verse(current_verse)
|
||||
if not is_chorus and memory is None:
|
||||
memory = []
|
||||
memorizing = True
|
||||
replay_index = 0
|
||||
current_verse = Verse(is_chorus)
|
||||
else: # end of verse/chorus
|
||||
if current_verse.is_chorus != is_chorus:
|
||||
print("ended chorus-verse with wrong command?")
|
||||
memorizing = False
|
||||
current_song.add_verse(current_verse)
|
||||
current_verse = None
|
||||
i -= 1
|
||||
continue
|
||||
re_capo_match = re.match(r"\\capo{(\d+?)}", remain)
|
||||
if re_capo_match and current_song:
|
||||
text = beginning + text[i + len(re_capo_match.group(0)):]
|
||||
current_song.set_capo(int(re_capo_match.group(1)))
|
||||
i -= 1
|
||||
continue
|
||||
if re.match(r"\\ifchorded", remain):
|
||||
text = beginning + text[i + len("\\ifchorded"):]
|
||||
i -= 1
|
||||
continue
|
||||
if re.match(r"\\else", remain):
|
||||
ignore = True
|
||||
text = beginning + text[i + len("\\else"):]
|
||||
i -= 1
|
||||
continue
|
||||
re_echo_match = re.match(r"\\echo[ \t]*?{((.|{.*?})*?)}", remain)
|
||||
if re_echo_match:
|
||||
text = beginning + re_echo_match.group(1) + "\\echoend" + text[i + len(re_echo_match.group(0)):]
|
||||
extra_put(extras, i, "echo")
|
||||
i -= 1
|
||||
continue
|
||||
if re.match(r"\\echoend", remain):
|
||||
text = beginning + text[i + len("\\echoend"):]
|
||||
extra_put(extras, i, "echo")
|
||||
i -= 1
|
||||
continue
|
||||
re_chord_match = re.match(r"\\\[(.+?)]", remain)
|
||||
if re_chord_match:
|
||||
text = beginning + text[i + len(re_chord_match.group(0)):]
|
||||
c = Chord(re_chord_match.group(1), transpose)
|
||||
extra_put(extras, i, "chord", c)
|
||||
if memorizing:
|
||||
memory.append(c)
|
||||
i -= 1
|
||||
continue
|
||||
if re.match(r"\^", remain):
|
||||
text = beginning + text[i + len("^"):]
|
||||
if memory is not None and replay_index < len(memory):
|
||||
extra_put(extras, i, "chord", memory[replay_index])
|
||||
replay_index += 1
|
||||
i -= 1
|
||||
continue
|
||||
re_dir_rep_match = re.match(r"\\([lr]rep)", remain)
|
||||
if re_dir_rep_match:
|
||||
text = beginning + text[i + len(re_dir_rep_match.group(0)):]
|
||||
extra_put(extras, i, "dir-rep", re_dir_rep_match.group(1))
|
||||
i -= 1
|
||||
continue
|
||||
re_rep_match = re.match(r"\\rep{(\d+?)}", remain)
|
||||
if re_rep_match:
|
||||
text = beginning + text[i + len(re_rep_match.group(0)):]
|
||||
extra_put(extras, i, 'rep', int(re_rep_match.group(1)))
|
||||
i -= 1
|
||||
continue
|
||||
if re.match(r"\\memorize", remain):
|
||||
text = beginning + text[i + len("\\memorize"):]
|
||||
memory = []
|
||||
memorizing = True
|
||||
i -= 1
|
||||
continue
|
||||
if re.match(r"\\replay", remain):
|
||||
text = beginning + text[i + len("\\replay"):]
|
||||
replay_index = 0
|
||||
i -= 1
|
||||
continue
|
||||
# Command lookup end, removing any unrecognized command
|
||||
re_macro_match = re.match(r"\\([^ \t{\[]+)[ \t]*?({.*?}|\[.*?])*", remain)
|
||||
if re_macro_match:
|
||||
text = beginning + text[i + len(re_macro_match.group(0)):]
|
||||
print("Removed an unrecognized command:", re_macro_match.group(0))
|
||||
i -= 1
|
||||
continue
|
||||
if not current_verse and text.strip() != '':
|
||||
print("l outside v:", text)
|
||||
continue
|
||||
if ignore or text.strip() == '':
|
||||
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)
|
||||
body = index_template % join_list([index_per_song_template %
|
||||
(s.get_url(),
|
||||
' class="hasChords"' if not s.chorded() else '',
|
||||
s.number, s.name,
|
||||
" por %s " % s.author if s.author else "",
|
||||
" basado en %s " % s.origin if s.origin else "")
|
||||
for s in self.songs])
|
||||
with open(index_file, 'w') as f:
|
||||
f.write(page_template % (index_css, body))
|
||||
|
||||
def print_songs(self, directory="."):
|
||||
for song in self.songs:
|
||||
song_dir = join(directory, song.get_url())
|
||||
if not os.path.exists(song_dir):
|
||||
os.mkdir(song_dir)
|
||||
with open(join(song_dir, "index.html"), 'w') as f:
|
||||
f.write(page_template % (song_css, str(song)))
|
||||
|
||||
|
||||
def copy_static(source_dir, target_dir):
|
||||
for f in os.listdir(source_dir):
|
||||
if re.search(r"\.(css|js)$", f):
|
||||
shutil.copy2(join(source_dir, f), target_dir)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
loader = SongLoader("latex/cancionero.tex")
|
||||
target_dir = "public/"
|
||||
if not os.path.exists(target_dir):
|
||||
os.mkdir(target_dir)
|
||||
loader.print_songs(target_dir)
|
||||
loader.print_index(target_dir + "index.html")
|
||||
copy_static("res", target_dir)
|
Loading…
Add table
Add a link
Reference in a new issue