Compare commits

..

1 Commits

Author SHA1 Message Date
a551fdf465
Enhance the HTML renderer
- Documenting rendering options in the HTML renderer
- Programmatically generate the styles easily
- Allow a group to be specified when getting the available options
- Create a get_option_groups() method to return the groups, which are now built dynamically
- Set a bunch of sane defaults
- Support additional markers in the chordpro file, and move to div-based HTML
- Add artist section
- Add key/capo section
2021-08-07 18:19:31 -07:00
2 changed files with 90 additions and 21 deletions

View File

@ -241,18 +241,33 @@ class Song(object):
elif Verse.is_verse_marker(line):
verse_name = Verse.get_verse_from_marker(line)
for verse in self.verses[::-1]:
if verse.title == verse_name or verse.type_ == "verse":
if verse.type_ != 'verse':
continue
if verse_name and verse.title == verse_name:
self.verse_order.append(verse)
break
elif not verse_name:
self.verse_order.append(verse)
break
elif Verse.is_chorus_marker(line):
chorus_name = Verse.get_chorus_from_marker(line)
for verse in self.verses[::-1]:
if verse.title == chorus_name or verse.type_ == "chorus":
if verse.type_ != 'chorus':
continue
if chorus_name and verse.title == chorus_name:
self.verse_order.append(verse)
break
elif not chorus_name:
self.verse_order.append(verse)
break
elif Verse.is_bridge_marker(line):
bridge_name = Verse.get_bridge_from_marker(line)
for verse in self.verses[::-1]:
if verse.title == bridge_name or verse.type_ == "bridge":
if verse.type_ != 'bridge':
continue
elif bridge_name and verse.title == bridge_name:
self.verse_order.append(verse)
break
elif not bridge_name:
self.verse_order.append(verse)
break

View File

@ -1,30 +1,37 @@
import os
# Tables -- don't work when rendered to PDF
# CHORD = '<td class="chord">{}</td>'
# SYLLB = '<td class="syllable">{}</td>'
# LINE = '<table class="line" border="0" cellpadding="0" cellspacing="0"><tr class="chords-line">{}</tr><tr ' \
# 'class="lyrics-line">{}</tr></table>'
# Divs
CHORD = '<div class="chord">{}</div>'
SYLLB = '<div class="syllable">{}</div>'
WRAPP = '<div class="wrapper">{}</div>'
LINE = '<div class="line">{}</div>'
STANZA = '''<section class="stanza-section {verse_type}-section">
<h4 class="stanza-heading {verse_type}-heading">{verse_name}</h4>
<h2 class="stanza-heading {verse_type}-heading">{verse_name}</h2>
<div class="stanza {verse_type}">
{verse_body}
</div>
</section>'''
TITLE = '<section class="metadata"><h1 class="title">{title}</h1><h3 class="composer">{composer}</h3></section>'
METADATA = '''<section class="metadata">
{metadata}
</section>'''
TITLE = '<h1 class="title">{title}</h1>'
ARTIST = '<p class="artist">As performed by {artist}</p>'
COMPOSER = '<p class="composer">Written by {composer}</p>'
KEY_CAPO = '<div class="key-capo">{key_capo}</div>'
KEY = '<div class="key">Key: {key}</div>'
CAPO = '<div class="capo">Capo: {capo}</div>'
COPYRIGHT = '<p class="copyright">{copyright}</p>'
FOOTER = '<footer class="footer">{footer}</footer>'
HTML = '''<html>
<head>
<title>{title}</title>
<style>
h1.title, h3.composer, h4.stanza-heading {{ font-weight: normal; }}
h4.stanza-heading {{ margin-bottom: 0; }}
.stanza-section {{ margin-bottom: 2rem; page-break-inside: avoid; }}
h1.title, h2.stanza-heading, p.composer, p.artist {{ font-weight: normal; margin-top: 0; margin-bottom: 0; }}
.metadata, .stanza-section {{ margin-bottom: 1.8rem; page-break-inside: avoid; }}
.key-capo {{ padding: 0.5rem 1rem; border: 1px solid #000; border-radius: 2px; float: right; clear: right; }}
.key-capo div {{ margin-top: 0.5rem; margin-bottom: 0.5rem; }}
.key-capo div:first-child {{ margin-top: 0; }}
.key-capo div:last-child {{ margin-bottom: 0; }}
footer, .footer {{ position: absolute; bottom: 0; height: 2rem; }}
.wrapper {{ display: inline-block !important; }}
{styles}
</style>
@ -114,6 +121,36 @@ HTML_OPTIONS = {
'default': False,
'group': 'composer'
},
'artist_font': {
'description': 'The font for the artist',
'type': str,
'default': None,
'group': 'artist'
},
'artist_size': {
'description': 'The size of the artist in pt',
'type': int,
'default': 12,
'group': 'artist'
},
'artist_is_bold': {
'description': 'Set to True to make the artist bold',
'type': bool,
'default': False,
'group': 'artist'
},
'artist_is_centered': {
'description': 'Center the artist on the page',
'type': bool,
'default': False,
'group': 'artist'
},
'artist_is_upper': {
'description': 'Force the artist to be uppercase',
'type': bool,
'default': False,
'group': 'artist'
},
'copyright_font': {
'description': 'The font for the copyright',
'type': str,
@ -415,6 +452,7 @@ def generate_option_styles(options):
def render(song, options=None, extra_styles=None):
"""Render a song to HTML"""
nl = os.linesep
styles = options and generate_option_styles(options) or []
if extra_styles:
styles.append(extra_styles)
@ -434,9 +472,25 @@ def render(song, options=None, extra_styles=None):
rendered_syllables.append(WRAPP.format(rendered_chord + rendered_syllable))
rendered_lines.append(LINE.format(''.join(rendered_syllables)))
rendered_verses.append(STANZA.format(verse_type=verse.type_ or '', verse_name=verse.title,
verse_body='\n'.join(rendered_lines)))
title = song.metadata.get('title') or 'Song'
metadata = TITLE.format(title=title, composer=song.metadata.get('artist') or
song.metadata.get('composer') or '')
body = metadata + '\n' + '\n'.join(rendered_verses)
return HTML.format(title=title, body=body, styles=os.linesep.join(styles))
verse_body=nl.join(rendered_lines)))
metadata_lines = []
if song.metadata.get('key') or song.metadata.get('capo'):
key_lines = []
if song.metadata.get('key'):
key_lines.append(KEY.format(key=song.metadata.get('key')))
if song.metadata.get('capo'):
key_lines.append(CAPO.format(capo=song.metadata.get('capo')))
if key_lines:
metadata_lines.append(KEY_CAPO.format(key_capo=''.join(key_lines)))
metadata_lines.append(TITLE.format(title=song.metadata.get('title') or 'Song'))
if song.metadata.get('composer'):
metadata_lines.append(COMPOSER.format(composer=song.metadata.get('composer')))
if song.metadata.get('artist'):
metadata_lines.append(ARTIST.format(artist=song.metadata.get('artist')))
metadata = METADATA.format(metadata=nl.join(metadata_lines))
footer = ''
# if song.metadata.get('copyright'):
# copyright = COPYRIGHT.format(copyright=song.metadata.get('copyright'))
# footer = FOOTER.format(footer=copyright)
body = metadata + nl + nl.join(rendered_verses) + nl + footer
return HTML.format(title=song.metadata.get('title') or 'Song', body=body, styles=nl.join(styles))