<file_sep>import pexpect
import os

class Player:
    
    def __init__(self, playIndex=None):
        """
        When the Player is instantiated, spawn pianobar in the terminal.
        If music defaults to playing, pause it and go to the station select screen.
        """
        print 'Launching Pandora player...'

        # First things first, clear that pesky state config file.
        # Otherwise, pianobar will default to playing a station,
        # which just throws everything off.
        if os.path.isfile(os.path.expanduser("~" + "/.config/pianobar/state")):
            os.system("rm ~/.config/pianobar/state")

        # Spawn the Pianobar
        self.child = pexpect.spawn('pianobar')

        # Now that we're waiting for a station, get the station dict.
        self.updateStations()

        # Initialize a few variables up in this bitch.
        self.waitingForStation = True
        self.currentStationIndex = -1 # By convention, this means no station yet.
        self.playing = False

        self.track = None
        self.artist = None
        self.album = None


    def playByIndex(self, index):
        """
        Takes in the index of a station to be played, and plays that station.
        """

        # Make sure the index supplied is valid.
        if not self.validateIndex(index):
            print "ERROR: Please supply a valid station number!"
            return

        # Make sure we're waiting for station.
        if not self.waitingForStation:
            self.child.send('s') # Change station
            self.waitingForStation = True
        else:
            pass

        self.child.sendline(str(index))
        self.playing = True
        self.waitingForStation = False
        self.currentStationIndex = int(index)
        self.currentStationName = self.indexDict[str(self.currentStationIndex)]

        print "Now playing station: " + self.indexDict[str(index)]

    def thumbsUp(self):
        """
        Thumbs up the current track.
        """
        self.updateTrack()
        print "Liked track " + self.track
        if self.waitingForStation:
            self.child.send('\n')
            self.waitingForStation = False
        self.child.send('+')

    def thumbsDown(self):
        """
        Thumbs down the current track.
        """
        self.updateTrack()
        print "Disliked track " + self.track
        if self.waitingForStation:
            self.child.send('\n')
            self.waitingForStation = False
        self.child.send('-')

    def next(self):
        """
        Skips to the next track.
        """
        print 'Skipping track...'
        if self.waitingForStation:
            self.child.send('\n')
            self.waitingForStation = False
        self.child.send('n')

    def updateTrack(self):
        """
        Figures out the name of the track currently playing.
        """
        # Flip through all the tracks that have happened since last time.
        newTrackFlag = False
        while True:
            i = self.child.expect(['\|>', pexpect.TIMEOUT], timeout=1)
            if i == 0: # Found another track
                newTrackFlag = True
            elif i == 1: # That was the last one!
                break

        # If this track is different from the old one,
        if newTrackFlag:
            # Get ["'Track', 'Name'", 'by', '"Artist', 'Name"', 'on', '"Album', 'Name"', '<3'?, '\xlb[2K']
            self.child.expect('#')
            wordList = self.child.before.split()

            hitByOn = 0
            trackList = []
            artistList = []
            albumList = []

            # parse that shit
            for i in range(len(wordList)):
                # if we're at the track
                if hitByOn == 0:
                    # if we're changing to the artist (happens at "by")
                    if i != 0 and (wordList[i-1][-1] == '"' and wordList[i] == 'by' and wordList[i+1][0] == '"'):
                        hitByOn = 1
                        continue
                    else:
                        trackList.append(wordList[i])

                # if we're at the artist
                elif hitByOn == 1:
                    # if we're changing to the album (happens at "on")
                    if wordList[i-1][-1] == '"' and wordList[i] == 'on' and wordList[i+1][0] == '"':
                        hitByOn = 2
                        continue
                    else:
                        artistList.append(wordList[i])

                # if we're at the album
                elif hitByOn == 2:
                    # if we're done
                    if wordList[i] == '<3' or i == len(wordList)-1:
                        break
                    else:
                        albumList.append(wordList[i])

            # Put that thing back where it came from, or so help me
            # (So help me! So help me!)
            self.track = " ".join(trackList)
            self.artist = " ".join(artistList)
            self.album = " ".join(albumList)


    def quit(self):
        """
        Exits gracefully from the Pianobar.
        """
        if self.waitingForStation:
            self.child.send('\n')
            self.child.expect('#')
            self.waitingForStation = False
            self.currentStationIndex = 0
        print "Exiting from Pandora player."
        self.child.sendline('q')

    def exit(self):
        self.quit()

    def validateIndex(self, index):
        """
        Returns True if index is a viable station index,
        and False if not.
        """
        return str(index) in self.indexDict.keys()

    def updateStations(self):
        """
        To be called whenever we reach the Station Select screen.
        Creates self.stationDict, which contains all stations:
        {stationTitle: stationIndex}
        and self.indexDict, which does it backward:
        {stationIndex: stationTitle}
        """

        self.child.expect('station:')

        lines = self.child.before.split('\r\n')
        stationList = [line for line in lines if "q" in line or "Q" in line]
        stationDict = {}
        indexDict = {}

        for i in stationList:
            name = " ".join(i.split()[3:])
            index = i.split()[1][:-1]
            stationDict[name] = index
            indexDict[index] = name

        self.stationDict = stationDict
        self.indexDict = indexDict

    def __str__(self):
        self.updateTrack()
        return 'Currently playing ' + self.track + " by " + self.artist + " on " + self.album


# Cool shit to show you that shit works!
if __name == "__main__":
    import time
    import tts

    player = Player()

    player.playByIndex(7)
    print player

    time.sleep(3)

    player.playByIndex(3)
    time.sleep(5)
    player.next()
    player.next()

    print player
    tts.say(player.__str__())

    time.sleep(5)

    player.quit()<file_sep>SmartRoom
=========

This repo will contain the source code to run on the Raspberry Pi which will control Smartroom in Brooks and Greg's room, 2013-2014.

Note: It might not wind up being called Smartroom. It's a working title.

Dependencies
------------
Pianobar: A Pandora app that runs in the terminal.
    sudo apt-get install pianobar
    cp /usr/share/doc/pianobar/contrib/config-example ~/.config/pianobar
    vim ~/.config/pianobar
Edit the `tls\_fingerprint` to be:

    ```
    2<PASSWORD>DAFA1<PASSWORD>
    ```

Notes
-----
I did not make the PyTTS speech synthesizer; <NAME> did. Thanks for being a pal, <NAME>!
<file_sep>#!/usr/bin/env python2
# -*- coding: utf-8 -*-

import httplib
import json
import sys

def speech_to_text(audio):
    url = "www.google.com"
    path = "/speech-api/v1/recognize?xjerr=1&client=chromium&lang=en"
    headers = { "Content-type": "audio/x-flac; rate=16000" };
    params = {"xjerr": "1", "client": "chromium"}
    conn = httplib.HTTPSConnection(url)
    conn.request("POST", path, audio, headers)
    response = conn.getresponse()
    data = response.read()
    jsdata = json.loads(data)
    return jsdata["hypotheses"][0]["utterance"]

if __name__ == "__main__":
    if len(sys.argv) != 2 or "--help" in sys.argv:
        print "Usage: stt.py <flac-audio-file>"
        sys.exit(-1)
    else:
        with open(sys.argv[1], "r") as f:
            speech = f.read()
        text = speech_to_text(speech)
        print text<file_sep>import os
from pytts import pytts

def say(string):
    pytts().say(string)

def sayNB(string):
    pytts().sayNB(string)

if __name__ == "__main__":
    say("Look, it works! Even with 'apostrophes' and \"quotes\".")
<file_sep>#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import gst
import gobject
from urllib2 import Request, urlopen

class pytts():
    def on_finish(self, bus, message): #Callback triggered at the end of the stream
        self.player.set_state(gst.STATE_NULL)
        self.mainloop.quit()
  
    def __init__(self):
        self.player = None
        self.mainloop = gobject.MainLoop() #Instantiate the mainloop even if not used

    def say(self, text, lang="en",volume=5.0):
        music_stream_uri = 'http://translate.google.com/translate_tts?'+'q='+text+'&tl='+lang+"&ie=UTF-8"
        self.player = gst.element_factory_make("playbin", "player") #Create the player
        self.player.set_property('uri', music_stream_uri) #Provide the source which is a stream
        self.player.set_property('volume',volume) #Val from 0.0 to 10 (float)
        self.player.set_state(gst.STATE_PLAYING) #Play

        bus = self.player.get_bus() #Get the bus (to send catch connect signals..)
        bus.add_signal_watch_full(1)
        bus.connect("message::eos", self.on_finish) #Connect end of stream to the callback
        self.mainloop.run() #Wait an event


    def sayNB(self, text, lang="en",volume=5.0): #NB for Non-Blocking
        music_stream_uri = 'http://translate.google.com/translate_tts?tl='+lang+'&q=' + text +"&ie=UTF-8"
        self.player = gst.element_factory_make("playbin", "player") #Create the player
        self.player.set_property('uri', music_stream_uri) #Provide the source which is a stream
        self.player.set_property('volume',volume) #Val from 0.0 to 10 (float)
        self.player.set_state(gst.STATE_PLAYING) #Play

    def download(self, text, lang="en", filename="translate_tts.mp3"):
        req = Request(url='http://translate.google.com/translate_tts')
        req.add_header('User-Agent', 'My agent !') #Needed otherwise return 403 Forbidden
        req.add_data("tl="+lang+"&q="+text+"&ie=UTF-8")
        fin = urlopen(req)
        mp3 = fin.read()
        fout = file(filename, "wb")
        fout.write(mp3)
        fout.close()
    
    def setVolume(self, val):
        self.player.set_property('volume',val) #Val from 0 to 1 (float)
    
if __name__=="__main__":
  input_string = sys.argv

  if len(input_string) < 3:
      print("Usage: ./tts.py language_code Your text separated with spaces.")
      sys.exit(1)

  input_string.pop(0) #remove the program name from the argv list
  lang = input_string[0] #Take the language which should be now the first args
  input_string.pop(0) #Pop it
  tts_string = '+'.join(input_string) #convert to url all the rest (with + replacing spaces) Nice but not needed
  
  pytts().say(tts_string, lang)
  
  sys.exit(0)