#!/usr/bin/python # -*- coding: utf-8 -*- # import getopt, sys import os.path import glob import re import json import locale import shutil import locale 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)) from xdg.BaseDirectory import * print 'xdg_data_home: %s' % xdg_data_home print 'xdg_data_dirs: %s' % xdg_data_dirs print 'xdg_config_home: %s' % xdg_config_home print 'xdg_config_dirs: %s' % xdg_config_dirs print 'xdg_cache_home: %s' % xdg_cache_home songbook_cache_home = os.path.join(xdg_cache_home, 'songbook') def makeCoverCache(library, cachePath): ''' 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 = glob.glob(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 songslist(library, songs): 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(x.title)) 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 = [] # parse the songbook data if "template" in sb: template = sb["template"] del sb["template"] if "songs" in sb: songs = sb["songs"] del sb["songs"] 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[6:], glob.glob(library + 'songs/*/*.sg')) if len(songs) > 0: out.write(formatDefinition('songslist', songslist(library, songs))) out.write('\\makeatother\n') # output grapihcs path #out.write('\\graphicspath{ {img/}, {' + songbook_cache_home + '/images/} }\n') # output template commentPattern = re.compile(r"^\s*%") f = open("templates/"+template) content = [ line for line in f if not commentPattern.match(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 += glob.glob(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: "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:d:l", ["help","songbook=","output=","depend","cache","library="]) except getopt.GetoptError, err: # print help and exit print str(err) usage() sys.exit(2) songbook = None depend = False output = None cache = False library = './' for o, a in opts: if o in ("-h", "--help"): usage() sys.exit() elif o in ("--cache"): cache = True 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"): library = a else: assert False, "unhandled option" makeCoverCache(library, os.path.join(songbook_cache_home, 'images')) 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()