Spotify Downloader with Kivy.

Let’s create a app with the help of python and kivy for windows or linux.

Image for post
Image for post

Libraries and framework will use

I assume you have already install the requirements. If you have problems with kivy you can check this ==> https://kivy.org/doc/stable/installation/installation-windows.html#install-win-dist

What will do? We will create a simply app contains 2 files, one to store or python code and the other to store the kv file. At the end the program will have the ability to download any public list from spotify using youtube.

The python file.

First let’s create a folder called spot. Inside this folder let’s create spd.py.

from kivy.app import App
from kivy.uix.label import Label
import pathlib
import subprocess
import os
from kivy.uix.boxlayout import BoxLayout
cur_dir = os.getcwd()

Nothing fancy here, just the imports.

Lets create our screen now.

class Homepage(BoxLayout):
url = ''

def __init__(self, **kwargs):
super(Homepage, self).__init__(**kwargs)
self.orientation = 'vertical'
self.show_music()

We will use boxlayout here with vertical orientation, so when we add our gadgets etc with kv file, the desired layout will be created. The url we added, we save the playlist url when user add the data. On show_music, search all the playlists user have added, and because we want them to load when the app is loading,we check if there is any.

def show_music(self):
self.ids.scroll.clear_widgets()
files = []
for file in os.listdir(cur_dir):
if file.endswith('.txt'):
files.append(file)
for fil in files:
label = Label(text=fil)
self.ids.scroll.add_widget(label)

def clear_url(self):
self.ids.url.text = ''

Show music is responsible, for showing playlists under the Show Playlist label. Because we will use it often, we want to clear always the widget before adding new music so clear_widget() does the job. Then we want to find any file with ends with .txt, is our folder, after we find them we add them to widget. With clear_url we clear the input which we added the playlist.

def download_list(self):
self.url = url = self.ids.url.text
subprocess.call(f'spotdl --playlist {url}', creationflags=subprocess.CREATE_NEW_CONSOLE)

self.clear_url()
self.show_music()

def clear_playlists(self):
path = pathlib.Path().absolute()
for file in os.listdir(cur_dir):
if file.endswith('.txt'):
file_to_r = pathlib.Path(f'{path}\{file}')
file_to_r.unlink()
self.show_music()

download_list, when the user added the url and pressed the button get, we get that url from the input text, and using subprocess to create a command line script to use spotdl. Because we don’t want our program to crash, we use the option CREATE_NEW_CONSOLE, to create new console. After the playlist is download we clear the url and refresh the scroll to show the added playlist.

With clear_playlists, again we search for files ends wit .txt on our folder and with pathlib and unlink we delete them.

def downloadMusic(self):
path = pathlib.Path().absolute()
files = []
for file in os.listdir(cur_dir):
if file.endswith('.txt'):
files.append(file)

for text in files:
folder = text.replace('.txt', '')
# print('path', path)
p = pathlib.Path(f"{folder}/")
p.mkdir(parents=True, exist_ok=True)
new_path = os.path.abspath(os.path.join(path, folder))
path_exists = os.path.isdir(new_path)

if path_exists:
os.chdir(path)
# os.system(f"start cmd /K cd {new_path} spotdl --list {text}")
subprocess.call(f'spotdl --list {text} --output-file {folder}', creationflags=subprocess.CREATE_NEW_CONSOLE)
# os.chdir(path)
file_to_rem = pathlib.Path(f'{path}\{text}')
file_to_rem.unlink()
else:
print('problrem')
self.show_music()

And finally how we download them. First we find our current folder, we search for the playlists, and then for every playlist we remove the .txt and we create a folder with the rest of the name. After that we join the path we are with the new folder and we check if anythingis ok , and then with the help of subprocess again we download every playlist on different folder using the spotdl again. Easy!

class SpdApp(App):

def build(self):
return Homepage()


if __name__ == '__main__':
app = SpdApp()
app.run()

Finally this boilerplate code so the app can run!

Together the script.

from kivy.app import App
from kivy.uix.label import Label
import pathlib
import subprocess
import os
from kivy.uix.boxlayout import BoxLayout
cur_dir = os.getcwd()


class Homepage(BoxLayout):
url = ''

def __init__(self, **kwargs):
super(Homepage, self).__init__(**kwargs)
self.orientation = 'vertical'
self.show_music()


def show_music(self):
self.ids.scroll.clear_widgets()
files = []
for file in os.listdir(cur_dir):
print(file)
if file.endswith('.txt'):
files.append(file)
for fil in files:
label = Label(text=fil)
self.ids.scroll.add_widget(label)

def clear_url(self):
self.ids.url.text = ''

def download_list(self):
self.url = url = self.ids.url.text
subprocess.call(f'spotdl --playlist {url}', creationflags=subprocess.CREATE_NEW_CONSOLE)

self.clear_url()
self.show_music()

def clear_playlists(self):
path = pathlib.Path().absolute()
for file in os.listdir(cur_dir):
if file.endswith('.txt'):
file_to_r = pathlib.Path(f'{path}\{file}')
file_to_r.unlink()
self.show_music()

def downloadMusic(self):
path = pathlib.Path().absolute()
files = []
for file in os.listdir(cur_dir):
if file.endswith('.txt'):
files.append(file)

for text in files:
folder = text.replace('.txt', '')
# print('path', path)
p = pathlib.Path(f"{folder}/")
p.mkdir(parents=True, exist_ok=True)
new_path = os.path.abspath(os.path.join(path, folder))
path_exists = os.path.isdir(new_path)

if path_exists:
os.chdir(path)
# os.system(f"start cmd /K cd {new_path} spotdl --list {text}")
subprocess.call(f'spotdl --list {text} --output-file {folder}', creationflags=subprocess.CREATE_NEW_CONSOLE)
# os.chdir(path)
file_to_rem = pathlib.Path(f'{path}\{text}')
file_to_rem.unlink()
else:
print('problrem')
self.show_music()

class SpdApp(App):

def build(self):
return Homepage()


if __name__ == '__main__':
app = SpdApp()
app.run()

The kv file.

Now we create the spd.kv file. This file contains all the buttons we reference before.

<Homepage>:
Label:
text: 'Spotify Downloader'
BoxLayout:
BoxLayout:
orientation: 'horizontal'
Button:
id: clearBtn
size_y: 0.3
text: 'Clear'
size_hint:(.2, 1)
background_color: 1, 1, 1, 1
on_release: root.clear_url()

TextInput:
id: url
size_hint:(.4, 1)
hint_text: 'Enter the playlist url'
Button:
id: searchBtn
size_y: 0.3
text: 'Get'
size_hint:(.4, 1)
background_color: 0,.5,1,1
on_release: root.download_list()

Label:
text: 'Show Playlists'

ScrollView:
size_hint: None, None
size: root.width, root.height-135
GridLayout:
id: scroll
cols: 2
spacing: 10
size_hint_y: None
row_force_default: True
row_default_height: 40


BoxLayout:
orientation: 'horizontal'
Button:
id: listButton
text: 'Clear Playlists'
size: 200,35
background_color: 0,.5,1,1
on_release: root.clear_playlists()

Button:
id: downloadButton
text: 'Download'
size: 200,35
background_color: 0,.5,1,1
on_release: root.downloadMusic()

As you can see, every line is translated to the image in the top of our page. Only note here is this on_release: root.download_list(), with this way we bind the function we created to our buttons!

That’s All. Thank for reading!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store