#!/usr/bin/env python3 from contextlib import contextmanager from datetime import datetime import locale from pathlib import Path import re from sys import argv from helpers import guess_language, read_concerts, relative_path # TODO: change some jargon: # - event => concert # - canceled => warning def split_concerts(concerts, threshold): cutoff = len(concerts) for i, c in enumerate(concerts): if c.time > threshold: cutoff = i break return reversed(concerts[:cutoff]), concerts[cutoff:] 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 = '''\
{pic_alt}

{summary}

{credits}
\ ''' @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'' 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])