#!/usr/bin/python3 import vlc import sys from log import DEBUG # 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 ui.main_window_ui import Ui_MainWindow from ui.dlg_search_database_ui import Ui_Dialog from config import Config from model import Settings, 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 class Window(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super().__init__(parent) self.setupUi(self) self.connectSignalsSlots() record = Settings.get_int("mainwindow_x") x = record.f_int or 1 record = Settings.get_int("mainwindow_y") y = record.f_int or 1 record = Settings.get_int("mainwindow_width") width = record.f_int or 1599 record = Settings.get_int("mainwindow_height") height = record.f_int or 981 self.setGeometry(x, y, width, height) for column in range(self.playlist.columnCount()): name = f"playlist_col_{str(column)}_width" record = Settings.get_int(name) if record.f_int is not None: self.playlist.setColumnWidth(column, record.f_int) def __del__(self): for column in range(self.playlist.columnCount()): name = f"playlist_col_{str(column)}_width" record = Settings.get_int(name) if record.f_int != self.playlist.columnWidth(column): record.update({'f_int': self.playlist.columnWidth(column)}) record = Settings.get_int("mainwindow_height") if record.f_int != self.height(): record.update({'f_int': self.height()}) record = Settings.get_int("mainwindow_width") if record.f_int != self.width(): record.update({'f_int': self.width()}) record = Settings.get_int("mainwindow_x") if record.f_int != self.x(): record.update({'f_int': self.x()}) record = Settings.get_int("mainwindow_y") if record.f_int != self.y(): record.update({'f_int': self.y()}) def connectSignalsSlots(self): self.fileButton.clicked.connect(self.selectFile) self.databaseButton.clicked.connect(self.selectFromDatabase) self.actionPlay_selected.triggered.connect(self.play_selected) def selectFromDatabase(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()) DEBUG(f"play_selected: track_id={track_id}") # TODO: get_path may raise exception track_path = Tracks.get_path(track_id) if track_path: DEBUG(f"play_selected: track_path={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 """ DEBUG(f"add_to_playlist: track.id={track.id}") 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.searchString.textEdited.connect(self.chars_typed) self.ui.matchList.itemDoubleClicked.connect(self.listdclick) record = Settings.get_int("dbdialog_width") width = record.f_int or 800 record = Settings.get_int("dbdialog_height") height = record.f_int or 600 self.resize(width, height) def __del__(self): record = Settings.get_int("dbdialog_height") if record.f_int != self.height(): record.update({'f_int': self.height()}) record = Settings.get_int("dbdialog_width") if record.f_int != self.width(): record.update({'f_int': self.width()}) def chars_typed(self, s): if len(s) >= 3: matches = Tracks.search_titles(s) self.ui.matchList.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.matchList.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 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}" def main(): app = QApplication(sys.argv) win = Window() win.show() sys.exit(app.exec()) if __name__ == "__main__": main()