#!/usr/bin/env python3 # -*- coding: utf-8 -*- __name__ = "SpotifyDL" import subprocess from configparser import ConfigParser import os.path import logging from enum import Enum defaultCredentialsLocation = '../config/zspotify.credentials' class SpotifyDLStatus(Enum): NONE = "none" RUNNING = "running" FINISHED = "finished" ERROR = "error" DISABLED = "disabled" class SpotifyDL(): def __init__(self, luniebox, credentialsLocation=defaultCredentialsLocation): if not luniebox.zspotify_path: raise ValueError("No zspotify path provivded!") else: self.zspotify_path = luniebox.zspotify_path if credentialsLocation: self.credentialsLocation = credentialsLocation else: raise ValueError("No credentialsLocation provivded!") username = luniebox.spotify.get_setting("username") if not username: raise ValueError("No username provided!") password = luniebox.spotify.get_setting("password") if not password: raise ValueError("No password provided!") root = luniebox.get_setting('mpd', 'library_path') if root: if not root.endswith("/"): root = root + "/" self.root = root else: raise ValueError("No root provided!") if not os.path.isfile(self.credentialsLocation): logging.getLogger('luniebox').info("initialize zspotify") p = subprocess.Popen([self.zspotify_path + 'venv/bin/python', self.zspotify_path + 'zspotify/__main__.py', '-s', '--credentials-location', self.credentialsLocation], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, shell=False, group="pi", user="pi") input = username + '\n' + password + '\n' out, err = p.communicate(input=input.encode()) logging.getLogger('luniebox').info(out) logging.getLogger('luniebox').warn(err) self.downloads = {} def download(self, uri): status = self.downloadStatus(uri) if status == SpotifyDLStatus.NONE or status == SpotifyDLStatus.ERROR: logging.getLogger('luniebox').info( "start download of '" + uri + "'") trackprefix = "" if uri.startswith('spotify:album:'): trackprefix = "{album_num}. " elif uri.startswith('spotify:playlist:'): trackprefix = "{playlist_num}. " p = subprocess.Popen([self.zspotify_path + 'venv/bin/python', self.zspotify_path + 'zspotify/__main__.py', "--root-path", self.root, '--credentials-location', self.credentialsLocation, "--download-real-time", "True", "--chunk-size", "50000", "--skip-existing-files", "True", "--skip-previously-downloaded", "True", "--output", uri + "/" + trackprefix + "{artist} - {song_name}.{ext}", uri], stdin=None, stdout=None, stderr=None, close_fds=True, shell=False, group="pi", user="pi") self.downloads[uri] = p return SpotifyDLStatus.RUNNING elif status == SpotifyDLStatus.RUNNING: logging.getLogger('luniebox').debug( "download for '" + uri + "' still running") elif status == SpotifyDLStatus.FINISHED: logging.getLogger('luniebox').debug( "alreaded downloaded '" + uri + "'") return status def downloadStatus(self, uri): doneFiledPath = self.root + uri + '/.spotifydl' if uri in self.downloads: if self.downloads[uri]: poll = self.downloads[uri].poll() if poll != None: self.downloads.pop(uri) if poll == 0: p = subprocess.Popen(["touch", doneFiledPath], stdin=None, stdout=None, stderr=None, close_fds=True, shell=False, group="pi", user="pi") p.communicate() return SpotifyDLStatus.FINISHED logging.getLogger('luniebox').warn( "download of '" + uri + "' exited with: " + str(poll)) return SpotifyDLStatus.ERROR return SpotifyDLStatus.RUNNING if os.path.exists(doneFiledPath): return SpotifyDLStatus.FINISHED return SpotifyDLStatus.NONE def getDownloads(self): downloads = {} for uri in self.downloads.keys(): downloads[uri] = str(self.downloadStatus(uri)) return downloads