Replaced prints with logging module

This commit is contained in:
Marco van Dijk 2021-07-27 16:19:08 +02:00
parent 30109a0a7f
commit 4ab8f6c836
6 changed files with 100 additions and 87 deletions

View File

@ -36,7 +36,8 @@ def initConfig():
} }
config['options'] = {'exporttoimg': 1, config['options'] = {'exporttoimg': 1,
'exporttotxt': 0, 'exporttotxt': 0,
'exporttoraw': 0 'exporttoraw': 0,
'logLevel': 3
} }
config['output'] = {'metafontfamily': 'fonts/CourierPrime-Regular.ttf', config['output'] = {'metafontfamily': 'fonts/CourierPrime-Regular.ttf',
'metaFontWeight': 32, 'metaFontWeight': 32,
@ -56,7 +57,7 @@ def initConfig():
'writeheaderfile': 0, 'writeheaderfile': 0,
'minPages': 2, 'minPages': 2,
'maxPages': 4, 'maxPages': 4,
'preferEvenPageNumbers': 1 'preferEvenPageNumbers': 0
} }
# (if CMD arguments: load CMD arguments to override specific settings) # (if CMD arguments: load CMD arguments to override specific settings)
with open('config.ini', 'w') as configfile: with open('config.ini', 'w') as configfile:

View File

@ -9,13 +9,11 @@
# #
# @section notes Notes # @section notes Notes
# #
# @section todo TODO
# - Move helper functions like stripEmptyLines to a separate file for
# - Move read functions to separate input functions (also to support more types of inputs)
import re import re
import lib.config import lib.config
from PIL import ImageFont from PIL import ImageFont
import logging
A4 = {'width': 210, 'height': 297} A4 = {'width': 210, 'height': 297}
A5 = {'width': 210, 'height': 148} A5 = {'width': 210, 'height': 148}
@ -47,30 +45,30 @@ def readSourceFile(inputFile):
def isTablatureData(inputString): def isTablatureData(inputString):
if not inputString: if not inputString:
return return
#print("Checking '{}' for line type".format(inputString)) logging.debug("Checking '{}' for line type".format(inputString))
# Assume tablature line if any character {/, #, (, ), } # Assume tablature line if any character {/, #, (, ), }
tablatureSpecificCharacterString = r"/#" tablatureSpecificCharacterString = r"/#"
if any(elem in inputString for elem in tablatureSpecificCharacterString): if any(elem in inputString for elem in tablatureSpecificCharacterString):
#print("'{}' is a tablature line, since it contains a tablature specific character".format(inputString)) logging.debug("'{}' is a tablature line, since it contains a tablature specific character".format(inputString))
return True return True
# Assume LYRIC line if any TEXT character OTHER THAN {a, b, c, d, e, f, g, h, b, x, m, j, n} # Assume LYRIC line if any TEXT character OTHER THAN {a, b, c, d, e, f, g, h, b, x, m, j, n}
lyricSpecificCharacterString = r"abcdefghbxmjn" lyricSpecificCharacterString = r"abcdefghbxmjn"
for char in inputString: for char in inputString:
if char.isalpha(): if char.isalpha():
if not char.lower() in lyricSpecificCharacterString: if not char.lower() in lyricSpecificCharacterString:
#print("'{}' is a LYRIC line, since it contains lyric specific text characters".format(inputString)) logging.debug("'{}' is a lyric line, since it contains lyric specific text characters".format(inputString))
return False return False
# Assume tablature line if any digit # Assume tablature line if any digit
if any(char.isdigit() for char in inputString): if any(char.isdigit() for char in inputString):
#print("'{}' is a tablature line, since it contains a number".format(inputString)) logging.debug("'{}' is a tablature line, since it contains a number".format(inputString))
return True return True
# Assume LYRIC line if any character {.} # Assume LYRIC line if any character {.}
lyricSpecialChars = r"." lyricSpecialChars = r"."
if any(elem in inputString for elem in lyricSpecialChars): if any(elem in inputString for elem in lyricSpecialChars):
#print("'{}' is a LYRIC line, since it contains lyric specific special characters".format(inputString)) logging.debug("'{}' is a lyric line, since it contains lyric specific special characters".format(inputString))
return False return False
# Else warn and assume tablature line # Else warn and assume tablature line
#print("Unable to identify if '{}' is a lyric or tablature line. Assuming it is a tablature line. Please improve the isTablatureData function".format(inputString)) # logging.warn("Unable to identify if '{}' is a lyric or tablature line. Assuming it is a tablature line. Please improve the isTablatureData function".format(inputString))
return True return True
"""!@brief Class containing Section specific data """!@brief Class containing Section specific data
@ -103,7 +101,6 @@ class Section:
headerWidth, headerHeight = fontTablature.getsize(self.header) headerWidth, headerHeight = fontTablature.getsize(self.header)
heightSum += headerHeight heightSum += headerHeight
maxWidth = headerWidth maxWidth = headerWidth
#print("With header, dimensions of section '{}' start at {}H{}B".format(self.header[:-2], heightSum, maxWidth))
while lineIterator < amountOfLines: while lineIterator < amountOfLines:
# Get chord&lyric line dimensions # Get chord&lyric line dimensions
lyricTextWidth, lyricTextHeight = fontLyrics.getsize(self.lyrics[lineIterator]) lyricTextWidth, lyricTextHeight = fontLyrics.getsize(self.lyrics[lineIterator])
@ -134,7 +131,7 @@ class Section:
continue continue
# Determine lyric or tablature line # Determine lyric or tablature line
currentIsTablature = isTablatureData(line) currentIsTablature = isTablatureData(line)
#print("Have line {} isTab={}, isLyric={}".format(line, currentIsTablature, not currentIsTablature)) logging.debug("Have line {} isTab={}, isLyric={}".format(line, currentIsTablature, not currentIsTablature))
# Initially just fill in the first line correctly # Initially just fill in the first line correctly
if isFirstLine: if isFirstLine:
isFirstLine = False isFirstLine = False
@ -146,16 +143,16 @@ class Section:
# we need to insert an empty line of the other type # we need to insert an empty line of the other type
elif currentIsTablature == prevWasTablature: elif currentIsTablature == prevWasTablature:
if currentIsTablature: if currentIsTablature:
#print("Inserting empty Lyric line") logging.debug("Inserting empty Lyric line")
self.tablatures.append(line) self.tablatures.append(line)
self.lyrics.append("") self.lyrics.append("")
else: else:
#print("Inserting empty tablature line") logging.debug("Inserting empty tablature line")
self.lyrics.append(line) self.lyrics.append(line)
self.tablatures.append("") self.tablatures.append("")
# also insert the current line # also insert the current line
elif currentIsTablature: elif currentIsTablature:
#print("Inserting empty Lyric line") logging.debug("Inserting empty Lyric line")
self.tablatures.append(line) self.tablatures.append(line)
else: else:
self.lyrics.append(line) self.lyrics.append(line)
@ -163,7 +160,7 @@ class Section:
prevWasTablature = currentIsTablature prevWasTablature = currentIsTablature
# Simple check to see if it probably exported correctly # Simple check to see if it probably exported correctly
if abs(len(self.lyrics) - len(self.tablatures)) > 1: if abs(len(self.lyrics) - len(self.tablatures)) > 1:
print("Unable to parse section {}, since there is a mismatch between the amount of lyrics ({}) and tablature ({}) lines.".format(self.header, len(self.lyrics), len(self.tablatures))) logging.error("Unable to parse section {}, since there is a mismatch between the amount of lyrics ({}) and tablature ({}) lines.".format(self.header, len(self.lyrics), len(self.tablatures)))
return return
# Add a trailing empty line if necessary # Add a trailing empty line if necessary
elif len(self.lyrics) > len(self.tablatures): elif len(self.lyrics) > len(self.tablatures):
@ -261,7 +258,7 @@ class Song:
currentHeight += metadataTextHeight currentHeight += metadataTextHeight
self.metadataWidth = maxWidth self.metadataWidth = maxWidth
self.metadataHeight = currentHeight self.metadataHeight = currentHeight
#print("metadata dimensions are {}h : {}w".format(currentHeight, maxWidth)) logging.debug("metadata dimensions are {}h : {}w".format(currentHeight, maxWidth))
"""!@brief Resizes all sections by a specified amount """!@brief Resizes all sections by a specified amount
Also recalculates all section sizes afterwards Also recalculates all section sizes afterwards
@ -269,7 +266,7 @@ class Song:
@return None @return None
""" """
def resizeAllSections(self, mutator): def resizeAllSections(self, mutator):
#print("Resizing font by {} to {}".format(mutator, self.fontSize)) logging.debug("Resizing font by {} to {}".format(mutator, self.fontSize))
self.fontSize += mutator self.fontSize += mutator
self.fontLyrics = ImageFont.truetype(self.fontFamilyLyrics, self.fontSize) self.fontLyrics = ImageFont.truetype(self.fontFamilyLyrics, self.fontSize)
self.fontTablature = ImageFont.truetype(self.fontFamilyTablature, self.fontSize) self.fontTablature = ImageFont.truetype(self.fontFamilyTablature, self.fontSize)
@ -298,10 +295,10 @@ class Song:
def fitSectionsByWidth(self): def fitSectionsByWidth(self):
self.prerenderSections() self.prerenderSections()
while not self.checkOverflowX(): while not self.checkOverflowX():
#print("Resizing down to prevent overflow on the width of the page") logging.debug("Resizing down to prevent overflow on the width of the page")
self.resizeAllSections(-1) self.resizeAllSections(-1)
while not self.checkOverflowMetadata(): while not self.checkOverflowMetadata():
#print("Resizing down to prevent overflow on the width of the page") logging.debug("Resizing down to prevent metadata overflow on the width of the page")
self.resizeMetadata(-1) self.resizeMetadata(-1)
"""!@brief Checks whether we are overflowing on the width of the page """!@brief Checks whether we are overflowing on the width of the page
@ -310,7 +307,7 @@ class Song:
def checkOverflowX(self): def checkOverflowX(self):
for section in self.sections: for section in self.sections:
if section.expectedWidth > self.imageWidth - self.extraHorizontalMargin - self.horizontalMargin - self.horizontalMargin: if section.expectedWidth > self.imageWidth - self.extraHorizontalMargin - self.horizontalMargin - self.horizontalMargin:
print("There is an overflow on width: this section has a width of {}, but we have {} ({}-{}-{}*2) amount of space".format(section.expectedWidth, self.imageWidth - self.extraHorizontalMargin - self.horizontalMargin - self.horizontalMargin, self.imageWidth, self.extraHorizontalMargin, self.horizontalMargin)) logging.debug("There is an overflow on width: this section has a width of {}, but we have {} ({}-{}-{}*2) amount of space".format(section.expectedWidth, self.imageWidth - self.extraHorizontalMargin - self.horizontalMargin - self.horizontalMargin, self.imageWidth, self.extraHorizontalMargin, self.horizontalMargin))
return False return False
return True return True
@ -329,9 +326,9 @@ class Song:
targetPageAmount = max(len(self.pages), self.minPages) targetPageAmount = max(len(self.pages), self.minPages)
if (targetPageAmount % 2) != 0 and self.preferEvenPageNumbers: if (targetPageAmount % 2) != 0 and self.preferEvenPageNumbers:
targetPageAmount += 1 targetPageAmount += 1
print("Increasing target page amount to {} to make it an even number".format(targetPageAmount)) logging.info("Increasing target page amount to {} to make it an even number".format(targetPageAmount))
originalFontsize = self.fontSize originalFontsize = self.fontSize
print("Starting font size increase with {} pages and {} font size".format(targetPageAmount, originalFontsize)) logging.debug("Starting font size increase with {} pages and {} font size".format(targetPageAmount, originalFontsize))
self.resizeAllSections(+1) self.resizeAllSections(+1)
self.sectionsToPages() self.sectionsToPages()
currentPageAmount = len(self.pages) currentPageAmount = len(self.pages)
@ -340,15 +337,15 @@ class Song:
self.resizeAllSections(+1) self.resizeAllSections(+1)
self.sectionsToPages() self.sectionsToPages()
currentPageAmount = len(self.pages) currentPageAmount = len(self.pages)
print("Current page amount is {} with font size {}".format(currentPageAmount, self.fontSize)) logging.debug("Current page amount is {} with font size {}".format(currentPageAmount, self.fontSize))
# Now undo latest increase to go back to target page amount # Now undo latest increase to go back to target page amount
self.resizeAllSections(-1) self.resizeAllSections(-1)
self.sectionsToPages() self.sectionsToPages()
currentPageAmount = len(self.pages) currentPageAmount = len(self.pages)
if targetPageAmount != currentPageAmount: if targetPageAmount != currentPageAmount:
print("Oops! While resizing up we changed the amount of pages from {} to {}".format(targetPageAmount, currentPageAmount)) logging.warning("Oops! While resizing up we changed the amount of pages from {} to {}".format(targetPageAmount, currentPageAmount))
if self.fontSize != originalFontsize: if self.fontSize != originalFontsize:
print("Managed to change the font size from {} to {}".format(originalFontsize, self.fontSize)) logging.debug("Managed to change the font size from {} to {}".format(originalFontsize, self.fontSize))
"""!@brief Tries to fill in the whitespace on the current render """!@brief Tries to fill in the whitespace on the current render
@ -375,14 +372,14 @@ class Song:
if whitespaceOnWidth > biggestWhitespace: if whitespaceOnWidth > biggestWhitespace:
biggestWhitespace = whitespaceOnWidth biggestWhitespace = whitespaceOnWidth
# Sections vary in width, some are very small to begin with # Sections vary in width, some are very small to begin with
print("The shortest line has {} whitespace, the largest line {}. The image is {} wide with {} total horizontal margins (={}), resulting in a {} min ratio and {} max ratio, with a min limit of {} and a max limit of {}".format(biggestWhitespace, smallestWhitespace, self.imageWidth, totalHorizontalMargin, imageWidthWithoutMargins, biggestWhitespace / imageWidthWithoutMargins, smallestWhitespace / imageWidthWithoutMargins, self.shortestLineWhitespaceRatioAllowed, self.longestLineWhitespaceRatioAllowed)) logging.debug("The shortest line has {} whitespace, the largest line {}. The image is {} wide with {} total horizontal margins (={}), resulting in a {} min ratio and {} max ratio, with a min limit of {} and a max limit of {}".format(biggestWhitespace, smallestWhitespace, self.imageWidth, totalHorizontalMargin, imageWidthWithoutMargins, biggestWhitespace / imageWidthWithoutMargins, smallestWhitespace / imageWidthWithoutMargins, self.shortestLineWhitespaceRatioAllowed, self.longestLineWhitespaceRatioAllowed))
# Make sure small lines fill the page enough # Make sure small lines fill the page enough
if biggestWhitespace / imageWidthWithoutMargins > self.shortestLineWhitespaceRatioAllowed: if biggestWhitespace / imageWidthWithoutMargins > self.shortestLineWhitespaceRatioAllowed:
print("Stopping resizing down, since the smallest section has {}% whitespace on the width of the image".format((biggestWhitespace / imageWidthWithoutMargins )* 100)) logging.debug("Stopping resizing down, since the smallest section has {}% whitespace on the width of the image".format((biggestWhitespace / imageWidthWithoutMargins )* 100))
return False return False
# Make sure the longest lines fill the page enough # Make sure the longest lines fill the page enough
if smallestWhitespace / imageWidthWithoutMargins > self.longestLineWhitespaceRatioAllowed: if smallestWhitespace / imageWidthWithoutMargins > self.longestLineWhitespaceRatioAllowed:
print("Stopping resizing down, since we largest section has {}% whitespace on the width of the image".format((smallestWhitespace / imageWidthWithoutMargins )* 100)) logging.debug("Stopping resizing down, since we largest section has {}% whitespace on the width of the image".format((smallestWhitespace / imageWidthWithoutMargins )* 100))
return False return False
# get first section on next page, if we have a next page to begin with # get first section on next page, if we have a next page to begin with
while currentPageIt < amountOfPages - 1: while currentPageIt < amountOfPages - 1:
@ -392,8 +389,8 @@ class Song:
whitespace = self.imageHeight - curPage.totalHeight whitespace = self.imageHeight - curPage.totalHeight
amountWeAreShort = nextFirstSection.expectedHeight - whitespace amountWeAreShort = nextFirstSection.expectedHeight - whitespace
shortInPercentages = amountWeAreShort / self.imageHeight shortInPercentages = amountWeAreShort / self.imageHeight
#print("Whitespace {} vs next section height {}".format(whitespace, nextFirstSection.expectedHeight)) logging.debug("Whitespace {} vs next section height {}".format(whitespace, nextFirstSection.expectedHeight))
#print("We are {} short to fit the next image (total image height {} => {}% of total height)".format(amountWeAreShort, self.imageHeight, shortInPercentages*100)) logging.debug("We are {} short to fit the next image (total image height {} => {}% of total height)".format(amountWeAreShort, self.imageHeight, shortInPercentages*100))
# Since we also resize based on minimum required whitespaces, we can be a bit more aggressive with this # Since we also resize based on minimum required whitespaces, we can be a bit more aggressive with this
if shortInPercentages < self.tryToShrinkRatio: if shortInPercentages < self.tryToShrinkRatio:
return True return True
@ -419,7 +416,9 @@ class Song:
# Now fit all sections # Now fit all sections
for section in self.sections: for section in self.sections:
if (section.expectedHeight == -1 or section.expectedWidth == -1): if (section.expectedHeight == -1 or section.expectedWidth == -1):
print("Warning: this file was not processed correctly. The expected dimensions are not set") logging.critical("Warning: this file was not processed correctly. The expected dimensions are not set")
self.pages = []
return
# See if the section would fit on the current page - if it does not, we have a filled page # See if the section would fit on the current page - if it does not, we have a filled page
if currentHeight + section.expectedHeight > self.imageHeight: if currentHeight + section.expectedHeight > self.imageHeight:
curPage.totalHeight = currentHeight curPage.totalHeight = currentHeight
@ -448,23 +447,23 @@ class Song:
# While not EOF: build sections until new section found. # While not EOF: build sections until new section found.
delimiterIndex = parseData.find("[") delimiterIndex = parseData.find("[")
if delimiterIndex == -1: if delimiterIndex == -1:
print("Cannot parse input file, since it is not delimited by '[<sectionName>]' entries") logging.error("Cannot parse input file, since it is not delimited by '[<sectionName>]' entries")
return return
# Start with metadata # Start with metadata
self.metadata = parseData[:delimiterIndex] self.metadata = parseData[:delimiterIndex]
print("Set '{}' as metadata".format(self.metadata)) logging.debug("Set '{}' as metadata".format(self.metadata))
parseData = parseData[delimiterIndex:] parseData = parseData[delimiterIndex:]
# We are now at the start of the first section, at the '[' character # We are now at the start of the first section, at the '[' character
lines = parseData.splitlines(True) lines = parseData.splitlines(True)
if not len(lines): if not len(lines):
return return
#print("We found {} lines of data".format(len(lines))) logging.debug("We found {} lines of data".format(len(lines)))
# Init first section by popping the delimiter # Init first section by popping the delimiter
thisSection = Section() thisSection = Section()
thisSection.header = lines.pop(0) thisSection.header = lines.pop(0)
# First line is always tab->lyric # First line is always tab->lyric
isTabLine = True isTabLine = True
print("First header is '{}'".format(thisSection.header)) logging.debug("First header is '{}'".format(thisSection.header))
for line in lines: for line in lines:
# If it is a [header], it is a new section # If it is a [header], it is a new section
if line[0] == '[': if line[0] == '[':
@ -473,20 +472,20 @@ class Song:
if thisSection.isParsed: if thisSection.isParsed:
self.sections.append(thisSection) self.sections.append(thisSection)
else: else:
print("Aborting parse due to section not being parseable.") logging.error("Aborting parse due to section not being parseable.")
return return
# Reset, new section # Reset, new section
thisSection = Section() thisSection = Section()
thisSection.header = line thisSection.header = line
#print("Header is '{}'".format(thisSection.header)) logging.debug("Header is '{}'".format(thisSection.header))
isTabLine = True isTabLine = True
# Else is has lines in order tabline->lyricline->repeat # Else is has lines in order tabline->lyricline->repeat
elif isTabLine: elif isTabLine:
#print("Adding Tabline is '{}'".format(line)) logging.debug("Adding Tabline is '{}'".format(line))
thisSection.tablatures.append(line) thisSection.tablatures.append(line)
isTabLine = False isTabLine = False
else: else:
#print("Adding Lyricline is '{}'".format(line)) logging.debug("Adding Lyricline is '{}'".format(line))
thisSection.lyrics.append(line) thisSection.lyrics.append(line)
isTabLine = True isTabLine = True
# Add final section data # Add final section data
@ -494,7 +493,7 @@ class Song:
if thisSection.isParsed: if thisSection.isParsed:
self.sections.append(thisSection) self.sections.append(thisSection)
else: else:
print("Aborting parse due to section not being parseable.") logging.error("Aborting parse due to section not being parseable.")
return return
self.isParsed = True self.isParsed = True
@ -506,15 +505,15 @@ class Song:
self.rawData = readSourceFile(self.inputFile) self.rawData = readSourceFile(self.inputFile)
# Clean up input # Clean up input
parseData = stripEmptyLines(self.rawData, self.keepEmptyLines) parseData = stripEmptyLines(self.rawData, self.keepEmptyLines)
#print("Clean data='{}'\n".format(parseData)) logging.debug("Clean data='{}'\n".format(parseData))
# While not EOF: build sections until new section found. # While not EOF: build sections until new section found.
delimiterIndex = parseData.find("[") delimiterIndex = parseData.find("[")
if delimiterIndex == -1: if delimiterIndex == -1:
print("Cannot parse input file, since it is not delimited by '[<sectionName>]' entries") logging.error("Cannot parse input file, since it is not delimited by '[<sectionName>]' entries")
return return
# Start with metadata # Start with metadata
self.metadata = parseData[:delimiterIndex] self.metadata = parseData[:delimiterIndex]
#print("Set '{}' as metadata".format(self.metadata)) logging.debug("Set '{}' as metadata".format(self.metadata))
parseData = parseData[delimiterIndex:] parseData = parseData[delimiterIndex:]
# We are now at the start of the first section, at the '[' character # We are now at the start of the first section, at the '[' character
while parseData: while parseData:
@ -523,7 +522,7 @@ class Song:
# Get header on the first line # Get header on the first line
delimiterIndex = parseData.find("]\r\n") delimiterIndex = parseData.find("]\r\n")
if delimiterIndex == -1: if delimiterIndex == -1:
print("Cannot parse input file, delimiter did not match '[<sectionName>]'") logging.error("Cannot parse input file, delimiter did not match '[<sectionName>]'")
return return
# Skip the ']\r\n' characters # Skip the ']\r\n' characters
thisSection.header = parseData[:delimiterIndex+3] thisSection.header = parseData[:delimiterIndex+3]
@ -538,14 +537,14 @@ class Song:
else: else:
# Set thisSection's data and remove it from the buffer # Set thisSection's data and remove it from the buffer
thisSection.rawData = parseData[:delimiterIndex] thisSection.rawData = parseData[:delimiterIndex]
#print("set rawData of '{}' to this section".format(thisSection.rawData)) logging.debug("set rawData of '{}' to this section".format(thisSection.rawData))
parseData = parseData[delimiterIndex:] parseData = parseData[delimiterIndex:]
# Finally parse section data # Finally parse section data
thisSection.initSections() thisSection.initSections()
if thisSection.isParsed: if thisSection.isParsed:
self.sections.append(thisSection) self.sections.append(thisSection)
else: else:
print("Aborting parse due to section not being parseable.") logging.error("Aborting parse due to section not being parseable.")
return return
self.isParsed = True self.isParsed = True

View File

@ -17,6 +17,7 @@
import lib.dataStructures import lib.dataStructures
import lib.config import lib.config
import os import os
import logging
"""!@brief Creates and inits a Song object """!@brief Creates and inits a Song object
This function creates a new Song object and sets the internal variables correctly This function creates a new Song object and sets the internal variables correctly
@ -32,7 +33,7 @@ def initSong(filePath):
thisSong.outputLocation = filePath[:filePath.rfind('.')] thisSong.outputLocation = filePath[:filePath.rfind('.')]
# title is just the name of the .txt file # title is just the name of the .txt file
thisSong.title = thisSong.outputLocation[filePath.rfind('/')+1:] thisSong.title = thisSong.outputLocation[filePath.rfind('/')+1:]
#print("Finished init for input file '{}'.\nBase output folder is '{}'\nSong title is '{}'\n".format(thisSong.inputFile, thisSong.outputLocation, thisSong.title)) logging.debug("Finished init for input file '{}'.\nBase output folder is '{}'\nSong title is '{}'\n".format(thisSong.inputFile, thisSong.outputLocation, thisSong.title))
return thisSong return thisSong
"""!@brief Creates a list of files found in a directory and its subdirectories """!@brief Creates a list of files found in a directory and its subdirectories
@ -43,7 +44,7 @@ def initSong(filePath):
""" """
def walkDirectory(root, depth): def walkDirectory(root, depth):
pathList = [] pathList = []
#print("Walking directory '{}'".format(root)) logging.debug("Walking directory '{}'".format(root))
def do_scan(start_dir,output,depth=2): def do_scan(start_dir,output,depth=2):
for f in os.listdir(start_dir): for f in os.listdir(start_dir):
ff = os.path.join(start_dir,f) ff = os.path.join(start_dir,f)
@ -73,10 +74,10 @@ def getSongObjects():
for inputFolder in configObj['inputfolders'].split(','): for inputFolder in configObj['inputfolders'].split(','):
for filePath in walkDirectory(inputFolder, recursionDepth): for filePath in walkDirectory(inputFolder, recursionDepth):
if ((filePath[filePath.find('.'):] == ".txt" ) and configObj['readtxt'] == '1') or ((filePath[filePath.find('.'):] == ".rawtxt" ) and configObj['readraw'] == '1'): if ((filePath[filePath.find('.'):] == ".txt" ) and configObj['readtxt'] == '1') or ((filePath[filePath.find('.'):] == ".rawtxt" ) and configObj['readraw'] == '1'):
#print("Found supported file '{}'".format(filePath)) logging.debug("Found supported file '{}'".format(filePath))
txtFileLocations.append(filePath) txtFileLocations.append(filePath)
#else: else:
#print("Skipping file '{}' for it is not a supported file".format(filePath)) logging.debug("Skipping file '{}' for it is not a supported file".format(filePath))
# create list of Song objects # create list of Song objects
while(txtFileLocations): while(txtFileLocations):
filePath = txtFileLocations.pop() filePath = txtFileLocations.pop()

45
main.py
View File

@ -14,11 +14,7 @@
# as best as it can, shrinking or growing sections to fit the remaining space # as best as it can, shrinking or growing sections to fit the remaining space
# #
# @section notes Notes # @section notes Notes
# - Splitting raw text into lyric and tablature info is very basic at the moment. # -
# We need a better way to classify & split the various channels (raw tab, lyrics, chords, more?) that can be expected in tablature
#
# @section todo TODO
# - Various prints should be printed at specific log levels, to easily switch between debug, info or warnings only
import lib.chordFinder import lib.chordFinder
import lib.dataStructures import lib.dataStructures
@ -27,6 +23,7 @@ import lib.transpose
import lib.config import lib.config
import output2img import output2img
import output2txt import output2txt
import logging
def main(): def main():
# Init config file # Init config file
@ -39,34 +36,53 @@ def main():
exportToTxt = configObj['exporttotxt'] == '1' exportToTxt = configObj['exporttotxt'] == '1'
exportToRaw = configObj['exporttoraw'] == '1' exportToRaw = configObj['exporttoraw'] == '1'
logLevel = int(configObj['loglevel'])
if logLevel == 1:
logLevel = logging.CRITICAL
elif logLevel == 2:
logLevel = logging.ERROR
elif logLevel == 3:
logLevel = logging.WARNING
elif logLevel == 4:
logLevel = logging.INFO
else:
logLevel = logging.DEBUG
logging.basicConfig()
logging.root.setLevel(logLevel)
logging.debug('Starting')
for song in songs:
logging.info("Found song '{}' at '{}'".format(song.title, song.inputFile))
# Convert all songs into sections # Convert all songs into sections
for song in songs: for song in songs:
print("Start parsing of file '{}'...".format(song.inputFile)) logging.info("Start parsing song '{}'...".format(song.title))
# Initialise internal data structures # Initialise internal data structures
print("song file extension {}".format(song.fileExtension)) logging.debug("song file extension {}".format(song.fileExtension))
if song.fileExtension == 'txt': if song.fileExtension == 'txt':
song.initSections() song.initSections()
elif song.fileExtension == 'rawtxt': elif song.fileExtension == 'rawtxt':
song.initPreprocessed() song.initPreprocessed()
else: else:
print("File extension '{}' not supported. Skipping...".format(song.fileExtension)) logging.warning("File extension '{}' not supported. Skipping...".format(song.fileExtension))
continue continue
# If input is .raw output. If output to raw is set, overwrite itself # If input is .raw output. If output to raw is set, overwrite itself
# ready quickly using rules # ready quickly using rules
if not song.isParsed: if not song.isParsed:
print("Song was not initialized correctly. Skipping...") logging.error("Song was not initialized correctly. Skipping...")
continue continue
if exportToTxt: if exportToTxt:
# Create subdirectory where we will output our images # Create subdirectory where we will output our images
targetDirectory = song.outputLocation + "-txt" targetDirectory = song.outputLocation + "-txt"
print("Successfully parsed file. Writing output to '{}'\n".format(targetDirectory)) logging.info("Successfully parsed file. Writing output to '{}'\n".format(targetDirectory))
# Write out metadata and sections, as many as can fit on one page # Write out metadata and sections, as many as can fit on one page
output2txt.outputToTxt(targetDirectory, False, song) output2txt.outputToTxt(targetDirectory, False, song)
if exportToRaw: if exportToRaw:
# Create subdirectory where we will output our images # Create subdirectory where we will output our images
targetDirectory = song.outputLocation + "-txt" targetDirectory = song.outputLocation + "-txt"
print("Successfully parsed file. Writing output to '{}'\n".format(targetDirectory)) logging.info("Successfully parsed file. Writing output to '{}'\n".format(targetDirectory))
# Write out metadata and sections, as many as can fit on one page # Write out metadata and sections, as many as can fit on one page
output2txt.outputToTxt(targetDirectory, True, song) output2txt.outputToTxt(targetDirectory, True, song)
if exportToImg: if exportToImg:
@ -76,11 +92,11 @@ def main():
song.sectionsToPages() song.sectionsToPages()
# Optimalisation: try to fill whitespace # Optimalisation: try to fill whitespace
while len(song.pages) > song.maxPages: while len(song.pages) > song.maxPages:
print("Resizing down since we have {} pages and want {} pages".format(len(song.pages), song.maxPages)) logging.debug("Resizing down since we have {} pages and want {} pages".format(len(song.pages), song.maxPages))
song.resizeAllSections(-1) song.resizeAllSections(-1)
song.sectionsToPages() song.sectionsToPages()
while song.canFillWhitespace(): while song.canFillWhitespace():
print("Resizing down to fill remaining vertical whitespace") logging.debug("Resizing down to fill remaining vertical whitespace")
song.resizeAllSections(-1) song.resizeAllSections(-1)
song.sectionsToPages() song.sectionsToPages()
# Optimalisation: increase font size to fit target page amount # Optimalisation: increase font size to fit target page amount
@ -88,9 +104,10 @@ def main():
# Parse as PNG a4 # Parse as PNG a4
# Create subdirectory where we will output our images # Create subdirectory where we will output our images
targetDirectory = song.outputLocation + "-a4-png" targetDirectory = song.outputLocation + "-a4-png"
print("Successfully parsed file. Writing output to '{}'\n".format(targetDirectory)) logging.info("Successfully parsed file. Writing output to '{}'\n".format(targetDirectory))
# Write out metadata and sections, as many as can fit on one page # Write out metadata and sections, as many as can fit on one page
output2img.outputToImage(targetDirectory, song) output2img.outputToImage(targetDirectory, song)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
logging.debug('Finished')

View File

@ -11,11 +11,10 @@
# @section notes Notes # @section notes Notes
# - # -
# #
# @section todo TODO
# - Various prints should be printed at specific log levels, to easily switch between debug, info or warnings only
import os import os
from PIL import Image, ImageDraw from PIL import Image, ImageDraw
import logging
"""!@brief Exports the song object to images """!@brief Exports the song object to images
This function renders the metadata and sections This function renders the metadata and sections
@ -30,9 +29,9 @@ def outputToImage(folderLocation, songObj):
# Create target Directory if doesn't exist # Create target Directory if doesn't exist
if not os.path.exists(folderLocation): if not os.path.exists(folderLocation):
os.mkdir(folderLocation) os.mkdir(folderLocation)
print("Directory " , folderLocation , " Created ") logging.info("Directory {} Created ".format(folderLocation))
#else: else:
#print("Directory " , folderLocation , " already exists") logging.debug("Directory {} already exists".format(folderLocation))
# Init image info # Init image info
imageNumber = 1 imageNumber = 1
@ -54,7 +53,7 @@ def outputToImage(folderLocation, songObj):
line = line.rstrip() line = line.rstrip()
if not line and not songObj.keepEmptyLines: if not line and not songObj.keepEmptyLines:
continue continue
#print("meta line '{}'".format(line)) logging.debug("Metadata '{}'".format(line))
metadataTextWidth, metadataTextHeight = songObj.fontMetadata.getsize(line) metadataTextWidth, metadataTextHeight = songObj.fontMetadata.getsize(line)
draw.text((horizontalMargin, currentHeight), line, fill=songObj.metadataColour, font=songObj.fontMetadata) draw.text((horizontalMargin, currentHeight), line, fill=songObj.metadataColour, font=songObj.fontMetadata)
currentHeight += metadataTextHeight currentHeight += metadataTextHeight
@ -67,10 +66,10 @@ def outputToImage(folderLocation, songObj):
lineIterator = 0 lineIterator = 0
amountOfLines = len(section.lyrics) amountOfLines = len(section.lyrics)
if (amountOfLines != len(section.tablatures)): if (amountOfLines != len(section.tablatures)):
print("Cannot write this section to file, since it was not processed correctly. There are {} tablature lines and {} lyric lines. Aborting...".format(len(section.chords), amountOfLines)) logging.critical("Cannot write this section to file, since it was not processed correctly. There are {} tablature lines and {} lyric lines. Aborting...".format(len(section.chords), amountOfLines))
return return
if (section.expectedHeight == -1 or section.expectedWidth == -1): if (section.expectedHeight == -1 or section.expectedWidth == -1):
print("Cannot write this section to file, since it was not processed correctly. The expected dimensions are not set. Aborting...") logging.critical("Cannot write this section to file, since it was not processed correctly. The expected dimensions are not set. Aborting...")
return return
# write section title # write section title
headerWidth, headerHeight = songObj.fontTablature.getsize(section.header) headerWidth, headerHeight = songObj.fontTablature.getsize(section.header)
@ -78,7 +77,7 @@ def outputToImage(folderLocation, songObj):
currentHeight += headerHeight currentHeight += headerHeight
# Write each line tablature&lyric data # Write each line tablature&lyric data
while lineIterator < amountOfLines: while lineIterator < amountOfLines:
#print("Printing tablatures line {} and lyrics line {}".format(section.tablatures[lineIterator], section.lyrics[lineIterator])) logging.debug("Printing tablatures line {} and lyrics line {}".format(section.tablatures[lineIterator], section.lyrics[lineIterator]))
# Get tablatures&lyric line # Get tablatures&lyric line
lyricTextWidth, lyricTextHeight = songObj.fontLyrics.getsize(section.lyrics[lineIterator]) lyricTextWidth, lyricTextHeight = songObj.fontLyrics.getsize(section.lyrics[lineIterator])
tablatureTextWidth, tablatureTextHeight = songObj.fontTablature.getsize(section.tablatures[lineIterator]) tablatureTextWidth, tablatureTextHeight = songObj.fontTablature.getsize(section.tablatures[lineIterator])
@ -88,7 +87,7 @@ def outputToImage(folderLocation, songObj):
draw.text((horizontalMargin ,currentHeight), section.lyrics[lineIterator], fill=songObj.fontColour, font=songObj.fontLyrics) draw.text((horizontalMargin ,currentHeight), section.lyrics[lineIterator], fill=songObj.fontColour, font=songObj.fontLyrics)
currentHeight += lyricTextHeight currentHeight += lyricTextHeight
lineIterator += 1 lineIterator += 1
#print("currentheight={}".format(currentHeight)) logging.debug("currentheight={}".format(currentHeight))
# If we stripped al whitespace, we need to add whitespace between sections # If we stripped al whitespace, we need to add whitespace between sections
if not songObj.keepEmptyLines: if not songObj.keepEmptyLines:
currentHeight += songObj.verticalMargin currentHeight += songObj.verticalMargin

View File

@ -8,13 +8,9 @@
# Generates PNG images of a specific dimension (currently A4) of tablature data # Generates PNG images of a specific dimension (currently A4) of tablature data
# Dynamically resizes specific sections to maximize using the entire paper (and avoid awkward page flips) # Dynamically resizes specific sections to maximize using the entire paper (and avoid awkward page flips)
# #
# @section notes Notes
# -
#
# @section todo TODO
# - Various prints should be printed at specific log levels, to easily switch between debug, info or warnings only
import os import os
import logging
"""!@brief Exports the song object to a txt file """!@brief Exports the song object to a txt file
Perfect to use as source file for any program which requires Perfect to use as source file for any program which requires
@ -34,9 +30,9 @@ def outputToTxt(folderLocation, printRaw, songObj):
# Create target Directory if doesn't exist # Create target Directory if doesn't exist
if not os.path.exists(folderLocation): if not os.path.exists(folderLocation):
os.mkdir(folderLocation) os.mkdir(folderLocation)
print("Directory " , folderLocation , " Created ") logging.info("Directory {} Created ".format(folderLocation))
#else: else:
#print("Directory " , folderLocation , " already exists") logging.debug("Directory {} already exists".format(folderLocation))
output = "" output = ""
emptyLines = [] emptyLines = []
@ -51,7 +47,7 @@ def outputToTxt(folderLocation, printRaw, songObj):
# remove any unwanted characters from metadata # remove any unwanted characters from metadata
if not songObj.keepEmptyLines and not line: if not songObj.keepEmptyLines and not line:
continue continue
#print("meta line '{}'".format(line)) logging.debug("Metadata '{}'".format(line))
output += line output += line
metadataLines.append(lineCounter) metadataLines.append(lineCounter)
lineCounter += 1 lineCounter += 1
@ -67,7 +63,7 @@ def outputToTxt(folderLocation, printRaw, songObj):
lineIterator = 0 lineIterator = 0
amountOfLines = len(section.lyrics) amountOfLines = len(section.lyrics)
if (amountOfLines != len(section.tablatures)): if (amountOfLines != len(section.tablatures)):
print("Cannot write this section to file, since it was not processed correctly. There are {} tablature lines and {} lyric lines. Aborting...".format(len(section.chords), amountOfLines)) logging.critical("Cannot write this section to file, since it was not processed correctly. There are {} tablature lines and {} lyric lines. Aborting...".format(len(section.chords), amountOfLines))
return return
# write section title # write section title
output += section.header.rstrip() + '\r\n' output += section.header.rstrip() + '\r\n'