pyrip/pyripgui.py

158 lines
5.6 KiB
Python

import argparse
import fstools
from gui import MainWindow, SelectionDialog, QueueWorker
import media
import os
from PySide6.QtCore import QObject, Signal, Slot
from PySide6.QtWidgets import QApplication, QMessageBox
import pyudev
from pyudev.pyside6 import MonitorObserver
from queue import Queue
import report
import sys
logger = report.app_logging_config()
# TODO: Stop / Kill Threads before close: QThread: Destroyed while thread '' is still running
MEDIA_GUI_DICT = {
MainWindow.KEY_ALBUM_ARTIST: media.KEY_ARTIST,
MainWindow.KEY_ALBUM_ALBUM: media.KEY_ALBUM,
MainWindow.KEY_ALBUM_YEAR: media.KEY_YEAR,
MainWindow.KEY_ALBUM_GENRE: media.KEY_GENRE
}
class ThisQueueWorker(QueueWorker):
def __init__(self, basepath):
super().__init__()
self.__basepath__ = basepath
class RipQueueWorker(ThisQueueWorker):
def progress_adaption(self, value, track_num):
self.progress_updated.emit(75 * value, track_num - 1)
def action(self, job_index):
logger.info("action: Start ripping track %02d...", job_index + 1)
# Rip track job_index
track_info = self.__job_data__.get(job_index)
if track_info is None:
msg = "No track information found for track %02d" % job_index
logger.error("action: " + msg)
self.set_error(msg)
else:
wavfile = media.track_to_targetpath(self.__basepath__, track_info, 'wav')
try:
fstools.mkdir(os.path.dirname(wavfile))
except PermissionError:
msg = f"Insufficient permissions to create ripping target path: {os.path.dirname(wavfile)}"
logger.error("action: " + msg)
self.set_error(msg)
else:
if media.disc_track_rip(job_index + 1, wavfile, self.progress_adaption) != 0:
msg = f"Unable to rip: {wavfile}"
logger.error("action: " + msg)
self.set_error(msg)
class EncodeQueueWorker(ThisQueueWorker):
def progress_adaption(self, value, track_num):
self.progress_updated.emit(75 + 25 * value, track_num - 1)
def action(self, job_index):
logger.info("action: Start encoding track %02d...", job_index + 1)
# Rip track job_index
track_info = self.__job_data__.get(job_index)
if track_info is None:
msg = "No track information found for track %02d" % job_index
logger.error("action: " + msg)
self.set_error(msg)
else:
wavfile = media.track_to_targetpath(self.__basepath__, track_info, 'wav')
rv = media.wav_to_mp3(wavfile, self.__basepath__, track_info, self.progress_adaption)
if rv != 0:
msg = f"Unable to encode: {wavfile}"
logger.exception("action: " + msg)
self.set_error(msg)
try:
os.remove(wavfile)
except Exception as e:
logger.error("action: Unable to delete wavfile %s", wavfile)
class RipMainWindow(MainWindow):
def read_it(self):
self.set_status("Reading data from disc...")
disc_data = media.get_media_data(media.get_disc_device(), self.cddb_choose_dialog)
if disc_data is None:
msg = "Could not read disc data!"
logger.error(msg)
self.set_status(msg)
QMessageBox.critical(self, "Error!", msg)
else:
self.clear()
# Set album info to gui
for key in MEDIA_GUI_DICT:
self.set_album_field(key, str(disc_data[MEDIA_GUI_DICT[key]]))
# Set tracks to gui
for track in disc_data[media.KEY_TRACKLIST]:
self.append_title(track[media.KEY_TITLE])
# Enable rip button
self.set_status("Disc data received")
self.button_rip.setEnabled(True)
def cddb_choose_dialog(self, what: int, info: dict):
if what == media.CALLBACK_CDDB_CHOICE:
values = tuple(info.values())
keys = tuple(info.keys())
dlg = SelectionDialog(self, "Multiple CDDB entries found. Choose one.", values)
if dlg.exec():
return keys[dlg.get_selected_index()]
def get_job_data(self, list_index):
list_item = self.list_widget.item(list_index)
row_widget = self.list_widget.itemWidget(list_item)
track_info = {}
track_info[media.KEY_TRACK] = list_index + 1
for key in MEDIA_GUI_DICT:
track_info[MEDIA_GUI_DICT[key]] = self.get_album_field(key)
track_info[media.KEY_TITLE] = row_widget.text_edit.toPlainText()
return track_info
def get_rip_worker(self):
return RipQueueWorker(self.__basepath__)
def get_encode_worker(self):
return EncodeQueueWorker(self.__basepath__)
if __name__ == "__main__":
#
# Command line arguments
#
default_baspath = os.path.join(os.getenv("HOME"), "pyrip")
parser = argparse.ArgumentParser(description='Description')
parser.add_argument('-b', '--basepath', help=f'The rip and encode basepath (default is {default_baspath})', default=default_baspath)
args = parser.parse_args()
#
# Initialise GUI
#
app = QApplication(sys.argv)
window = RipMainWindow(args.basepath)
#
# Start media observer
#
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
observer = MonitorObserver(monitor)
observer.deviceEvent.connect(window.device_callback)
observer.daemon = True
monitor.start()
#
# Start GUI
#
window.show()
sys.exit(app.exec())