Skip to content

Project Structure

Joe Schmitt edited this page Jun 28, 2017 · 10 revisions

Libby is a NodeJS function written to be deployed as an Amazon Lambda function in response to events from the Alexa Skills Kit SDK.

Source Files

The project source files are contained in the src/ directory. All source files are written in ES6/ES2017, and compiled down to code that can run on the version of NodeJS on Lambda using Babel. Babel outputs the compiled js files to the dist/ directory, and it is this directory that is actually pointed to whenever the application runs.

Babel will automatically compile the current source whenever you run npm install, as well as whenever you run unit tests using npm test, whenever you test your changes using npm start, as well as when you package the app using npm run package. If you'd like to manually run this compilation step outside of these scenarios, you can do so by running the build script using npm run build.

API

The API directory contains the necessary modules needed for communicating with the various PVR providers.

Glossary of Terms

  • Provider: A provider is the PVR service being used to track movies and TV shows, for example Sonarr or Couch Potato.
  • Provider Type: Movies or TV Shows. A provider type is linked to a single provider, so that the application can request the API for "movies" and it'll get the correct PVR provider.

API Modules

  • config.js: This module is responsible for reading the configuration settings set in the config JSON files. It also handles inheriting server settings in all of the providers. It exports a function that simply returns a JSON object with the config needed to initialize an API instance based on what provider
  • getProvider.js: This module is responsible for returning the correct instance of an API provider given a provider type. You give it a type such as "movies", and it'll return the correct API service used to load movies from your PVR server based on the config file.
  • index.js This lists the currently active API providers that are available. If the API isn't listed here, it's not supported. The keys here must match the value set in the config, so if you're trying to add a new PVR provider, keep that in mind.

The rest of the files in this directory are the individual API provider modules. They all conform to the same Interface, meaning they all have the exact same list of functions and return the exact same structured data. This allows the rest of the code to not care if it's calling "search" on Couch Potato or Radarr, it just cares that it gets back an Object with a title. All API provider modules must expose the following functions:

  1. default -- The default function returns an instance of the API provider. This is mostly used internally.
  2. list -- The list function simply lists out the media currently available on the PVR server. It takes an optional parameter which allows you to filter the list by title.
  3. search -- The search function searches for new media not currently on the PVR server. It takes a query parameter.
  4. add -- The add function adds new media to the PVR server.

Handlers

The handler functions are responsible for handling the various intents it receives from Amazon. Each function exported from a handler module maps to a specific intent request from the ASK request.

The handlers are grouped into 3 different types:

General

The general handlers handle things such as the Welcome and Help intents, as well as what to do when the user says "Yes", "No", or "Cancel".

Movies

The movie handlers handle the intents for adding and finding a movie.

Shows

The shows handlers handle the intents for adding and finding tv shows.

The handlers are the meat and potatoes of this project, and is where the majority of the exciting logic goes. They're also the most important to be well unit-tested, as they directly affect what users see and hear from Alexa.

Responses

The response functions are helper functions intended to centralize what our skill actually responds with when it receives an intent request. The Responses are broken down into the exact same types as the handlers: general, movies, and shows.

The responses themselves are actually tagged template functions. This means that when using them, you have to call them as a function instead of just using them directly like you would a string. The reason for this is they take dynamic variables in their responses, such as the movie name or release date. So instead of simply responding with ADD_NOT_FOUND, we respond with ADD_NOT_FOUND('The Dark Knight'), which turns into: "No movie found for The Dark Knight".

Lib

This directory contains generic library helper functions used through the application. Any reusable code that isn't related to API, Handlers, or Responses should go in here.

Models

The models/ contains files used to generate the Interaction Models the ASK uses to interpret what you've asked Alexa to do. The primary way this works is through the use of sample utterances, which are phrases you provide to Alexa that shows how you should parse what the user is asking for.

Alexa works best by giving it as many different phrases and wordings as possible. Since it can get wholly unmanageable to hand-write a bunch of variations of the same phrases, we instead use the alexa-utterances project to take a model template and use it to generate a huge list of sample utterances. The template model used to generate each slot can be found in models/schemas/. Contributions to these models is highly encouraged, as the more variation we have the more accurate Alexa will be.

After you make changes to the models, run npm run gen-interaction to output the changes into the interaction_model directory. Always make sure to commit these newly generated files alongside your model changes, as some people might only copy these from the Github page and not from their locally downloaded directory.

Unit Tests