luniebox/application/luniebox.py

389 lines
14 KiB
Python
Raw Normal View History

2022-02-06 10:19:03 +01:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
__name__ = "Luniebox"
import sys
import logging
import subprocess
import time
from enum import Enum
from configparser import ConfigParser
2022-02-24 16:12:47 +01:00
from turtle import update
2022-02-06 10:19:03 +01:00
import RPi.GPIO as GPIO
from spotifydl import SpotifyDL, SpotifyDLStatus
from mpd import MPDClient
from ExtendedMFRC522 import ExtendedMFRC522
from spotify import Spotify
import util
defaultConfigFilePath = '../config/luniebox.cfg'
class PlayerService(Enum):
NONE = 0
SPOTIFY = 1
MPD = 2
class Luniebox(object):
def __init__(self, configFilePath=defaultConfigFilePath):
self.configFilePath = configFilePath
self.read_config()
GPIO.setwarnings(False)
self.reader = ExtendedMFRC522(encoding="ascii")
loglevel = 'INFO'
if self.get_setting('logging', 'level'):
loglevel = self.get_setting('logging', 'level')
logger = logging.getLogger('luniebox')
logger.setLevel(logging._nameToLevel[loglevel])
logFormatter = logging.Formatter(
style='{', datefmt='%Y-%m-%d %H:%M:%S', fmt='{asctime} {levelname}: {message}')
logstdoutHandler = logging.StreamHandler(sys.stdout)
logstdoutHandler.setFormatter(logFormatter)
logger.addHandler(logstdoutHandler)
if self.get_setting('mpd', 'disabled', '') != 'True':
self.mpd = MPDClient()
self.mpd.host = "localhost"
self.mpd.port = 6600
self.mpd.timeout = 10
if self.mpd_connect():
logging.getLogger('luniebox').debug("connected to mpd")
else:
logging.getLogger('luniebox').info("mpd disabled")
self.mpd = False
if self.get_setting('spotify', 'disabled', '') != 'True':
self.spotify = Spotify(luniebox=self)
if self.spotify_connect():
logging.getLogger('luniebox').debug("connected to spotify")
self.zspotify_path = False
self.spotifydl = False
self.zspotify_path = self.get_setting('spotify', 'zspotify_path')
if self.zspotify_path and self.mpd:
self.spotifydl_connect()
else:
logging.getLogger('luniebox').info("spotify disabled")
self.spotify = False
if not self.config.has_option('api', 'api_key'):
self.set_setting('api', 'api_key', util.randomString(64))
self.current = self.get_setting('luniebox', 'current')
self.service = PlayerService.NONE
if self.current != None:
2022-02-11 15:54:54 +01:00
if self.current.startswith('spotify:'):
2022-02-06 10:19:03 +01:00
self.service = PlayerService.SPOTIFY
2022-02-11 15:54:54 +01:00
elif self.current.startswith('mpd:'):
2022-02-06 10:19:03 +01:00
self.service = PlayerService.MPD
self.volume_max = int(self.get_setting('luniebox', 'volume_max', 100))
self.volume = int(self.get_setting(
'luniebox', 'volume', self.volume_max))
self.volume_step = int(self.get_setting('luniebox', 'volume_step', 5))
self.wind_step = int(self.get_setting('luniebox', 'wind_step', 10))
self.resume = True
def mpd_connect(self):
if not self.get_setting('luniebox', 'setup'):
return False
if not self.mpd:
logging.getLogger('luniebox').warn("mpd disabled!")
return False
try:
self.mpd.disconnect()
except:
pass
tries = 0
while tries < 5:
try:
self.mpd.connect(self.mpd.host, self.mpd.port)
return True
except:
subprocess.call(["systemctl", "restart", "mpd"])
time.sleep(1)
tries += 1
logging.getLogger('luniebox').error(
"Could not connect to MPD service!")
return False
def spotify_connect(self, restart=False, max_tries=5):
if not self.get_setting('luniebox', 'setup'):
return False
if not self.spotify:
logging.getLogger('luniebox').warn("spotify disabled!")
return False
if restart:
subprocess.run(["sudo", "systemctl", "restart", "spotifyd"])
2022-02-13 12:09:17 +01:00
time.sleep(20)
2022-02-06 10:19:03 +01:00
tries = 0
spotifyd_status = subprocess.call(
["systemctl", "is-active", "--quiet", "spotifyd"])
while spotifyd_status != 0 and tries < max_tries:
subprocess.call(["systemctl", "restart", "spotifyd"])
2022-02-13 12:09:17 +01:00
tries = tries + 1
2022-02-10 16:44:22 +01:00
time.sleep(10 * tries)
2022-02-06 10:19:03 +01:00
spotifyd_status = subprocess.call(
["systemctl", "is-active", "--quiet", "spotifyd"])
if spotifyd_status == 0:
return True
logging.getLogger('luniebox').error("spotifyd service not running!")
return False
def spotifydl_connect(self):
if not self.get_setting('luniebox', 'setup'):
return False
if self.spotifydl:
return True
if not self.zspotify_path or not self.mpd:
logging.getLogger('luniebox').warn("spotifydl disabled!")
return False
try:
2022-02-11 16:00:12 +01:00
self.spotifydl = SpotifyDL(self)
2022-02-06 10:19:03 +01:00
logging.getLogger('luniebox').info("spotifydl enabled!")
return True
except Exception as exception:
2022-02-06 10:19:03 +01:00
logging.getLogger('luniebox').warning(
"error on setup spotifydl: " + str(exception))
2022-02-06 10:19:03 +01:00
return False
def read_config(self):
configParser = ConfigParser()
dataset = configParser.read(self.configFilePath)
if len(dataset) != 1:
raise ValueError(
"Config file {} not found!".format(self.configFilePath))
self.config = configParser
def get_setting(self, section, key, default=None):
if self.config.has_option(section, key):
return self.config[section][key]
return default
def set_setting(self, section, key, value):
if not self.config.has_section(section):
self.config.add_section(section)
self.config.set(section, key, str(value))
with open(self.configFilePath, 'w') as configfile:
self.config.write(configfile)
def rfid_write(self, data):
self.reader.write(data.strip())
def rfid_readOnce(self):
id, text = self.reader.read()
logging.getLogger('luniebox').debug(
"Once ID: %s Text: %s" % (id, text))
return text.strip()
def vol_up(self):
self.change_volume(self.volume_step)
def vol_down(self):
self.change_volume(-1 * self.volume_step)
def change_volume(self, change):
self.volume += change
if self.volume > self.volume_max:
self.volume = self.volume_max
if self.volume < 0:
self.volume = 0
if self.service == PlayerService.SPOTIFY and self.spotify_connect():
self.spotify.volume(self.volume)
elif self.service == PlayerService.MPD and self.mpd_connect():
self.mpd.setvol(self.volume)
self.set_setting('luniebox', 'volume', str(self.volume))
logging.getLogger('luniebox').debug("vol: " + str(self.volume))
def fastforward(self):
if not self.resume:
logging.getLogger('luniebox').debug('seek ff')
if self.service == PlayerService.SPOTIFY and self.spotify_connect():
self.spotify.fastforward(self.wind_step)
elif self.service == PlayerService.MPD and self.mpd_connect():
self.mpd.seekcur(self.wind_step)
def rewind(self):
if not self.resume:
logging.getLogger('luniebox').debug('seek rew')
if self.service == PlayerService.SPOTIFY and self.spotify_connect():
self.spotify.rewind(self.wind_step)
elif self.service == PlayerService.MPD and self.mpd_connect():
self.mpd.seekcur(-1 * self.wind_step)
def next(self):
if not self.resume:
logging.getLogger('luniebox').debug('next')
if self.service == PlayerService.SPOTIFY and self.spotify_connect():
self.spotify.next()
elif self.service == PlayerService.MPD and self.mpd_connect():
self.mpd.next()
def previous(self):
if not self.resume:
logging.getLogger('luniebox').debug('prev')
if self.service == PlayerService.SPOTIFY and self.spotify_connect():
self.spotify.previous()
elif self.service == PlayerService.MPD and self.mpd_connect():
self.mpd.previous()
def pause(self):
if not self.resume:
if self.mpd_connect():
self.mpd.pause(1)
logging.getLogger('luniebox').debug("pause mpd")
if self.spotify_connect(max_tries=2):
self.spotify.pause()
logging.getLogger('luniebox').debug("pause spotify")
self.resume = True
def play(self, text):
if text != "":
2022-02-11 15:54:54 +01:00
if text.startswith('spotify:') and self.spotify:
2022-02-06 10:19:03 +01:00
self.service = PlayerService.SPOTIFY
2022-02-11 15:54:54 +01:00
elif text.startswith('mpd:') and self.mpd:
2022-02-06 10:19:03 +01:00
self.service = PlayerService.MPD
2022-02-11 15:54:54 +01:00
else:
self.service = PlayerService.NONE
2022-02-06 10:19:03 +01:00
if self.service == PlayerService.SPOTIFY and self.spotifydl_connect():
downloadStatus = self.spotifydl.downloadStatus(text)
2022-02-11 15:54:54 +01:00
if downloadStatus == SpotifyDLStatus.FINISHED and self.mpd_connect():
self.mpd.update()
self.mpd.idle('update')
2022-02-06 10:19:03 +01:00
self.service = PlayerService.MPD
elif self.get_setting('spotify', 'auto_download') == 'True' and downloadStatus == SpotifyDLStatus.NONE or downloadStatus == SpotifyDLStatus.ERROR:
self.spotifydl.download(text)
2022-02-11 15:54:54 +01:00
if self.service == PlayerService.SPOTIFY and self.spotify_connect():
2022-02-06 10:19:03 +01:00
if text != self.current:
2022-02-11 15:54:54 +01:00
self.spotify.volume(self.volume)
if self.spotify.play(text):
2022-02-06 10:19:03 +01:00
self.current = text
2022-02-11 15:54:54 +01:00
self.set_setting(
'luniebox', 'current', self.current)
2022-02-06 10:19:03 +01:00
self.resume = False
2022-02-11 15:54:54 +01:00
logging.getLogger('luniebox').debug(
"play spotify: " + self.current)
else:
logging.getLogger('luniebox').warn(
"cannot play spotify: " + self.current)
2022-02-06 10:19:03 +01:00
elif self.resume and text == self.current:
2022-02-11 15:54:54 +01:00
self.spotify.volume(self.volume)
play = self.current
if self.spotify.is_active():
play = None
if self.spotify.play(play):
2022-02-06 10:19:03 +01:00
self.resume = False
2022-02-11 15:54:54 +01:00
logging.getLogger('luniebox').debug(
"resume spotify: " + self.current)
else:
logging.getLogger('luniebox').warn(
"cannot resume spotify: " + self.current)
return True
elif self.service == PlayerService.MPD and self.mpd_connect():
if text != self.current:
try:
self.mpd.setvol(self.volume)
self.mpd.clear()
mpd_uri = text.replace('mpd:', '')
self.mpd.add(mpd_uri)
self.mpd.play()
except Exception as exception:
logging.getLogger('luniebox').warning(
"cannot not play mpd '" + text + "': " + str(exception))
return False
self.current = text
self.set_setting('luniebox', 'current', self.current)
self.resume = False
if text.startswith('spotify:'):
logging.getLogger('luniebox').debug(
"play spotify from mpd: " + text)
else:
logging.getLogger('luniebox').debug(
"play mpd: " + self.current)
elif self.resume and text == self.current:
try:
self.mpd.setvol(self.volume)
self.mpd.play()
except Exception as exception:
logging.getLogger('luniebox').warning(
"cannot not resume mpd '" + self.current + "': " + str(exception))
return False
self.resume = False
if text.startswith('spotify:'):
logging.getLogger('luniebox').debug(
"resume spotify from mpd: " + text)
else:
logging.getLogger('luniebox').debug(
"resume mpd: " + self.current)
return True
elif text != None:
logging.getLogger('luniebox').info(
"invalid value(?): " + str(text))
return False
return False
2022-02-06 10:19:03 +01:00
def stop(self):
self.pause()
def sort_mpd(self, object):
if 'directory' in object:
return object['directory']
elif 'file' in object:
return object['file']
return ''
def mpd_list(self, path=''):
if self.mpd_connect():
try:
2022-02-24 16:12:47 +01:00
self.mpd(update(path))
2022-02-06 10:19:03 +01:00
result = self.mpd.listfiles(path)
return sorted(result, key=self.sort_mpd)
except:
return []
return None
def mpd_status(self):
if self.mpd_connect():
status = self.mpd.status()
status['song'] = self.mpd.currentsong()
return status
return None
luniebox = Luniebox()