def do(self, filenames, cut_action=None): # widgets archive_directory = self.__app.config.get('general', 'folder_archive') dialog = self.__gui.dialog_archive result, renamed_filenames, archive_to = dialog.run( filenames, archive_directory) if result: self.update_list = True for original, new_name in renamed_filenames.items(): # add extension to renamed file if needed extension = splitext(original)[1] if not new_name.endswith(extension): new_name += extension new_name = join(dirname(original), new_name.replace('/', '_')) if new_name != original: fileoperations.rename_file(original, new_name) fileoperations.move_file(new_name, archive_to) dialog.hide()
def do(self, filenames): if len(filenames) == 1: message = "Es ist eine Datei ausgewählt. Soll diese Datei " else: message = "Es sind %s Dateien ausgewählt. Sollen diese Dateien " % len(filenames) if self.__gui.question_box(message + "in den Müll verschoben werden?"): self.update_list = True for f in filenames: if f.endswith("otrkey"): fileoperations.move_file(f, self.__app.config.get('general', 'folder_trash_otrkeys')) else: fileoperations.move_file(f, self.__app.config.get('general', 'folder_trash_avis'))
def do(self, downloads): downloads_count = len(downloads) if downloads_count == 1: question = "Soll der Download wirklich entfernt werden?" else: question = "Sollen %i Downloads wirklich entfernt werden?" % downloads_count dialog = gtk.MessageDialog(self.__gui.main_window, 0, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, question) checkbutton = gtk.CheckButton('Die heruntergeladene Datei in den Müll verschieben\n(Fertige Downloads werden nicht verschoben)') checkbutton.set_active(True) checkbutton.show() dialog.vbox.pack_end(checkbutton) response = dialog.run() if response == gtk.RESPONSE_YES: model = self.__gui.main_window.treeview_download.get_model() refs = [] for row in model: if row[0] in downloads: refs.append(gtk.TreeRowReference(model, row.path)) files = [ os.path.join(row[0].information['output'], row[0].filename + '.torrent'), os.path.join(row[0].information['output'], row[0].filename + '.aria2'), os.path.join(row[0].information['output'], row[0].filename + '.cutlist'), os.path.join(self.__app.config.get('general', 'folder_trash_otrkeys'), row[0].filename + '.segments'), ] for file in files: if os.path.exists(file): fileoperations.remove_file(file, None) if checkbutton.get_active() and not row[0].information['status'] in [DownloadStatus.FINISHED, DownloadStatus.SEEDING]: otrkey = os.path.join(row[0].information['output'], row[0].filename) # move otrkey to trash if os.path.exists(otrkey): fileoperations.move_file(otrkey, self.__app.config.get('general', 'folder_trash_otrkeys'), None) # move avi file of otrdecoder to trash avi_file = os.path.splitext(otrkey)[0] if os.path.exists(avi_file): fileoperations.move_file(avi_file, self.__app.config.get('general', 'folder_trash_avis'), None) row[0].stop() for ref in refs: iter = model.get_iter(ref.get_path()) model.remove(iter) dialog.destroy()
def do(self, filenames, cut_action=None): for f in filenames: if f.endswith("otrkey"): fileoperations.move_file(f, self.__app.config.get('general', 'folder_new_otrkeys')) elif f.endswith("ac3"): fileoperations.move_file(f, self.__app.config.get('general', 'folder_uncut_avis')) elif self.__app.uncut_video.match(f): fileoperations.move_file(f, self.__app.config.get('general', 'folder_uncut_avis')) else: fileoperations.move_file(f, self.__app.config.get('general', 'folder_cut_avis'))
def do(self, filenames): for f in filenames: if f.endswith("otrkey"): fileoperations.move_file(f, self.__app.config.get('general', 'folder_new_otrkeys')) elif f.endswith("ac3"): fileoperations.move_file(f, self.__app.config.get('general', 'folder_uncut_avis')) elif self.__app.uncut_video.match(f): fileoperations.move_file(f, self.__app.config.get('general', 'folder_uncut_avis')) else: fileoperations.move_file(f, self.__app.config.get('general', 'folder_cut_avis'))
def do(self, filenames): # widgets archive_directory = self.__app.config.get('general', 'folder_archive') dialog = self.__gui.dialog_archive result, renamed_filenames, archive_to = dialog.run(filenames, archive_directory) if result: self.update_list = True for original, new_name in renamed_filenames.iteritems(): # add extension to renamed file if needed extension = splitext(original)[1] if not new_name.endswith(extension): new_name += extension new_name = join(dirname(original), new_name.replace('/', '_')) if new_name != original: fileoperations.rename_file(original, new_name) fileoperations.move_file(new_name, archive_to) dialog.hide()
def decode(self, file_conclusions): self.log.debug("Decoder: {}".format( self.config.get('programs', 'decoder'))) otrtool = shutil.which("otrtool") # no decoder # --> otrtool if not "decode" and not "otrtool" in self.config.get( 'programs', 'decoder'): # no decoder specified self.gui.message_error_box( "Es ist kein korrekter Dekoder angegeben!") return False elif self.config.get_program('decoder') == 'otrtool' and not otrtool: # otrtool not found in path self.gui.message_error_box( "Der Dekoder otrtool ist ausgewählt, wurde aber nicht im \ Pfad gefunden!" ) return False elif '/' in self.config.get_program( 'decoder'): # It's an external program isexe = os.path.isfile( self.config.get_program('decoder')) and os.access( self.config.get_program('decoder'), os.X_OK) if not isexe: # File doen't exist or is not executable self.gui.message_error_box( "Der externe Dekoder wurde nicht gefunden oder ist \ nicht ausführbar." ) return False # <-- otrtool # retrieve email and password email = self.config.get('general', 'email') password = self.config.get('general', 'password') if not email or not password: self.gui.dialog_email_password.set_email_password(email, password) # let the user type in his data through a dialog response = self.gui.dialog_email_password.run() self.gui.dialog_email_password.hide() if response == Gtk.ResponseType.OK: email, password = self.gui.dialog_email_password.get_email_password( ) else: # user pressed cancel return False # now this method may not return "False" self.gui.main_window.set_tasks_visible(True) self.gui.main_window.block_gui(True) # decode each file for count, file_conclusion in enumerate(file_conclusions): # update progress self.gui.main_window.set_tasks_text( "Datei %s/%s dekodieren" % (count + 1, len(file_conclusions))) # --> otrtool if 'otrtool' in self.config.get_program('decoder'): command = [ self.config.get_program('decoder'), "-x", "-g", "-e", email, "-p", password, "-O", self.config.get('general', 'folder_uncut_avis') + "/" + basename( file_conclusion.otrkey[0:len(file_conclusion.otrkey) - 7]), file_conclusion.otrkey ] else: verify = True command = [ self.config.get_program('decoder'), "-i", file_conclusion.otrkey, "-e", email, "-p", password, "-o", self.config.get('general', 'folder_uncut_avis') ] if not self.config.get('general', 'verify_decoded'): verify = False command += ["-q"] # <-- otrtool try: process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError: file_conclusion.decode.status = Status.ERROR file_conclusion.decode.message = "Dekoder wurde nicht gefunden." continue # --> otrtool if 'otrtool' in self.config.get_program('decoder'): error_message = "" file_count = count + 1, len(file_conclusions) # list of non error strings nonerror = [ "OK", "gui", "OTR-Tool, ", "Keyphrase from", "Keyphrase:", "Decrypting", "Trying to contact", "Server responded", "info:", "warning:" ] for line in iter(process.stderr.readline, ''): line = line.decode("utf-8") if not line: break # Gathering errors if not any(x in line for x in nonerror): error_message += line.strip() if "Decrypting" in line: self.gui.main_window.set_tasks_text( "Datei %s/%s dekodieren und prüfen" % file_count) if ("gui" in line) and not ("Finished" in line): progress = int(line[5:]) # update progress self.gui.main_window.set_tasks_progress(progress) while Gtk.events_pending(): Gtk.main_iteration() # <-- otrtool else: while True: l = "" while True: c = process.stdout.read(1).decode('utf-8') if c == "\r" or c == "\n": break l += c if not l: break try: if verify: file_count = count + 1, len(file_conclusions) if "input" in l: self.gui.main_window.set_tasks_text( "Eingabedatei %s/%s kontrollieren" % file_count) elif "output" in l: self.gui.main_window.set_tasks_text( "Ausgabedatei %s/%s kontrollieren" % file_count) elif "Decoding" in l: self.gui.main_window.set_tasks_text( "Datei %s/%s dekodieren" % file_count) if len(l) > 13 and l[12].isdigit(): progress = int(l[10:13]) # update progress self.gui.main_window.set_tasks_progress(progress) while Gtk.events_pending(): Gtk.main_iteration() except ValueError: pass # errors? errors = process.stderr.readlines() error_message = "" for error in errors: error = error.decode('ISO-8859-1') if not 'libmediaclient' in error: error_message += error.strip() if error_message == "": # dekodieren erfolgreich file_conclusion.decode.status = Status.OK file_conclusion.uncut_video = join( self.config.get('general', 'folder_uncut_avis'), basename( file_conclusion.otrkey[0:len(file_conclusion.otrkey) - 7])) # move otrkey to trash if self.config.get('general', 'move_otrkey_to_trash_after_decode'): target = self.config.get('general', 'folder_trash_otrkeys') fileoperations.move_file(file_conclusion.otrkey, target) else: file_conclusion.decode.status = Status.ERROR try: str(error_message) except UnicodeDecodeError: error_message = str(error_message, 'iso-8859-1') file_conclusion.decode.message = error_message return True
def mp4(): # env my_env = os.environ.copy() my_env["LANG"] = "C" for count, filename in enumerate(filenames): # analyse file cutter = Cut(self.app, self.gui) fps, dar, sar, max_frames, ac3_stream, error = cutter.analyse_mediafile(filename) if fps == None: self.errors[filename] = error continue # mkvmerge pass yield 0, count self.progress = 0 if os.path.splitext(filename)[1] != ".mkv": mkvpass_file = fileoperations.make_unique_filename(os.path.splitext(filename)[0] + "_remux.mkv") try: p = subprocess.Popen( [ self.app.config.get_program("mkvmerge"), "--ui-language", "en_US", "-o", mkvpass_file, filename, ], stdout=subprocess.PIPE, env=my_env, ) except OSError: self.errors[filename] = "MKVmerge wurde nicht gefunden!" continue p.stdout.readline() line = "" while p.poll() == None: # read progress from stdout char = p.stdout.read(1) line += char progress = "" if char == ":": if "Error" in line or "Warning" in line: break while char != "%": char = p.stdout.read(1) progress += char try: self.progress = int(progress.strip(" %")) yield 4, self.progress except ValueError: pass exit_code = p.poll() if exit_code == 0 or exit_code == 1: pass else: error = p.stdout.readline() if os.path.exists(mkvpass_file): fileoperations.remove_file(mkvpass_file) try: error = error.split(":")[1] except IndexError: pass if "unknown type" in error: error = "Datei konnte nicht gelesen werden." self.errors[filename] = error continue else: mkvpass_file = filename # norm volume ausrechnen yield 5, count if self.Config["NormalizeAudio"] and self.Config["EncodeAudioToAAC"]: vol, error = self.get_norm_volume(filename) else: vol = 1.0 # ffmpeg pass yield 1, count self.progress = 0 ffmpegpass_file = fileoperations.make_unique_filename(os.path.splitext(filename)[0] + "_remux.mp4") if self.Config["EncodeAudioToAAC"]: if self.Config["EncodeOnlyFirstAudioToAAC"]: aacaudiostreams = "-c:a:0" else: aacaudiostreams = "-c:a" # convert first audio stream to aac ffmpeg = self.app.config.get_program("ffmpeg") if "nonfree" in ffmpeg: # nonfree ffmpeg version with fdk support available audiocodec = [ "-c:a", "copy", aacaudiostreams, "libfdk_aac", "-flags", "+qscale", "-profile:a:0", "aac_low", "-global_quality", "5", "-afterburner", "1", ] else: # only gpl version of ffmpeg available -> use standard aac codec audiocodec = [ "-c:a", "copy", aacaudiostreams, "aac", "-strict", "-2", "-profile:a:0", "aac_low", "-ab", "192k", "-cutoff", "18000", ] else: # only copy audio ffmpeg = path.get_tools_path("intern-ffmpeg") audiocodec = ["-c:a", "copy"] if self.Config["DownMixStereo"] and self.Config["EncodeAudioToAAC"]: audiocodec.extend(["-ac:0", "2"]) if ac3_stream == None: # no ac3 stream found - all streams are muxed map = ["-map", "0"] else: if self.Config["RemoveOtherAudioStreamsThanAC3"]: # mux only video and ac3 stream map = ["-map", "0:v", "-map", ac3_stream] else: map = ["-map", "0"] args = [ ffmpeg, "-loglevel", "info", "-y", "-drc_scale", "1.0", "-i", mkvpass_file, "-vcodec", "copy", "-af", "volume=volume=" + str(vol), "-vsync", "1", "-async", "1000", "-dts_delta_threshold", "100", "-vf", "fps=" + str(fps), ffmpegpass_file, ] map.extend(audiocodec) args[8:8] = map try: p = subprocess.Popen(args, stderr=subprocess.PIPE, universal_newlines=True) except OSError: self.errors[filename] = "FFMPEG (intern) wurde nicht gefunden!" if os.path.exists(mkvpass_file) and filename != mkvpass_file: fileoperations.remove_file(mkvpass_file) continue yield 4, 0 line = "" infos_match = re.compile(r"frame=\ {0,1}(\d{1,})") while p.poll() == None: line = p.stderr.readline() m = re.search(infos_match, line) if m and max_frames != 0: next = float(float(m.group(1)) / float(max_frames)) * 100 if next > self.progress: self.progress = next yield 4, self.progress else: pass exit_code = p.poll() if os.path.exists(mkvpass_file) and filename != mkvpass_file: fileoperations.remove_file(mkvpass_file) if exit_code == 0: if self.Config["DumpAVIs"]: yield 3, self.success new_filename = os.path.join( self.app.config.get("general", "folder_trash_avis"), os.path.basename(filename) ) if os.path.exists(new_filename): fileoperations.remove_file(new_filename) fileoperations.move_file(filename, self.app.config.get("general", "folder_trash_avis")) else: self.errors[filename] = "Fehler beim Erzeugen der MP4 Datei durch FFMPEG" if os.path.exists(ffmpegpass_file): fileoperations.remove_file(ffmpegpass_file) continue # mp4box - last turn self.progress = 0 mp4boxpass_file = fileoperations.make_unique_filename(os.path.splitext(filename)[0] + ".mp4") if self.Config["DontOptimizeMP4"]: os.rename(ffmpegpass_file, mp4boxpass_file) self.success += 1 continue yield 2, count try: p = subprocess.Popen( [ self.app.config.get_program("mp4box"), "-keep-all", "-new", "-packed", "-fps", str(fps), "-add", ffmpegpass_file, mp4boxpass_file, ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) except OSError: self.errors[filename] = "MP4Box (intern) wurde nicht gefunden!" if os.path.exists(ffmpegpass_file): fileoperations.remove_file(ffmpegpass_file) continue yield 4, 0 infos_match = re.compile(r".*\((\d{2,})\/\d{2,}\).*") while p.poll() == None: line = p.stdout.read(60) m = re.search(infos_match, line) if m: self.progress = int(m.group(1)) yield 4, self.progress if "Importing" in line: yield 2, count elif "Writing" in line: yield 6, count else: pass exit_code = p.poll() if os.path.exists(ffmpegpass_file): fileoperations.remove_file(ffmpegpass_file) if exit_code == 0: self.success += 1 else: self.errors[filename] = "Fehler beim Erzeugen der MP4 Datei durch MP4Box"
def mp4(): # env my_env = os.environ.copy() my_env["LANG"] = "C" for count, filename in enumerate(filenames): # analyse file cutter = Cut(self.app, self.gui) fps, dar, sar, max_frames, ac3_stream, error = cutter.analyse_mediafile( filename) if fps == None: self.errors[filename] = error continue # mkvmerge pass yield 0, count self.progress = 0 if os.path.splitext(filename)[1] != '.mkv': mkvpass_file = fileoperations.make_unique_filename( os.path.splitext(filename)[0] + "_remux.mkv") try: p = subprocess.Popen([ self.app.config.get_program('mkvmerge'), '--ui-language', 'en_US', "-o", mkvpass_file, filename ], stdout=subprocess.PIPE, env=my_env) except OSError: self.errors[ filename] = "MKVmerge wurde nicht gefunden!" continue p.stdout.readline() line = "" while p.poll() == None: # read progress from stdout char = p.stdout.read(1) line += char.decode('utf-8') progress = '' if char == ':': if "Error" in line or "Warning" in line: break while char != '%': char = p.stdout.read(1) progress += char try: self.progress = int(progress.strip(' %')) yield 4, self.progress except ValueError: pass exit_code = p.poll() if exit_code == 0 or exit_code == 1: pass else: error = p.stdout.readline() if os.path.exists(mkvpass_file): fileoperations.remove_file(mkvpass_file) try: error = error.split(":")[1] except IndexError: pass if "unknown type" in error: error = "Datei konnte nicht gelesen werden." self.errors[filename] = error continue else: mkvpass_file = filename # norm volume ausrechnen yield 5, count if self.Config['NormalizeAudio'] and self.Config[ 'EncodeAudioToAAC']: vol, error = self.get_norm_volume(filename) else: vol = 1.0 # ffmpeg pass yield 1, count self.progress = 0 ffmpegpass_file = fileoperations.make_unique_filename( os.path.splitext(filename)[0] + "_remux.mp4") if self.Config['EncodeAudioToAAC']: if self.Config['EncodeOnlyFirstAudioToAAC']: aacaudiostreams = '-c:a:0' else: aacaudiostreams = '-c:a' # convert first audio stream to aac ffmpeg = self.app.config.get_program('ffmpeg') if 'nonfree' in ffmpeg: # nonfree ffmpeg version with fdk support available audiocodec = [ '-c:a', 'copy', aacaudiostreams, 'libfdk_aac', '-flags', '+qscale', '-profile:a:0', 'aac_low', '-global_quality', '5', '-afterburner', '1' ] else: # only gpl version of ffmpeg available -> use standard aac codec audiocodec = [ '-c:a', 'copy', aacaudiostreams, 'aac', '-strict', '-2', '-profile:a:0', 'aac_low', '-ab', '192k', '-cutoff', '18000' ] else: # only copy audio ffmpeg = path.get_tools_path('intern-ffmpeg') audiocodec = ['-c:a', 'copy'] if self.Config['DownMixStereo'] and self.Config[ 'EncodeAudioToAAC']: audiocodec.extend(['-ac:0', '2']) if ac3_stream == None: # no ac3 stream found - all streams are muxed map = ['-map', '0'] else: if self.Config['RemoveOtherAudioStreamsThanAC3']: # mux only video and ac3 stream map = ['-map', '0:v', '-map', ac3_stream] else: map = ['-map', '0'] args = [ ffmpeg, "-loglevel", "info", "-y", "-drc_scale", "1.0", "-i", mkvpass_file, "-vcodec", "copy", '-af', 'volume=volume=' + str(vol), "-vsync", "1", '-async', '1000', "-dts_delta_threshold", "100", "-vf", "fps=" + str(fps), ffmpegpass_file ] map.extend(audiocodec) args[8:8] = map try: p = subprocess.Popen(args, stderr=subprocess.PIPE, universal_newlines=True) except OSError: self.errors[ filename] = "FFMPEG (intern) wurde nicht gefunden!" if os.path.exists( mkvpass_file) and filename != mkvpass_file: fileoperations.remove_file(mkvpass_file) continue yield 4, 0 line = "" infos_match = re.compile(r"frame=\ {0,1}(\d{1,})") while p.poll() == None: line = p.stderr.readline() m = re.search(infos_match, line) if m and max_frames != 0: next = float( float(m.group(1)) / float(max_frames)) * 100 if next > self.progress: self.progress = next yield 4, self.progress else: pass exit_code = p.poll() if os.path.exists(mkvpass_file) and filename != mkvpass_file: fileoperations.remove_file(mkvpass_file) if exit_code == 0: if self.Config['DumpAVIs']: yield 3, self.success new_filename = os.path.join( self.app.config.get('general', 'folder_trash_avis'), os.path.basename(filename)) if os.path.exists(new_filename): fileoperations.remove_file(new_filename) fileoperations.move_file( filename, self.app.config.get('general', 'folder_trash_avis')) else: self.errors[ filename] = "Fehler beim Erzeugen der MP4 Datei durch FFMPEG" if os.path.exists(ffmpegpass_file): fileoperations.remove_file(ffmpegpass_file) continue # mp4box - last turn self.progress = 0 mp4boxpass_file = fileoperations.make_unique_filename( os.path.splitext(filename)[0] + ".mp4") if self.Config['DontOptimizeMP4']: os.rename(ffmpegpass_file, mp4boxpass_file) self.success += 1 continue yield 2, count try: p = subprocess.Popen([ self.app.config.get_program('mp4box'), "-keep-all", "-new", "-packed", "-fps", str(fps), "-add", ffmpegpass_file, mp4boxpass_file ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except OSError: self.errors[ filename] = "MP4Box (intern) wurde nicht gefunden!" if os.path.exists(ffmpegpass_file): fileoperations.remove_file(ffmpegpass_file) continue yield 4, 0 infos_match = re.compile(r".*\((\d{2,})\/\d{2,}\).*") while p.poll() == None: line = p.stdout.read(60) line = line.decode('utf-8') m = re.search(infos_match, line) if m: self.progress = int(m.group(1)) yield 4, self.progress if 'Importing' in line: yield 2, count elif 'Writing' in line: yield 6, count else: pass exit_code = p.poll() if os.path.exists(ffmpegpass_file): fileoperations.remove_file(ffmpegpass_file) if exit_code == 0: self.success += 1 else: self.errors[ filename] = "Fehler beim Erzeugen der MP4 Datei durch MP4Box"
def mkvmerge(): # env my_env = os.environ.copy() my_env["LANG"] = "C" for count, filename in enumerate(filenames): yield 0, count yield 3, 0 self.progress = 0 #analyse file cutter = Cut(self.app, self.gui) fps, dar, sar, max_frames, ac3_stream, error = cutter.analyse_mediafile( filename) if fps == None: self.errors[filename] = error continue # encode aac with ffmpeg if self.Config['EncodeAudioToAAC']: #norm volume ausrechnen yield 5, count if self.Config['NormalizeAudio'] and self.Config[ 'EncodeAudioToAAC']: vol, error = self.get_norm_volume(filename) else: vol = 1.0 # ffmpeg pass yield 1, count self.progress = 0 ffmpegpass_file = fileoperations.make_unique_filename( os.path.splitext(filename)[0] + "_remux.mkv") # convert first audio stream to aac if self.Config['EncodeOnlyFirstAudioToAAC']: aacaudiostreams = '-c:a:0' else: aacaudiostreams = '-c:a' # convert first audio stream to aac ffmpeg = self.app.config.get_program('ffmpeg') if 'nonfree' in ffmpeg: # nonfree ffmpeg version with fdk support available audiocodec = [ '-c:a', 'copy', aacaudiostreams, 'libfdk_aac', '-flags', '+qscale', '-profile:a:0', 'aac_low', '-global_quality', '5', '-afterburner', '1' ] else: # only gpl version of ffmpeg available -> use standard aac codec audiocodec = [ '-c:a', 'copy', aacaudiostreams, 'aac', '-strict', '-2', '-profile:a:0', 'aac_low', '-ab', '192k', '-cutoff', '18000' ] if self.Config['DownMixStereo'] and self.Config[ 'EncodeAudioToAAC']: audiocodec.extend(['-ac:0', '2']) if ac3_stream == None: # no ac3 stream found - all streams are muxed map = ['-map', '0'] else: if self.Config['RemoveOtherAudioStreamsThanAC3']: # mux only video and ac3 stream map = ['-map', '0:v', '-map', ac3_stream] else: map = ['-map', '0'] args = [ ffmpeg, "-loglevel", "info", "-y", "-drc_scale", "1.0", "-i", filename, "-vn", '-af', 'volume=volume=' + str(vol), "-vsync", "1", '-async', '1000', "-dts_delta_threshold", "100", "-vf", "fps=" + str(fps), '-threads', '0', ffmpegpass_file ] map.extend(audiocodec) args[8:8] = map try: p = subprocess.Popen(args, stderr=subprocess.PIPE, universal_newlines=True) except OSError: self.errors[ filename] = "FFMPEG (intern) wurde nicht gefunden!" continue yield 4, 0 line = "" infos_match = re.compile( r"time=(\d{2,}):(\d{2,}):(\d{2,}.\d{2,})") while p.poll() == None: line = p.stderr.readline() m = re.search(infos_match, line) if m and max_frames != 0: frame = (float(m.group(1)) * 3600 + float(m.group(2)) * 60 + float(m.group(3))) * fps next = float(frame / float(max_frames)) * 100 if next > self.progress: self.progress = next yield 4, self.progress else: pass exit_code = p.poll() if exit_code == 0: pass else: self.errors[ filename] = "Fehler beim Erzeugen der MP4 Datei durch FFMPEG" if os.path.exists(ffmpegpass_file): fileoperations.remove_file(ffmpegpass_file) continue # mkvmerge pass yield 2, count self.progress = 0 mkvpass_file = fileoperations.make_unique_filename( os.path.splitext(filename)[0] + ".mkv") if self.Config['EncodeAudioToAAC']: args = [ self.app.config.get_program('mkvmerge'), '--engage', 'no_cue_duration', '--engage', 'no_cue_relative_position', '--ui-language', 'en_US', "-o", mkvpass_file, '-A', filename, '-D', ffmpegpass_file ] else: if self.Config[ 'RemoveOtherAudioStreamsThanAC3'] and ac3_stream: args = [ self.app.config.get_program('mkvmerge'), '--engage', 'no_cue_duration', '--engage', 'no_cue_relative_position', '--ui-language', 'en_US', "-o", mkvpass_file, '-a', ac3_stream[2], filename ] else: args = [ self.app.config.get_program('mkvmerge'), '--engage', 'no_cue_duration', '--engage', 'no_cue_relative_position', '--ui-language', 'en_US', "-o", mkvpass_file, filename ] p = subprocess.Popen(args, stdout=subprocess.PIPE, env=my_env) p.stdout.readline() line = "" while p.poll() == None: # read progress from stdout char = p.stdout.read(1) line += char progress = '' if char == ':': if "Error" in line or "Warning" in line: break while char != '%': char = p.stdout.read(1) progress += char try: self.progress = int(progress.strip(' %')) yield 3, self.progress except ValueError: pass exit_code = p.poll() if exit_code == 0 or exit_code == 1: self.success += 1 if self.Config['EncodeAudioToAAC']: fileoperations.remove_file(ffmpegpass_file) if self.Config['DumpAVIs']: if self.Config['DumpAVIs_delete']: fileoperations.remove_file(filename) else: new_filename = os.path.join( self.app.config.get('general', 'folder_trash_avis'), os.path.basename(filename)) if os.path.exists(new_filename): fileoperations.remove_file(new_filename) fileoperations.move_file( filename, self.app.config.get('general', 'folder_trash_avis')) else: error = p.stdout.readline() try: error = error.split(":")[1] except IndexError: pass if "unknown type" in error: error = "Datei konnte nicht gelesen werden." self.errors[filename] = error
def mkvmerge(): # env my_env = os.environ.copy() my_env["LANG"] = "C" for count, filename in enumerate(filenames): yield 0, count yield 3, 0 self.progress = 0 #analyse file cutter = Cut(self.app, self.gui) fps, dar, sar, max_frames, ac3_stream, error = cutter.analyse_mediafile(filename) if fps == None: self.errors[filename] = error continue # encode aac with ffmpeg if self.Config['EncodeAudioToAAC']: #norm volume ausrechnen yield 5, count if self.Config['NormalizeAudio'] and self.Config['EncodeAudioToAAC']: vol, error = self.get_norm_volume(filename) else: vol = 1.0 # ffmpeg pass yield 1, count self.progress = 0 ffmpegpass_file = fileoperations.make_unique_filename(os.path.splitext(filename)[0] + "_remux.mkv") # convert first audio stream to aac if self.Config['EncodeOnlyFirstAudioToAAC']: aacaudiostreams = '-c:a:0' else: aacaudiostreams = '-c:a' # convert first audio stream to aac ffmpeg = self.app.config.get_program('ffmpeg') if 'nonfree' in ffmpeg: # nonfree ffmpeg version with fdk support available audiocodec = ['-c:a', 'copy', aacaudiostreams, 'libfdk_aac', '-flags', '+qscale', '-profile:a:0', 'aac_low', '-global_quality', '5' ,'-afterburner', '1'] else: # only gpl version of ffmpeg available -> use standard aac codec audiocodec = ['-c:a', 'copy', aacaudiostreams, 'aac', '-strict', '-2','-profile:a:0', 'aac_low', '-ab' ,'192k', '-cutoff', '18000'] if self.Config['DownMixStereo'] and self.Config['EncodeAudioToAAC']: audiocodec.extend(['-ac:0', '2']) if ac3_stream == None: # no ac3 stream found - all streams are muxed map = ['-map', '0'] else: if self.Config['RemoveOtherAudioStreamsThanAC3']: # mux only video and ac3 stream map = ['-map', '0:v', '-map', ac3_stream] else: map = ['-map' ,'0'] args = [ffmpeg, "-loglevel", "info", "-y", "-drc_scale", "1.0", "-i", filename, "-vn", '-af', 'volume=volume=' + str(vol), "-vsync", "1", '-async', '1000', "-dts_delta_threshold", "100", "-vf", "fps="+ str(fps), '-threads', '0', ffmpegpass_file] map.extend(audiocodec) args[8:8] = map try: p = subprocess.Popen(args, stderr=subprocess.PIPE, universal_newlines=True) except OSError: self.errors[filename] = "FFMPEG (intern) wurde nicht gefunden!" continue yield 4, 0 line = "" infos_match = re.compile(r"time=(\d{2,}):(\d{2,}):(\d{2,}.\d{2,})") while p.poll() == None: line = p.stderr.readline() m = re.search(infos_match,line) if m and max_frames != 0: frame = (float(m.group(1))*3600 + float(m.group(2))*60 + float(m.group(3)))*fps next = float( frame / float(max_frames) ) * 100 if next > self.progress: self.progress = next yield 4, self.progress else: pass exit_code = p.poll() if exit_code == 0: pass else: self.errors[filename] = "Fehler beim Erzeugen der MP4 Datei durch FFMPEG" if os.path.exists(ffmpegpass_file): fileoperations.remove_file(ffmpegpass_file) continue # mkvmerge pass yield 2, count self.progress = 0 mkvpass_file = fileoperations.make_unique_filename(os.path.splitext(filename)[0] + ".mkv") if self.Config['EncodeAudioToAAC']: args = [self.app.config.get_program('mkvmerge'), '--engage', 'no_cue_duration', '--engage', 'no_cue_relative_position', '--ui-language', 'en_US',"-o", mkvpass_file, '-A', filename, '-D', ffmpegpass_file] else: if self.Config['RemoveOtherAudioStreamsThanAC3'] and ac3_stream: args = [self.app.config.get_program('mkvmerge'), '--engage', 'no_cue_duration', '--engage', 'no_cue_relative_position', '--ui-language', 'en_US', "-o", mkvpass_file, '-a', ac3_stream[2], filename] else: args = [self.app.config.get_program('mkvmerge'), '--engage', 'no_cue_duration', '--engage', 'no_cue_relative_position', '--ui-language', 'en_US', "-o", mkvpass_file, filename] p = subprocess.Popen(args, stdout=subprocess.PIPE, env=my_env) p.stdout.readline() line = "" while p.poll() == None: # read progress from stdout char = p.stdout.read(1) line += char progress = '' if char == ':': if "Error" in line or "Warning" in line: break while char != '%': char = p.stdout.read(1) progress += char try: self.progress = int(progress.strip(' %')) yield 3, self.progress except ValueError: pass exit_code = p.poll() if exit_code == 0 or exit_code == 1: self.success += 1 if self.Config['EncodeAudioToAAC']: fileoperations.remove_file(ffmpegpass_file) if self.Config['DumpAVIs']: if self.Config['DumpAVIs_delete']: fileoperations.remove_file(filename) else: new_filename = os.path.join(self.app.config.get('general', 'folder_trash_avis'), os.path.basename(filename)) if os.path.exists(new_filename): fileoperations.remove_file(new_filename) fileoperations.move_file(filename, self.app.config.get('general', 'folder_trash_avis')) else: error = p.stdout.readline() try: error = error.split(":")[1] except IndexError: pass if "unknown type" in error: error = "Datei konnte nicht gelesen werden." self.errors[filename] = error
def show_conclusions(self): conclusions = self.app.gui.dialog_conclusion._run( self.conclusions, self.app.rename_by_schema, self.app.config.get('general', 'folder_archive')) self.app.gui.main_window.builder.get_object('box_conclusion').hide() self.conclusions = [] # create cutlists cutlists = [] for conclusion in conclusions: if conclusion.action == Action.DECODE: continue print "[Conclusion] for file ", conclusion.uncut_video # rename print "[Conclusion] Rename?" if conclusion.cut.rename: print "[Conclusion] true" extension = os.path.splitext(conclusion.cut_video)[1] if not conclusion.cut.rename.endswith(extension): conclusion.cut.rename += extension new_filename = os.path.join( self.app.config.get('general', 'folder_cut_avis'), conclusion.cut.rename.replace('/', '_')) new_filename = fileoperations.make_unique_filename( new_filename) if conclusion.cut_video != new_filename: conclusion.cut_video = fileoperations.rename_file( conclusion.cut_video, new_filename) # move cut video to archive print "[Conclusion] Move to archive?" if conclusion.cut.archive_to: print "[Conclusion] true" fileoperations.move_file(conclusion.cut_video, conclusion.cut.archive_to) # move uncut video to trash if it's ok print "[Conclusion] Move to trash?" if conclusion.cut.status == Status.OK and conclusion.cut.delete_uncut: print "[Conclusion] true" if os.path.exists(conclusion.uncut_video): # move to trash target = self.app.config.get('general', 'folder_trash_avis') conclusion.uncut_video = fileoperations.move_file( conclusion.uncut_video, target) if os.path.exists(conclusion.ac3_file): target = self.app.config.get('general', 'folder_trash_avis') fileoperations.move_file(conclusion.ac3_file, target) # remove local cutlists print "[Conclusion] Remove local cutlist?" if self.app.config.get('general', 'delete_cutlists'): print "[Conclusion] true" if conclusion.cut.cutlist.local_filename: if os.path.exists( conclusion.cut.cutlist.local_filename): fileoperations.remove_file( conclusion.cut.cutlist.local_filename) print "[Conclusion] Create cutlist?" if conclusion.cut.create_cutlist: print "[Conclusion] true" if "VirtualDub" in conclusion.cut.cutlist.intended_app: intended_app_name = "VirtualDub" else: intended_app_name = "Avidemux" if not conclusion.cut.cutlist.local_filename: conclusion.cut.cutlist.local_filename = self.app.config.get( 'general', 'folder_uncut_avis') + '/' + os.path.basename( conclusion.uncut_video) + ".cutlist" conclusion.cut.cutlist.author = self.app.config.get( 'general', 'cutlist_username') conclusion.cut.cutlist.intended_version = open( path.getdatapath("VERSION"), 'r').read().strip() conclusion.cut.cutlist.smart = self.app.config.get( 'general', 'smart') conclusion.cut.cutlist.write_local_cutlist( conclusion.uncut_video, intended_app_name, conclusion.cut.my_rating) if conclusion.cut.upload_cutlist: cutlists.append(conclusion.cut.cutlist) # upload cutlists: def upload(): error_messages = [] for cutlist in cutlists: error_message = cutlist.upload( self.app.config.get('general', 'server'), self.app.config.get('general', 'cutlist_hash')) if error_message: error_messages.append(error_message) else: if self.app.config.get('general', 'delete_cutlists'): fileoperations.remove_file(cutlist.local_filename) count = len(cutlists) message = "Es wurden %s/%s Cutlisten hochgeladen!" % ( str(count - len(error_messages)), str(count)) if len(error_messages) > 0: message += " (" + ", ".join(error_messages) + ")" yield message if len(cutlists) > 0: print "[Conclusion] Upload cutlists" if self.app.gui.question_box( "Soll(en) %s Cutlist(en) hochgeladen werden?" % len(cutlists)): def change_status(message): self.app.gui.main_window.change_status(0, message) GeneratorTask(upload, change_status).start() # rate cutlists def rate(): yield 0 # fake generator messages = [] count = 0 for conclusion in conclusions: if conclusion.action == Action.DECODE: continue if conclusion.cut.my_rating > -1: print "Rate with ", conclusion.cut.my_rating success, message = conclusion.cut.cutlist.rate( conclusion.cut.my_rating, self.app.config.get('general', 'server')) if success: count += 1 else: messages += [message] if count > 0 or len(messages) > 0: if count == 0: text = "Es wurde keine Cutlist bewertet!" if count == 1: text = "Es wurde 1 Cutlist bewertet!" else: text = "Es wurden %s Cutlisten bewertet!" % count if len(messages) > 0: text += " (Fehler: %s)" % ", ".join(messages) self.app.gui.main_window.change_status(0, text) print "[Conclusion] Rate cutlists" GeneratorTask(rate).start()
def show_conclusions(self): conclusions = self.app.gui.dialog_conclusion._run(self.conclusions, self.app.rename_by_schema, self.app.config.get('general', 'folder_archive')) self.app.gui.main_window.builder.get_object('box_conclusion').hide() self.conclusions = [] # create cutlists cutlists = [] for conclusion in conclusions: if conclusion.action == Action.DECODE: continue print "[Conclusion] for file ", conclusion.uncut_video # rename print "[Conclusion] Rename?" if conclusion.cut.rename: print "[Conclusion] true" extension = os.path.splitext(conclusion.cut_video)[1] if not conclusion.cut.rename.endswith(extension): conclusion.cut.rename += extension new_filename = os.path.join(self.app.config.get('general', 'folder_cut_avis'), conclusion.cut.rename.replace('/', '_')) #new_filename = fileoperations.make_unique_filename(new_filename) if conclusion.cut_video != new_filename: conclusion.cut_video = fileoperations.rename_file(conclusion.cut_video, new_filename) # move cut video to archive print "[Conclusion] Move to archive?" if conclusion.cut.archive_to: print "[Conclusion] true" fileoperations.move_file(conclusion.cut_video, conclusion.cut.archive_to) # move uncut video to trash if it's ok print "[Conclusion] Move to trash?" if conclusion.cut.status == Status.OK and conclusion.cut.delete_uncut: print "[Conclusion] true" if os.path.exists(conclusion.uncut_video): # move to trash target = self.app.config.get('general', 'folder_trash_avis') conclusion.uncut_video = fileoperations.move_file(conclusion.uncut_video, target) if os.path.exists(conclusion.ac3_file): target = self.app.config.get('general', 'folder_trash_avis') fileoperations.move_file(conclusion.ac3_file, target) # remove local cutlists print "[Conclusion] Remove local cutlist?" if self.app.config.get('general', 'delete_cutlists'): print "[Conclusion] true" if conclusion.cut.cutlist.local_filename: if os.path.exists(conclusion.cut.cutlist.local_filename): fileoperations.remove_file(conclusion.cut.cutlist.local_filename) print "[Conclusion] Create cutlist?" if conclusion.cut.create_cutlist: print "[Conclusion] true" if "VirtualDub" in conclusion.cut.cutlist.intended_app: intended_app_name = "VirtualDub" else: intended_app_name = "Avidemux" if not conclusion.cut.cutlist.local_filename: conclusion.cut.cutlist.local_filename = self.app.config.get('general', 'folder_uncut_avis') + '/' + os.path.basename(conclusion.uncut_video) + ".cutlist" conclusion.cut.cutlist.author = self.app.config.get('general', 'cutlist_username') conclusion.cut.cutlist.intended_version = open(path.getdatapath("VERSION"), 'r').read().strip() conclusion.cut.cutlist.smart = self.app.config.get('general', 'smart') conclusion.cut.cutlist.write_local_cutlist(conclusion.uncut_video, intended_app_name, conclusion.cut.my_rating) if conclusion.cut.upload_cutlist: cutlists.append(conclusion.cut.cutlist) # upload cutlists: def upload(): error_messages = [] for cutlist in cutlists: error_message = cutlist.upload(self.app.config.get('general', 'server'), self.app.config.get('general', 'cutlist_hash')) if error_message: error_messages.append(error_message) else: if self.app.config.get('general', 'delete_cutlists'): fileoperations.remove_file(cutlist.local_filename) count = len(cutlists) message = "Es wurden %s/%s Cutlisten hochgeladen!" % (str(count - len(error_messages)), str(count)) if len(error_messages) > 0: message += " (" + ", ".join(error_messages) + ")" yield message if len(cutlists) > 0: print "[Conclusion] Upload cutlists" if self.app.gui.question_box("Soll(en) %s Cutlist(en) hochgeladen werden?" % len(cutlists)): def change_status(message): self.app.gui.main_window.change_status(0, message) GeneratorTask(upload, change_status).start() # rate cutlists def rate(): yield 0 # fake generator messages = [] count = 0 for conclusion in conclusions: if conclusion.action == Action.DECODE: continue if conclusion.cut.my_rating > -1: print "Rate with ", conclusion.cut.my_rating success, message = conclusion.cut.cutlist.rate(conclusion.cut.my_rating, self.app.config.get('general', 'server')) if success: count += 1 else: messages += [message] if count > 0 or len(messages) > 0: if count == 0: text = "Es wurde keine Cutlist bewertet!" if count == 1: text = "Es wurde 1 Cutlist bewertet!" else: text = "Es wurden %s Cutlisten bewertet!" % count if len(messages) > 0: text += " (Fehler: %s)" % ", ".join(messages) self.app.gui.main_window.change_status(0, text) print "[Conclusion] Rate cutlists" GeneratorTask(rate).start()
def decode(self, file_conclusions): # no decoder if not "decode" in self.config.get('programs', 'decoder'): # no decoder specified # dialog box: no decoder self.gui.message_error_box( "Es ist kein korrekter Dekoder angegeben!") return False # retrieve email and password email = self.config.get('general', 'email') password = base64.b64decode(self.config.get('general', 'password')) if not email or not password: self.gui.dialog_email_password.set_email_password(email, password) # let the user type in his data through a dialog response = self.gui.dialog_email_password.run() self.gui.dialog_email_password.hide() if response == RESPONSE_OK: email, password = self.gui.dialog_email_password.get_email_password( ) else: # user pressed cancel return False # now this method may not return "False" self.gui.main_window.set_tasks_visible(True) self.gui.main_window.block_gui(True) # decode each file for count, file_conclusion in enumerate(file_conclusions): # update progress self.gui.main_window.set_tasks_text( "Datei %s/%s dekodieren" % (count + 1, len(file_conclusions))) verify = True command = [ self.config.get_program('decoder'), "-i", file_conclusion.otrkey, "-e", email, "-p", password, "-o", self.config.get('general', 'folder_uncut_avis') ] if not self.config.get('general', 'verify_decoded'): verify = False command += ["-q"] try: process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError: file_conclusion.decode.status = Status.ERROR file_conclusion.decode.message = "Dekoder wurde nicht gefunden." continue while True: l = "" while True: c = process.stdout.read(1) if c == "\r" or c == "\n": break l += c if not l: break try: if verify: file_count = count + 1, len(file_conclusions) if "input" in l: self.gui.main_window.set_tasks_text( "Eingabedatei %s/%s kontrollieren" % file_count) elif "output" in l: self.gui.main_window.set_tasks_text( "Ausgabedatei %s/%s kontrollieren" % file_count) elif "Decoding" in l: self.gui.main_window.set_tasks_text( "Datei %s/%s dekodieren" % file_count) progress = int(l[10:13]) # update progress self.gui.main_window.set_tasks_progress(progress) while events_pending(): main_iteration(False) except ValueError: pass # errors? errors = process.stderr.readlines() error_message = "" for error in errors: if not 'libmediaclient' in error: error_message += error.strip() if error_message == "": # dekodieren erfolgreich file_conclusion.decode.status = Status.OK file_conclusion.uncut_video = join( self.config.get('general', 'folder_uncut_avis'), basename( file_conclusion.otrkey[0:len(file_conclusion.otrkey) - 7])) # move otrkey to trash if self.config.get('general', 'move_otrkey_to_trash_after_decode'): target = self.config.get('general', 'folder_trash_otrkeys') fileoperations.move_file(file_conclusion.otrkey, target) else: file_conclusion.decode.status = Status.ERROR try: unicode(error_message) except UnicodeDecodeError: error_message = unicode(error_message, 'iso-8859-1') file_conclusion.decode.message = error_message return True
def decode(self, file_conclusions): # no decoder if not "decode" in self.config.get('programs', 'decoder'): # no decoder specified # dialog box: no decoder self.gui.message_error_box("Es ist kein korrekter Dekoder angegeben!") return False # retrieve email and password email = self.config.get('general', 'email') password = base64.b64decode(self.config.get('general', 'password')) if not email or not password: self.gui.dialog_email_password.set_email_password(email, password) # let the user type in his data through a dialog response = self.gui.dialog_email_password.run() self.gui.dialog_email_password.hide() if response == RESPONSE_OK: email, password = self.gui.dialog_email_password.get_email_password() else: # user pressed cancel return False # now this method may not return "False" self.gui.main_window.set_tasks_visible(True) self.gui.main_window.block_gui(True) # decode each file for count, file_conclusion in enumerate(file_conclusions): # update progress self.gui.main_window.set_tasks_text("Datei %s/%s dekodieren" % (count + 1, len(file_conclusions))) verify = True command = [self.config.get_program('decoder'), "-i", file_conclusion.otrkey, "-e", email, "-p", password, "-o", self.config.get('general', 'folder_uncut_avis')] if not self.config.get('general', 'verify_decoded'): verify = False command += ["-q"] try: process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError: file_conclusion.decode.status = Status.ERROR file_conclusion.decode.message = "Dekoder wurde nicht gefunden." continue while True: l = "" while True: c = process.stdout.read(1) if c == "\r" or c == "\n": break l += c if not l: break try: if verify: file_count = count + 1, len(file_conclusions) if "input" in l: self.gui.main_window.set_tasks_text("Eingabedatei %s/%s kontrollieren" % file_count) elif "output" in l: self.gui.main_window.set_tasks_text("Ausgabedatei %s/%s kontrollieren" % file_count) elif "Decoding" in l: self.gui.main_window.set_tasks_text("Datei %s/%s dekodieren" % file_count) progress = int(l[10:13]) # update progress self.gui.main_window.set_tasks_progress(progress) while events_pending(): main_iteration(False) except ValueError: pass # errors? errors = process.stderr.readlines() error_message = "" for error in errors: if not 'libmediaclient' in error: error_message += error.strip() if error_message == "": # dekodieren erfolgreich file_conclusion.decode.status = Status.OK file_conclusion.uncut_video = join(self.config.get('general', 'folder_uncut_avis'), basename(file_conclusion.otrkey[0:len(file_conclusion.otrkey)-7])) # move otrkey to trash if self.config.get('general', 'move_otrkey_to_trash_after_decode'): target = self.config.get('general', 'folder_trash_otrkeys') fileoperations.move_file(file_conclusion.otrkey, target) else: file_conclusion.decode.status = Status.ERROR try: unicode(error_message) except UnicodeDecodeError: error_message = unicode(error_message, 'iso-8859-1') file_conclusion.decode.message = error_message return True
def do(self, downloads, cut_action=None): downloads_count = len(downloads) if downloads_count == 1: question = "Soll der Download wirklich entfernt werden?" else: question = "Sollen %i Downloads wirklich entfernt werden?" % downloads_count dialog = Gtk.MessageDialog(self.__gui.main_window, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, question) checkbutton = Gtk.CheckButton( 'Die heruntergeladene Datei in den Müll verschieben\n(Fertige Downloads werden nicht verschoben)' ) checkbutton.set_active(True) checkbutton.show() dialog.vbox.pack_end(checkbutton, False, False, 0) response = dialog.run() if response == Gtk.ResponseType.OK: model = self.__gui.main_window.treeview_download.get_model() refs = [] for row in model: if row[0] in downloads: refs.append(Gtk.TreeRowReference.new(model, row.path)) files = [ os.path.join(row[0].information['output'], row[0].filename + '.torrent'), os.path.join(row[0].information['output'], row[0].filename + '.aria2'), os.path.join(row[0].information['output'], row[0].filename + '.cutlist'), os.path.join( self.__app.config.get('general', 'folder_trash_otrkeys'), row[0].filename + '.segments'), ] for file in files: if os.path.exists(file): fileoperations.remove_file(file, None) if checkbutton.get_active( ) and not row[0].information['status'] in [ DownloadStatus.FINISHED, DownloadStatus.SEEDING ]: otrkey = os.path.join(row[0].information['output'], row[0].filename) # move otrkey to trash if os.path.exists(otrkey): fileoperations.move_file( otrkey, self.__app.config.get('general', 'folder_trash_otrkeys'), None) # move avi file of otrdecoder to trash avi_file = os.path.splitext(otrkey)[0] if os.path.exists(avi_file): fileoperations.move_file( avi_file, self.__app.config.get('general', 'folder_trash_avis'), None) row[0].stop() for ref in refs: iter = model.get_iter(ref.get_path()) model.remove(iter) dialog.destroy()