From 5cfc567eb2e0c4227616eda6e9265e8f7df28443 Mon Sep 17 00:00:00 2001
From: k9wolf8634
Date: Sat, 16 Jul 2022 18:18:31 +0800
Subject: [PATCH 01/12] Add global mediakey listening
---
requirements.txt | 3 ++-
source/audio.py | 11 +++++++++++
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/requirements.txt b/requirements.txt
index 75f5aa7..577756b 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,4 +9,5 @@ pyqtdarktheme
python-vlc
requests
tqdm
-pydub
\ No newline at end of file
+pydub
+keyboard
\ No newline at end of file
diff --git a/source/audio.py b/source/audio.py
index 8b8c20f..018f47f 100644
--- a/source/audio.py
+++ b/source/audio.py
@@ -5,6 +5,7 @@
import music_tag
import logging
import struct
+import keyboard
from pathlib import Path
from PyQt5 import QtCore, QtGui, QtTest
from PyQt5.QtCore import pyqtSignal, QThreadPool, QObject
@@ -50,6 +51,7 @@ def __init__(self, window):
set_button_icon(self.window.shuffleBtn, SHUFFLE_OFF_ICON)
set_button_icon(self.window.repeatBtn, REPEAT_OFF_ICON)
set_button_icon(self.window.listenQueueBtn, LISTEN_QUEUE_ICON)
+ keyboard.on_press(self.key_pressed)
def play(self, item, playlist_tree):
@@ -250,6 +252,14 @@ def init_signals(self):
self.window.shuffleBtn.clicked.connect(self.toggle_shuffle)
self.window.repeatBtn.clicked.connect(self.toggle_repeat)
+ def key_pressed(self, e):
+ if e.name == "play/pause media":
+ self.window.playBtn.click()
+ elif e.name == "next track":
+ self.window.nextBtn.click()
+ elif e.name == "previous track":
+ self.window.prevBtn.click()
+
class AudioPlayer:
@@ -349,3 +359,4 @@ def find_id_in_metadata(path):
tag = music_tag.load_file(path)
data = parse_meta_data(tag[COMMENT])
return data.get(ID) if None else ""
+
From 871698f904748e69d7c08246d3f71ce77faef56f Mon Sep 17 00:00:00 2001
From: k9wolf8634
Date: Sat, 16 Jul 2022 18:33:26 +0800
Subject: [PATCH 02/12] Add config option to disable media keys
---
source/audio.py | 3 ++-
source/config.py | 6 ++++++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/source/audio.py b/source/audio.py
index 018f47f..bb281e5 100644
--- a/source/audio.py
+++ b/source/audio.py
@@ -51,7 +51,8 @@ def __init__(self, window):
set_button_icon(self.window.shuffleBtn, SHUFFLE_OFF_ICON)
set_button_icon(self.window.repeatBtn, REPEAT_OFF_ICON)
set_button_icon(self.window.listenQueueBtn, LISTEN_QUEUE_ICON)
- keyboard.on_press(self.key_pressed)
+ if Config.get_enable_media_keys():
+ keyboard.on_press(self.key_pressed)
def play(self, item, playlist_tree):
diff --git a/source/config.py b/source/config.py
index 18a74f3..2199f28 100644
--- a/source/config.py
+++ b/source/config.py
@@ -29,6 +29,7 @@
PRINT_ERRORS = 'PRINT_ERRORS'
PRINT_DOWNLOADS = 'PRINT_DOWNLOADS'
TEMP_DOWNLOAD_DIR = 'TEMP_DOWNLOAD_DIR'
+ENABLE_MEDIA_KEYS = 'ENABLE_MEDIA_KEYS'
CONFIG_VALUES = {
ROOT_PATH: { 'default': '../ZSpotify Music/', 'type': str, 'arg': '--root-path' },
@@ -54,6 +55,7 @@
PRINT_ERRORS: { 'default': 'True', 'type': bool, 'arg': '--print-errors' },
PRINT_DOWNLOADS: { 'default': 'False', 'type': bool, 'arg': '--print-downloads' },
TEMP_DOWNLOAD_DIR: { 'default': '', 'type': str, 'arg': '--temp-download-dir' },
+ ENABLE_MEDIA_KEYS: { 'default': 'True', 'type': bool, 'arg': '--enable-media-keys' }
}
OUTPUT_DEFAULT_PLAYLIST = '{playlist}/{artist} - {song_name}.{ext}'
@@ -211,6 +213,10 @@ def get_temp_download_dir(cls) -> str:
def get_total_search_results(cls):
return cls.get(TOTAL_SEARCH_RESULTS)
+ @classmethod
+ def get_enable_media_keys(cls):
+ return cls.get(ENABLE_MEDIA_KEYS)
+
@classmethod
def get_output(cls, mode: str) -> str:
v = cls.get(OUTPUT)
From 235614dc95086018903a52ca103f4b84caedb6ff Mon Sep 17 00:00:00 2001
From: k9er <67886793+otta8634@users.noreply.github.com>
Date: Sat, 16 Jul 2022 07:50:44 -0700
Subject: [PATCH 03/12] Hide platform links
Resolves #4 for now until links are updated.
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 77c5eba..488031c 100755
--- a/README.md
+++ b/README.md
@@ -7,7 +7,9 @@
+
From 15cf6cea2dfe728dd02af6c6f8a3cb05ce748aeb Mon Sep 17 00:00:00 2001
From: k9wolf8634
Date: Sun, 17 Jul 2022 01:13:36 +0800
Subject: [PATCH 04/12] Minor GUI changes
---
source/main_window.py | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/source/main_window.py b/source/main_window.py
index 6fc478d..3363474 100644
--- a/source/main_window.py
+++ b/source/main_window.py
@@ -10,8 +10,16 @@
from PyQt5 import QtCore, QtGui, QtWidgets
+_translate = QtCore.QCoreApplication.translate
class Ui_MainWindow(object):
+ def __init__(self):
+ self.largeFont = QtGui.QFont()
+ self.largeFont.setPointSize(11)
+ self.largeBoldFont = QtGui.QFont()
+ self.largeBoldFont.setPointSize(11)
+ self.largeBoldFont.setBold(True)
+
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1440, 855)
@@ -84,13 +92,14 @@ def setupUi(self, MainWindow):
self.musicTabs = QtWidgets.QTabWidget(self.centralwidget)
self.musicTabs.setStyleSheet("QTabWidget::pane\n"
"{\n"
-" border:0px;\n"
+" border: 0px;\n"
"}\n"
"\n"
"QTabWidget::tab-bar\n"
"{\n"
" alignment: center;\n"
"}")
+ self.musicTabs.setFont(self.largeFont)
self.musicTabs.setTabPosition(QtWidgets.QTabWidget.West)
self.musicTabs.setTabBarAutoHide(True)
self.musicTabs.setObjectName("musicTabs")
@@ -104,6 +113,7 @@ def setupUi(self, MainWindow):
"{\n"
" alignment: center;\n"
"}")
+ self.libraryTabs.setFont(self.largeFont)
self.libraryTabs.setObjectName("libraryTabs")
self.downloadedTab = QtWidgets.QWidget()
self.downloadedTab.setObjectName("downloadedTab")
@@ -212,6 +222,7 @@ def setupUi(self, MainWindow):
self.verticalLayout_7.setContentsMargins(3, 0, 3, 3)
self.verticalLayout_7.setObjectName("verticalLayout_7")
self.queueTabs = QtWidgets.QTabWidget(self.queueTabLayout)
+ self.queueTabs.setFont(self.largeFont)
self.queueTabs.setObjectName("queueTabs")
self.queueTreeTab = QtWidgets.QWidget()
self.queueTreeTab.setObjectName("queueTreeTab")
@@ -245,12 +256,14 @@ def setupUi(self, MainWindow):
self.playingInfo1.setMinimumSize(QtCore.QSize(250, 0))
self.playingInfo1.setMaximumSize(QtCore.QSize(250, 16777215))
self.playingInfo1.setText("")
+ self.playingInfo1.setFont(self.largeBoldFont)
self.playingInfo1.setObjectName("playingInfo1")
self.verticalLayout_6.addWidget(self.playingInfo1)
self.playingInfo2 = QtWidgets.QLabel(self.mediaControls)
self.playingInfo2.setMinimumSize(QtCore.QSize(250, 0))
self.playingInfo2.setMaximumSize(QtCore.QSize(250, 16777215))
self.playingInfo2.setText("")
+ self.playingInfo2.setFont(self.largeFont)
self.playingInfo2.setObjectName("playingInfo2")
self.verticalLayout_6.addWidget(self.playingInfo2)
self.horizontalLayout_5.addLayout(self.verticalLayout_6)
@@ -270,6 +283,7 @@ def setupUi(self, MainWindow):
self.repeatBtn.setIcon(icon)
self.repeatBtn.setFlat(True)
self.repeatBtn.setObjectName("repeatBtn")
+ self.repeatBtn.setToolTip(_translate("MainWindow", "Repeat"))
self.horizontalLayout_7.addWidget(self.repeatBtn)
self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
self.horizontalLayout_8.setContentsMargins(-1, -1, 0, -1)
@@ -284,6 +298,7 @@ def setupUi(self, MainWindow):
self.prevBtn.setIconSize(QtCore.QSize(16, 16))
self.prevBtn.setFlat(True)
self.prevBtn.setObjectName("prevBtn")
+ self.prevBtn.setToolTip(_translate("MainWindow", "Previous"))
self.horizontalLayout_8.addWidget(self.prevBtn)
self.verticalLayout_5 = QtWidgets.QVBoxLayout()
self.verticalLayout_5.setContentsMargins(0, -1, -1, 20)
@@ -299,6 +314,7 @@ def setupUi(self, MainWindow):
self.playBtn.setIconSize(QtCore.QSize(24, 24))
self.playBtn.setFlat(True)
self.playBtn.setObjectName("playBtn")
+ self.playBtn.setToolTip(_translate("MainWindow", "Play/Pause"))
self.verticalLayout_5.addWidget(self.playBtn)
self.horizontalLayout_8.addLayout(self.verticalLayout_5)
self.nextBtn = QtWidgets.QPushButton(self.mediaControls)
@@ -310,6 +326,7 @@ def setupUi(self, MainWindow):
self.nextBtn.setIconSize(QtCore.QSize(16, 16))
self.nextBtn.setFlat(True)
self.nextBtn.setObjectName("nextBtn")
+ self.nextBtn.setToolTip(_translate("MainWindow", "Next"))
self.horizontalLayout_8.addWidget(self.nextBtn)
self.horizontalLayout_7.addLayout(self.horizontalLayout_8)
self.shuffleBtn = QtWidgets.QPushButton(self.mediaControls)
@@ -320,6 +337,7 @@ def setupUi(self, MainWindow):
self.shuffleBtn.setIconSize(QtCore.QSize(16, 16))
self.shuffleBtn.setFlat(True)
self.shuffleBtn.setObjectName("shuffleBtn")
+ self.shuffleBtn.setToolTip(_translate("MainWindow", "Shuffle"))
self.horizontalLayout_7.addWidget(self.shuffleBtn)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_7.addItem(spacerItem3)
@@ -365,6 +383,7 @@ def setupUi(self, MainWindow):
self.listenQueueBtn.setIconSize(QtCore.QSize(20, 20))
self.listenQueueBtn.setFlat(True)
self.listenQueueBtn.setObjectName("listenQueueBtn")
+ self.listenQueueBtn.setToolTip(_translate("MainWindow", "Queue"))
self.horizontalLayout_5.addWidget(self.listenQueueBtn)
self.volIconLabel = QtWidgets.QLabel(self.mediaControls)
self.volIconLabel.setMinimumSize(QtCore.QSize(16, 16))
@@ -633,7 +652,6 @@ def setupUi(self, MainWindow):
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
- _translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "ZSpotify"))
self.searchInput.setPlaceholderText(_translate("MainWindow", "Search Spotify"))
self.searchBtn.setText(_translate("MainWindow", "Search"))
From 12a0d6f200c000ec1bdc447f69dfb84c4cbcea48 Mon Sep 17 00:00:00 2001
From: k9wolf8634
Date: Sun, 17 Jul 2022 01:30:12 +0800
Subject: [PATCH 05/12] Turn volume icon into button, add muting ability
---
source/audio.py | 23 ++++++++++++++++++++---
source/main_window.py | 25 +++++++++++++------------
source/main_window.ui | 26 +++++++++-----------------
3 files changed, 42 insertions(+), 32 deletions(-)
diff --git a/source/audio.py b/source/audio.py
index bb281e5..e21d8b4 100644
--- a/source/audio.py
+++ b/source/audio.py
@@ -35,11 +35,14 @@ def __init__(self, window):
self.playlist_tree = None
self.shuffle = False
self.repeat = False
+
self.listen_queue = []
self.shuffle_queue = []
self.awaiting_play = False
self.queue_next_song = False
self.paused = False
+ self.muted = False
+ self._volume = 100
self.seeking = False
self.worker = None
self.audio_player = AudioPlayer(self.update_music_progress)
@@ -51,6 +54,7 @@ def __init__(self, window):
set_button_icon(self.window.shuffleBtn, SHUFFLE_OFF_ICON)
set_button_icon(self.window.repeatBtn, REPEAT_OFF_ICON)
set_button_icon(self.window.listenQueueBtn, LISTEN_QUEUE_ICON)
+ set_button_icon(self.window.volIconBtn, VOL_ICON)
if Config.get_enable_media_keys():
keyboard.on_press(self.key_pressed)
@@ -152,10 +156,12 @@ def on_progress_finished(self):
self.on_next()
def set_volume(self, value):
+ self._volume = value
+ self.muted = False
self.audio_player.set_volume(value)
if value == 0:
- set_label_image(self.window.volIconLabel, MUTE_ICON)
- else: set_label_image(self.window.volIconLabel, VOL_ICON)
+ self.set_button_icon(self.window.volIconBtn, MUTE_ICON)
+ else: self.set_button_icon(self.window.volIconBtn, VOL_ICON)
def on_press_play(self):
if self.audio_player.is_playing():
@@ -222,6 +228,16 @@ def on_play_queue_song(self):
if item in self.shuffle_queue:
self.shuffle_queue
+ def toggle_mute(self):
+ if self.muted:
+ self.audio_player.set_volume(self._volume)
+ if self._volume != 0:
+ self.set_button_icon(self.window.volIconBtn, VOL_ICON)
+ else:
+ self.audio_player.set_volume(0)
+ self.set_button_icon(self.window.volIconBtn, MUTE_ICON)
+ self.muted = not self.muted
+
def update_playing_info(self, item):
self.window.playingInfo1.setText(item.title)
@@ -235,7 +251,7 @@ def set_button_icon(self, btn, icon_path):
btn.setIcon(icon)
def set_vol_icon(self, icon_path):
- lbl = self.window.volIconLabel
+ lbl = self.window.volIconBtn
pixmap = QPixmap(icon_path)
lbl.setPixmap(pixmap)
lbl.setScaledContents(True)
@@ -252,6 +268,7 @@ def init_signals(self):
self.window.prevBtn.clicked.connect(self.on_prev)
self.window.shuffleBtn.clicked.connect(self.toggle_shuffle)
self.window.repeatBtn.clicked.connect(self.toggle_repeat)
+ self.window.volIconBtn.clicked.connect(self.toggle_mute)
def key_pressed(self, e):
if e.name == "play/pause media":
diff --git a/source/main_window.py b/source/main_window.py
index 3363474..78d0450 100644
--- a/source/main_window.py
+++ b/source/main_window.py
@@ -385,15 +385,16 @@ def setupUi(self, MainWindow):
self.listenQueueBtn.setObjectName("listenQueueBtn")
self.listenQueueBtn.setToolTip(_translate("MainWindow", "Queue"))
self.horizontalLayout_5.addWidget(self.listenQueueBtn)
- self.volIconLabel = QtWidgets.QLabel(self.mediaControls)
- self.volIconLabel.setMinimumSize(QtCore.QSize(16, 16))
- self.volIconLabel.setMaximumSize(QtCore.QSize(16, 16))
- self.volIconLabel.setText("")
- self.volIconLabel.setTextFormat(QtCore.Qt.RichText)
- self.volIconLabel.setPixmap(QtGui.QPixmap("Resources/volIcon.png"))
- self.volIconLabel.setScaledContents(True)
- self.volIconLabel.setObjectName("volIconLabel")
- self.horizontalLayout_5.addWidget(self.volIconLabel)
+ self.volIconBtn = QtWidgets.QPushButton(self.mediaControls)
+ self.volIconBtn.setText("")
+ icon6 = QtGui.QIcon()
+ icon6.addPixmap(QtGui.QPixmap("Resources/volIcon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+ self.volIconBtn.setIcon(icon6)
+ self.volIconBtn.setIconSize(QtCore.QSize(16, 16))
+ self.volIconBtn.setFlat(True)
+ self.volIconBtn.setObjectName("volIconBtn")
+ self.volIconBtn.setToolTip(_translate("MainWindow", "Mute/Unmute"))
+ self.horizontalLayout_5.addWidget(self.volIconBtn)
self.label_7 = QtWidgets.QLabel(self.mediaControls)
self.label_7.setText("")
self.label_7.setTextFormat(QtCore.Qt.RichText)
@@ -630,9 +631,9 @@ def setupUi(self, MainWindow):
self.dirBtn.setMinimumSize(QtCore.QSize(30, 0))
self.dirBtn.setMaximumSize(QtCore.QSize(40, 40))
self.dirBtn.setText("")
- icon6 = QtGui.QIcon()
- icon6.addPixmap(QtGui.QPixmap("Resources/folderIcon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
- self.dirBtn.setIcon(icon6)
+ icon7 = QtGui.QIcon()
+ icon7.addPixmap(QtGui.QPixmap("Resources/folderIcon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+ self.dirBtn.setIcon(icon7)
self.dirBtn.setObjectName("dirBtn")
self.horizontalLayout_4.addWidget(self.dirBtn)
self.horizontalLayout_4.setStretch(1, 3)
diff --git a/source/main_window.ui b/source/main_window.ui
index 0f5e7c1..6ab374c 100644
--- a/source/main_window.ui
+++ b/source/main_window.ui
@@ -1125,29 +1125,21 @@ QTabWidget::tab-bar
-
-
-
-
- 16
- 16
-
+
+
+
-
+
+
+ Resources/volIcon.pngResources/volIcon.png
+
+
16
16
-
-
-
-
- Qt::RichText
-
-
- Resources/volIcon.png
-
-
+
true
From 8b3d8c11b78e567b30a792c8a07d08f8d14d3ba5 Mon Sep 17 00:00:00 2001
From: k9wolf8634
Date: Sun, 17 Jul 2022 03:59:10 +0800
Subject: [PATCH 06/12] GUI changes, downloaded file cover-art, queue fixes
---
source/appGui.py | 42 ++++++++++----
source/audio.py | 31 ++++++++---
source/config.py | 8 ++-
source/itemTree.py | 19 ++++++-
source/main_window.py | 126 ++++++++++++++++++++++--------------------
5 files changed, 143 insertions(+), 83 deletions(-)
diff --git a/source/appGui.py b/source/appGui.py
index 1b4a47b..e0909dc 100755
--- a/source/appGui.py
+++ b/source/appGui.py
@@ -9,6 +9,7 @@
import sys
import requests
import logging
+from mutagen.id3 import ID3
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import QThreadPool
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog, QTreeWidgetItem, QLineEdit
@@ -76,6 +77,7 @@ def __init__(self, parent=None):
self.download_tree.focus()
self.reconnecting = False
+
def show(self):
super().show()
if not ZSpotify.login():
@@ -144,8 +146,11 @@ def display_results(self, results):
def update_item_info(self, item, headers, labels):
if not item: return
self.selected_item = item
- worker = Worker(self._cover_art_loader, item)
- QThreadPool.globalInstance().start(worker)
+ if item.downloaded:
+ self.extract_cover_art(item)
+ else:
+ worker = Worker(self._cover_art_loader, item)
+ QThreadPool.globalInstance().start(worker)
[lbl.setText("") for lbl in self.info_labels]
if "Index" in headers:
labels.pop(headers.index("Index"))
@@ -183,6 +188,20 @@ def request_cover_art(self, url):
lbl.setScaledContents(True)
lbl.show()
+ def extract_cover_art(self, item):
+ tags = ID3(item.path)
+ pict = [v for v in tags.values() if v.FrameID == "APIC"]
+ if not len(pict):
+ pass
+ if not pict[0]:
+ pass
+ pixmap = QPixmap()
+ pixmap.loadFromData(pict[0].data)
+ lbl = self.coverArtLabel
+ lbl.setPixmap(pixmap)
+ lbl.setScaledContents(True)
+ lbl.show()
+
def update_result_amount(self, index):
amount = int(self.resultAmountCombo.itemText(index))
Config.set(TOTAL_SEARCH_RESULTS, amount)
@@ -239,6 +258,7 @@ def init_signals(self):
tree.signals.onSelected.connect(self.update_item_labels)
tree.signals.doubleClicked.connect(self.on_try_play_item)
tree.signals.onListenQueued.connect(self.music_controller.queue_track)
+ tree.signals.onListenUnqueued.connect(self.music_controller.remove_track)
tree.signals.onDownloadQueued.connect(self.download_controller.on_click_download)
return_shortcut = QtWidgets.QShortcut(QtCore.Qt.Key_Return,
tree.tree,
@@ -339,32 +359,32 @@ def init_tree_views(self):
self.songs_tree.set_header_item(
Track("Index", 0, "Title", "Artists", "Album", duration="Duration", release_date="Release Date"))
- self.artists_tree = ItemTree(self.artistsTree, lambda artist: QTreeWidgetItem([str(artist.index), artist.name]))
+ self.artists_tree = ItemTree(self.artistsTree, lambda artist: QTreeWidgetItem([str(artist.index), artist.name]), "artists")
self.artists_tree.set_header_item(Artist("Index", 0, "Name"))
self.albums_tree = ItemTree(self.albumsTree,
lambda album: QTreeWidgetItem([str(album.index), album.title, album.artists, \
- str(album.total_tracks), str(album.release_date)]))
+ str(album.total_tracks), str(album.release_date)]), "albums")
self.albums_tree.set_header_item(Album("Index", 0, "Title", "Artists", "Total Tracks", "Release Date"))
self.playlists_tree = ItemTree(self.playlistsTree,
lambda playlist: QTreeWidgetItem([str(playlist.index), playlist.title, \
str(playlist.creator),
- str(playlist.total_tracks)]))
+ str(playlist.total_tracks)]), "playlists")
self.playlists_tree.set_header_item(Playlist("Index", 0, "Title", "Author", "Total Tracks"))
self.download_tree = ItemTree(self.downloadedTree,
- lambda track: QTreeWidgetItem([track.title, track.artists, track.album]))
- self.download_tree.set_header_item(Track("", 0, "Title", "Artists", "Albums"))
+ lambda track: QTreeWidgetItem([track.title, track.artists, track.album]), "download")
+ self.download_tree.set_header_item(Track("", 0, "Title", "Artists", "Album"))
self.liked_tree = ItemTree(self.likedTree,
- lambda track: QTreeWidgetItem([track.title, track.artists, track.album]))
- self.liked_tree.set_header_item(Track("", 0, "Title", "Artists", "Albums"))
+ lambda track: QTreeWidgetItem([track.title, track.artists, track.album]), "liked")
+ self.liked_tree.set_header_item(Track("", 0, "Title", "Artists", "Album"))
self.liked_tree.load_function = self.init_liked_view
self.queue_tree = ItemTree(self.queueTree,
- lambda track: QTreeWidgetItem([track.title, track.artists, track.album]), False)
- self.queue_tree.set_header_item(Track("", 0, "Title", "Artists", "Albums"))
+ lambda track: QTreeWidgetItem([track.title, track.artists, track.album]), "queue", False)
+ self.queue_tree.set_header_item(Track("", 0, "Title", "Artists", "Album"))
self.queue_tree.load_function = self.init_queue_view
self.search_trees = [self.songs_tree, self.artists_tree, self.albums_tree, self.playlists_tree]
diff --git a/source/audio.py b/source/audio.py
index e21d8b4..986cf61 100644
--- a/source/audio.py
+++ b/source/audio.py
@@ -57,6 +57,8 @@ def __init__(self, window):
set_button_icon(self.window.volIconBtn, VOL_ICON)
if Config.get_enable_media_keys():
keyboard.on_press(self.key_pressed)
+ if not Config.get_relative_time():
+ self.window.remainingTimeLabel.setText(self.window._translate("MainWindow", "0:00"))
def play(self, item, playlist_tree):
@@ -87,12 +89,14 @@ def start_progress_worker(self):
def pause(self):
self.set_button_icon(self.window.playBtn, PLAY_ICON)
+ self.window.playBtn.setToolTip(self.window._translate("MainWindow", "Play"))
self.paused = True
self.queue_next_song = False
self.audio_player.pause()
def unpause(self):
self.set_button_icon(self.window.playBtn, PAUSE_ICON)
+ self.window.playBtn.setToolTip(self.window._translate("MainWindow", "Pause"))
self.paused = False
self.queue_next_song = True
self.audio_player.unpause()
@@ -103,7 +107,7 @@ def queue_track(self, item, index=-1):
if index == -1:
self.listen_queue.append(item)
else:
- self.listen_queue.insert(index,item)
+ self.listen_queue.insert(index,item)
def remove_track(self, item):
if not item: return
@@ -118,17 +122,21 @@ def toggle_shuffle(self):
if self.shuffle:
if self.playlist_tree and self.playlist_tree.items:
self.set_button_icon(self.window.shuffleBtn, SHUFFLE_ON_ICON)
+ self.window.shuffleBtn.setToolTip(self.window._translate("MainWindow", "Disable shuffle"))
self.shuffle_queue = self.playlist_tree.items.copy()
random.shuffle(self.shuffle_queue)
else:
self.set_button_icon(self.window.shuffleBtn, SHUFFLE_OFF_ICON)
+ self.window.shuffleBtn.setToolTip(self.window._translate("MainWindow", "Enable shuffle"))
def toggle_repeat(self):
self.repeat = not self.repeat
if self.repeat:
self.set_button_icon(self.window.repeatBtn, REPEAT_ON_ICON)
+ self.window.repeatBtn.setToolTip(self.window._translate("MainWindow", "Disable repeat"))
else:
self.set_button_icon(self.window.repeatBtn, REPEAT_OFF_ICON)
+ self.window.repeatBtn.setToolTip(self.window._translate("MainWindow", "Enable repeat"))
def update_music_progress(self, perc, elapsed, total):
if not self.seeking:
@@ -138,9 +146,9 @@ def update_music_progress(self, perc, elapsed, total):
duration = self.audio_player.player.get_length()
playback_bar_perc = self.window.playbackBar.value()/self.window.playbackBar.maximum()
self.window.elapsedTimeLabel.setText(ms_to_time_str(duration * playback_bar_perc))
- self.window.remainingTimeLabel.setText(f"-{ms_to_time_str(duration * (1-playback_bar_perc))}")
+ self.window.remainingTimeLabel.setText(f"-{ms_to_time_str(duration * (1-playback_bar_perc))}" if Config.get_relative_time() else ms_to_time_str(int(total)))
self.window.elapsedTimeLabel.setText(ms_to_time_str(elapsed))
- self.window.remainingTimeLabel.setText(f"-{ms_to_time_str(int(total)-int(elapsed))}")
+ self.window.remainingTimeLabel.setText(f"-{ms_to_time_str(int(total)-int(elapsed))}" if Config.get_relative_time() else ms_to_time_str(int(total)))
def run_progress_bar(self, signal, *args, **kwargs):
while self.audio_player.is_playing() or self.awaiting_play:
@@ -161,7 +169,10 @@ def set_volume(self, value):
self.audio_player.set_volume(value)
if value == 0:
self.set_button_icon(self.window.volIconBtn, MUTE_ICON)
- else: self.set_button_icon(self.window.volIconBtn, VOL_ICON)
+ self.window.volIconBtn.setToolTip(self.window._translate("MainWindow", "Unmute"))
+ else:
+ self.set_button_icon(self.window.volIconBtn, VOL_ICON)
+ self.window.volIconBtn.setToolTip(self.window._translate("MainWindow", "Mute"))
def on_press_play(self):
if self.audio_player.is_playing():
@@ -229,19 +240,21 @@ def on_play_queue_song(self):
self.shuffle_queue
def toggle_mute(self):
+ self.muted = not self.muted
if self.muted:
+ self.audio_player.set_volume(0)
+ self.set_button_icon(self.window.volIconBtn, MUTE_ICON)
+ self.window.volIconBtn.setToolTip(self.window._translate("MainWindow", "Unmute"))
+ else:
self.audio_player.set_volume(self._volume)
if self._volume != 0:
self.set_button_icon(self.window.volIconBtn, VOL_ICON)
- else:
- self.audio_player.set_volume(0)
- self.set_button_icon(self.window.volIconBtn, MUTE_ICON)
- self.muted = not self.muted
+ self.window.volIconBtn.setToolTip(self.window._translate("MainWindow", "Mute"))
def update_playing_info(self, item):
self.window.playingInfo1.setText(item.title)
- self.window.playingInfo1.setToolTip(item.title)
+ self.window.playingInfo1.setToolTip(f"On album {item.album}")
self.window.playingInfo2.setText(item.artists)
self.window.playingInfo2.setToolTip(item.artists)
diff --git a/source/config.py b/source/config.py
index 2199f28..613713d 100644
--- a/source/config.py
+++ b/source/config.py
@@ -30,6 +30,7 @@
PRINT_DOWNLOADS = 'PRINT_DOWNLOADS'
TEMP_DOWNLOAD_DIR = 'TEMP_DOWNLOAD_DIR'
ENABLE_MEDIA_KEYS = 'ENABLE_MEDIA_KEYS'
+RELATIVE_TIME = 'RELATIVE_TIME'
CONFIG_VALUES = {
ROOT_PATH: { 'default': '../ZSpotify Music/', 'type': str, 'arg': '--root-path' },
@@ -55,7 +56,8 @@
PRINT_ERRORS: { 'default': 'True', 'type': bool, 'arg': '--print-errors' },
PRINT_DOWNLOADS: { 'default': 'False', 'type': bool, 'arg': '--print-downloads' },
TEMP_DOWNLOAD_DIR: { 'default': '', 'type': str, 'arg': '--temp-download-dir' },
- ENABLE_MEDIA_KEYS: { 'default': 'True', 'type': bool, 'arg': '--enable-media-keys' }
+ ENABLE_MEDIA_KEYS: { 'default': 'True', 'type': bool, 'arg': '--enable-media-keys' },
+ RELATIVE_TIME: { 'default': 'True', 'type': bool, 'arg': '--relative-time' }
}
OUTPUT_DEFAULT_PLAYLIST = '{playlist}/{artist} - {song_name}.{ext}'
@@ -217,6 +219,10 @@ def get_total_search_results(cls):
def get_enable_media_keys(cls):
return cls.get(ENABLE_MEDIA_KEYS)
+ @classmethod
+ def get_relative_time(cls):
+ return cls.get(RELATIVE_TIME)
+
@classmethod
def get_output(cls, mode: str) -> str:
v = cls.get(OUTPUT)
diff --git a/source/itemTree.py b/source/itemTree.py
index 7903365..1d7ee31 100644
--- a/source/itemTree.py
+++ b/source/itemTree.py
@@ -5,8 +5,9 @@
class ItemTree:
- def __init__(self, tree, tree_widget_builder = None, can_play = True):
+ def __init__(self, tree, tree_widget_builder = None, name = "", can_play = True):
self.tree = tree
+ self.name = name
self.items = []
self.tree_items = {}
self.selected_item = None
@@ -31,8 +32,10 @@ def add_item(self, item):
self.items.append(item)
self.tree_items[item] = widget_item
self.tree.addTopLevelItem(widget_item)
+ self.update_index(item)
def remove_item(self, item):
+ if item not in self.items: return
self.items.remove(item)
if item in self.tree_items:
index = self.item_index(item)
@@ -84,6 +87,9 @@ def item_index(self, item):
return i
return -1
+ def update_index(self, item):
+ item.index = self.item_index(item)
+
def current_item_index(self):
item = self.get_selected_item()
if not item: return -1
@@ -96,6 +102,7 @@ def clear(self):
self.tree.clear()
+ # FIXME: doesn't work properly if multiple of same entry
def get_selected_item(self):
tree_widget = self.tree.currentItem()
if tree_widget:
@@ -148,14 +155,23 @@ def on_download_item(self):
def on_listen_queue(self):
if not self.selected_item: return
+ if self.name == "queue":
+ self.add_item(self.selected_item)
self.signals.onListenQueued.emit(self.selected_item)
+ def on_listen_unqueue(self):
+ if not self.selected_item: return
+ self.signals.onListenUnqueued.emit(self.selected_item)
+ self.remove_item(self.selected_item)
+
def on_context_menu(self, pos):
if not self.selected_item: return
node = self.tree.mapToGlobal(pos)
self.popup_menu = QMenu(None)
if self.selected_item.downloaded:
self.popup_menu.addAction("Add to listen queue", self.on_listen_queue)
+ if self.name == "queue":
+ self.popup_menu.addAction("Remove from listen queue", self.on_listen_unqueue)
else:
self.popup_menu.addAction("Add to download queue", self.on_download_item)
if self.selected_item.downloaded:
@@ -175,4 +191,5 @@ class ItemTreeSignals(QObject):
onSelected = pyqtSignal(list)
onDeleted = pyqtSignal(Item, QTreeWidget)
onListenQueued = pyqtSignal(Item)
+ onListenUnqueued = pyqtSignal(Item)
onDownloadQueued = pyqtSignal(Item)
diff --git a/source/main_window.py b/source/main_window.py
index 78d0450..e2fa174 100644
--- a/source/main_window.py
+++ b/source/main_window.py
@@ -10,10 +10,11 @@
from PyQt5 import QtCore, QtGui, QtWidgets
-_translate = QtCore.QCoreApplication.translate
class Ui_MainWindow(object):
def __init__(self):
+ self._translate = QtCore.QCoreApplication.translate
+
self.largeFont = QtGui.QFont()
self.largeFont.setPointSize(11)
self.largeBoldFont = QtGui.QFont()
@@ -151,6 +152,7 @@ def setupUi(self, MainWindow):
self.verticalLayout_15.setContentsMargins(1, 0, 1, 1)
self.verticalLayout_15.setObjectName("verticalLayout_15")
self.searchTabs = QtWidgets.QTabWidget(self.resultLayout)
+ self.searchTabs.setFont(self.largeFont)
self.searchTabs.setStyleSheet("")
self.searchTabs.setTabPosition(QtWidgets.QTabWidget.North)
self.searchTabs.setElideMode(QtCore.Qt.ElideRight)
@@ -283,7 +285,7 @@ def setupUi(self, MainWindow):
self.repeatBtn.setIcon(icon)
self.repeatBtn.setFlat(True)
self.repeatBtn.setObjectName("repeatBtn")
- self.repeatBtn.setToolTip(_translate("MainWindow", "Repeat"))
+ self.repeatBtn.setToolTip(self._translate("MainWindow", "Enable repeat"))
self.horizontalLayout_7.addWidget(self.repeatBtn)
self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
self.horizontalLayout_8.setContentsMargins(-1, -1, 0, -1)
@@ -298,7 +300,7 @@ def setupUi(self, MainWindow):
self.prevBtn.setIconSize(QtCore.QSize(16, 16))
self.prevBtn.setFlat(True)
self.prevBtn.setObjectName("prevBtn")
- self.prevBtn.setToolTip(_translate("MainWindow", "Previous"))
+ self.prevBtn.setToolTip(self._translate("MainWindow", "Previous"))
self.horizontalLayout_8.addWidget(self.prevBtn)
self.verticalLayout_5 = QtWidgets.QVBoxLayout()
self.verticalLayout_5.setContentsMargins(0, -1, -1, 20)
@@ -314,7 +316,7 @@ def setupUi(self, MainWindow):
self.playBtn.setIconSize(QtCore.QSize(24, 24))
self.playBtn.setFlat(True)
self.playBtn.setObjectName("playBtn")
- self.playBtn.setToolTip(_translate("MainWindow", "Play/Pause"))
+ self.playBtn.setToolTip(self._translate("MainWindow", "Play"))
self.verticalLayout_5.addWidget(self.playBtn)
self.horizontalLayout_8.addLayout(self.verticalLayout_5)
self.nextBtn = QtWidgets.QPushButton(self.mediaControls)
@@ -326,7 +328,7 @@ def setupUi(self, MainWindow):
self.nextBtn.setIconSize(QtCore.QSize(16, 16))
self.nextBtn.setFlat(True)
self.nextBtn.setObjectName("nextBtn")
- self.nextBtn.setToolTip(_translate("MainWindow", "Next"))
+ self.nextBtn.setToolTip(self._translate("MainWindow", "Next"))
self.horizontalLayout_8.addWidget(self.nextBtn)
self.horizontalLayout_7.addLayout(self.horizontalLayout_8)
self.shuffleBtn = QtWidgets.QPushButton(self.mediaControls)
@@ -337,7 +339,7 @@ def setupUi(self, MainWindow):
self.shuffleBtn.setIconSize(QtCore.QSize(16, 16))
self.shuffleBtn.setFlat(True)
self.shuffleBtn.setObjectName("shuffleBtn")
- self.shuffleBtn.setToolTip(_translate("MainWindow", "Shuffle"))
+ self.shuffleBtn.setToolTip(self._translate("MainWindow", "Enable shuffle"))
self.horizontalLayout_7.addWidget(self.shuffleBtn)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_7.addItem(spacerItem3)
@@ -383,7 +385,7 @@ def setupUi(self, MainWindow):
self.listenQueueBtn.setIconSize(QtCore.QSize(20, 20))
self.listenQueueBtn.setFlat(True)
self.listenQueueBtn.setObjectName("listenQueueBtn")
- self.listenQueueBtn.setToolTip(_translate("MainWindow", "Queue"))
+ self.listenQueueBtn.setToolTip(self._translate("MainWindow", "Queue"))
self.horizontalLayout_5.addWidget(self.listenQueueBtn)
self.volIconBtn = QtWidgets.QPushButton(self.mediaControls)
self.volIconBtn.setText("")
@@ -393,7 +395,7 @@ def setupUi(self, MainWindow):
self.volIconBtn.setIconSize(QtCore.QSize(16, 16))
self.volIconBtn.setFlat(True)
self.volIconBtn.setObjectName("volIconBtn")
- self.volIconBtn.setToolTip(_translate("MainWindow", "Mute/Unmute"))
+ self.volIconBtn.setToolTip(self._translate("MainWindow", "Mute"))
self.horizontalLayout_5.addWidget(self.volIconBtn)
self.label_7 = QtWidgets.QLabel(self.mediaControls)
self.label_7.setText("")
@@ -653,59 +655,61 @@ def setupUi(self, MainWindow):
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
- MainWindow.setWindowTitle(_translate("MainWindow", "ZSpotify"))
- self.searchInput.setPlaceholderText(_translate("MainWindow", "Search Spotify"))
- self.searchBtn.setText(_translate("MainWindow", "Search"))
- self.resultAmountCombo.setItemText(0, _translate("MainWindow", "10"))
- self.resultAmountCombo.setItemText(1, _translate("MainWindow", "20"))
- self.resultAmountCombo.setItemText(2, _translate("MainWindow", "30"))
- self.resultAmountCombo.setItemText(3, _translate("MainWindow", "40"))
- self.resultAmountCombo.setItemText(4, _translate("MainWindow", "50"))
- self.label_6.setText(_translate("MainWindow", "Results"))
- self.loginBtn.setText(_translate("MainWindow", "Login"))
+ MainWindow.setWindowTitle(self._translate("MainWindow", "ZSpotify"))
+ MainWindow.setWindowIcon(QtGui.QIcon("Resources/ZSpot_Icon.png"))
+ self.searchInput.setPlaceholderText(self._translate("MainWindow", "Search Spotify"))
+ self.searchBtn.setText(self._translate("MainWindow", "Search"))
+ self.resultAmountCombo.setItemText(0, self._translate("MainWindow", "10"))
+ self.resultAmountCombo.setItemText(1, self._translate("MainWindow", "20"))
+ self.resultAmountCombo.setItemText(2, self._translate("MainWindow", "30"))
+ self.resultAmountCombo.setItemText(3, self._translate("MainWindow", "40"))
+ self.resultAmountCombo.setItemText(4, self._translate("MainWindow", "50"))
+ self.label_6.setText(self._translate("MainWindow", "Results"))
+ self.loginBtn.setText(self._translate("MainWindow", "Login"))
self.downloadedTree.setSortingEnabled(True)
- self.downloadedTree.headerItem().setText(1, _translate("MainWindow", "Artists"))
- self.downloadedTree.headerItem().setText(2, _translate("MainWindow", "Album"))
- self.libraryTabs.setTabText(self.libraryTabs.indexOf(self.downloadedTab), _translate("MainWindow", "Downloaded"))
+ self.downloadedTree.headerItem().setText(1, self._translate("MainWindow", "Artists"))
+ self.downloadedTree.headerItem().setText(2, self._translate("MainWindow", "Album"))
+ self.libraryTabs.setTabText(self.libraryTabs.indexOf(self.downloadedTab), self._translate("MainWindow", "Downloaded"))
self.likedTree.setSortingEnabled(True)
- self.libraryTabs.setTabText(self.libraryTabs.indexOf(self.likedTab), _translate("MainWindow", "Liked"))
- self.musicTabs.setTabText(self.musicTabs.indexOf(self.libraryLayout), _translate("MainWindow", "Your Library"))
- self.songsTree.headerItem().setText(0, _translate("MainWindow", "Index"))
- self.songsTree.headerItem().setText(1, _translate("MainWindow", "Title"))
- self.songsTree.headerItem().setText(2, _translate("MainWindow", "Artists"))
- self.songsTree.headerItem().setText(3, _translate("MainWindow", "Album"))
- self.songsTree.headerItem().setText(4, _translate("MainWindow", "Duration"))
- self.songsTree.headerItem().setText(5, _translate("MainWindow", "Release Date"))
- self.searchTabs.setTabText(self.searchTabs.indexOf(self.songsTab), _translate("MainWindow", "Songs"))
- self.artistsTree.headerItem().setText(0, _translate("MainWindow", "Index"))
- self.artistsTree.headerItem().setText(1, _translate("MainWindow", "Name"))
- self.searchTabs.setTabText(self.searchTabs.indexOf(self.artistsTab), _translate("MainWindow", "Artists"))
- self.albumsTree.headerItem().setText(0, _translate("MainWindow", "Index"))
- self.albumsTree.headerItem().setText(1, _translate("MainWindow", "Title"))
- self.albumsTree.headerItem().setText(2, _translate("MainWindow", "Artists"))
- self.albumsTree.headerItem().setText(3, _translate("MainWindow", "Total Tracks"))
- self.albumsTree.headerItem().setText(4, _translate("MainWindow", "Release Date"))
- self.searchTabs.setTabText(self.searchTabs.indexOf(self.albumsTab), _translate("MainWindow", "Albums"))
- self.playlistsTree.headerItem().setText(0, _translate("MainWindow", "Index"))
- self.playlistsTree.headerItem().setText(1, _translate("MainWindow", "Title"))
- self.playlistsTree.headerItem().setText(2, _translate("MainWindow", "Creator"))
- self.playlistsTree.headerItem().setText(3, _translate("MainWindow", "Total Tracks"))
- self.searchTabs.setTabText(self.searchTabs.indexOf(self.playlistsTab), _translate("MainWindow", "Playlists"))
- self.musicTabs.setTabText(self.musicTabs.indexOf(self.resultLayout), _translate("MainWindow", "Search Results"))
- self.queueTree.headerItem().setText(0, _translate("MainWindow", "Title"))
- self.queueTree.headerItem().setText(1, _translate("MainWindow", "Artists"))
- self.queueTree.headerItem().setText(2, _translate("MainWindow", "Album"))
- self.queueTabs.setTabText(self.queueTabs.indexOf(self.queueTreeTab), _translate("MainWindow", "Queue"))
- self.musicTabs.setTabText(self.musicTabs.indexOf(self.queueTabLayout), _translate("MainWindow", "Queue"))
- self.elapsedTimeLabel.setText(_translate("MainWindow", "0:00"))
- self.remainingTimeLabel.setText(_translate("MainWindow", "-0:00"))
- self.dlQualityHeader.setText(_translate("MainWindow", "Download Quality:"))
- self.dlQualityLabel.setText(_translate("MainWindow", "320kbps"))
- self.fileFormatHeader.setText(_translate("MainWindow", "File Format:"))
- self.fileFormatCombo.setItemText(0, _translate("MainWindow", ".mp3"))
- self.fileFormatCombo.setItemText(1, _translate("MainWindow", ".ogg"))
- self.label_5.setText(_translate("MainWindow", "Download in Real Time:"))
- self.label_2.setText(_translate("MainWindow", "Download Queue:"))
- self.downloadBtn.setText(_translate("MainWindow", "Download "))
- self.dirBtn.setToolTip(_translate("MainWindow", "Change download directory"))
+ self.libraryTabs.setTabText(self.libraryTabs.indexOf(self.likedTab), self._translate("MainWindow", "Liked"))
+ self.musicTabs.setTabText(self.musicTabs.indexOf(self.libraryLayout), self._translate("MainWindow", "Your Library"))
+ self.songsTree.headerItem().setText(0, self._translate("MainWindow", "Index"))
+ self.songsTree.headerItem().setText(1, self._translate("MainWindow", "Title"))
+ self.songsTree.headerItem().setText(2, self._translate("MainWindow", "Artists"))
+ self.songsTree.headerItem().setText(3, self._translate("MainWindow", "Album"))
+ self.songsTree.headerItem().setText(4, self._translate("MainWindow", "Duration"))
+ self.songsTree.headerItem().setText(5, self._translate("MainWindow", "Release Date"))
+ self.searchTabs.setTabText(self.searchTabs.indexOf(self.songsTab), self._translate("MainWindow", "Songs"))
+ self.artistsTree.headerItem().setText(0, self._translate("MainWindow", "Index"))
+ self.artistsTree.headerItem().setText(1, self._translate("MainWindow", "Name"))
+ self.searchTabs.setTabText(self.searchTabs.indexOf(self.artistsTab), self._translate("MainWindow", "Artists"))
+ self.albumsTree.headerItem().setText(0, self._translate("MainWindow", "Index"))
+ self.albumsTree.headerItem().setText(1, self._translate("MainWindow", "Title"))
+ self.albumsTree.headerItem().setText(2, self._translate("MainWindow", "Artists"))
+ self.albumsTree.headerItem().setText(3, self._translate("MainWindow", "Total Tracks"))
+ self.albumsTree.headerItem().setText(4, self._translate("MainWindow", "Release Date"))
+ self.searchTabs.setTabText(self.searchTabs.indexOf(self.albumsTab), self._translate("MainWindow", "Albums"))
+ self.playlistsTree.headerItem().setText(0, self._translate("MainWindow", "Index"))
+ self.playlistsTree.headerItem().setText(1, self._translate("MainWindow", "Title"))
+ self.playlistsTree.headerItem().setText(2, self._translate("MainWindow", "Creator"))
+ self.playlistsTree.headerItem().setText(3, self._translate("MainWindow", "Total Tracks"))
+ self.searchTabs.setTabText(self.searchTabs.indexOf(self.playlistsTab), self._translate("MainWindow", "Playlists"))
+ self.musicTabs.setTabText(self.musicTabs.indexOf(self.resultLayout), self._translate("MainWindow", "Search Results"))
+ self.queueTree.headerItem().setText(0, self._translate("MainWindow", "Title"))
+ self.queueTree.headerItem().setText(1, self._translate("MainWindow", "Artists"))
+ self.queueTree.headerItem().setText(2, self._translate("MainWindow", "Album"))
+ self.queueTabs.setTabText(self.queueTabs.indexOf(self.queueTreeTab), self._translate("MainWindow", "Queue"))
+ self.musicTabs.setTabText(self.musicTabs.indexOf(self.queueTabLayout), self._translate("MainWindow", "Queue"))
+ self.elapsedTimeLabel.setText(self._translate("MainWindow", "0:00"))
+ self.remainingTimeLabel.setText(self._translate("MainWindow", "-0:00"))
+ self.dlQualityHeader.setText(self._translate("MainWindow", "Download Quality:"))
+ self.dlQualityLabel.setText(self._translate("MainWindow", "320kbps"))
+ self.fileFormatHeader.setText(self._translate("MainWindow", "File Format:"))
+ self.fileFormatCombo.setItemText(0, self._translate("MainWindow", ".mp3"))
+ self.fileFormatCombo.setItemText(1, self._translate("MainWindow", ".ogg"))
+ self.label_5.setText(self._translate("MainWindow", "Download in Real Time:"))
+ self.label_2.setText(self._translate("MainWindow", "Download Queue:"))
+ self.downloadBtn.setText(self._translate("MainWindow", "Download "))
+ self.dirBtn.setToolTip(self._translate("MainWindow", "Change download directory"))
+
from view import SeekableSlider
From a74fd9852ee6ea9242e2c6aa5f1e7531fc0be8cc Mon Sep 17 00:00:00 2001
From: k9wolf8634
Date: Tue, 19 Jul 2022 03:02:02 +0800
Subject: [PATCH 07/12] Add explanation of new config values
---
README.md | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 488031c..90ab18d 100755
--- a/README.md
+++ b/README.md
@@ -116,8 +116,8 @@ Be aware you have to set boolean values in the commandline like this: `--downloa
| Key (zs-config) | commandline parameter | Description
|------------------------------|----------------------------------|---------------------------------------------------------------------|
-| ROOT_PATH | --root-path | directory where ZSpotify saves the music
-| ROOT_PODCAST_PATH | --root-podcast-path | directory where ZSpotify saves the podcasts
+| ROOT_PATH | --root-path | Directory where ZSpotify saves the music
+| ROOT_PODCAST_PATH | --root-podcast-path | Directory where ZSpotify saves the podcasts
| SKIP_EXISTING_FILES | --skip-existing-files | Skip songs with the same name
| SKIP_PREVIOUSLY_DOWNLOADED | --skip-previously-downloaded | Create a .song_archive file and skip previously downloaded songs
| DOWNLOAD_FORMAT | --download-format | The download audio format (aac, fdk_aac, m4a, mp3, ogg, opus, vorbis)
@@ -125,8 +125,8 @@ Be aware you have to set boolean values in the commandline like this: `--downloa
| ANTI_BAN_WAIT_TIME | --anti-ban-wait-time | The wait time between bulk downloads
| OVERRIDE_AUTO_WAIT | --override-auto-wait | Totally disable wait time between songs with the risk of instability
| CHUNK_SIZE | --chunk-size | chunk size for downloading
-| SPLIT_ALBUM_DISCS | --split-album-discs | split downloaded albums by disc
-| DOWNLOAD_REAL_TIME | --download-real-time | only downloads songs as fast as they would be played, can prevent account bans
+| SPLIT_ALBUM_DISCS | --split-album-discs | Split downloaded albums by disc
+| DOWNLOAD_REAL_TIME | --download-real-time | Only downloads songs as fast as they would be played, can prevent account bans
| LANGUAGE | --language | Language for spotify metadata
| BITRATE | --bitrate | Overwrite the bitrate for ffmpeg encoding
| SONG_ARCHIVE | --song-archive | The song_archive file for SKIP_PREVIOUSLY_DOWNLOADED
@@ -138,6 +138,8 @@ Be aware you have to set boolean values in the commandline like this: `--downloa
| PRINT_ERRORS | --print-errors | Print errors
| PRINT_DOWNLOADS | --print-downloads | Print messages when a song is finished downloading
| TEMP_DOWNLOAD_DIR | --temp-download-dir | Download tracks to a temporary directory first
+| ENABLE_MEDIA_KEYS | --enable-media-keys | Allows use of the media keys on your keyboard to play/pause, change track
+| RELATIVE_TIME | --relative-time | Changes the song duration time to time remaining
### Output format:
From 1ed0a3fd46328876c2272b5780d1dd128b6fc252 Mon Sep 17 00:00:00 2001
From: k9er
Date: Mon, 18 Jul 2022 12:11:35 -0700
Subject: [PATCH 08/12] Fix markdown
---
README.md | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/README.md b/README.md
index 90ab18d..647f6c7 100755
--- a/README.md
+++ b/README.md
@@ -78,6 +78,7 @@ MAC:
Command Line Usage
+```
Basic command line usage:
python zspotify