2022-02-06 10:19:03 +01:00
|
|
|
#!/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():
|
|
|
|
|
2022-02-11 15:54:54 +01:00
|
|
|
def __init__(self, luniebox, credentialsLocation=defaultCredentialsLocation):
|
|
|
|
|
|
|
|
if not luniebox.zspotify_path:
|
2022-02-06 10:19:03 +01:00
|
|
|
raise ValueError("No zspotify path provivded!")
|
2022-02-11 15:54:54 +01:00
|
|
|
else:
|
|
|
|
self.zspotify_path = luniebox.zspotify_path
|
|
|
|
|
2022-02-06 10:19:03 +01:00
|
|
|
if credentialsLocation:
|
|
|
|
self.credentialsLocation = credentialsLocation
|
|
|
|
else:
|
|
|
|
raise ValueError("No credentialsLocation provivded!")
|
2022-02-11 15:54:54 +01:00
|
|
|
|
|
|
|
username = luniebox.spotify.get_setting("username")
|
2022-02-06 10:19:03 +01:00
|
|
|
if not username:
|
|
|
|
raise ValueError("No username provided!")
|
2022-02-11 15:54:54 +01:00
|
|
|
|
|
|
|
password = luniebox.spotify.get_setting("password")
|
2022-02-06 10:19:03 +01:00
|
|
|
if not password:
|
|
|
|
raise ValueError("No password provided!")
|
2022-02-11 15:54:54 +01:00
|
|
|
|
|
|
|
root = luniebox.get_setting('mpd', 'library_path')
|
2022-02-06 10:19:03 +01:00
|
|
|
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
|