158 lines
5.6 KiB
Python
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())
|