|
| 1 | +#!/usr/bin/python |
| 2 | +# -*- coding: utf-8 -*- |
| 3 | + |
| 4 | +def convert(path, f, target=None): |
| 5 | + import re #für Regular Expressions (google es ;)) |
| 6 | + from collections import OrderedDict #andernfalls würde sich Vers1, Chorus usw immer alphabetisch sortieren |
| 7 | + from pandas import read_csv, Index |
| 8 | + #alle Imports für die PDF Generierung (unbedingt für nächster Zelle mit pyth ausführen) |
| 9 | + from reportlab.pdfgen import canvas |
| 10 | + from reportlab.lib.pagesizes import A4 |
| 11 | + from reportlab.lib.units import inch |
| 12 | + from reportlab.pdfbase.pdfmetrics import stringWidth |
| 13 | + from reportlab.lib import styles, colors |
| 14 | + from reportlab.platypus import Paragraph |
| 15 | + #RTF einlese Package |
| 16 | + from pyth.plugins.rtf15.reader import Rtf15Reader |
| 17 | + from pyth.plugins.plaintext.writer import PlaintextWriter |
| 18 | + #RTF einlesen |
| 19 | + doc = Rtf15Reader.read(f) |
| 20 | + raw = PlaintextWriter.write(doc).getvalue() |
| 21 | + pattern="(^[\xc3\x9f\xc3\x84\xc3\x96\xc3\x9c\xc3\xa4\xc3\xbc\xc3\xb6\w\s]+\n+)(key:[\w#]+\n+)?(bpm:[\d]+\n+)?(.+)(CCLI Song # (\d+)\\n+(.+)\\n+\\xc2\\xa9 (.+))" |
| 22 | + match = re.search(pattern,raw,re.DOTALL) |
| 23 | + info_dict = {} |
| 24 | + info_dict['title'] = match.group(1).replace('\n','') |
| 25 | + if match.group(2): |
| 26 | + info_dict['key'] = match.group(2).replace('\n','').replace('key:','') |
| 27 | + else: |
| 28 | + print "No key found" |
| 29 | + if match.group(3): |
| 30 | + info_dict['bpm'] = match.group(3).replace('\n','').replace('bpm:','') |
| 31 | + else: |
| 32 | + print "No bpm found" |
| 33 | + info_dict['song'] = match.group(4) |
| 34 | + info_dict['ccli_nr'] = match.group(6) |
| 35 | + info_dict['composer'] = match.group(7).replace('\n','') |
| 36 | + info_dict['copyright'] = match.group(8) |
| 37 | + akkorde = read_csv("Akkorde.csv",sep=";") |
| 38 | + def getTransformedKey (source, target, chord): |
| 39 | + return(akkorde[target][Index(akkorde[source]).get_loc(chord)]) |
| 40 | + def replChords (matchObj): |
| 41 | + return ('['+getTransformedKey(source = info_dict['key'], target = target, chord = matchObj.group(1))+']') |
| 42 | + def transform(): |
| 43 | + info_dict['song'] = re.sub('\[([\w\d#/]+)\]', replChords, info_dict['song']) |
| 44 | + info_dict['key'] = target |
| 45 | + #target = request.form['trans_key'] |
| 46 | + if (target and target != info_dict['key']): |
| 47 | + transform() |
| 48 | + #Einzelne Zeilen aus dem RTF in Liste laden |
| 49 | + line_list = info_dict.get('song').split('\n\n') |
| 50 | + line_list |
| 51 | + pattern = '^(Verse\s?\d*|Chorus\s?\d*|Instrumental|Bridge|Pre-Chorus|Intro)$' #Dieses Pattern funktioniert auf alles VersX und Chorus in eckiger Klammer (porbier regexr.com) |
| 52 | + song_dict = OrderedDict() #Das oben erwähnte Ordered Dict |
| 53 | + in_element = False #mit diesem Flag könnte man sich später noch title: composer: key: usw holen (so weit bin ich noch nicht) |
| 54 | + element = None #hier wird gleich drin gespeichert, in welcher Untergruppe wir jeweils sind |
| 55 | + for i in range(len(line_list)): |
| 56 | + if in_element: #wenn wir in einem Element sind, werden alle folgenden Zeilen zu diesem Eintrag hinzugefügt |
| 57 | + if not re.search(pattern,line_list[i]): |
| 58 | + song_dict[element].extend([line_list[i]]) |
| 59 | + match = re.search(pattern,line_list[i]) #Bis wir den ersten Match haben (zB VersX oder Chorus), gibt es auch kein Element |
| 60 | + if match: #Wenn wir jedoch ein Match haben, sind wir in einem Element. Dieses wird neu im Dictonary angelegt. |
| 61 | + in_element = True |
| 62 | + element = match.group(1) |
| 63 | + song_dict[element] = [] #Wir geben an, dass hinter diesem Dictonary Eintrag eine neue Liste steht. |
| 64 | + |
| 65 | + |
| 66 | + def createPDF(fontSize = 13): |
| 67 | + width, height = A4 #keep for later |
| 68 | + font = 'Helvetica' |
| 69 | + lineHeight = fontSize + .75 * fontSize |
| 70 | + wordSpace = 3 |
| 71 | + boarder = inch |
| 72 | + topBoarder = .75*boarder |
| 73 | + instrSpaces = 5 |
| 74 | + chordstyle = styles.ParagraphStyle('chord') |
| 75 | + chordstyle.fontSize = fontSize |
| 76 | + hstyle = styles.ParagraphStyle('heading') |
| 77 | + hstyle.fontSize = fontSize +1 |
| 78 | + tstyle = styles.ParagraphStyle('title') |
| 79 | + tstyle.fontSize = fontSize +5 |
| 80 | + copyrightstyle = styles.ParagraphStyle('copyright') |
| 81 | + copyrightstyle.fontSize = 8 |
| 82 | + |
| 83 | + |
| 84 | + pattern = '\[([\w\d#/]+)\]' |
| 85 | + y = height - topBoarder - fontSize |
| 86 | + x = boarder |
| 87 | + realWidth = width - 2*boarder |
| 88 | + c = canvas.Canvas(path+info_dict['title']+'-'+info_dict['key']+'.pdf', pagesize=A4) |
| 89 | + c.setFont(font, fontSize-1) |
| 90 | + |
| 91 | + P1 = Paragraph("<u><b>"+info_dict['title']+"</b></u>",tstyle) |
| 92 | + P1.wrap(realWidth, height) |
| 93 | + P1.drawOn(c,x,y) |
| 94 | + |
| 95 | + if info_dict.has_key('key'): |
| 96 | + P1 = Paragraph("<b>"+info_dict['key']+"</b>",chordstyle) |
| 97 | + P1.wrap(realWidth, height) |
| 98 | + P1.drawOn(c,width-boarder-stringWidth(info_dict['key'], font, chordstyle.fontSize),y) |
| 99 | + if info_dict.has_key('bpm'): |
| 100 | + c.drawRightString(width-boarder,y-lineHeight,'%s'%info_dict['bpm']) |
| 101 | + P1 = Paragraph(info_dict['composer'],copyrightstyle) |
| 102 | + P1.wrap(realWidth, height) |
| 103 | + P1.drawOn(c,x,y-lineHeight) |
| 104 | + |
| 105 | + c.setFont(font, fontSize) |
| 106 | + y -= hstyle.fontSize + 2*lineHeight |
| 107 | + |
| 108 | + for key in song_dict: |
| 109 | + P1 = Paragraph("<b><i>"+key+"</i></b>",hstyle) |
| 110 | + P1.wrap(realWidth, height) |
| 111 | + P1.drawOn(c,x,y) |
| 112 | + xOfLast = boarder |
| 113 | + lineCount = 0 |
| 114 | + if re.search(pattern, song_dict.get(key)[0]): |
| 115 | + y -= 1.8 * (lineHeight) #Abstand von Überschrift zu erster Zeile wenn Akkorde |
| 116 | + else: |
| 117 | + y -= 1.2 * (lineHeight) #Abstand von Überschrift zu erster Zeile wenn keine Akkorde |
| 118 | + if (key in ["Instrumental", "Intro"]): |
| 119 | + for line in song_dict.get(key): |
| 120 | + line = line.replace('[','').replace(']','').replace(' ',' '*(instrSpaces)) |
| 121 | + P1 = Paragraph("<b>"+line+"</b>",chordstyle) |
| 122 | + P1.wrap(realWidth, height) |
| 123 | + P1.drawOn(c,x,y) |
| 124 | + y -= 1.5 * lineHeight #Abstand nach jedem Abschnitt |
| 125 | + else: |
| 126 | + for line in song_dict.get(key): |
| 127 | + if ((xOfLast + stringWidth(line, font, fontSize)) < (width - boarder)) and (lineCount < 2): |
| 128 | + x = xOfLast |
| 129 | + lineCount += 1 |
| 130 | + elif not re.search(pattern, line): |
| 131 | + y -= 1 * lineHeight |
| 132 | + else: |
| 133 | + y -= 1.5 * lineHeight |
| 134 | + lineCount = 1 |
| 135 | + line = line.decode('utf-8') |
| 136 | + last_was_chord = False |
| 137 | + x_min = 0 |
| 138 | + cursor = 0 |
| 139 | + while cursor < len(line): |
| 140 | + l = line[cursor] |
| 141 | + if l == ' ': |
| 142 | + if last_was_chord: |
| 143 | + x += last_cord_length |
| 144 | + last_was_chord = False |
| 145 | + else: |
| 146 | + x += wordSpace |
| 147 | + elif l == '[': |
| 148 | + end = line.find(']', cursor) |
| 149 | + chord = line[cursor+1:end] |
| 150 | + P1 = Paragraph("<b>"+chord+"</b>",chordstyle) |
| 151 | + P1.wrap(realWidth, height) |
| 152 | + if x < x_min: |
| 153 | + x = x_min |
| 154 | + P1.drawOn(c,x,y+fontSize+0.01*fontSize**2) |
| 155 | + cursor = end |
| 156 | + last_was_chord = True |
| 157 | + last_cord_length = stringWidth(chord, font, fontSize) |
| 158 | + x_min = x + last_cord_length + wordSpace*7 |
| 159 | + else: |
| 160 | + last_was_chord = False |
| 161 | + c.drawString(x,y,l) |
| 162 | + x += stringWidth(l, font, fontSize) |
| 163 | + cursor += 1 |
| 164 | + xOfLast = x + wordSpace |
| 165 | + x = boarder |
| 166 | + y -= 1.5 * lineHeight #Abstand nach jedem Abschnitt |
| 167 | + |
| 168 | + |
| 169 | + P1 = Paragraph(u'\u00a9 '+ |
| 170 | + info_dict['copyright']+ |
| 171 | + '<br/>Gebrauch nur zur Nutzung im Rahmen von Veranstaltungen der City Chapel Stuttgart',copyrightstyle) |
| 172 | + P1.wrap(realWidth, height) |
| 173 | + P1.drawOn(c,x,boarder-P1.height)# + lineHeight) |
| 174 | + |
| 175 | + c.showPage() |
| 176 | + c.save() |
| 177 | + return(y < boarder) |
| 178 | + |
| 179 | + nochmal = True |
| 180 | + fontSize = 13 |
| 181 | + while (nochmal): |
| 182 | + nochmal = createPDF(fontSize) |
| 183 | + fontSize -= .5 |
0 commit comments