def installZip(self, fn, install_dir): debug_log("installZip: Installing {} to {}...".format(fn, install_dir)) self.statusLabel.setText(self.tr("Installing")+" {}...".format(os.path.basename(fn))) QApplication.processEvents() zip_f = zipfile.ZipFile(fn) zip_f.extractall(path=app_dirs.user_cache_dir + "/" + install_dir) self.statusLabel.setText("") QApplication.processEvents()
def run(self): try: sox_output,output_err = runCmd([self.sox_bin,self.fn,"-n","spectrogram","-l","-p{}".format(self.palette),"-c ","-o",self.temp_file],self.cmd_timeout) except SubprocessError as e: debug_log(e,logging.ERROR) self.temp_file = "" if not self.temp_file == "": try: info = infoobj(infoobj.SPECTROGRAM,self.temp_file,self.grid,self.fn) self.infodlg_q.put(info) # Timer watches this queue and updates gui except Exception as e: debug_log(e,logging.ERROR)
def updateGui(self): ''' called from timer - subprocesses post to queue when finished ''' if not self.infodlg_q.empty(): update_info = self.infodlg_q.get(False, 1) # class infoobj # type - type of update e.g. "Spectrogram" # data - handler specific data # layout - QLayout to update # fn - name of file the update is for if not isinstance(update_info, infoobj): debug_log( "updateGui received wrong data: {}".format(update_info), logging.WARNING) return if update_info.type in [ infoobj.BITGRAPH, infoobj.BITHIST, infoobj.SPECTROGRAM ]: debug_log("updateGui received type {} update".format( update_info.type)) px = QLabel() dlg = findDlg(update_info.fn, self.debug_enabled, self.infodlg_list) if dlg is not None: layout = dlg.findChild(QGridLayout, update_info.layout) if layout is not None: layout.addWidget(px) px.setPixmap(QPixmap(update_info.data)) else: debug_log( "updateGui ran but layout not found type={} str={} layout={}" .format(update_info.type, update_info.data, update_info.layout), logging.WARNING) else: debug_log( "updateGui couldn't find dlg type={} str={} layout={}". format(update_info.type, update_info.data, update_info.layout), logging.WARNING) try: os.remove( update_info.data) # delete generated spectrogram image except OSError: pass elif update_info.type == infoobj.SCANNER_OUTPUT: debug_log("updateGui received Scanner_Output update") if update_info.layout is not None: textEdit_scanner = QTextEdit() textEdit_scanner.setReadOnly(True) textEdit_scanner.setPlainText(update_info.data) update_info.layout.addWidget(textEdit_scanner)
def run(self): temp_file = "" debug_log("aucdtect thread started for row {}, file: {}".format(self.row,self.filenameStr)) if os.path.lexists(self.filenameStr): try: temp_file = getTempFileName() if not self.decoder_bin == "": # need to decode to wav decoder_output,output_err = runCmd([self.decoder_bin,self.decoder_options,self.filenameStr,"-o",temp_file],self.cmd_timeout) output_str,output_err = runCmd([self.aucdtect_bin,self.aucdtect_options,temp_file],self.cmd_timeout) else: output_str,output_err = runCmd([self.aucdtect_bin,self.aucdtect_options,self.filenameStr],self.cmd_timeout) except SubprocessError as e: debug_log("Exception {} in runCmd {} for file {}".format(e,self.aucdtect_bin,self.filenameStr),logging.ERROR) output_str = "Error" else: output_str = "Error" try: os.remove(temp_file) except OSError: pass if not (output_str == "Error"): song_info = parse_aucdtect_output(output_str) debug_log("aucdtect thread finished - row {}, result: {}".format(self.row,song_info.quality)) else: song_info = song_info_obj() song_info.result_type = song_info_obj.SCANNER_OUTPUT song_info.cmd_error = True debug_log("aucdtect thread finished with cmd error - row {}, result: {}".format(self.row,output_str),logging.WARNING) maininfo_obj = main_info(main_info.SCANNER_OUTPUT,output_str,self.row,song_info) self.main_q.put(maininfo_obj)
def run(self): try: if self.debug_enabled: debug_log("error check thread started for row {}, file: {}".format(self.row,self.filenameStr)) if os.path.lexists(self.filenameStr): try: output_str,output_err = runCmd([self.decoder_bin,self.decoder_options,self.filenameStr],self.cmd_timeout) except: output_str = "Error" else: output_str = "Error" if self.debug_enabled: debug_log("error check thread file: {} does not exist".format(self.filenameStr)) if self.use_stderr: # flac writes everything to stderr check_str = output_err else: check_str = output_str if (check_str == "Error") or ("ERROR while decoding" in check_str): self.main_q.put((self.row,{'result_type':'Error_Check','error':True},check_str)) if self.debug_enabled: debug_log("error check thread finished with error - row {}, result: {}".format(self.row,check_str)) else: self.main_q.put((self.row,{'result_type':'Error_Check','error':False},check_str)) if self.debug_enabled: debug_log("error check thread finished - row {}, result: {}".format(self.row,check_str)) except Exception as e: self.debug_log(e)
def checkInstalled(tool): debug_log("Checking for {}".format(tool)) bin_exe = "" if tool == 'MediaInfo': bin_exe = findMediaInfoBin() elif tool == 'mp3guessenc': bin_exe = findGuessEncBin() elif tool == 'SoX': bin_exe = findSoxBin() elif tool == 'Gnuplot': bin_exe = findGnuPlotBin() elif tool == 'FFmpeg': bin_exe = findffprobeBin() elif tool == 'auCDtect': bin_exe = findauCDtectBin() elif tool == 'Flac': bin_exe = findFlacBin() else: debug_log("checkInstalled unknown tool {}".format(tool)) return (bin_exe == "") or os.path.exists(bin_exe)
def run(self): temp_file = "" if self.debug_enabled: debug_log("aucdtect thread started for row {}, file: {}".format(self.row,self.filenameStr)) if os.path.lexists(self.filenameStr): try: temp_file = getTempFileName() if not self.decoder_bin == "": # need to decode to wav decoder_output,output_err = runCmd([self.decoder_bin,self.decoder_options,self.filenameStr,"-o",temp_file],self.cmd_timeout) output_str,output_err = runCmd([self.aucdtect_bin,self.aucdtect_options,temp_file],self.cmd_timeout) else: output_str,output_err = runCmd([self.aucdtect_bin,self.aucdtect_options,self.filenameStr],self.cmd_timeout) except: output_str = "Error" else: output_str = "Error" try: os.remove(temp_file) except OSError: pass if not (output_str == "Error"): song_info = parse_aucdtect_output(output_str) if self.debug_enabled: debug_log("aucdtect thread finished - row {}, result: {}".format(self.row,song_info['quality'])) self.main_q.put((self.row,song_info,output_str)) else: self.main_q.put((self.row,{'result_type':'Scanner_Output','error':True},output_str)) if self.debug_enabled: debug_log("aucdtect thread finished with error - row {}, result: {}".format(self.row,output_str))
def run(self): assert len(self.x) == len(self.y) datfile = getTempFileName() + ".dat" with open(datfile, "w") as tf: for i in range(0,len(self.x)): tf.write(str(self.x[i]) + " " + str(self.y[i]) + "\n") cmdfile_template = app_dirs.user_config_dir + "/bithist.plot" pngfile = getTempFileName() + ".png" if not os.path.lexists(cmdfile_template): with open(cmdfile_template, "w") as cft: cft.write(str("set style data histogram\nset style fill solid border\nset boxwidth 0.95 relative\nset grid\n")) cft.write(str("set title \"Bitrate distribution\"\n")) cft.write(str("set xlabel \"Bitrate (kB)\"\n")) cft.write(str("set ylabel \"Number of frames\"\n")) cft.write(str("set terminal png size 800,600 enhanced font \"Helvetica,20\"\nset output '{pngfile}'\n")) cft.write(str("plot '{datfile}' using 2:xticlabels(1) notitle\n")) cmdfile = getTempFileName() + ".plot" with open(cmdfile, "w") as cf: with open(cmdfile_template, "r") as cft: for line in cft: if "{datfile}" in line: cf.write(line.replace("{datfile}",datfile)) elif "{pngfile}" in line: cf.write(line.replace("{pngfile}",pngfile)) else: cf.write(line) output_str = "" try: debug_log("running {} with cmdfile {}".format(self.gnuplot_bin,cmdfile)) output_str,output_err = runCmd([self.gnuplot_bin,"{}".format(cmdfile)],self.cmd_timeout) debug_log(output_str) debug_log(output_err) except SubprocessError as e: debug_log(e,logging.ERROR) return None try: os.remove(cmdfile) os.remove(datfile) except OSError: pass info = infoobj(infoobj.BITHIST,pngfile,self.grid,self.fn) self.infodlg_q.put(info)
def installSelected(self): debug_log("installSelected") self.install_button.setEnabled(False) it = QTreeWidgetItemIterator(self.tw) if not os.path.exists(app_dirs.user_cache_dir): os.mkdir(app_dirs.user_cache_dir) if not os.path.exists(app_dirs.user_cache_dir): os.mkdir(app_dirs.user_cache_dir) while it.value(): item = it.value() if (not item.isDisabled()) and (item.checkState(0) == 2): url_test = item.data(0, dataURL) install_dir = item.data(0, dataInstallDir) if url_test is not None: fn = os.path.basename(url_test) self.statusLabel.setText(self.tr("Downloading")+" {}...".format(fn)) QApplication.processEvents() try: r = requests.get(url_test) r.raise_for_status() debug_log("{}".format(r.headers)) with open(app_dirs.user_cache_dir + "/" + fn, "wb") as zip_f: zip_f.write(r.content) self.installZip(app_dirs.user_cache_dir + "/" + fn, install_dir) item.setText(3, self.tr("Installed")) QApplication.processEvents() item.setDisabled(True) except requests.exceptions.HTTPError: debug_log( "Error {} downloading file {}, headers: {}".format(r.status_code, url_test, r.headers), logging.WARNING) except requests.exceptions.RequestException as e: debug_log(e, logging.ERROR) self.statusLabel.setText("") it += 1 self.install_button.setEnabled(True)
def getDLsize(self): debug_log("getDLsize called") it = QTreeWidgetItemIterator(self.tw) while it.value(): item = it.value() url_test = item.data(0, dataURL) if url_test is not None: try: r = requests.head(url_test) r.raise_for_status() try: size = (int(r.headers['Content-Length']) / 1024) / 1024 except ValueError: size = 0 if size > 0: item.setText(2, "{} MiB".format(round(size, 2))) except requests.exceptions.HTTPError: debug_log("Error {} getting DL size: {}".format(r.status_code, r.headers)) item.setText(2, r.status_code) except requests.exceptions.RequestException as e: item.setText(2, self.tr("Error")) debug_log(e, logging.ERROR) it += 1
def __init__(self, filenameStr, frame_hist, infodlg_list, debug_enabled=False): super(FileInfo, self).__init__() self.ui = Ui_FileInfoDialog() self.ui.setupUi(self) self.setWindowTitle( self.tr("Info") + " - {}".format(os.path.basename(filenameStr))) self.filename = filenameStr self.frame_hist = frame_hist # tuple self.infodlg_q = queue.Queue() self.infodlg_threadpool = QThreadPool(None) self.debug_enabled = debug_enabled self.infodlg_list = infodlg_list self.infodlg_list.add( self) # keep track of dialogs so we can reuse them if still open windowGeometry = settings.value("State/InfoWindowGeometry") if windowGeometry is not None: self.restoreGeometry(windowGeometry) tabWidget = self.findChild(QTabWidget, "tabWidget") tabWidget.clear() if self.frame_hist is not None: x, y = self.frame_hist else: x = [] y = [] debug_log("Frame histogram - {}".format(self.frame_hist), logging.DEBUG) debug_log("Frame histogram - {}".format(x), logging.DEBUG) debug_log("Frame histogram - {}".format(y), logging.DEBUG) if len(x) > 0: try: debug_log( "Running gnuplot to create frame histogram for file {}". format(filenameStr)) tab = QWidget() grid = QGridLayout(tab) grid.setObjectName("BitrateHistLayout-{}".format( md5Str(filenameStr))) tabWidget.addTab(tab, self.tr("Bitrate Distribution")) thread = makeBitHistThread( filenameStr, grid.objectName(), settings.value("Options/Proc_Timeout", 300, type=int), self.infodlg_q, findGnuPlotBin(), x, y) self.infodlg_threadpool.start(thread) except Exception as e: debug_log(e, logging.ERROR) updateGuiTimer = QTimer(self) updateGuiTimer.timeout.connect(self.updateGui) updateGuiTimer.setInterval(100) updateGuiTimer.start() debug_log("Running scanner for file {}".format(filenameStr)) tab = QWidget() grid = QGridLayout(tab) grid.setObjectName("OutputLayout-{}".format(md5Str(filenameStr))) tabWidget.addTab(tab, self.tr("Scanner Output")) mp3guessenc_bin = findGuessEncBin() if (mp3guessenc_bin == "") or (not os.path.exists(mp3guessenc_bin)): mp3guessenc_bin = "" mediainfo_bin = findMediaInfoBin() if (mediainfo_bin == "") or (not os.path.exists(mediainfo_bin)): mediainfo_bin = "" threads = getScannerThread( grid.objectName(), filenameStr, mp3guessenc_bin, mediainfo_bin, grid, settings.value("Options/Proc_Timeout", 300, type=int), debug_enabled, None, self.infodlg_q) if threads: for thread in threads: if isinstance(thread, QRunnable): self.infodlg_threadpool.start(thread) else: debug_log( "getScannerThread not QRunnable: {}".format(thread), logging.WARNING) if settings.value('Options/EnableSpectrogram', True, type=bool): tab = QWidget() grid = QGridLayout(tab) grid.setObjectName("SpectrogramLayout-{}".format( md5Str(filenameStr))) tabWidget.addTab(tab, self.tr("Spectrogram")) sox_bin = findSoxBin() temp_file = getTempFileName() + ".png" palette = settings.value('Options/SpectrogramPalette', 1, type=int) debug_log("Running sox to create spectrogram for file {}".format( filenameStr)) thread = makeSpectrogramThread( filenameStr, sox_bin, temp_file, palette, grid.objectName(), settings.value("Options/Proc_Timeout", 300, type=int), self.infodlg_q) self.infodlg_threadpool.start(thread) if settings.value('Options/EnableBitGraph', True, type=bool): tab = QWidget() grid = QGridLayout(tab) grid.setObjectName("BitgraphLayout-{}".format(md5Str(filenameStr))) tabWidget.addTab(tab, self.tr("Bitrate Graph")) debug_log( "Running ffprobe to create bitrate graph for file {}".format( filenameStr)) thread = makeBitGraphThread( filenameStr, grid.objectName(), findffprobeBin(), settings.value("Options/Proc_Timeout", 300, type=int), self.infodlg_q, findGnuPlotBin()) self.infodlg_threadpool.start(thread)
def loadToolsJSON(self, tw): json_tools_path = app_dirs.user_config_dir + "/tools_urls.json" if not os.path.exists(json_tools_path): # todo: update if too old try: r = requests.get(json_url) r.raise_for_status() with open(json_tools_path, "w") as f: f.write(r.text) except requests.exceptions.RequestException as e: debug_log(e, logging.ERROR) if not os.path.exists(json_tools_path): return with open(json_tools_path, "r") as tools_url_file: tools_json = json.load(tools_url_file) tw.setColumnCount(4) tw.headerItem().setHidden(False) tw.headerItem().setText(0, self.tr("Name")) tw.headerItem().setText(1, self.tr("Category")) tw.headerItem().setText(2, self.tr("Download")) tw.headerItem().setText(3, self.tr("Status")) req = QTreeWidgetItem() req.setText(0, self.tr("Required")) # req.setCheckState(0,2) tw.addTopLevelItem(req) opt = QTreeWidgetItem() opt.setText(0, self.tr("Optional")) # opt.setCheckState(0,0) tw.addTopLevelItem(opt) for title, values in tools_json.items(): item = QTreeWidgetItem() item.setText(0, title) font = item.font(0) font.setBold(True) item.setFont(0, font) required = values['required'] platform_s = values['platform'] if required: req.addChild(item) item.setCheckState(0, 2) else: opt.addChild(item) item.setCheckState(0, 0) if self.checkInstalled(title): item.setText(3, self.tr("Installed")) item.setDisabled(True) item.setCheckState(0, 2) else: item.setText(3, self.tr("Not installed")) url = values['url'] try: url64 = values['url64'] except KeyError: url64 = "" install_dir = values['install_dir'] if (platform.machine() == "AMD64") and not (url64 == ""): item.setData(0, dataURL, url64) else: item.setData(0, dataURL, url) item.setData(0, dataInstallDir, install_dir) category = values['category'] item.setText(1, category) description = values['description'] di = QTreeWidgetItem() label = QLabel(description) label.setWordWrap(True) item.addChild(di) tw.setItemWidget(di, 0, label) tw.setFirstItemColumnSpanned(di, False) item.setExpanded(True) # req.setChildIndicatorPolicy(QTreeWidgetItem.DontShowIndicator) # opt.setChildIndicatorPolicy(QTreeWidgetItem.DontShowIndicator) req.setExpanded(True) opt.setExpanded(True) tw.resizeColumnToContents(1) tw.resizeColumnToContents(2) tw.resizeColumnToContents(3) tw.resizeColumnToContents(0) delayTimer = QTimer(self) delayTimer.timeout.connect(self.getDLsize) delayTimer.setInterval(100) delayTimer.setSingleShot(True) delayTimer.start()
def run(self): output_str = "" debug_log("scanner thread running for row {}, file: {}".format(self.row,self.filenameStr)) if os.path.lexists(self.filenameStr): try: output_str,output_err = runCmd([self.binary,self.options,self.filenameStr],self.cmd_timeout) except SubprocessError as e: debug_log("Exception {} in runCmd {} for file {}".format(e,self.binary,self.filenameStr),logging.ERROR) output_str = "Error running command {}".format(self.binary) else: output_str = "Error: file {} not found".format(self.filenameStr) # handle the case where file has been deleted while in queue e.g. temp files or user deletion if self.fileinfo_dialog_update is not None: info = infoobj(infoobj.SCANNER_OUTPUT,output_str,self.fileinfo_dialog_update,self.filenameStr) self.infodlg_q.put(info) return if not (output_str.startswith("Error")): if self.scanner_name == "mp3guessenc": song_info = parse_mp3guessenc_output(output_str) elif self.scanner_name == "mediainfo": song_info = parse_mediainfo_output(output_str) else: # unknown debug_log("scanner thread finished but scanner {} unknown".format(self.scanner_name),logging.WARNING) return debug_log("{} scanner thread finished - row {}, result: {}".format(self.scanner_name,self.row,song_info.encoder)) debug_log("{} scanner thread posting to queue - row {}".format(self.scanner_name,self.row)) else: debug_log("{} scanner thread posting to queue with cmd error - row {}".format(self.scanner_name,self.row),logging.WARNING) song_info = song_info_obj() song_info.result_type = song_info_obj.SCANNER_OUTPUT song_info.cmd_error = True debug_log("{} scanner thread finished with cmd error - row {}, result: {}".format(self.scanner_name,self.row,output_str),logging.WARNING) maininfo_obj = main_info(main_info.SCANNER_OUTPUT,output_str,self.row,song_info) self.main_q.put(maininfo_obj)
def run(self): output_str = "" try: output_str,output_err = runCmd([self.ffprobe_bin,"-show_packets","-of","json",self.fn],self.cmd_timeout) except SubprocessError as e: debug_log(e,logging.ERROR) return None x_list = [] y_list = [] try: json_packet_data = json.loads(output_str) packets = json_packet_data["packets"] except Exception as e: debug_log("Exception in makeBitGraphThread: {}".format(e),logging.ERROR) return None for dictionary in packets: if not dictionary["codec_type"] == "audio": continue try: x = float(dictionary["pts_time"]) # time except (KeyError, ValueError, OverflowError) as e: x = 0 try: t = float(dictionary["duration_time"]) # duration except (KeyError, ValueError, OverflowError) as e: t = 0 try: sz = float(dictionary["size"]) # size in bytes except (KeyError, ValueError, OverflowError) as e: sz = 0 try: y = round(((sz*8)/1024)/t) except (ZeroDivisionError, ValueError, OverflowError) as e: y = 0 if y > 0: y_list.append(y) # bitrate x_list.append(round(x,3)) assert len(x_list) == len(y_list) datfile = getTempFileName() + ".dat" with open(datfile, "w") as tf: # datfile tho for i in range(0,len(x_list)): tf.write(str(x_list[i]) + " " + str(y_list[i]) + "\n") cmdfile_template = app_dirs.user_config_dir + "/bitgraph.plot" pngfile = getTempFileName() + ".png" if not os.path.lexists(cmdfile_template): with open(cmdfile_template, "w") as cft: cft.write(str("set style line 1 lc rgb '#0060ad' lt 1 lw 2 pt 0 ps 1.5 # --- blue\n")) cft.write(str("set title \"Bitrate vs time\"\n")) cft.write(str("set xlabel \"Time (s)\"\n")) cft.write(str("set ylabel \"Bitrate (KiB)\"\n")) cft.write(str("set terminal png size 800,600 enhanced font \"Helvetica,20\"\nset output '{pngfile}'\n")) cft.write(str("plot '{datfile}' notitle with lines\n")) cmdfile = getTempFileName() + ".plot" with open(cmdfile, "w") as cf: with open(cmdfile_template, "r") as cft: for line in cft: if "{datfile}" in line: cf.write(line.replace("{datfile}",datfile)) elif "{pngfile}" in line: cf.write(line.replace("{pngfile}",pngfile)) else: cf.write(line) output_str = "" try: debug_log("running {} with cmdfile {}".format(self.gnuplot_bin,cmdfile)) output_str,output_err = runCmd([self.gnuplot_bin,"{}".format(cmdfile)],self.cmd_timeout) except SubprocessError as e: debug_log(e,logging.ERROR) return None try: os.remove(cmdfile) os.remove(datfile) except OSError: pass info = infoobj(infoobj.BITGRAPH,pngfile,self.grid,self.fn) self.infodlg_q.put(info)
def run(self): try: debug_log("error check thread started for row {}, file: {}".format(self.row,self.filenameStr)) if os.path.lexists(self.filenameStr): try: cmd = [self.decoder_bin,self.decoder_options,self.filenameStr] debug_log("cmd: {}".format(cmd)) output_str,output_err = runCmd(cmd,self.cmd_timeout) except SubprocessError as e: debug_log("Exception {} in runCmd {} for file {}".format(e,self.decoder_bin,self.filenameStr),logging.ERROR) output_str = "Error" output_err = "Error" else: output_str = "Error" output_err = "Error" debug_log("error check thread file: {} does not exist".format(self.filenameStr),logging.WARNING) if self.use_stderr: # flac writes everything to stderr check_str = output_err else: check_str = output_str song_info = song_info_obj() song_info.result_type = song_info_obj.ERROR_CHECK maininfo_obj = main_info(main_info.ERROR_CHECK,check_str,self.row,song_info) if (check_str == "Error") or ("ERROR while decoding" in check_str): if check_str == "Error": song_info.cmd_error = True else: song_info.file_error = True debug_log("error check thread finished with error - row {}, result: {}".format(self.row,check_str),logging.WARNING) else: song_info.file_error = False debug_log("error check thread finished - row {}, result: {}".format(self.row,check_str)) self.main_q.put(maininfo_obj) except Exception as e: debug_log(e,logging.ERROR)
def run(self): output_str = "" if self.debug_enabled: debug_log("scanner thread running for row {}, file: {}".format(self.row,self.filenameStr)) if os.path.lexists(self.filenameStr): try: output_str,output_err = runCmd([self.binary,self.options,self.filenameStr],self.cmd_timeout) except: output_str = "Error" else: output_str = "Error" # handle the case where file has been deleted while in queue e.g. temp files or user deletion if self.fileinfo_dialog_update: self.infodlg_q.put(("Scanner_Output",output_str,self.row,self.filenameStr)) return if not (output_str == "Error"): if self.scanner_name == "mp3guessenc": song_info = parse_mp3guessenc_output(output_str) elif self.scanner_name == "mediainfo": song_info = parse_mediainfo_output(output_str) else: # unknown debug_log("scanner thread finished but scanner unknown") return if self.debug_enabled: debug_log("scanner thread finished - row {}, result: {}".format(self.row,song_info['encoder'])) if self.debug_enabled: debug_log("scanner thread posting to queue - row {}".format(self.row)) self.main_q.put((self.row,song_info,output_str)) else: if self.debug_enabled: debug_log("scanner thread posting to queue with error - row {}".format(self.row)) self.main_q.put((self.row,{'result_type':'Scanner_Output','error':True},output_str)) if self.debug_enabled: debug_log("scanner thread finished with error - row {}, result: {}".format(self.row,output_str))