spotify/spotify.py

140 lines
5.6 KiB
Python

import config
import logging
import paho.mqtt.client as paho
import report
import socket
import subprocess
import time
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import config
import json
try:
from config import APP_NAME as ROOT_LOGGER_NAME
except ImportError:
ROOT_LOGGER_NAME = 'root'
logger = logging.getLogger(ROOT_LOGGER_NAME).getChild('main')
class librespot(object):
ON_CMD = ['play', ]
OFF_CMD = ['pause', 'stop', ]
def __init__(self, state_callback, title_callback):
logger.info("Starting Librespot...")
self.__state_callback__ = state_callback
self.__title_callback__ = title_callback
self.__process__ = subprocess.Popen(["librespot", "-v", "--name", config.DEVICE_NAME],
shell=False,
# We pipe the output to an internal pipe
stderr=subprocess.PIPE)
self.__state__ = None
self.__preload_state__ = False
self.__title__ = None
self.__spot_id__ = None
self.__spot_id_preload__ = None
self.set_state(False)
self.set_title("")
def run(self):
while True:
output = self.__process__.stderr.readline()
# Polling returns None when the program is still running, return_code otherwise
return_code = self.__process__.poll()
if return_code is not None:
self.__process__.close()
# Program ended, get exit/return code
raise RuntimeError("Command '{}' finished with exit code {}".format(command, return_code))
# If the output is not empty, feed it to the function, strip the newline first
if output:
out_txt = output.decode('utf-8').strip('\n').strip()
out_txt = out_txt[out_txt.find(']') + 2:]
#logger.debug("librespot output: %s", out_txt)
# TODO: Parse for "librespot output: Loading <Here Ever After> with Spotify URI <spotify:track:0zckHMfaB6vT5o23ZVBLHJ>"
if out_txt.lower().startswith("loading"):
logger.debug("librespot: %s", out_txt)
if self.__preload_state__:
self.__spot_id_preload__ = out_txt.split("<")[2][:-1]
logger.info("Upcomming Track-ID %s identified", self.__spot_id__)
else:
self.__spot_id__ = out_txt.split("<")[2][:-1]
logger.info("Current Track-ID %s identified", self.__spot_id__)
if "command=" in out_txt:
command = out_txt[out_txt.find('command=') + 8:].strip().lower()
logger.debug("librespot command: %s", command)
if command.startswith("preload"):
self.__preload_state__ = True
if command.startswith("load"):
self.set_state(command.split(',')[2].strip() == 'true')
#
self.__preload_state__ = False
self.__spot_id__ = self.__spot_id_preload__
#
elif command in self.ON_CMD:
self.set_state(True)
elif command in self.OFF_CMD:
self.set_state(False)
if self.__state__:
self.set_title(self.get_title_by_id())
else:
self.set_title("")
def get_title_by_id(self):
if self.__spot_id__ is None:
return ""
else:
sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials(client_id=config.SPOTIFY_CLIENT_ID,client_secret=config.SPOTIFY_CLIENT_SECRET))
try:
track = sp.track(self.__spot_id__)
except Exception:
return None
return track["artists"][0]["name"] + " - " + track["name"]
def set_state(self, target_state):
if target_state != self.__state__:
self.__state__ = target_state
logger.info("spotify state changed to %s", self.__state__)
self.__state_callback__(self.__state__)
def set_title(self, title):
if title != self.__title__:
self.__title__ = title
logger.info("spotify title changed to \"%s\"", self.__title__)
self.__title_callback__(self.__title__)
def send_state_msg_mqtt(state):
client= paho.Client("spotify")
client.username_pw_set(config.MQTT_USER, config.MQTT_PASS)
try:
client.connect(config.MQTT_SERVER, 1883)
topic = config.MQTT_TOPIC + "/state"
logger.info("Sending Spotify status information to mqtt %s = %s", topic, str(state))
client.publish(topic, "true" if state else "false")
except (socket.timeout, OSError) as e:
logger.warning("Erro while sending state information")
def send_title_msg_mqtt(title):
client= paho.Client("spotify")
client.username_pw_set(config.MQTT_USER, config.MQTT_PASS)
try:
client.connect(config.MQTT_SERVER, 1883)
topic = config.MQTT_TOPIC + "/title"
logger.info("Sending Spotify status information to mqtt %s = %s", topic, title)
client.publish(topic, title)
except (socket.timeout, OSError) as e:
logger.warning("Erro while sending title information")
if __name__ == '__main__':
report.appLoggingConfigure(config.__BASEPATH__, config.LOGTARGET, ((config.APP_NAME, config.LOGLVL), ), fmt=config.formatter, host=config.LOGHOST, port=config.LOGPORT)
ls = librespot(send_state_msg_mqtt, send_title_msg_mqtt)
ls.run()