[^\n]+)\n'),
)
CONCERT_RE = re.compile(''.join(CONCERT_LINES), flags=re.DOTALL)
def guess_language(filename):
parent = str(Path(filename).parent)
if parent == '.':
return 'fr'
return parent
def read_concerts(filename):
with open(filename) as f:
concerts = (
Concert.deserialize(match)
for match in re.finditer(CONCERT_RE, f.read())
)
return tuple(sorted(concerts, key=attrgetter('time')))
def split_concerts(concerts, threshold):
for i, c in enumerate(concerts):
if c.time > threshold:
return concerts[:i], concerts[i:]
return concerts, ()
LOCALIZED_TEXT = {
'en': {
'past': 'Past concerts',
'next': 'Next concerts',
'alt': 'Illustration:',
'hint': 'Click on a concert to obtain more information.',
},
'fr': {
'past': 'Concerts passés',
'next': 'Prochains concerts',
'alt': 'Illustration :',
'hint': "Cliquez sur un concert pour obtenir plus d'informations.",
}
}
THUMBNAILS_TEMPLATE = '''\
{heading}
{thumbnails}
\
'''
THUMBNAIL_TEMPLATE = '''\
\
'''
@contextmanager
def tmplocale(lang):
old_lang, encoding = locale.getlocale()
try:
locale.setlocale(locale.LC_TIME, (lang, encoding))
yield
finally:
locale.setlocale(locale.LC_TIME, (old_lang, encoding))
def format_credits(illustration):
credits = illustration.source_name
if illustration.source_link is not None:
credits = (f''
f'{illustration.source_name}'
'')
if illustration.license_info is not None:
credits += ' / ' + illustration.license_info.format()
return credits
def format_thumbnail(concert, imgdir, lang):
eventclasses = ('event',)
with tmplocale(lang):
day = f'{concert.time.day} {concert.time.strftime("%B %Y")}'
summary = f'{concert.place}
{day}'
if concert.warning is not None:
eventclasses += ('canceled',)
summary = (f'{concert.warning}\n'
f' {summary}')
alt_prefix = LOCALIZED_TEXT[lang]['alt']
return THUMBNAIL_TEMPLATE.format_map({
'eventclasses': ' '.join(eventclasses),
'eventid': f'concert-{concert.time.strftime("%F")}',
'pic_file': Path(imgdir, 'concerts', concert.illustration.file),
'pic_alt': f'{alt_prefix} {concert.illustration.alt_text}',
'summary': summary,
'credits': format_credits(concert.illustration)
})
def print_thumbnails_section(concerts, imgdir, section, lang):
if not concerts:
return
thumbnails = '\n'.join(
format_thumbnail(c, imgdir, lang) for c in concerts
)
print(THUMBNAILS_TEMPLATE.format(heading=LOCALIZED_TEXT[lang][section],
time=section,
thumbnails=thumbnails))
def print_thumbnails(concerts, imgdir, lang):
today = datetime.fromordinal(
datetime.today().date().toordinal()
)
past_concerts, next_concerts = split_concerts(concerts, today)
print('')
print_thumbnails_section(next_concerts, imgdir, 'next', lang)
print_thumbnails_section(past_concerts, imgdir, 'past', lang)
print('
')
DETAILS_TEMPLATE = '''\
{details}
\
'''
DATE_FORMATTERS = {
'en': {
'date': lambda d: d.strftime('%A %B %-d, %Y'),
'time': lambda d: d.strftime('%I:%M %p'),
},
'fr': {
'date': lambda d: d.strftime('%A %-d %B %Y').capitalize(),
'time': lambda d: d.strftime('%Hh%M'),
},
}
def detail_block(tag, classes, content):
opener = f'<{tag} class="{" ".join(classes)}">'
closer = f'{tag}>'
if isinstance(content, str):
return f' {opener}{content}{closer}'
return '\n'.join((
' '+opener,
*(' '+line for line in content),
' '+closer,
))
def break_lines(lines):
return tuple(line+'
' for line in lines[:-1]) + (lines[-1],)
TOUCHUPS = (
(re.compile('([0-9])(st|nd|rd|th|er|ère|nde|ème)'), r'\1\2'),
(re.compile('(https://[^ ]+)'), r'\1'),
(re.compile('([^ ]+@[^ ]+)'), r'\1'),
)
def touchup_plaintext(plaintext):
text = plaintext
for regexp, repl in TOUCHUPS:
text = regexp.sub(repl, text)
return text
def print_concert_details(concert, lang):
concert_id = f'concert-{concert.time.strftime("%F")}'
classes = ('details',)
blocks = []
if concert.warning is not None:
classes += ('canceled',)
blocks.append(
detail_block('p', ('canceled',), concert.warning)
)
with tmplocale(lang):
day = DATE_FORMATTERS[lang]['date'](concert.time)
hour = DATE_FORMATTERS[lang]['time'](concert.time)
address_lines = break_lines(concert.address.splitlines())
piece_list = tuple(
f'{touchup_plaintext(line)}'
for line in concert.pieces.splitlines()
)
blocks.extend((
detail_block('p', ('detail', 'date'), day),
detail_block('p', ('detail', 'time'), hour),
detail_block('p', ('detail', 'place'), address_lines),
detail_block('ol', ('detail', 'program'), piece_list),
))
instructions = [
f' {touchup_plaintext(line)}
'
for line in concert.instructions.splitlines()
]
print(f' ')
print('\n'.join(blocks+instructions))
print('
')
def print_details(concerts, lang):
print('')
print(f'
{LOCALIZED_TEXT[lang]["hint"]}
')
for c in concerts:
print_concert_details(c, lang)
print('
')
def main(concerts_src):
imgdir = relative_path(to='images', ref=concerts_src)
lang = guess_language(concerts_src)
concerts = read_concerts(concerts_src)
print_thumbnails(concerts, imgdir, lang)
print_details(concerts, lang)
if __name__ == '__main__':
main(argv[1])