mirror of https://github.com/patacrep/patacrep.git
Romain Goffe
12 years ago
6 changed files with 5 additions and 424 deletions
@ -1,282 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
|
|||
import getopt, sys |
|||
import os.path |
|||
import re |
|||
import json |
|||
import locale |
|||
import shutil |
|||
import locale |
|||
import platform |
|||
|
|||
from utils.utils import recursiveFind |
|||
|
|||
reTitle = re.compile('(?<=beginsong\\{)(.(?<!\\}]))+') |
|||
reArtist = re.compile('(?<=by=)(.(?<![,\\]\\}]))+') |
|||
reAlbum = re.compile('(?<=album=)(.(?<![,\\]\\}]))+') |
|||
|
|||
class Song: |
|||
def __init__(self, title, artist, album, path): |
|||
self.title = title |
|||
self.artist = artist |
|||
self.album = album |
|||
self.path = path |
|||
def __repr__(self): |
|||
return repr((self.title, self.artist, self.album, self.path)) |
|||
|
|||
if platform.system() == "Linux": |
|||
from xdg.BaseDirectory import * |
|||
cachePath = os.path.join(xdg_cache_home, 'songbook') |
|||
else: |
|||
cachePath = os.path.join('cache', 'songbook') |
|||
|
|||
def makeCoverCache(library): |
|||
''' |
|||
Copy all pictures found in the libraries into a unique cache |
|||
folder. |
|||
''' |
|||
# create the cache directory if it does not exist |
|||
if not os.path.exists(cachePath): |
|||
os.makedirs(cachePath) |
|||
|
|||
# copy pictures file into the cache directory |
|||
covers = recursiveFind(os.path.join(library, 'songs'), '*.jpg') |
|||
for cover in covers: |
|||
coverPath = os.path.join(cachePath, os.path.basename(cover)) |
|||
shutil.copy(cover, coverPath) |
|||
|
|||
def matchRegexp(reg, iterable): |
|||
return [ m.group(1) for m in (reg.match(l) for l in iterable) if m ] |
|||
|
|||
def unprefixed(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 |
|||
|
|||
def songslist(library, songs, prefixes): |
|||
song_objects = [] |
|||
for s in songs: |
|||
path = library + 'songs/' + s |
|||
with open(path, 'r+') as f: |
|||
data = f.read() |
|||
title = reTitle.search(data).group(0) |
|||
artist = reArtist.search(data.replace("{","")).group(0) |
|||
match = reAlbum.search(data.replace("{","")) |
|||
if match: |
|||
album = match.group(0) |
|||
else: |
|||
album = '' |
|||
song_objects.append(Song(title, artist, album, path)) |
|||
|
|||
song_objects = sorted(song_objects, key=lambda x: locale.strxfrm(unprefixed(x.title, prefixes))) |
|||
song_objects = sorted(song_objects, key=lambda x: locale.strxfrm(x.album)) |
|||
song_objects = sorted(song_objects, key=lambda x: locale.strxfrm(x.artist)) |
|||
|
|||
result = [ '\\input{{{0}}}'.format(song.path.replace("\\","/").strip()) for song in song_objects ] |
|||
return '\n'.join(result) |
|||
|
|||
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 = [] |
|||
titleprefixwords = "" |
|||
prefixes = [] |
|||
|
|||
# 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"]: |
|||
titleprefixwords += "\\titleprefixword{%s}\n" % prefix |
|||
sb["titleprefixwords"] = titleprefixwords |
|||
|
|||
parameters = parseTemplate("templates/"+template) |
|||
|
|||
# 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))) |
|||
# output songslist |
|||
if songs == "all": |
|||
songs = map(lambda x: x[len(library) + 6:], recursiveFind(os.path.join(library, 'songs'), '*.sg')) |
|||
|
|||
if len(songs) > 0: |
|||
out.write(formatDefinition('songslist', songslist(library, songs, prefixes))) |
|||
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("getCacheDirectory").search(line): |
|||
line = line.replace("\\getCacheDirectory", cachePath.replace("\\","/") + "/") |
|||
content[index] = line |
|||
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 makeDepend(sb, library, output): |
|||
name = output[:-2] |
|||
|
|||
indexPattern = re.compile(r"^[^%]*\\(?:newauthor|new)index\{.*\}\{(.*?)\}") |
|||
lilypondPattern = re.compile(r"^[^%]*\\(?:lilypond)\{(.*?)\}") |
|||
|
|||
# check for deps (in sb data) |
|||
deps = []; |
|||
if sb["songs"] == "all": |
|||
deps += recursiveFind(os.path.join(library, 'songs'), '*.sg') |
|||
else: |
|||
deps += map(lambda x: library + "songs/" + x, sb["songs"]) |
|||
|
|||
# check for lilypond deps (in songs data) if necessary |
|||
lilypond = [] |
|||
if "bookoptions" in sb and "lilypond" in sb["bookoptions"]: |
|||
for filename in deps: |
|||
tmpl = open(filename) |
|||
lilypond += matchRegexp(lilypondPattern, tmpl) |
|||
tmpl.close() |
|||
|
|||
# check for index (in template file) |
|||
if "template" in sb: |
|||
filename = sb["template"] |
|||
else: |
|||
filename = "patacrep.tmpl" |
|||
tmpl = open("templates/"+filename) |
|||
idx = map(lambda x: x.replace("\getname", name), matchRegexp(indexPattern, tmpl)) |
|||
tmpl.close() |
|||
|
|||
# write .d file |
|||
out = open(output, 'w') |
|||
out.write('{0} {1} : {2}\n'.format(output, name+".tex", ' '.join(deps))) |
|||
out.write('{0} : {1}\n'.format(name+".pdf", ' '.join(map(lambda x: x+".sbx",idx)+map(lambda x: library+"lilypond/"+x+".pdf", lilypond)))) |
|||
out.write('\t$(LATEX) {0}\n'.format(name+".tex")) |
|||
out.write('{0} : {1}\n'.format(' '.join(map(lambda x: x+".sxd",idx)), name+".aux")) |
|||
out.close() |
|||
|
|||
def usage(): |
|||
print "No usage information yet." |
|||
|
|||
def main(): |
|||
locale.setlocale(locale.LC_ALL, '') # set script locale to match user's |
|||
try: |
|||
opts, args = getopt.getopt(sys.argv[1:], |
|||
"hs:o:l:d", |
|||
["help","songbook=","output=","depend","library="]) |
|||
except getopt.GetoptError, err: |
|||
# print help and exit |
|||
print str(err) |
|||
usage() |
|||
sys.exit(2) |
|||
|
|||
songbook = None |
|||
depend = False |
|||
output = None |
|||
library = './' |
|||
|
|||
for o, a in opts: |
|||
if o in ("-h", "--help"): |
|||
usage() |
|||
sys.exit() |
|||
elif o in ("-s", "--songbook"): |
|||
songbook = a |
|||
elif o in ("-d", "--depend"): |
|||
depend = True |
|||
elif o in ("-o", "--output"): |
|||
output = a |
|||
elif o in ("-l", "--library"): |
|||
if not a.endswith('/'): |
|||
a += '/' |
|||
library = a |
|||
else: |
|||
assert False, "unhandled option" |
|||
|
|||
makeCoverCache(library) |
|||
if songbook and output: |
|||
f = open(songbook) |
|||
sb = json.load(f) |
|||
f.close() |
|||
|
|||
if depend: |
|||
makeDepend(sb, library, output) |
|||
else: |
|||
makeTexFile(sb, library, output) |
|||
|
|||
if __name__ == '__main__': |
|||
main() |
@ -1,138 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# Generate indexes files for the Crep's chordbook compilation. This is |
|||
# a replacement for the original makeindex program written in C that |
|||
# produces an index file (.sbx) from a file generated by the latex |
|||
# compilation of the songbook (.sxd). |
|||
# |
|||
# Usage : songbook-makeindex.py src |
|||
# src is the .sxd file generated by latex |
|||
# |
|||
|
|||
import os.path |
|||
import glob |
|||
import re |
|||
import sys |
|||
from optparse import OptionParser |
|||
import sortindex |
|||
import locale |
|||
|
|||
# Pattern set to ignore latex command in title prefix |
|||
keywordPattern = re.compile(r"^%(\w+)\s?(.*)$") |
|||
firstLetterPattern = re.compile(r"^(?:\{?\\\w+\}?)*[^\w]*(\w)") |
|||
|
|||
class index: |
|||
data = dict() |
|||
keywords = dict() |
|||
|
|||
def filter(self, key): |
|||
letter = firstLetterPattern.match(key).group(1) |
|||
if re.match('\d',letter): |
|||
letter = '0-9' |
|||
return (letter.upper(), key) |
|||
|
|||
def keyword(self, key, word): |
|||
if not self.keywords.has_key(key): |
|||
self.keywords[key] = [] |
|||
self.keywords[key].append(word) |
|||
|
|||
def compileKeywords(self): |
|||
self.prefix_patterns = [] |
|||
if 'prefix' in self.keywords: |
|||
for prefix in self.keywords['prefix']: |
|||
self.prefix_patterns.append(re.compile(r"^(%s)\b\s*(.*)$" % prefix)) |
|||
|
|||
def add(self, key, number, link): |
|||
for pattern in self.prefix_patterns: |
|||
match = pattern.match(key) |
|||
if match: |
|||
key = "%s (%s)" % (match.group(2), match.group(1)) |
|||
break # Only one match per key |
|||
(first, key) = self.filter(key) |
|||
if not self.data.has_key(first): |
|||
self.data[first] = dict() |
|||
if not self.data[first].has_key(key): |
|||
self.data[first][key] = [] |
|||
self.data[first][key].append({'num':number, 'link':link}) |
|||
|
|||
def refToStr(self, ref): |
|||
if sys.version_info >= (2,6): |
|||
return '\\hyperlink{{{0[link]}}}{{{0[num]}}}'.format(ref) |
|||
else: |
|||
return '\\hyperlink{%(link)s}{%(num)s}' % ref |
|||
|
|||
def entryToStr(self, key, entry): |
|||
if sys.version_info >= (2,6): |
|||
return '\\idxentry{{{0}}}{{{1}}}\n'.format(key, '\\\\'.join(map(self.refToStr, entry))) |
|||
else: |
|||
return '\\idxentry{%s}{%s}\n' % (key, '\\\\'.join(map(self.refToStr, entry))) |
|||
|
|||
def idxBlockToStr(self, letter, entries): |
|||
str = '\\begin{idxblock}{'+letter+'}'+'\n' |
|||
for key in sorted(entries.keys(), key=sortindex.sortkey): |
|||
str += self.entryToStr(key, entries[key]) |
|||
str += '\\end{idxblock}'+'\n' |
|||
return str |
|||
|
|||
def entriesToStr(self): |
|||
str = "" |
|||
for letter in sorted(self.data.keys()): |
|||
str += self.idxBlockToStr(letter, self.data[letter]) |
|||
return str |
|||
|
|||
def processSXDEntry(tab): |
|||
return (tab[0], tab[1], tab[2]) |
|||
|
|||
def processSXD(filename): |
|||
file = open(filename) |
|||
data = [] |
|||
for line in file: |
|||
data.append(line.strip()) |
|||
file.close() |
|||
|
|||
type = data[0] |
|||
i = 1 |
|||
idx = index() |
|||
|
|||
if len(data) > 1: |
|||
while data[i].startswith('%'): |
|||
keywords = keywordPattern.match(data[i]).groups() |
|||
idx.keyword(keywords[0],keywords[1]) |
|||
i += 1 |
|||
|
|||
idx.compileKeywords() |
|||
for i in range(i,len(data),3): |
|||
entry = processSXDEntry(data[i:i+3]) |
|||
idx.add(entry[0],entry[1],entry[2]) |
|||
return idx |
|||
|
|||
def usage(exitCode=None): |
|||
print "usage: songbook-makeindex.py [options] source" |
|||
sys.exit(exitCode) |
|||
|
|||
def main(): |
|||
locale.setlocale(locale.LC_ALL, '') |
|||
usage = "usage: %prog [options] FILE" |
|||
parser = OptionParser(usage) |
|||
parser.add_option("-o", "--output", dest="filename", |
|||
help="write result into FILE", metavar="FILE") |
|||
(options, args) = parser.parse_args() |
|||
|
|||
# Args processing |
|||
if len(args) != 1: |
|||
parser.error("incorrect number of arguments") |
|||
if not os.path.exists(args[0]): |
|||
parser.error("inexistant input file") |
|||
|
|||
# Options processing |
|||
if options.filename: |
|||
output = open(options.filename,"w") |
|||
else: |
|||
output = sys.stdout |
|||
|
|||
# Actual processing |
|||
idx = processSXD(args[0]) |
|||
output.write(idx.entriesToStr()) |
|||
|
|||
if __name__ == '__main__': |
|||
main() |
Loading…
Reference in new issue