Browse Source

early version without makefile

to produce a pdf, run
$./songbook.py -s books/songbook.sb
remotes/origin/next
Romain Goffe 12 years ago
parent
commit
2bae15ee06
  1. 0
      index.py
  2. 282
      python/template.py
  3. 6
      song.py
  4. 138
      songbook-makeindex.py
  5. 3
      songbook.py
  6. 0
      tools.py

0
python/index.py → index.py

282
python/template.py

@ -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()

6
python/song.py → song.py

@ -7,15 +7,15 @@ import re
reTitle = re.compile('(?<=beginsong\\{)(.(?<!\\}]))+') reTitle = re.compile('(?<=beginsong\\{)(.(?<!\\}]))+')
reArtist = re.compile('(?<=by=)(.(?<![,\\]\\}]))+') reArtist = re.compile('(?<=by=)(.(?<![,\\]\\}]))+')
reAlbum = re.compile('(?<=album=)(.(?<![,\\]\\}]))+') reAlbum = re.compile('(?<=album=)(.(?<![,\\]\\}]))+')
reLilypond = re.compile('(?<=album=)(.(?<![,\\]\\}]))+') #reLilypond = re.compile('(?<=album=)(.(?<![,\\]\\}]))+')
class Song: class Song:
def __init__(self, title, artist, album, path): def __init__(self, title, artist, album, path, isLilypond):
self.title = title self.title = title
self.artist = artist self.artist = artist
self.album = album self.album = album
self.path = path self.path = path
self.isLilypond = isLilypond self.isLilypond = isLilypond
def __repr__(self): def __repr__(self):
return repr((self.title, self.artist, self.album, self.path)) return repr((self.title, self.artist, self.album, self.path, self.isLilypond))

138
songbook-makeindex.py

@ -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()

3
songbook.py

@ -36,11 +36,12 @@ def songslist(library, songs, prefixes):
title = reTitle.search(data).group(0) title = reTitle.search(data).group(0)
artist = reArtist.search(data.replace("{","")).group(0) artist = reArtist.search(data.replace("{","")).group(0)
match = reAlbum.search(data.replace("{","")) match = reAlbum.search(data.replace("{",""))
lilypond = False
if match: if match:
album = match.group(0) album = match.group(0)
else: else:
album = '' album = ''
song_objects.append(Song(title, artist, album, path)) song_objects.append(Song(title, artist, album, path, lilypond))
song_objects = sorted(song_objects, key=lambda x: locale.strxfrm(unprefixed(x.title, prefixes))) 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.album))

0
python/tools.py → tools.py

Loading…
Cancel
Save