More abcfield.py updates and mark it Python 3.

- Move title fixups into Python.
- Move key display name expansion into Python.
- Add Dottes-specific header continuation line format. None of the usual
  tools appears to support the official +: continuation.
This commit is contained in:
Jim Hague 2016-10-31 23:48:45 +00:00
parent 3d8f52e639
commit fbd277f6c9
3 changed files with 138 additions and 120 deletions

View File

@ -1,8 +1,20 @@
#!/usr/bin/env python #!/usr/bin/env python3
# #
# Extact a text field (title, by default) from a .abc file, and print it out # Extact a text field (title, by default) from a .abc file, and print it out
# with any ABC accented characters converted to HTML (default) or Latex. # with any ABC accented characters converted to HTML (default) or Latex.
# Recognise continuation fields and print those too. #
# Optionally rearrange a field into display format:
# * In Title fields, change 'sort' form such as 'Exploding Potato, The'
# to display format 'The Exploding Potato'.
# * In Key fields, translate the ABC key representation to full text,
# e.g. G#dor becomes G# Dorian.
#
# Recognise continuation header fields and print those too. The ABC standard
# defines continuation fields as starting ':+'. Regrettably none of the tools
# I am using the Booke recognise that syntax, so I am adopting a Booke
# convention of '<header>:+' *also* being a continuation. Note that a
# continuation is a distinct line in the field value; the value has a line
# break between it and the previous line.
# #
import optparse import optparse
@ -87,7 +99,18 @@ accentedletters = {
"ss" : ("&szlig;", "\\ss"), "ss" : ("&szlig;", "\\ss"),
} }
def convertField(t, options): abckeys = {
"m": "Minor",
"min": "Minor",
"mix": "Mixolydian",
"dor": "Dorian",
"phr": "Phrygian",
"lyd": "Lydian",
"loc": "Locrian",
}
# Convert ABC accented chars to HTML entities or LaTex.
def convertAccents(t, latex=False):
res = "" res = ""
while True: while True:
p = t.partition('\\') p = t.partition('\\')
@ -97,66 +120,121 @@ def convertField(t, options):
abc = p[2][0:2] abc = p[2][0:2]
t = p[2][2:] t = p[2][2:]
if abc in accentedletters: if abc in accentedletters:
if options.html: if latex:
res += accentedletters[abc][0]
else:
res += accentedletters[abc][1] res += accentedletters[abc][1]
else:
res += accentedletters[abc][0]
else: else:
res += "\\" + abc res += "\\" + abc
return res return res
def process(inf, options): # Convert Title fields from sort to display, so Bat, The->The Bat.
n = options.index def convertTitleToDisplay(t):
found = False p = t.rpartition(',')
if p[1] == "":
return t
else:
return p[2].strip() + " " + p[0].strip()
# Convert Key field from ABC to display, so G#dor->G# Dorian.
def convertKeyToDisplay(t):
letter = t[0].upper()
accidental = ""
mode = ""
try:
accidental = t[1]
if accidental == '#' or accidental == 'b':
mode = t[2:]
else:
accidental = ""
mode = t[1:]
except IndexError:
pass
mode = mode.strip().lower()
return letter + accidental + ' ' + abckeys.get(mode, "Major")
# Return the raw text for a given field. Optionally the nth field is taken,
# or the field data must start with a designated string to be recognised.
def getFieldText(inf, field, n = 1, starts = None):
res = None
for line in inf: for line in inf:
line = line.strip() line = line.strip()
if len(line) > 2 and line[1] == ':': if len(line) > 2 and line[1] == ':':
if found: if line[0] == "+" or (line[0] == field and line[2] == "+"):
if line[0] != '+': if not res:
break
line = line[2:].strip()
elif line[0] == options.field:
if n > 1:
n = n - 1
continue continue
if line[0] == "+":
line = line[2:]
else: else:
line = line[2:].strip() line = line[3:]
if len(options.starts) > 0: res = res + '\n' + line.strip()
if line.find(options.starts) == 0:
line = line[len(options.starts):].strip()
else:
continue
else: else:
continue if res:
found = True break
print(convertField(line, options)) if line[0] == field:
return found line = line[2:].strip()
if starts:
if line.find(starts) != 0:
continue
line = line[len(starts):].strip()
if n > 1:
n = n - 1
continue
res = line
return res
parser = optparse.OptionParser(usage="usage: %prog [options] [filename]\n\n" # Return display text for a given field.
" Extract field data from ABC file.") def getFieldDisplayText(inf, field, n = 1, starts = None, latex = False):
parser.add_option("-f", "--field", dest="field", default="T", res = getFieldText(inf, field, n, starts)
help="extract the field FIELD", metavar="FIELD") if res:
parser.add_option("-l", "--latex", dest="latex", if field.upper() == "T":
action="store_true", default=False, res = convertTitleToDisplay(res)
help="convert special characters for LaTeX") elif field.upper() == "K":
parser.add_option("-n", "--index", dest="index", res = convertKeyToDisplay(res)
action="store", type="int", default=1, res = convertAccents(res, latex)
help="report INDEXth value [default: %default]", return res
metavar="INDEX")
parser.add_option("-s", "--starts", dest="starts",
action="store", type="string", default="",
help="report only if line starts CONTENT and remove CONTENT",
metavar="CONTENT")
(options, args) = parser.parse_args()
res = False if __name__ == "__main__":
if len(args) > 0: def process(inf, options):
for arg in args: if options.display:
try: line = getFieldDisplayText(inf, options.field, options.index, options.starts, options.latex)
inf = open(arg, "r") else:
res = res or process(inf, options) line = getFieldText(inf, options.field, options.index, options.starts)
finally: if line:
inf.close() print(line)
else: return True
res = process(sys.stdin, options) else:
sys.exit(int(not res)) return False
# execute only if run as a script
parser = optparse.OptionParser(usage="usage: %prog [options] [filename]\n\n"
" Extract field data from ABC file.")
parser.add_option("-f", "--field", dest="field", default="T",
help="extract the field FIELD", metavar="FIELD")
parser.add_option("-l", "--latex", dest="latex",
action="store_true", default=False,
help="convert special characters for LaTeX")
parser.add_option("-d", "--display", dest="display",
action="store_true", default=False,
help="convert to display text")
parser.add_option("-n", "--index", dest="index",
action="store", type="int", default=1,
help="report INDEXth value [default: %default]",
metavar="INDEX")
parser.add_option("-s", "--starts", dest="starts",
action="store", type="string", default=None,
help="report only if line starts CONTENT and remove CONTENT",
metavar="CONTENT")
(options, args) = parser.parse_args()
res = False
if len(args) > 0:
for arg in args:
try:
inf = open(arg, "r")
res = res or process(inf, options)
finally:
inf.close()
else:
res = process(sys.stdin, options)
sys.exit(int(not res))

View File

@ -8,13 +8,6 @@
# makeGraphics.sh to make these. # makeGraphics.sh to make these.
# #
# Restore titles like 'Exploding Potato, The' to the
# expected 'The Exploding Potato'.
fixtitle()
{
retval=`echo "$1" | sed -e "s/\(.*\), *\(.*\)/\2 \1/"`
}
if [ $# != 1 ]; then if [ $# != 1 ]; then
echo "Usage: makeBookeTunePages.sh <book dir name>" echo "Usage: makeBookeTunePages.sh <book dir name>"
exit 1 exit 1
@ -38,12 +31,8 @@ find $booke -name "*.abc" | sort |
while read filename while read filename
do do
name=`basename $filename .abc` name=`basename $filename .abc`
title=`$dir/abcfield.py --field T --latex $filename` title=`$dir/abcfield.py --field T --latex --display $filename`
fixtitle "$title" subtitle=`$dir/abcfield.py --index 2 --field T --latex --display $filename`
title=$retval
subtitle=`$dir/abcfield.py --index 2 --field T --latex $filename`
fixtitle "$subtitle"
subtitle=$retval
composer=`$dir/abcfield.py --field C --latex $filename` composer=`$dir/abcfield.py --field C --latex $filename`
changefile=`$dir/abcfield.py --field N --starts "Change:" $filename` changefile=`$dir/abcfield.py --field N --starts "Change:" $filename`
@ -51,9 +40,7 @@ find $booke -name "*.abc" | sort |
changetitle="" changetitle=""
if [ -n "$changefile" ]; then if [ -n "$changefile" ]; then
changename=`basename $changefile .abc` changename=`basename $changefile .abc`
changetitle=`$dir/abcfield.py --field T --latex $booke/$changefile` changetitle=`$dir/abcfield.py --field T --latex --display $booke/$changefile`
fixtitle "$changetitle"
changetitle=$retval
fi fi
credit=`$dir/abcfield.py --field N --starts "Credit:" $filename` credit=`$dir/abcfield.py --field N --starts "Credit:" $filename`

View File

@ -7,44 +7,6 @@
#set -x #set -x
# Restore titles like 'Exploding Potato, The' to the
# expected 'The Exploding Potato'.
fixtitle()
{
retval=`echo "$1" | sed -e "s/\(.*\), *\(.*\)/\2 \1/"`
}
# Format a key in ABC (G, Gmin, etc.) in standard presentation format.
fixkey()
{
letter=${1:0:1}
accidental=${1:1:1}
if [ "$accidental" != "#" -a "$accidental" != "b" ]; then
accidental=""
mode=${1:1:3}
else
mode=${1:2:3}
fi
mode=${mode,,}
mode=${mode/ //g}
if [ "$mode" = "m" -o "$mode" = "min" ]; then
mode="Minor"
elif [ "$mode" = "mix" ]; then
mode="Mixolydian"
elif [ "$mode" = "dor" ]; then
mode="Dorian"
elif [ "$mode" = "phr" ]; then
mode="Phrygian"
elif [ "$mode" = "lyd" ]; then
mode="Lydian"
elif [ "$mode" = "loc" ]; then
mode="Locrian"
else
mode="Major"
fi
retval="${letter}${accidental} ${mode}"
}
if [ $# -lt 2 -o $# -gt 3 ]; then if [ $# -lt 2 -o $# -gt 3 ]; then
echo "Usage: makeWeb.sh <book dir name> <master book dir name> [<instrument name>]" echo "Usage: makeWeb.sh <book dir name> <master book dir name> [<instrument name>]"
exit 1 exit 1
@ -105,22 +67,15 @@ find $bookedir -name "*.abc" | sort |
name=`basename $filename .abc` name=`basename $filename .abc`
# Extract items to substitute in the web page. # Extract items to substitute in the web page.
title=`$dir/abcfield.py --field T $filename` title=`$dir/abcfield.py --field T --display $filename`
fixtitle "$title" subtitle=`$dir/abcfield.py --index 2 --field T --display $filename`
title=$retval
subtitle=`$dir/abcfield.py --index 2 --field T $filename`
fixtitle "$subtitle"
subtitle=$retval
composer=`$dir/abcfield.py --field C $filename` composer=`$dir/abcfield.py --field C $filename`
changefile=`$dir/abcfield.py --field N --starts "Change:" $filename` changefile=`$dir/abcfield.py --field N --starts "Change:" $filename`
changetitle="" changetitle=""
changevisibility="no" changevisibility="no"
if [ -n "$changefile" ]; then if [ -n "$changefile" ]; then
changetitle=`$dir/abcfield.py --field T $bookedir/$changefile` changetitle=`$dir/abcfield.py --field T --display $bookedir/$changefile`
changevisibility="yes" changevisibility="yes"
fixtitle "$changetitle"
changetitle=$retval
fi fi
credit=`$dir/abcfield.py --field N --starts "Credit:" $filename` credit=`$dir/abcfield.py --field N --starts "Credit:" $filename`
creditvisibility="no" creditvisibility="no"
@ -128,9 +83,7 @@ find $bookedir -name "*.abc" | sort |
creditvisibility="yes" creditvisibility="yes"
fi fi
lastchanged=`hg log --limit 1 --template "{date|shortdate}" $masterbookedir/${name}.abc` lastchanged=`hg log --limit 1 --template "{date|shortdate}" $masterbookedir/${name}.abc`
key=`$dir/abcfield.py --field K $filename` key=`$dir/abcfield.py --field K --display $filename`
fixkey $key
key=$retval
# Copy the ABC into the web. # Copy the ABC into the web.
cp $filename $webdir cp $filename $webdir