Compare commits
No commits in common. "main" and "v0.1a2" have entirely different histories.
8 changed files with 47 additions and 231 deletions
15
README.md
15
README.md
|
@ -5,14 +5,11 @@ Currently, it just has really basic features but many more things are planned.
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
| Feature | Description | State |
|
| Feature | Description | State |
|
||||||
|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------|
|
|------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------|
|
||||||
| Playlists | You can create and load `.m3u` playlists, edit them and they will get stored on the disk automatically. | <input type="checkbox" disabled checked /> Implemented |
|
| Playlists | You can create and load `.m3u` playlists, edit them and they will get stored on the disk automatically. | <input type="checkbox" disabled checked /> Implemented |
|
||||||
| Background Job Monitor | A QDockWidget where background processes are listed. | <input type="checkbox" disabled checked /> Implemented |
|
| Background Job Monitor | A QDockWidget where background processes are listed. | <input type="checkbox" disabled checked /> Implemented |
|
||||||
| Audio effects | Audio effects like normalizing and an equalizer. This can be implemented pretty easily because Wobuzz uses [Pydub](https://pydub.com/), which has these effects built in. | <input type="checkbox" disabled /> Not Implemented |
|
| Audio effects | Audio effects like normalizing and an equalizer. This can be implemented pretty easily because Wobuzz uses [Pydub](https://pydub.com/), which has these effects built in. | <input type="checkbox" disabled /> Not Implemented |
|
||||||
| Soundcloud downloader | A simple Soundcloud-downloader like maybe integrating [SCDL](https://pypi.org/project/scdl/) would be really cool. | <input type="checkbox" disabled /> Not Implemented |
|
|
||||||
| Synchronisation between devices | This should be pretty hard to implement and idk. if i will ever make it, but synchronisation could be pretty practical e.g. if you have multiple audio systems in different rooms. | <input type="checkbox" disabled /> Not Implemented |
|
|
||||||
| Audio visualization | Firstly, rather simple audio visualization like an oscilloscope would be cool, also something more complicated like [ProjectM](https://github.com/projectM-visualizer/projectm) could be integrated. | <input type="checkbox" disabled /> Not Implemented |
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
@ -26,7 +23,7 @@ there you can find the commands that you need for the installation.
|
||||||
You firstly have to install the newest dependencies:
|
You firstly have to install the newest dependencies:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
sudo apt install xcb libxcb-cursor0 ffmpeg python3-pip git
|
sudo apt install xcb libxcb-cursor0 ffmpeg
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, you can install the newest unstable version using just one more command:
|
Now, you can install the newest unstable version using just one more command:
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -26,7 +26,6 @@ setuptools.setup(
|
||||||
url="https://teapot.informationsanarchistik.de/Wobbl/Wobuzz",
|
url="https://teapot.informationsanarchistik.de/Wobbl/Wobuzz",
|
||||||
author="The Wobbler",
|
author="The Wobbler",
|
||||||
author_email="emil@i21k.de",
|
author_email="emil@i21k.de",
|
||||||
license="GNU GPLv3",
|
|
||||||
packages=setuptools.find_packages(include=["wobuzz", "wobuzz.*"]),
|
packages=setuptools.find_packages(include=["wobuzz", "wobuzz.*"]),
|
||||||
package_data={"": ["*.txt", "*.svg"]},
|
package_data={"": ["*.txt", "*.svg"]},
|
||||||
install_requires=[
|
install_requires=[
|
||||||
|
|
|
@ -22,15 +22,7 @@ class Playlist:
|
||||||
# no other playlist can be created using the same name
|
# no other playlist can be created using the same name
|
||||||
self.app.utils.unique_names.append(self.title)
|
self.app.utils.unique_names.append(self.title)
|
||||||
|
|
||||||
# the number is the index of the header section,
|
self.sorting: list[Qt.SortOrder] | None = None # Custom sort order if None
|
||||||
# the bool is the sorting order (True = ascending, False = descending)
|
|
||||||
self.sorting: list[tuple[int, bool]] = [
|
|
||||||
(0, True),
|
|
||||||
(1, True),
|
|
||||||
(2, True),
|
|
||||||
(3, True),
|
|
||||||
(4, True)
|
|
||||||
]
|
|
||||||
self.tracks: list[Track] = []
|
self.tracks: list[Track] = []
|
||||||
self.current_track_index = 0
|
self.current_track_index = 0
|
||||||
self.current_track: Track | None = None
|
self.current_track: Track | None = None
|
||||||
|
@ -134,87 +126,7 @@ class Playlist:
|
||||||
self.app.gui.on_background_job_stop(process_title)
|
self.app.gui.on_background_job_stop(process_title)
|
||||||
|
|
||||||
def load_from_wbz(self, path):
|
def load_from_wbz(self, path):
|
||||||
file = open(path, "r")
|
self.load_from_m3u(path) # placeholder
|
||||||
m3u = file.read()
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
lines = m3u.split("\n") # m3u entries are separated by newlines
|
|
||||||
lines = lines[:-1] # remove last entry because it is just an empty string
|
|
||||||
|
|
||||||
num_lines = len(lines)
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
|
|
||||||
process_title = f'Loading Playlist "{self.title}"'
|
|
||||||
|
|
||||||
self.app.gui.on_background_job_start(
|
|
||||||
process_title,
|
|
||||||
f'Loading the tracks of "{self.title}".',
|
|
||||||
num_lines,
|
|
||||||
lambda: i
|
|
||||||
)
|
|
||||||
|
|
||||||
while i < num_lines:
|
|
||||||
line = lines[i]
|
|
||||||
|
|
||||||
if line.startswith("#"): # comments and EXTM3U/WOBUZZM3U
|
|
||||||
if line.startswith("#SORT: "): # sort
|
|
||||||
sort_line = line[6:] # delete "#SORT: " from the line
|
|
||||||
|
|
||||||
sorting = sort_line.split(", ") # split into the sort column specifier and the sort order
|
|
||||||
# e.g. ["0", "True"]
|
|
||||||
|
|
||||||
del self.sorting[0] # delete first sort so the length stays at 6
|
|
||||||
|
|
||||||
# convert these from strings back to int and bool and append them to the sorting
|
|
||||||
self.sorting.append((int(sorting[0]), sorting[1] == "True"))
|
|
||||||
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif line.startswith("http"): # filter out urls
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
continue
|
|
||||||
|
|
||||||
self.append_track(Track(self.app, line, cache=i == 0)) # first track is cached
|
|
||||||
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
# set current track to the first track if there is no currently playing track
|
|
||||||
if self.current_track is None and self.has_tracks():
|
|
||||||
self.current_track = self.tracks[0]
|
|
||||||
|
|
||||||
list(self.views.values())[0].sort() # execute sort() on the first view
|
|
||||||
|
|
||||||
self.loaded = True
|
|
||||||
|
|
||||||
self.app.gui.on_background_job_stop(process_title)
|
|
||||||
|
|
||||||
def sync(self, view, user_sort: bool=False):
|
|
||||||
num_tracks = view.topLevelItemCount()
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
|
|
||||||
while i < num_tracks:
|
|
||||||
track_item = view.topLevelItem(i)
|
|
||||||
track = track_item.track
|
|
||||||
|
|
||||||
track_item.index = i
|
|
||||||
|
|
||||||
if user_sort:
|
|
||||||
track_item.index_user_sort = i
|
|
||||||
|
|
||||||
self.tracks[i] = track
|
|
||||||
|
|
||||||
track.set_occurrences()
|
|
||||||
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
# make sure the next track is cached (could be moved by user)
|
|
||||||
if self.app.player.current_playlist == self and self.has_tracks():
|
|
||||||
self.app.player.cache_next_track()
|
|
||||||
|
|
||||||
def has_tracks(self):
|
def has_tracks(self):
|
||||||
return len(self.tracks) > 0
|
return len(self.tracks) > 0
|
||||||
|
@ -257,15 +169,7 @@ class Playlist:
|
||||||
return self.current_track.sound, self.current_track.duration
|
return self.current_track.sound, self.current_track.duration
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
wbz_data = ""
|
||||||
first_view = list(self.views.values())[0]
|
|
||||||
first_view.sortItems(4, Qt.SortOrder.AscendingOrder)
|
|
||||||
self.sync(first_view)
|
|
||||||
|
|
||||||
wbz_data = "#WOBUZZM3U\n" # header
|
|
||||||
|
|
||||||
for sort_column, order in self.sorting:
|
|
||||||
wbz_data += f"#SORT: {sort_column}, {order}\n"
|
|
||||||
|
|
||||||
for track in self.tracks:
|
for track in self.tracks:
|
||||||
wbz_data += f"{track.path}\n"
|
wbz_data += f"{track.path}\n"
|
||||||
|
|
|
@ -67,7 +67,7 @@ class Track:
|
||||||
|
|
||||||
self.duration = len(self.audio) # track duration in milliseconds
|
self.duration = len(self.audio) # track duration in milliseconds
|
||||||
|
|
||||||
self.tags = TinyTag.get(self.path, ignore_errors=True, duration=False, image=True) # metadata with images
|
self.tags = TinyTag.get(self.path, ignore_errors=True, duration=False, image=True) # metadata with images
|
||||||
|
|
||||||
self.cached = True
|
self.cached = True
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
from PyQt6.QtCore import Qt, pyqtSignal
|
from PyQt6.QtCore import pyqtSignal
|
||||||
from PyQt6.QtGui import QDropEvent, QIcon
|
from PyQt6.QtGui import QDropEvent, QIcon, QFont
|
||||||
from PyQt6.QtWidgets import QTreeWidget, QAbstractItemView
|
from PyQt6.QtWidgets import QTreeWidget, QAbstractItemView, QFrame
|
||||||
|
|
||||||
from .track import TrackItem
|
from .track import TrackItem
|
||||||
|
|
||||||
|
|
||||||
class PlaylistView(QTreeWidget):
|
class PlaylistView(QTreeWidget):
|
||||||
itemDropped = pyqtSignal(QTreeWidget, list)
|
itemDropped = pyqtSignal(QTreeWidget, list)
|
||||||
sort_signal = pyqtSignal(int, Qt.SortOrder)
|
|
||||||
|
|
||||||
playing_mark = QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStart)
|
normal_font = QFont()
|
||||||
|
bold_font = QFont()
|
||||||
|
bold_font.setBold(True)
|
||||||
|
|
||||||
def __init__(self, playlist, dock, parent=None):
|
def __init__(self, playlist, dock, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
@ -21,16 +22,14 @@ class PlaylistView(QTreeWidget):
|
||||||
|
|
||||||
self.app = playlist.app
|
self.app = playlist.app
|
||||||
|
|
||||||
self.header = self.header()
|
|
||||||
self.header.setSectionsClickable(True)
|
|
||||||
self.header.setSortIndicatorShown(True)
|
|
||||||
|
|
||||||
playlist.views[id(dock)] = self
|
playlist.views[id(dock)] = self
|
||||||
|
|
||||||
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
||||||
|
|
||||||
self.setColumnCount(4)
|
self.setColumnCount(4)
|
||||||
|
|
||||||
|
self.playing_mark = QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStart)
|
||||||
|
|
||||||
headers = [
|
headers = [
|
||||||
"#",
|
"#",
|
||||||
"Title",
|
"Title",
|
||||||
|
@ -42,70 +41,30 @@ class PlaylistView(QTreeWidget):
|
||||||
self.setHeaderLabels(headers)
|
self.setHeaderLabels(headers)
|
||||||
|
|
||||||
self.itemActivated.connect(self.on_track_activation)
|
self.itemActivated.connect(self.on_track_activation)
|
||||||
self.header.sectionClicked.connect(self.on_header_click)
|
|
||||||
self.sort_signal.connect(self.sortItems)
|
|
||||||
|
|
||||||
def on_header_click(self, section_index: int):
|
def on_user_sort(self):
|
||||||
if section_index == 0: # this would just invert the current sorting
|
|
||||||
return
|
|
||||||
|
|
||||||
sorting = self.playlist.sorting
|
|
||||||
last_sort_section_index, order = sorting[4]
|
|
||||||
|
|
||||||
if last_sort_section_index == section_index:
|
|
||||||
order = not order # invert order
|
|
||||||
|
|
||||||
self.playlist.sorting[4] = (section_index, order) # set sorting
|
|
||||||
|
|
||||||
# convert True/False to Qt.SortOrder.AscendingOrder/Qt.SortOrder.DescendingOrder
|
|
||||||
qorder = Qt.SortOrder.AscendingOrder if order else Qt.SortOrder.DescendingOrder
|
|
||||||
|
|
||||||
self.header.setSortIndicator(section_index, qorder)
|
|
||||||
|
|
||||||
else:
|
|
||||||
del sorting[0] # remove first sort
|
|
||||||
sorting.append((section_index, True)) # last sort is this section index, ascending
|
|
||||||
|
|
||||||
self.header.setSortIndicator(section_index, Qt.SortOrder.AscendingOrder)
|
|
||||||
|
|
||||||
self.sort()
|
|
||||||
|
|
||||||
def sort(self):
|
|
||||||
for index, order in self.playlist.sorting:
|
|
||||||
# convert True/False to Qt.SortOrder.AscendingOrder/Qt.SortOrder.DescendingOrder
|
|
||||||
qorder = Qt.SortOrder.AscendingOrder if order else Qt.SortOrder.DescendingOrder
|
|
||||||
|
|
||||||
# somehow, QTreeWidget.sortItems() cant be called from a thread, so we have to use a signal to execute it
|
|
||||||
# in the main thread
|
|
||||||
self.sort_signal.emit(index, qorder)
|
|
||||||
# self.sortItems(index, qorder)
|
|
||||||
|
|
||||||
self.on_sort()
|
|
||||||
|
|
||||||
def on_sort(self, user_sort: bool=False):
|
|
||||||
num_tracks = self.topLevelItemCount()
|
num_tracks = self.topLevelItemCount()
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
|
|
||||||
while i < num_tracks:
|
while i < num_tracks:
|
||||||
track = self.topLevelItem(i)
|
track_item = self.topLevelItem(i)
|
||||||
|
track = track_item.track
|
||||||
|
|
||||||
|
track_item.index_user_sort = i
|
||||||
|
track_item.index = i
|
||||||
|
|
||||||
|
track_item.setText(5, str(i + 1))
|
||||||
|
|
||||||
|
self.playlist.tracks[i] = track
|
||||||
|
|
||||||
|
track.set_occurrences()
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
track.setText(0, str(i)) # 0 = index
|
# make sure the next track is cached (could be moved by user)
|
||||||
|
if self.app.player.current_playlist == self.playlist and self.app.player.current_playlist.has_tracks():
|
||||||
if user_sort:
|
self.app.player.cache_next_track()
|
||||||
track.setText(4, str(i)) # 4 = user sort index
|
|
||||||
|
|
||||||
if user_sort:
|
|
||||||
if not self.playlist.sorting[4][0] == 4: # set last sort to user sort
|
|
||||||
del self.playlist.sorting[0]
|
|
||||||
|
|
||||||
self.playlist.sorting.append((4, True))
|
|
||||||
|
|
||||||
self.header.setSortIndicator(4, Qt.SortOrder.AscendingOrder)
|
|
||||||
|
|
||||||
self.playlist.sync(self, user_sort) # sync playlist to this view
|
|
||||||
|
|
||||||
def dropEvent(self, event: QDropEvent):
|
def dropEvent(self, event: QDropEvent):
|
||||||
# receive items that were dropped and create new items from its tracks (new items bc. widgets can only have
|
# receive items that were dropped and create new items from its tracks (new items bc. widgets can only have
|
||||||
|
@ -133,7 +92,7 @@ class PlaylistView(QTreeWidget):
|
||||||
|
|
||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
self.on_sort(True)
|
self.on_user_sort()
|
||||||
|
|
||||||
def dragEnterEvent(self, event):
|
def dragEnterEvent(self, event):
|
||||||
# store dragged items in gui.dropped, so the other playlist can receive it
|
# store dragged items in gui.dropped, so the other playlist can receive it
|
||||||
|
@ -174,15 +133,21 @@ class PlaylistView(QTreeWidget):
|
||||||
|
|
||||||
# unmark the previous track in all playlists
|
# unmark the previous track in all playlists
|
||||||
for item in previous_track.items:
|
for item in previous_track.items:
|
||||||
item.unmark()
|
item.setIcon(0, QIcon(None))
|
||||||
|
item.setFont(1, self.normal_font)
|
||||||
|
item.setFont(2, self.normal_font)
|
||||||
|
item.setFont(3, self.normal_font)
|
||||||
|
|
||||||
if track:
|
if track:
|
||||||
playlist_tabs.setTabIcon(index, self.playing_mark) # mark this playlist
|
playlist_tabs.setTabIcon(index, self.playing_mark) # mark this playlist
|
||||||
|
|
||||||
# mark the current track in this playlist
|
# mark the current track in this playlist
|
||||||
item = self.topLevelItem(self.app.player.current_playlist.current_track_index)
|
item = self.topLevelItem(self.app.player.current_playlist.current_track_index)
|
||||||
item.mark()
|
item.setIcon(0, self.playing_mark)
|
||||||
|
item.setFont(1, self.bold_font)
|
||||||
|
item.setFont(2, self.bold_font)
|
||||||
|
item.setFont(3, self.normal_font)
|
||||||
|
|
||||||
def append_track(self, track):
|
def append_track(self, track):
|
||||||
TrackItem(track, self.topLevelItemCount(), self)
|
TrackItem(track, self.topLevelItemCount() - 1, self)
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,20 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
from PyQt6.QtCore import Qt
|
from PyQt6.QtCore import Qt
|
||||||
from PyQt6.QtGui import QFont, QIcon, QPalette
|
|
||||||
from PyQt6.QtWidgets import QTreeWidgetItem
|
from PyQt6.QtWidgets import QTreeWidgetItem
|
||||||
|
|
||||||
|
|
||||||
class TrackItem(QTreeWidgetItem):
|
class TrackItem(QTreeWidgetItem):
|
||||||
normal_font = QFont()
|
|
||||||
bold_font = QFont()
|
|
||||||
bold_font.setBold(True)
|
|
||||||
|
|
||||||
playing_mark = QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStart)
|
|
||||||
|
|
||||||
def __init__(self, track, index, parent=None):
|
def __init__(self, track, index, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
self.track = track
|
self.track = track
|
||||||
self.index_user_sort = index
|
self.index_user_sort = index
|
||||||
|
|
||||||
self.index = index
|
self.index = index
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
self.playlist = parent.playlist
|
self.playlist = parent.playlist
|
||||||
|
|
||||||
palette = parent.palette()
|
|
||||||
|
|
||||||
self.highlight_color = palette.color(QPalette.ColorRole.Highlight)
|
|
||||||
self.base_color = palette.color(QPalette.ColorRole.Base)
|
|
||||||
|
|
||||||
track.items.append(self)
|
track.items.append(self)
|
||||||
|
|
||||||
track.set_occurrences()
|
track.set_occurrences()
|
||||||
|
@ -43,26 +31,3 @@ class TrackItem(QTreeWidgetItem):
|
||||||
self.setText(3, track.tags.album)
|
self.setText(3, track.tags.album)
|
||||||
self.setText(4, str(self.index_user_sort + 1))
|
self.setText(4, str(self.index_user_sort + 1))
|
||||||
|
|
||||||
def mark(self):
|
|
||||||
self.setIcon(0, self.playing_mark)
|
|
||||||
self.setFont(1, self.bold_font)
|
|
||||||
self.setFont(2, self.bold_font)
|
|
||||||
self.setFont(3, self.normal_font)
|
|
||||||
|
|
||||||
def unmark(self):
|
|
||||||
self.setIcon(0, QIcon(None))
|
|
||||||
self.setFont(1, self.normal_font)
|
|
||||||
self.setFont(2, self.normal_font)
|
|
||||||
self.setFont(3, self.normal_font)
|
|
||||||
|
|
||||||
def __lt__(self, other):
|
|
||||||
# make numeric strings get sorted the right way
|
|
||||||
|
|
||||||
column = self.parent.sortColumn()
|
|
||||||
|
|
||||||
if column == 0 or column == 4:
|
|
||||||
return int(self.text(column)) < int(other.text(column))
|
|
||||||
|
|
||||||
else:
|
|
||||||
return super().__lt__(other)
|
|
||||||
|
|
||||||
|
|
|
@ -50,11 +50,12 @@ class TrackInfo(QToolBar):
|
||||||
def update_info(self):
|
def update_info(self):
|
||||||
current_playlist = self.app.player.current_playlist
|
current_playlist = self.app.player.current_playlist
|
||||||
|
|
||||||
if current_playlist is not None and current_playlist.current_track is not None:
|
if current_playlist is not None:
|
||||||
current_track = current_playlist.current_track
|
current_track = current_playlist.current_track
|
||||||
title = current_track.tags.title
|
title = current_track.tags.title
|
||||||
artist = current_track.tags.artist
|
artist = current_track.tags.artist
|
||||||
album = current_track.tags.album
|
album = current_track.tags.album
|
||||||
|
cover_data = current_track.tags.images.any.data
|
||||||
|
|
||||||
self.title.setText(title)
|
self.title.setText(title)
|
||||||
|
|
||||||
|
@ -70,15 +71,6 @@ class TrackInfo(QToolBar):
|
||||||
else:
|
else:
|
||||||
self.album.setText("No Album")
|
self.album.setText("No Album")
|
||||||
|
|
||||||
cover = current_track.tags.images.any
|
|
||||||
|
|
||||||
if cover is None:
|
|
||||||
self.track_cover.setPixmap(self.wobuzz_logo)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
cover_data = cover.data
|
|
||||||
|
|
||||||
if isinstance(cover_data, bytes):
|
if isinstance(cover_data, bytes):
|
||||||
cover_pixmap = QPixmap()
|
cover_pixmap = QPixmap()
|
||||||
cover_pixmap.loadFromData(cover_data)
|
cover_pixmap.loadFromData(cover_data)
|
||||||
|
@ -88,10 +80,4 @@ class TrackInfo(QToolBar):
|
||||||
else:
|
else:
|
||||||
self.track_cover.setPixmap(self.wobuzz_logo)
|
self.track_cover.setPixmap(self.wobuzz_logo)
|
||||||
|
|
||||||
else:
|
|
||||||
self.title.setText("No Playing Track")
|
|
||||||
self.artist.setText("")
|
|
||||||
self.album.setText("")
|
|
||||||
self.track_cover.setPixmap(self.wobuzz_logo)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ class TrackProgressSlider(QSlider):
|
||||||
def on_release(self):
|
def on_release(self):
|
||||||
self.dragged = False
|
self.dragged = False
|
||||||
|
|
||||||
if self.app.player.current_playlist is not None and self.app.player.current_playlist.has_tracks():
|
if self.app.player.current_playlist.has_tracks():
|
||||||
self.app.player.seek(self.value())
|
self.app.player.seek(self.value())
|
||||||
|
|
||||||
def update_progress(self):
|
def update_progress(self):
|
||||||
|
|
Loading…
Add table
Reference in a new issue