Commit ccd1c5f0 authored by Simon Will's avatar Simon Will
Browse files

Look up band info in Metal Archives

parent 5300becd
Loading
Loading
Loading
Loading
+103 −12
Original line number Diff line number Diff line
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from itertools import chain
import re
from typing import Sequence

from flask import Flask
from flask_ask import Ask, statement
import jinja2
import metallum

app = Flask(__name__)
ask = Ask(app, '/')

@ask.intent('BandLookup')
def hello(bandName):
    if bandName == 'darkthrone':
        genre = 'Black Metal'
    elif bandName == 'joy division':
        genre = 'Post Punk'

def starts_with_vowel(s: str) -> bool:
    return s and s[0].lower() in {'a', 'e', 'i', 'o', 'u'}


def format_genres(genres: Sequence[str]) -> str:
    cleaned_genres = []
    for i, genre in enumerate(genres):
        cleaned_genres.append(genre.replace(' (early)', '')
                              .replace(' (mid)', '')
                              .replace(' (later)', ''))
        if i == len(genres) - 1:
            # Don’t append comma or “and” after the last genre.
            pass
        elif i == len(genres) - 2:
            # Append “and” after the last genre.
            cleaned_genres.append('and')
        else:
        genre = None
            cleaned_genres.append(',')

    if len(cleaned_genres) == 1:
        return cleaned_genres[0]
    else:
        cleaned_genres[-2] = 'and'
        return ' '.join(cleaned_genres)


BAND_TEMPLATE = jinja2.Template(
    '''{% if band.genres | length == 1 %}
    {{ band.name }} is {{ 'an' if starts_with_vowel(band.genres[0]) else 'a' }} {{ band.genres[0] }} band from {{ band.country }}.
    {% else %}
    {{ band.name }} is a band from {{ band.country }} who have played {{ format_genres(band.genres) }}
    {% endif %}
    They formed in {{ band.formed_in }} and
    {% if band.status == 'Active' %}
    are still active.
    {% else %}
    are not active, any more.
    {% endif %}
    '''
)

BAND_RESULTS_TEMPLATE = jinja2.Template(
    '''There are {{ band_results | length }} bands called {{ band_results[0].name }}:
    {% for result in band_results %}
    A band from {{ result.country }} playing {{ format_genres(result.genres) }}.
    {% endfor %}
    '''
)

DEFAULT_ENVIRONMENT = {'format_genres': format_genres,
                       'starts_with_vowel': starts_with_vowel}

    if genre:
        speech_text = '{} is a {} band.'.format(bandName, genre)

def render_template(template, **env):
    final_env = {k: v for k, v in chain(DEFAULT_ENVIRONMENT.items(),
                                        env.items())}
    return template.render(**final_env)


def describe_band(band: metallum.Band) -> str:
    rendered = render_template(BAND_TEMPLATE, band=band)
    with_cleaned_whitespace = re.sub(r'\s+', ' ', rendered).strip()
    return with_cleaned_whitespace


def name_bands(band_results: Sequence[metallum.BandResult]) -> str:
    rendered = render_template(BAND_RESULTS_TEMPLATE,
                               band_results=band_results)
    with_cleaned_whitespace = re.sub(r'\s+', ' ', rendered).strip()
    return with_cleaned_whitespace


def say_number_of_bands(band_results: Sequence[metallum.BandResult]) -> str:
    return ('There are {} bands called {}.'
            .format(len(band_results), band_results[0].name))


def band_lookup(band_name: str) -> str:
    search_results = metallum.band_search(band_name)
    if len(search_results) == 0:
        response = ('I don’t know anything about the band {}, sorry.'
                    .format(band_name))
    elif len(search_results) == 1:
        band = search_results[0].get()
        response = describe_band(band)
    elif len(search_results) < 5:
        response = name_bands(search_results)
    else:
        speech_text = 'I don’t know anything about {}, sorry.'.format(
            bandName)
        response = say_number_of_bands(search_results)
    return response


@ask.intent('BandLookup')
def band_lookup_endpoint(bandName: str) -> statement:
    response = band_lookup(bandName)
    return statement(response).simple_card('BandLookup', response)

    return statement(speech_text).simple_card('Hello', speech_text)

if __name__ == '__main__':
    app.run()