Skip to content

Instantly share code, notes, and snippets.

@mlapida
Last active December 7, 2017 08:00
Show Gist options
  • Select an option

  • Save mlapida/22162294400b18a63c6c to your computer and use it in GitHub Desktop.

Select an option

Save mlapida/22162294400b18a63c6c to your computer and use it in GitHub Desktop.

Revisions

  1. Michael Lapidakis renamed this gist Jan 29, 2016. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. Michael Lapidakis revised this gist Dec 29, 2015. 2 changed files with 0 additions and 32 deletions.
    23 changes: 0 additions & 23 deletions IntentSchema.json
    Original file line number Diff line number Diff line change
    @@ -1,23 +0,0 @@
    {
    "intents": [
    {
    "intent": "Plex"
    },
    {
    "intent": "Download"
    },
    {
    "intent": "OnDeck"
    },
    {
    "intent": "AMAZON.HelpIntent"
    },
    {
    "intent": "AMAZON.StopIntent"
    },
    {
    "intent": "AMAZON.CancelIntent"
    }
    ]
    }

    9 changes: 0 additions & 9 deletions SampleUtterance.txt
    Original file line number Diff line number Diff line change
    @@ -1,9 +0,0 @@
    Plex what is on deck
    Plex what can I watch tonight

    OnDeck what is on deck
    OnDeck what can I watch tonight

    Download what is new in downloads
    Download what has been downloaded recently
    Download list all downloads
  3. Michael Lapidakis revised this gist Dec 29, 2015. 2 changed files with 32 additions and 0 deletions.
    23 changes: 23 additions & 0 deletions IntentSchema.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    {
    "intents": [
    {
    "intent": "Plex"
    },
    {
    "intent": "Download"
    },
    {
    "intent": "OnDeck"
    },
    {
    "intent": "AMAZON.HelpIntent"
    },
    {
    "intent": "AMAZON.StopIntent"
    },
    {
    "intent": "AMAZON.CancelIntent"
    }
    ]
    }

    9 changes: 9 additions & 0 deletions SampleUtterance.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    Plex what is on deck
    Plex what can I watch tonight

    OnDeck what is on deck
    OnDeck what can I watch tonight

    Download what is new in downloads
    Download what has been downloaded recently
    Download list all downloads
  4. Michael Lapidakis revised this gist Dec 28, 2015. No changes.
  5. Michael Lapidakis revised this gist Dec 28, 2015. No changes.
  6. Michael Lapidakis created this gist Dec 25, 2015.
    279 changes: 279 additions & 0 deletions PlexToAlexa.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,279 @@
    from __future__ import print_function
    import urllib
    import urllib2
    import xml.etree.ElementTree
    import logging

    #enable basic logging to CloudWatch Logs
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)

    def lambda_handler(event, context):

    print("event.session.application.applicationId=" +
    event['session']['application']['applicationId'])

    #only run if requested by a specific app ID (past your app ID below)
    if (event['session']['application']['applicationId'] !=
    "amzn1.echo-sdk-ams.app.[AppIDHere]"):
    raise ValueError("Invalid Application ID")

    if event['session']['new']:
    on_session_started({'requestId': event['request']['requestId']},
    event['session'])

    if event['request']['type'] == "LaunchRequest":
    return on_launch(event['request'], event['session'])
    elif event['request']['type'] == "IntentRequest":
    return on_intent(event['request'], event['session'])
    elif event['request']['type'] == "SessionEndedRequest":
    return on_session_ended(event['request'], event['session'])


    def on_session_started(session_started_request, session):
    #called when the session starts

    #nothing to do here

    print("on_session_started requestId=" + session_started_request['requestId']
    + ", sessionId=" + session['sessionId'])


    def on_launch(launch_request, session):
    #called when the user launches the skill without specifying what they want

    print("on_launch requestId=" + launch_request['requestId'] +
    ", sessionId=" + session['sessionId'])
    # Dispatch to your skill's launch
    return get_welcome_response()


    def on_intent(intent_request, session):
    #called when the user specifies an intent for this skill

    print("on_intent requestId=" + intent_request['requestId'] +
    ", sessionId=" + session['sessionId'])

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']

    #Plex Credentials - Please Fill In
    username = "[username here]"
    password = "[password]"

    authKey = plex_login(username,password)

    # Dispatch to your skill's intent handlers
    if intent_name == "Plex":
    return plex_list_on_desk(intent, session, authKey)
    elif intent_name == "OnDeck":
    return plex_list_on_desk(intent, session, authKey)
    elif intent_name == "Download":
    return plex_list_download(intent, session, authKey)
    elif intent_name == "AMAZON.HelpIntent":
    return get_welcome_response()
    else:
    raise ValueError("Invalid intent")


    def on_session_ended(session_ended_request, session):
    #Called when the user ends the session

    print("on_session_ended requestId=" + session_ended_request['requestId'] +
    ", sessionId=" + session['sessionId'])
    # add cleanup logic here

    # --------------- Functions that control the skill's behavior ------------------


    def get_welcome_response():
    #the standard welcome message

    session_attributes = {}
    card_title = "Welcome"
    speech_output = "Welcome to the Plex Skill. " \
    "You can requet items on deck " \
    "or list downloads"
    # If the user either does not reply to the welcome message or says something
    # that is not understood, they will be prompted again with this text.
    reprompt_text = "Welcome to the Plex Skill. " \
    "You can requet items on deck " \
    "or list downloads"
    should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
    card_title, speech_output, reprompt_text, should_end_session))


    def plex_list_on_desk(intent, session, authKey):
    #return on deck TV shows

    card_title = intent['name']
    session_attributes = {}
    should_end_session = True

    #call the on deck function
    OnDeck = ret_on_deck(str(find_plex_server(authKey)),authKey)

    speech_output = OnDeck

    reprompt_text = OnDeck

    return build_response(session_attributes, build_speechlet_response(
    card_title, speech_output, reprompt_text, should_end_session))

    def plex_list_download(intent, session, authKey):
    #return recently downloaded

    card_title = intent['name']
    session_attributes = {}
    should_end_session = True

    #call the recently downloaded function
    OnDeck = ret_download(str(find_plex_server(authKey)),authKey)

    speech_output = OnDeck

    reprompt_text = OnDeck

    return build_response(session_attributes, build_speechlet_response(
    card_title, speech_output, reprompt_text, should_end_session))

    # --------------- Helpers that build all of the responses ----------------------

    def build_speechlet_response(title, output, reprompt_text, should_end_session):
    #creates the JSON payload for Alexa

    return {
    'outputSpeech': {
    'type': 'PlainText',
    'text': output
    },
    'card': {
    'type': 'Simple',
    'title': 'SessionSpeechlet - ' + title,
    'content': 'SessionSpeechlet - ' + output
    },
    'reprompt': {
    'outputSpeech': {
    'type': 'PlainText',
    'text': reprompt_text
    }
    },
    'shouldEndSession': should_end_session
    }

    def build_response(session_attributes, speechlet_response):
    return {
    'version': '1.0',
    'sessionAttributes': session_attributes,
    'response': speechlet_response
    }

    # --------------- Functions specific to Plex ----------------------

    def find_plex_server(authKey):
    #Select the first server you find
    url = "https://plex.tv/devices.xml?X-Plex-Token=" + authKey

    try:
    request = urllib2.Request(url)
    result = urllib2.urlopen(request)
    e = xml.etree.ElementTree.fromstring(result.read())
    x = 0

    #[TODO]: There should be a better way to do this. Check the API docs
    for atype in e.findall('Device'):
    if atype.get('provides') == "server":
    for conns in atype.findall('Connection'):
    if x == 0:
    return(conns.get('uri'))
    x += 1

    except urllib2.URLError, e:
    print(e)

    def ret_on_deck(url,authKey):
    #returns a list of TV Shows that are "on deck"
    MainServerURL = url + "/library/onDeck?X-Plex-Token=" + authKey

    s = "TV Shows On Deck: \n"

    try:
    request = urllib2.Request(MainServerURL)
    result = urllib2.urlopen(request)
    e = xml.etree.ElementTree.fromstring(result.read())

    #look for the TV shows only
    for atype in e.findall('Video'):
    if atype.get('librarySectionTitle') == "TV Shows":
    s += atype.get('grandparentTitle').split("(")[0].strip() + ". \n"

    return s

    except urllib2.URLError, e:
    print(e)

    def ret_download(url,authKey):
    #returns a list of downloads
    MainServerURL = url + "/library/recentlyAdded?X-Plex-Token=" + authKey

    #start the string
    s = "Recently Added: \n"

    #number of shows to list
    c = 5

    try:
    request = urllib2.Request(MainServerURL)
    result = urllib2.urlopen(request)
    e = xml.etree.ElementTree.fromstring(result.read())
    t = 0
    m = 0

    #search for TV shows
    for atype in e.findall('Directory'):
    if t == 0:
    s = s + "In TV: \n"
    if atype.get('type') == "season" and t < c:
    s += atype.get('parentTitle').split("(")[0].strip() + ". \n"
    t += 1

    #search for Movies
    for atype in e.findall('Video'):
    if m == 0:
    s += "In Movies: \n"
    if atype.get('type') == "movie" and m < c:
    s += atype.get('title').split("(")[0].strip() + ". \n"
    m += 1

    return s

    except urllib2.URLError, e:
    print(e)

    def plex_login(username,password):
    #returns a Plex auth token

    try:
    url = "https://plex.tv/users/sign_in.xml"

    headers = {
    'x-plex-device-name': "AWS Lambda",
    'x-plex-device': "AWSv01",
    'x-plex-client-identifier': "049ouolknf9u42oihen"
    }

    values = {
    'user[login]' : username,
    'user[password]': password
    }

    data = urllib.urlencode(values)
    req = urllib2.Request(url,data,headers)
    response = urllib2.urlopen(req)

    e = xml.etree.ElementTree.fromstring(response.read())
    return(e.get('authenticationToken'))

    except urllib2.URLError, e:
    print(e)