mirror of https://github.com/patacrep/patacrep.git
Luthaf
11 years ago
12 changed files with 512 additions and 368 deletions
@ -1,21 +0,0 @@ |
|||||
#!/usr/bin/python |
|
||||
# -*- coding: utf-8 -*- |
|
||||
# |
|
||||
|
|
||||
import re |
|
||||
|
|
||||
reTitle = re.compile('(?<=beginsong\\{)(.(?<!\\}]))+') |
|
||||
reArtist = re.compile('(?<=by=)(.(?<![,\\]\\}]))+') |
|
||||
reAlbum = re.compile('(?<=album=)(.(?<![,\\]\\}]))+') |
|
||||
#reLilypond = re.compile('(?<=album=)(.(?<![,\\]\\}]))+') |
|
||||
|
|
||||
class Song: |
|
||||
def __init__(self, title, artist, album, path, isLilypond): |
|
||||
self.title = title |
|
||||
self.artist = artist |
|
||||
self.album = album |
|
||||
self.path = path |
|
||||
self.isLilypond = isLilypond |
|
||||
def __repr__(self): |
|
||||
return repr((self.title, self.artist, self.album, self.path, self.isLilypond)) |
|
||||
|
|
@ -1,16 +1,5 @@ |
|||||
#!/usr/bin/python |
#!/usr/bin/env python |
||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
# |
|
||||
|
|
||||
import fnmatch |
|
||||
import os |
|
||||
|
|
||||
def recursiveFind(root_directory, pattern): |
|
||||
matches = [] |
|
||||
for root, dirnames, filenames in os.walk(root_directory): |
|
||||
for filename in fnmatch.filter(filenames, pattern): |
|
||||
matches.append(os.path.join(root, filename)) |
|
||||
return matches |
|
||||
|
|
||||
def split_author_names(string): |
def split_author_names(string): |
||||
"""Split author between first and last name. |
"""Split author between first and last name. |
@ -0,0 +1,191 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from subprocess import call |
||||
|
import glob |
||||
|
import json |
||||
|
import os.path |
||||
|
import re |
||||
|
|
||||
|
from songbook.files import recursiveFind |
||||
|
from songbook.index import processSXD |
||||
|
from songbook.songs import Song, SongsList |
||||
|
|
||||
|
def parseTemplate(template): |
||||
|
embeddedJsonPattern = re.compile(r"^%%:") |
||||
|
f = open(template) |
||||
|
code = [ line[3:-1] for line in f if embeddedJsonPattern.match(line) ] |
||||
|
f.close() |
||||
|
data = json.loads(''.join(code)) |
||||
|
parameters = dict() |
||||
|
for param in data: |
||||
|
parameters[param["name"]] = param |
||||
|
return parameters |
||||
|
|
||||
|
def toValue(parameter, data): |
||||
|
if "type" not in parameter: |
||||
|
return data |
||||
|
elif parameter["type"] == "stringlist": |
||||
|
if "join" in parameter: |
||||
|
joinText = parameter["join"] |
||||
|
else: |
||||
|
joinText = '' |
||||
|
return joinText.join(data) |
||||
|
elif parameter["type"] == "color": |
||||
|
return data[1:] |
||||
|
elif parameter["type"] == "font": |
||||
|
return data+'pt' |
||||
|
elif parameter["type"] == "enum": |
||||
|
return data |
||||
|
elif parameter["type"] == "file": |
||||
|
return data |
||||
|
elif parameter["type"] == "flag": |
||||
|
if "join" in parameter: |
||||
|
joinText = parameter["join"] |
||||
|
else: |
||||
|
joinText = '' |
||||
|
return joinText.join(data) |
||||
|
|
||||
|
def formatDeclaration(name, parameter): |
||||
|
value = "" |
||||
|
if "default" in parameter: |
||||
|
value = parameter["default"] |
||||
|
return '\\def\\set@{name}#1{{\\def\\get{name}{{#1}}}}\n'.format(name=name) + formatDefinition(name, toValue(parameter, value)) |
||||
|
|
||||
|
def formatDefinition(name, value): |
||||
|
return '\\set@{name}{{{value}}}\n'.format(name=name, value=value) |
||||
|
|
||||
|
def makeTexFile(sb, library, output): |
||||
|
name = output[:-4] |
||||
|
|
||||
|
# default value |
||||
|
template = "patacrep.tmpl" |
||||
|
songs = [] |
||||
|
|
||||
|
prefixes_tex = "" |
||||
|
prefixes = [] |
||||
|
|
||||
|
authwords_tex = "" |
||||
|
authwords = {"after": ["by"], "ignore": ["unknown"], "sep": ["and"]} |
||||
|
|
||||
|
# parse the songbook data |
||||
|
if "template" in sb: |
||||
|
template = sb["template"] |
||||
|
del sb["template"] |
||||
|
if "songs" in sb: |
||||
|
songs = sb["songs"] |
||||
|
del sb["songs"] |
||||
|
if "titleprefixwords" in sb: |
||||
|
prefixes = sb["titleprefixwords"] |
||||
|
for prefix in sb["titleprefixwords"]: |
||||
|
prefixes_tex += "\\titleprefixword{%s}\n" % prefix |
||||
|
sb["titleprefixwords"] = prefixes_tex |
||||
|
if "authwords" in sb: |
||||
|
# Populating default value |
||||
|
for key in ["after", "sep", "ignore"]: |
||||
|
if key not in sb["authwords"]: |
||||
|
sb["authwords"][key] = authwords[key] |
||||
|
# Processing authwords values |
||||
|
authwords = sb["authwords"] |
||||
|
for key in ["after", "sep", "ignore"]: |
||||
|
for word in authwords[key]: |
||||
|
if key == "after": |
||||
|
authwords_tex += "\\auth%sword{%s}\n" % ("by", word) |
||||
|
else: |
||||
|
authwords_tex += "\\auth%sword{%s}\n" % (key, word) |
||||
|
sb["authwords"] = authwords_tex |
||||
|
if "after" in authwords: |
||||
|
authwords["after"] = [re.compile(r"^.*%s\b(.*)" % after) for after in authwords["after"]] |
||||
|
if "sep" in authwords: |
||||
|
authwords["sep"] = [" %s" % sep for sep in authwords["sep"]] + [","] |
||||
|
authwords["sep"] = [re.compile(r"^(.*)%s (.*)$" % sep) for sep in authwords["sep"] ] |
||||
|
|
||||
|
if "lang" not in sb: |
||||
|
sb["lang"] = "french" |
||||
|
if "sort" in sb: |
||||
|
sort = sb["sort"] |
||||
|
del sb["sort"] |
||||
|
else: |
||||
|
sort = [u"by", u"album", u"@title"] |
||||
|
Song.sort = sort |
||||
|
Song.prefixes = prefixes |
||||
|
Song.authwords = authwords |
||||
|
|
||||
|
parameters = parseTemplate("templates/"+template) |
||||
|
|
||||
|
# compute songslist |
||||
|
if songs == "all": |
||||
|
songs = map(lambda x: x[len(library) + 6:], recursiveFind(os.path.join(library, 'songs'), '*.sg')) |
||||
|
songslist = SongsList(library, sb["lang"]) |
||||
|
songslist.append_list(songs) |
||||
|
|
||||
|
sb["languages"] = ",".join(songslist.languages()) |
||||
|
|
||||
|
# output relevant fields |
||||
|
out = open(output, 'w') |
||||
|
out.write('%% This file has been automatically generated, do not edit!\n') |
||||
|
out.write('\\makeatletter\n') |
||||
|
# output automatic parameters |
||||
|
out.write(formatDeclaration("name", {"default":name})) |
||||
|
out.write(formatDeclaration("songslist", {"type":"stringlist"})) |
||||
|
# output template parameter command |
||||
|
for name, parameter in parameters.iteritems(): |
||||
|
out.write(formatDeclaration(name, parameter)) |
||||
|
# output template parameter values |
||||
|
for name, value in sb.iteritems(): |
||||
|
if name in parameters: |
||||
|
out.write(formatDefinition(name, toValue(parameters[name],value))) |
||||
|
|
||||
|
if len(songs) > 0: |
||||
|
out.write(formatDefinition('songslist', songslist.latex())) |
||||
|
out.write('\\makeatother\n') |
||||
|
|
||||
|
# output template |
||||
|
commentPattern = re.compile(r"^\s*%") |
||||
|
f = open("templates/"+template) |
||||
|
content = [ line for line in f if not commentPattern.match(line) ] |
||||
|
|
||||
|
for index, line in enumerate(content): |
||||
|
if re.compile("getLibraryImgDirectory").search(line): |
||||
|
line = line.replace("\\getLibraryImgDirectory", library + "img/") |
||||
|
content[index] = line |
||||
|
if re.compile("getLibraryLilypondDirectory").search(line): |
||||
|
line = line.replace("\\getLibraryLilypondDirectory", library + "lilypond/") |
||||
|
content[index] = line |
||||
|
|
||||
|
f.close() |
||||
|
out.write(''.join(content)) |
||||
|
|
||||
|
out.close() |
||||
|
|
||||
|
def buildsongbook(sb, basename, library): |
||||
|
"""Build a songbook |
||||
|
|
||||
|
Arguments: |
||||
|
- sb: Python representation of the .sb songbook configuration file. |
||||
|
- library: directory containing the "songs" directory, itself containing |
||||
|
songs. |
||||
|
- basename: basename of the songbook to be built. |
||||
|
""" |
||||
|
|
||||
|
texFile = basename + ".tex" |
||||
|
pdfFile = basename + ".pdf" |
||||
|
|
||||
|
# Make TeX file |
||||
|
makeTexFile(sb, library, texFile) |
||||
|
|
||||
|
# First pdflatex pass |
||||
|
call(["pdflatex", texFile]) |
||||
|
|
||||
|
# Make index |
||||
|
sxdFiles = glob.glob("%s_*.sxd" % basename) |
||||
|
print sxdFiles |
||||
|
for sxdFile in sxdFiles: |
||||
|
print "processing " + sxdFile |
||||
|
idx = processSXD(sxdFile) |
||||
|
indexFile = open(sxdFile[:-3]+"sbx", "w") |
||||
|
indexFile.write(idx.entriesToStr().encode('utf8')) |
||||
|
indexFile.close() |
||||
|
|
||||
|
# Second pdflatex pass |
||||
|
call(["pdflatex", texFile]) |
@ -0,0 +1,14 @@ |
|||||
|
#!/usr/bin/python |
||||
|
# -*- coding: utf-8 -*- |
||||
|
# |
||||
|
|
||||
|
import fnmatch |
||||
|
import os |
||||
|
|
||||
|
def recursiveFind(root_directory, pattern): |
||||
|
matches = [] |
||||
|
for root, dirnames, filenames in os.walk(root_directory): |
||||
|
for filename in fnmatch.filter(filenames, pattern): |
||||
|
matches.append(os.path.join(root, filename)) |
||||
|
return matches |
||||
|
|
@ -0,0 +1,119 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from unidecode import unidecode |
||||
|
import locale |
||||
|
import os.path |
||||
|
import re |
||||
|
|
||||
|
from songbook.authors import processauthors |
||||
|
from songbook.plastex import parsetex |
||||
|
|
||||
|
class Song: |
||||
|
#: Ordre de tri |
||||
|
sort = [] |
||||
|
#: Préfixes à ignorer pour le tri par titres |
||||
|
prefixes = [] |
||||
|
#: Dictionnaire des options pour le traitement des auteurs |
||||
|
authwords = {"after": [], "ignore": [], "sep": []} |
||||
|
|
||||
|
def __init__(self, path, languages, titles, args): |
||||
|
self.titles = titles |
||||
|
self.normalized_titles = [locale.strxfrm(unprefixed_title(unidecode(unicode(title, "utf-8")), self.prefixes)) for title in titles] |
||||
|
self.args = args |
||||
|
self.path = path |
||||
|
self.languages = languages |
||||
|
if "by" in self.args.keys(): |
||||
|
self.normalized_authors = [ |
||||
|
locale.strxfrm(author) |
||||
|
for author |
||||
|
in processauthors(self.args["by"], **self.authwords) |
||||
|
] |
||||
|
else: |
||||
|
self.normalized_authors = [] |
||||
|
|
||||
|
def __repr__(self): |
||||
|
return repr((self.titles, self.args, self.path)) |
||||
|
|
||||
|
def __cmp__(self, other): |
||||
|
if not isinstance(other, Song): |
||||
|
return NotImplemented |
||||
|
for key in self.sort: |
||||
|
if key == "@title": |
||||
|
self_key = self.normalized_titles |
||||
|
other_key = other.normalized_titles |
||||
|
elif key == "@path": |
||||
|
self_key = locale.strxfrm(self.path) |
||||
|
other_key = locale.strxfrm(other.path) |
||||
|
elif key == "by": |
||||
|
self_key = self.normalized_authors |
||||
|
other_key = other.normalized_authors |
||||
|
else: |
||||
|
self_key = locale.strxfrm(self.args.get(key, "")) |
||||
|
other_key = locale.strxfrm(other.args.get(key, "")) |
||||
|
|
||||
|
if self_key < other_key: |
||||
|
return -1 |
||||
|
elif self_key > other_key: |
||||
|
return 1 |
||||
|
return 0 |
||||
|
|
||||
|
def unprefixed_title(title, prefixes): |
||||
|
"""Remove the first prefix of the list in the beginning of title (if any). |
||||
|
""" |
||||
|
for prefix in prefixes: |
||||
|
match = re.compile(r"^(%s)\b\s*(.*)$" % prefix).match(title) |
||||
|
if match: |
||||
|
return match.group(2) |
||||
|
return title |
||||
|
|
||||
|
class SongsList: |
||||
|
"""Manipulation et traitement de liste de chansons""" |
||||
|
|
||||
|
def __init__(self, library, language): |
||||
|
self._library = library |
||||
|
self._language = language |
||||
|
|
||||
|
# Liste triée des chansons |
||||
|
self.songs = [] |
||||
|
|
||||
|
|
||||
|
def append(self, filename): |
||||
|
"""Ajout d'une chanson à la liste |
||||
|
|
||||
|
Effets de bord : analyse syntaxique plus ou moins sommaire du fichier |
||||
|
pour en extraire et traiter certaines information (titre, langue, |
||||
|
album, etc.). |
||||
|
""" |
||||
|
path = os.path.join(self._library, 'songs', filename) |
||||
|
# Exécution de PlasTeX |
||||
|
data = parsetex(path) |
||||
|
|
||||
|
song = Song(path, data['languages'], data['titles'], data['args']) |
||||
|
low, high = 0, len(self.songs) |
||||
|
while low != high: |
||||
|
middle = (low + high) / 2 |
||||
|
if song < self.songs[middle]: |
||||
|
high = middle |
||||
|
else: |
||||
|
low = middle + 1 |
||||
|
self.songs.insert(low, song) |
||||
|
|
||||
|
def append_list(self, filelist): |
||||
|
"""Ajoute une liste de chansons à la liste |
||||
|
|
||||
|
L'argument est une liste de chaînes, représentant des noms de fichiers. |
||||
|
""" |
||||
|
for filename in filelist: |
||||
|
self.append(filename) |
||||
|
|
||||
|
def latex(self): |
||||
|
"""Renvoie le code LaTeX nécessaire pour intégrer la liste de chansons. |
||||
|
""" |
||||
|
result = [ '\\input{{{0}}}'.format(song.path.replace("\\","/").strip()) for song in self.songs] |
||||
|
result.append('\\selectlanguage{%s}' % self._language) |
||||
|
return '\n'.join(result) |
||||
|
|
||||
|
def languages(self): |
||||
|
"""Renvoie la liste des langues utilisées par les chansons""" |
||||
|
return set().union(*[set(song.languages) for song in self.songs]) |
@ -0,0 +1,157 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
import json |
||||
|
import os.path |
||||
|
import re |
||||
|
|
||||
|
from songbook.files import recursiveFind |
||||
|
from songbook.songs import Song, SongsList |
||||
|
|
||||
|
def parseTemplate(template): |
||||
|
embeddedJsonPattern = re.compile(r"^%%:") |
||||
|
f = open(template) |
||||
|
code = [ line[3:-1] for line in f if embeddedJsonPattern.match(line) ] |
||||
|
f.close() |
||||
|
data = json.loads(''.join(code)) |
||||
|
parameters = dict() |
||||
|
for param in data: |
||||
|
parameters[param["name"]] = param |
||||
|
return parameters |
||||
|
|
||||
|
def toValue(parameter, data): |
||||
|
if "type" not in parameter: |
||||
|
return data |
||||
|
elif parameter["type"] == "stringlist": |
||||
|
if "join" in parameter: |
||||
|
joinText = parameter["join"] |
||||
|
else: |
||||
|
joinText = '' |
||||
|
return joinText.join(data) |
||||
|
elif parameter["type"] == "color": |
||||
|
return data[1:] |
||||
|
elif parameter["type"] == "font": |
||||
|
return data+'pt' |
||||
|
elif parameter["type"] == "enum": |
||||
|
return data |
||||
|
elif parameter["type"] == "file": |
||||
|
return data |
||||
|
elif parameter["type"] == "flag": |
||||
|
if "join" in parameter: |
||||
|
joinText = parameter["join"] |
||||
|
else: |
||||
|
joinText = '' |
||||
|
return joinText.join(data) |
||||
|
|
||||
|
def formatDeclaration(name, parameter): |
||||
|
value = "" |
||||
|
if "default" in parameter: |
||||
|
value = parameter["default"] |
||||
|
return '\\def\\set@{name}#1{{\\def\\get{name}{{#1}}}}\n'.format(name=name) + formatDefinition(name, toValue(parameter, value)) |
||||
|
|
||||
|
def formatDefinition(name, value): |
||||
|
return '\\set@{name}{{{value}}}\n'.format(name=name, value=value) |
||||
|
|
||||
|
def makeTexFile(sb, library, output): |
||||
|
name = output[:-4] |
||||
|
|
||||
|
# default value |
||||
|
template = "patacrep.tmpl" |
||||
|
songs = [] |
||||
|
|
||||
|
prefixes_tex = "" |
||||
|
prefixes = [] |
||||
|
|
||||
|
authwords_tex = "" |
||||
|
authwords = {"after": ["by"], "ignore": ["unknown"], "sep": ["and"]} |
||||
|
|
||||
|
# parse the songbook data |
||||
|
if "template" in sb: |
||||
|
template = sb["template"] |
||||
|
del sb["template"] |
||||
|
if "songs" in sb: |
||||
|
songs = sb["songs"] |
||||
|
del sb["songs"] |
||||
|
if "titleprefixwords" in sb: |
||||
|
prefixes = sb["titleprefixwords"] |
||||
|
for prefix in sb["titleprefixwords"]: |
||||
|
prefixes_tex += "\\titleprefixword{%s}\n" % prefix |
||||
|
sb["titleprefixwords"] = prefixes_tex |
||||
|
if "authwords" in sb: |
||||
|
# Populating default value |
||||
|
for key in ["after", "sep", "ignore"]: |
||||
|
if key not in sb["authwords"]: |
||||
|
sb["authwords"][key] = authwords[key] |
||||
|
# Processing authwords values |
||||
|
authwords = sb["authwords"] |
||||
|
for key in ["after", "sep", "ignore"]: |
||||
|
for word in authwords[key]: |
||||
|
if key == "after": |
||||
|
authwords_tex += "\\auth%sword{%s}\n" % ("by", word) |
||||
|
else: |
||||
|
authwords_tex += "\\auth%sword{%s}\n" % (key, word) |
||||
|
sb["authwords"] = authwords_tex |
||||
|
if "after" in authwords: |
||||
|
authwords["after"] = [re.compile(r"^.*%s\b(.*)" % after) for after in authwords["after"]] |
||||
|
if "sep" in authwords: |
||||
|
authwords["sep"] = [" %s" % sep for sep in authwords["sep"]] + [","] |
||||
|
authwords["sep"] = [re.compile(r"^(.*)%s (.*)$" % sep) for sep in authwords["sep"] ] |
||||
|
|
||||
|
if "lang" not in sb: |
||||
|
sb["lang"] = "french" |
||||
|
if "sort" in sb: |
||||
|
sort = sb["sort"] |
||||
|
del sb["sort"] |
||||
|
else: |
||||
|
sort = [u"by", u"album", u"@title"] |
||||
|
Song.sort = sort |
||||
|
Song.prefixes = prefixes |
||||
|
Song.authwords = authwords |
||||
|
|
||||
|
parameters = parseTemplate("templates/"+template) |
||||
|
|
||||
|
# compute songslist |
||||
|
if songs == "all": |
||||
|
songs = map(lambda x: x[len(library) + 6:], recursiveFind(os.path.join(library, 'songs'), '*.sg')) |
||||
|
songslist = SongsList(library, sb["lang"]) |
||||
|
songslist.append_list(songs) |
||||
|
|
||||
|
sb["languages"] = ",".join(songslist.languages()) |
||||
|
|
||||
|
# output relevant fields |
||||
|
out = open(output, 'w') |
||||
|
out.write('%% This file has been automatically generated, do not edit!\n') |
||||
|
out.write('\\makeatletter\n') |
||||
|
# output automatic parameters |
||||
|
out.write(formatDeclaration("name", {"default":name})) |
||||
|
out.write(formatDeclaration("songslist", {"type":"stringlist"})) |
||||
|
# output template parameter command |
||||
|
for name, parameter in parameters.iteritems(): |
||||
|
out.write(formatDeclaration(name, parameter)) |
||||
|
# output template parameter values |
||||
|
for name, value in sb.iteritems(): |
||||
|
if name in parameters: |
||||
|
out.write(formatDefinition(name, toValue(parameters[name],value))) |
||||
|
|
||||
|
if len(songs) > 0: |
||||
|
out.write(formatDefinition('songslist', songslist.latex())) |
||||
|
out.write('\\makeatother\n') |
||||
|
|
||||
|
# output template |
||||
|
commentPattern = re.compile(r"^\s*%") |
||||
|
f = open("templates/"+template) |
||||
|
content = [ line for line in f if not commentPattern.match(line) ] |
||||
|
|
||||
|
for index, line in enumerate(content): |
||||
|
if re.compile("getLibraryImgDirectory").search(line): |
||||
|
line = line.replace("\\getLibraryImgDirectory", library + "img/") |
||||
|
content[index] = line |
||||
|
if re.compile("getLibraryLilypondDirectory").search(line): |
||||
|
line = line.replace("\\getLibraryLilypondDirectory", library + "lilypond/") |
||||
|
content[index] = line |
||||
|
|
||||
|
f.close() |
||||
|
out.write(''.join(content)) |
||||
|
|
||||
|
out.close() |
||||
|
|
Loading…
Reference in new issue