class MainWindow(object): def __init__(self, marshaller): # Threads self.helperThread = HelperThread(marshaller) self.inserterThread = InserterThread(self.helperThread) self.inserterThread.message_callback = self.on_inserter_thread_callback # Gtk self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.builder = Gtk.Builder() prepare_builder_for_translation(self.builder) self.builder.add_from_file(path_with("glade", "mainWindow.glade")) self.window = self.builder.get_object("mainWindow") self.insertLinksDialog = InsertLinksDialog() self.aboutDialog = AboutDialog() self.optionsDialog = OptionsDialog() self.destination = definitions.OPTIONS.defaultFolder self.folderChoose = Gtk.FileChooserDialog( title=_("Choose destination folder"), action=Gtk.FileChooserAction.SELECT_FOLDER, buttons=(Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)) # DownloadAndEncode, title, state self.liststore = self.builder.get_object("videoListStore") self.marshaller = marshaller self.marshaller.on_video_start_download = lambda x, y: GObject.idle_add(lambda *args: self.refresh_marshaller(), None) self.marshaller.on_video_progress = lambda *args: GObject.idle_add(lambda *args: self.refresh_download_progress(), None) self.marshaller.on_video_start_encoding = lambda x, y, z: GObject.idle_add(self.on_video_start_encoding, None) self.marshaller.on_video_finish = lambda x, y: GObject.idle_add(self.on_video_finish, x, y) self.helperThread.start() self.inserterThread.start() self.treeview = self.builder.get_object("videoTreeView") cellRendererTitle = Gtk.CellRendererText() columnTitle = Gtk.TreeViewColumn(_("Title"), cellRendererTitle, text=1) cellRendererState = Gtk.CellRendererText() columnState = Gtk.TreeViewColumn(_("State"), cellRendererState, text=2) self.treeview.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY) self.treeview.connect("drag-data-received", self.onTreeViewDragDataRecieved) self.treeview.drag_dest_add_text_targets() self.clear_list = self.builder.get_object("clearList") self.clear_list.set_sensitive(False) self.set_destination = self.builder.get_object("setDestination") self.treeview.append_column(columnTitle) self.treeview.append_column(columnState) self.popupTreeView = self.builder.get_object("popupTreeView") self.progressbar = self.builder.get_object("progressbar") self.download_progressbar = self.builder.get_object("downloadProgressbar") self.download_progressbar.set_show_text(True) self.download_progressbar.set_text("") self.general_data = self.builder.get_object("generalData") self.statusbar = self.builder.get_object("statusbar") ctx_id = self.statusbar.get_context_id("inserter") self.statusbar.push(ctx_id, _("Ready!")) self.itemFeedback = self.builder.get_object("imagemenuitemFeedback") self.refresh_marshaller() self.reset_destination() self.reset_data_label() self.builder.connect_signals(self) # LibNotify if not definitions.WINDOWS: self.notification = Notify.Notification.new("Bat-man", "", path_with("glade", "batman-logo.png")) def on_inserter_thread_callback(self, inserter, element): # BUGFIX? return # Inserter has a new message! Let's hear it... size = len(self.inserterThread.queue) # WTF? ctx_id = self.statusbar.get_context_id("inserter") # Updating statusbar... if element == None and size > 0: self.statusbar.push(ctx_id, _("Adding videos... ({}/{})").format(0, size)) elif element == None and size == 0: self.statusbar.push(ctx_id, _("Ready!")) else: i = self.inserterThread.queue.index(element) self.statusbar.push(ctx_id, _("Adding videos... ({}/{})").format(i, size)) # Updating data label self.reset_data_label() def on_video_start_encoding(self, *args): logging.info("on_video_start_encoding called") self.refresh_marshaller() self.refresh_download_progress() def on_video_finish(self, marshaller, video): logging.info("on_video_finish called") self.refresh_marshaller() self.refresh_download_progress() self.reset_data_label() if not definitions.WINDOWS: finished = len(self.marshaller.finished) total = len(self.marshaller.all) string = _("\"{}\" finished. ({}/{})").format(video.video.title, finished, total) self.notification.update("Bat-man", string, path_with("glade", "batman-logo.png")) self.notification.show() def reset_data_label(self): self.general_data.set_text(_("- {} video(s)\n"\ "- Destination: {}").format(len(self.marshaller.all), self.destination)) def reset_destination(self): for i in self.marshaller.all: i.set_outfolder(self.destination) def refresh_marshaller(self): progress = 0 size = len(self.marshaller.all) self.liststore.clear() for video in self.marshaller.all: state = self.marshaller.find_state_of_video(video) if state == bd.DownloadAndEncodeMarshaller.NON_EXISTANT: progress += 0 self.liststore.append([video, video.video.title, _("Non existant")]) elif state == bd.DownloadAndEncodeMarshaller.PENDING: progress += 0 self.liststore.append([video, video.video.title, _("Pending")]) elif state == bd.DownloadAndEncodeMarshaller.DOWNLOADING: progress += 1/3/size self.liststore.append([video, video.video.title, _("Downloading")]) elif state == bd.DownloadAndEncodeMarshaller.ENCODING: progress += 2/3/size self.liststore.append([video, video.video.title, _("Encoding")]) elif state == bd.DownloadAndEncodeMarshaller.FINISHED: progress += 1/size self.liststore.append([video, video.video.title, _("Finished")]) elif state == bd.DownloadAndEncodeMarshaller.NOT_FOUND: progress += 0 self.liststore.append([video, video.video.title, _("Not found")]) self.progressbar.set_fraction(progress) # Should we be able to activate clear list? if len(self.marshaller.finished) > 0: self.clear_list.set_sensitive(True) def refresh_download_progress(self): size = len(self.marshaller.downloading) progress = 0.0 speed = 0 for video in self.marshaller.downloading: # May happen it be None, there is a small-to-medium gap between the # start of the download function(where it is set as downloading by # the marshaller) and the current downloading. if video.download_progress != None: progress += video.download_progress[2]/size speed += video.download_progress[3] self.download_progressbar.set_fraction(progress) if size != 0: self.download_progressbar.set_text("{:.2%} @ {:.0f} KBps".format(progress, speed/size)) else: self.download_progressbar.set_text("") def onItemInsertActivate(self, *args): links = self.insertLinksDialog.add_new_links() self.insertLinksDialog.hide() if links != None: for l in links: if l.strip() != "": self.inserterThread.add_video_to_download(l, self.destination, definitions.OPTIONS.quality, definitions.OPTIONS.VBRquality) self.refresh_marshaller() self.reset_data_label() def onCloseCalled(self, *args): Gtk.main_quit() self.inserterThread.quit() self.helperThread.quit() # self.inserterThread.join() # self.helperThread.join() #Helper thread won't be joined. Sorry, die now. # del self.inserterThread # del self.helperThread # del self.marshaller sys.exit(0) # Kill thread? Need to see this. Or sys.exit def onItemAboutActivate(self, *args): self.aboutDialog.dialog.run() self.aboutDialog.dialog.hide() def onItemFeedbackActivate(self, *args): feedback.open_email_sender_for_feedback() def onItemOptionsActivate(self, *args): self.optionsDialog.dialog.run() self.optionsDialog.dialog.hide() # Reloading codecs if they are changed - reload on batch_downloader self.marshaller.reload_codecs() def onSetDestinationClicked(self, *args): response = self.folderChoose.run() self.folderChoose.hide() if response == Gtk.ResponseType.OK: self.destination = self.folderChoose.get_filename() definitions.OPTIONS.defaultFolder = self.destination definitions.OPTIONS.write() self.reset_destination() self.reset_data_label() def onClearListClicked(self, *args): for video in self.marshaller.finished: try: self.marshaller.finished.remove(video) self.marshaller.all.remove(video) except Exception as e: logging.debug(e.strerror) self.refresh_marshaller() self.reset_data_label() # Dumb logic - if we cleared the list already, the list can't be cleared. # At least this is what I think. self.clear_list.set_sensitive(False) def onTreeViewClicked(self, widget, event): # 3 == right click if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3: self.popupTreeView.popup(None, None, None, None, event.button, event.time) def onTreeViewPaste(self, *args): content = self.clipboard.wait_for_text() if content != None: for line in content.split("\n"): self.inserterThread.add_video_to_download(line, self.destination, definitions.OPTIONS.quality, definitions.OPTIONS.VBRquality) self.refresh_marshaller() self.reset_data_label() def onTreeViewDragDataRecieved(self, widget, drag_context, x, y, data, info, time): links = data.get_text().split("\n") for line in links: self.inserterThread.add_video_to_download(line, self.destination, definitions.OPTIONS.quality, definitions.OPTIONS.VBRquality) self.refresh_marshaller() self.reset_data_label()