#!/usr/bin/python3 import vlc import sys from log import INFO, ERROR, DEBUG from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow from PyQt5.QtWidgets import QTableWidgetItem, QFileDialog, QListWidgetItem from threading import Timer from tinytag import TinyTag from ui.main_window_ui import Ui_MainWindow from ui.dlg_search_database_ui import Ui_Dialog from config import Config from model import Tracks class RepeatedTimer: def __init__(self, interval, function, *args, **kwargs): self._timer = None self.interval = interval self.function = function self.args = args self.kwargs = kwargs self.is_running = False self.start() def _run(self): self.is_running = False self.start() self.function(*self.args, **self.kwargs) def start(self): if not self.is_running: self._timer = Timer(self.interval, self._run) self._timer.start() self.is_running = True def stop(self): self._timer.cancel() self.is_running = False def ms_to_mmss(ms, decimals=0): if not ms: return "-" if ms < 0: sign = "-" else: sign = "" minutes, remainder = divmod(ms, 60 * 1000) seconds = remainder / 1000 return f"{sign}{minutes:.0f}:{seconds:02.{decimals}f}" class Window(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super().__init__(parent) self.setupUi(self) self.connectSignalsSlots() self.resize(1599, 981) self.playlist.setColumnWidth(0, 0) self.playlist.setColumnWidth(1, 70) self.playlist.setColumnWidth(2, 381) self.playlist.setColumnWidth(3, 322) self.playlist.setColumnWidth(4, 78) self.playlist.setColumnWidth(5, 68) self.playlist.setColumnWidth(6, 47) self.playlist.setColumnWidth(7, 577) def __del__(self): for column in range(self.playlist.columnCount()): print(f"Column {column}: {self.playlist.columnWidth(column)}") print(f"Window height: {self.height()} Window width: {self.width()}") def connectSignalsSlots(self): self.fileButton.clicked.connect(self.selectFile) self.databaseButton.clicked.connect(self.selectDatabase) self.actionPlay_selected.triggered.connect(self.play_selected) def selectDatabase(self): dlg = DbDialog(self) dlg.exec() def play_selected(self): if self.playlist.selectionModel().hasSelection(): row = self.playlist.currentRow() track_id = int(self.playlist.item(row, 0).text()) # TODO: get_path may raise exception track_path = Tracks.get_path(track_id) if track_path: INFO(f"play: {track_path}") player = vlc.MediaPlayer(track_path) player.play() def selectFile(self): dlg = QFileDialog() dlg.setFileMode(QFileDialog.ExistingFile) dlg.setViewMode(QFileDialog.Detail) dlg.setDirectory(Config.ROOT) dlg.setNameFilter("Music files (*.flac *.mp3)") if dlg.exec_(): pass # TODO Add to database # for fname in dlg.selectedFiles(): # track = Track(fname) # self.add_to_playlist(track) def add_to_playlist(self, track): """ Add track to playlist track is an instance of Track """ pl = self.playlist row = pl.rowCount() pl.insertRow(row) item = QTableWidgetItem(str(track.id)) pl.setItem(row, 0, item) item = QTableWidgetItem(str(track.start_gap)) pl.setItem(row, 1, item) item = QTableWidgetItem(track.title) pl.setItem(row, 2, item) item = QTableWidgetItem(track.artist) pl.setItem(row, 3, item) item = QTableWidgetItem(ms_to_mmss(track.duration)) pl.setItem(row, 4, item) item = QTableWidgetItem(track.path) pl.setItem(row, 7, item) class DbDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_Dialog() self.ui.setupUi(self) self.ui.lineEdit.textEdited.connect(self.chars_typed) self.ui.listWidget.itemDoubleClicked.connect(self.listdclick) def chars_typed(self, s): if len(s) >= 3: matches = Tracks.search_titles(s) self.ui.listWidget.clear() if matches: for track in matches: t = QListWidgetItem() t.setText( f"{track.title} - {track.artist} " f"[{ms_to_mmss(track.duration)}]" ) t.setData(Qt.UserRole, track.id) self.ui.listWidget.addItem(t) def listdclick(self, entry): track_id = entry.data(Qt.UserRole) track = Tracks.track_from_id(track_id) self.parent().add_to_playlist(track) def main(): app = QApplication(sys.argv) win = Window() win.show() sys.exit(app.exec()) if __name__ == "__main__": main()