Source code for examples.halliwell

"""Example aSlack bot to give you information on movies."""
import re
from textwrap import dedent

import asyncio

from atmdb import TMDbClient
from atmdb.utils import find_overlapping_actors, find_overlapping_movies

from aslack import __version__ as aslack_version
from aslack.slack_bot import SlackBot, BotMessageHandler


QUOTED = re.compile(r'"([^"]+)"')
"""Regular expression to extract quoted text."""


[docs]class ActorOverlapQueryHandler(BotMessageHandler): """Handles queries about movies with the same group of actors. If you send me a message asking 'actors in' with a quoted list of movies I will find movies featuring all of those actors. """ PHRASE = 'actors in' async def __anext__(self): if not self.text: raise StopAsyncIteration titles = QUOTED.findall(self.text) self.text = None try: people = await find_overlapping_actors(titles, self.bot.tmdb_client) except ValueError as err: return err.args[0] if not people: return 'No actors found.' return '\n\n'.join(['Results found:'] + [ ' - {0.name} [{0.url}]'.format(person) for person in people ])
[docs]class MovieOverlapQueryHandler(BotMessageHandler): """Handles queries about actors in the same group of movies. If you send me a message asking 'movies with' with a quoted list of actors I will find movies featuring all of those actors. """ PHRASE = 'movies with' async def __anext__(self): if not self.text: raise StopAsyncIteration names = QUOTED.findall(self.text) self.text = None try: movies = await find_overlapping_movies(names, self.bot.tmdb_client) except ValueError as err: return err.args[0] if not movies: return 'No movies found.' return '\n\n'.join(['Results found:'] + [ ' - {0.title} [{0.url}]'.format(movie) for movie in movies ])
[docs]class MovieQueryHandler(BotMessageHandler): """Handles queries about specific movies. If you send me a message starting with the word 'movie' I will tell you about that movie. """ PHRASE = 'movie' async def __anext__(self): if self.text is None: raise StopAsyncIteration title = self.text.split(' ', maxsplit=2)[-1] self.text = None movies = await self.bot.tmdb_client.find_movie(title) if movies: return str(movies[0]) return 'No movies found matching {!r}'.format(title)
[docs]class PersonQueryHandler(BotMessageHandler): """Handles queries about specific people. If you send me a message starting with the word 'person' I will tell you about that person. """ PHRASE = 'person' async def __anext__(self): if self.text is None: raise StopAsyncIteration name = self.text.split(' ', maxsplit=2)[-1] self.text = None people = await self.bot.tmdb_client.find_person(name) if people: return str(people[0]) return 'No people found matching {!r}'.format(name)
[docs]class Halliwell(SlackBot): """The filmgoer's companion. Arguments: id_ (:py:class:`str`): The BOT's Slack ID. user (:py:class:`str`): The BOT's friendly name. api (:py:class:`~.SlackApi`): The Slack API wrapper. tmdb_client (:py:class:`atmdb.client.TMDbClient`): The TMDb client. """ INSTRUCTIONS = dedent(""" Halliwell: The filmgoer's companion. An aSlack and aTMDb BOT running on Cloud Foundry. For more information, see https://github.com/textbook/aslack. """) MESSAGE_FILTERS = [ ActorOverlapQueryHandler, MovieOverlapQueryHandler, MovieQueryHandler, PersonQueryHandler, ] VERSION = 'Halliwell v0.3.0 (aSlack v{})'.format(aslack_version) def __init__(self, id_, user, api, tmdb_client=None): super().__init__(id_, user, api) if tmdb_client is None: tmdb_client = TMDbClient.from_env() self.tmdb_client = tmdb_client
if __name__ == '__main__': # pylint: disable=wrong-import-position,wrong-import-order import logging import sys logging.basicConfig( datefmt='%Y/%m/%d %H.%M.%S', format='%(levelname)s:%(name)s:%(message)s', level=logging.INFO, stream=sys.stdout, ) LOOP = asyncio.get_event_loop() BOT = LOOP.run_until_complete(Halliwell.from_api_token()) LOOP.run_until_complete(BOT.join_rtm())