From 5d4c3839c4d23eca4d89d8525be85434537e99cc Mon Sep 17 00:00:00 2001 From: Derek Anderson Date: Thu, 6 Sep 2018 12:03:18 -0700 Subject: [PATCH 1/7] start of file queue support re #65 --- gnomecast.py | 168 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 131 insertions(+), 37 deletions(-) diff --git a/gnomecast.py b/gnomecast.py index 734e518..0f1b700 100644 --- a/gnomecast.py +++ b/gnomecast.py @@ -218,8 +218,8 @@ def __init__(self): self.fn = None self.last_fn_played = None self.transcoder = None - self.subtitles = None self.duration = None + self.subtitles = None self.seeking = False self.last_known_volume_level = None bus = dbus.SessionBus() if DBUS_AVAILABLE else None @@ -302,23 +302,20 @@ def video(id, ext): def update_status(self, did_transcode=False): if did_transcode: self.save_button.set_visible(True) - if self.fn is None: - self.file_button.set_label("Choose an audio or video file...") - return - fn = os.path.basename(self.fn) - MAX_LEN = 40 - if len(fn) > MAX_LEN: - fn = fn[:MAX_LEN-10] + '...' + fn[-10:] - notes = [fn] - if self.duration is not None: - notes.append(self.humanize_seconds(self.duration)) - else: - notes.append('Loading...') # if self.last_known_player_state and self.last_known_player_state!='UNKNOWN': # notes.append('Cast: %s' % self.last_known_player_state) - if self.transcoder and not self.transcoder.done and self.duration: - notes.append('Converting: %i%%' % (self.transcoder.progress_seconds*100 // self.duration)) - self.file_button.set_label(' - '.join(notes)) + for row in self.files_store: + if row[1]!=self.fn: continue + row[6] = 'media-playback-start' + duration = row[2] + if self.transcoder and duration: + if self.transcoder.done: + row[5] = 100 + else: + row[5] = self.transcoder.progress_seconds*100 // duration + print('Converting: %i%%' % (self.transcoder.progress_seconds*100 // duration)) + elif duration: + row[5] = 100 def monitor_cast(self): while True: @@ -438,16 +435,49 @@ def build_gui(self): hbox.pack_start(refresh_button, False, False, 0) win.add(vbox_outer) + + # list of queued files + self.files_store = Gtk.ListStore(str, str, int, str, str, int, str) # name, path, duration, duration_str, thumbnail_fn, transcode_progress, status_icon + self.files_view = Gtk.TreeView(self.files_store) + self.files_view.set_headers_visible(False) + column = Gtk.TreeViewColumn("Name", Gtk.CellRendererText(), text=0) + column.set_expand(True) + self.files_view.append_column(column) + r = Gtk.CellRendererText() + r.props.xalign = 1.0 + self.files_view.append_column(Gtk.TreeViewColumn("Duration", r, text=3)) + column_progress = Gtk.TreeViewColumn("Progress", Gtk.CellRendererProgress(), value=5) + self.files_view.append_column(column_progress) + + column_pixbuf = Gtk.TreeViewColumn("Playing", Gtk.CellRendererPixbuf(), icon_name=6) + self.files_view.append_column(column_pixbuf) + + select = self.files_view.get_selection() + select.connect("changed", self.on_files_view_selection_changed) + self.files_view.connect("row-activated", self.on_files_view_row_activated) + + + self.scrolled_window = Gtk.ScrolledWindow() + self.scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) + self.scrolled_window.add(self.files_view) + self.scrolled_window.set_min_content_height(24) + #self.scrolled_window.set_visible(False) + vbox.pack_start(self.scrolled_window, True, True, 0) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8) vbox.pack_start(hbox, False, False, 0) - self.file_button = button1 = Gtk.Button("Choose an audio or video file...") - button1.connect("clicked", self.on_file_clicked) - hbox.pack_start(button1, True, True, 0) + self.file_button = Gtk.Button(" Add one or more audio or video files...", image=Gtk.Image(stock=Gtk.STOCK_ADD)) + self.file_button.set_always_show_image(True) + self.file_button.connect("clicked", self.on_file_clicked) + hbox.pack_start(self.file_button, True, True, 0) self.save_button = Gtk.Button(None, image=Gtk.Image(stock=Gtk.STOCK_SAVE)) self.save_button.set_tooltip_text('Overwrite original file with transcoded version.') self.save_button.connect("clicked", self.save_transcoded_file) hbox.pack_start(self.save_button, False, False, 0) + self.remove_button = Gtk.Button(None, image=Gtk.Image(stock=Gtk.STOCK_REMOVE)) + self.remove_button.set_tooltip_text('Overwrite original file with transcoded version.') + #self.remove_button.connect("clicked", self.save_transcoded_file) + hbox.pack_start(self.remove_button, False, False, 0) self.subtitle_store = subtitle_store = Gtk.ListStore(str, int, str) subtitle_store.append(["No subtitles.", -1, None]) @@ -516,6 +546,35 @@ def f(scale, s): def scrubber_move_started(self, scale, scroll_type, seconds): print('scrubber_move_started', seconds) self.seeking = True + + def on_files_view_selection_changed(self, selection): + model, treeiter = selection.get_selected() + if treeiter is not None: + print("You selected", model[treeiter]) + + def on_files_view_row_activated(self, widget, row, col): + model = widget.get_model() + print('double-clicked', model[row][:]) + fn = model[row][1] + if fn: + self.select_file(fn) + return True + + def queue_files(self, files): + existing_files = set([row[1] for row in self.files_store]) + for fn in files: + if fn in existing_files: continue + display = os.path.basename(fn) + MAX_LEN = 40 + if len(display) > MAX_LEN: + display = display[:MAX_LEN-10] + '...' + display[-10:] + self.files_store.append([display, fn, None, '...', None, None, None]) + threading.Thread(target=self.gen_thumbnail, args=[fn]).start() + threading.Thread(target=self.get_info, args=[fn]).start() + self.scrolled_window.set_visible(True) + self.scrolled_window.set_min_content_height(24*min(len(self.files_store),3)) + if len(files) and self.fn is None: + self.select_file(files[0]) @throttle(seconds=1) def volume_moved(self, button, volume): @@ -583,6 +642,9 @@ def quit(self, a=0, b=0): if self.cast: self.cast.media_controller.stop() self.restore_screensaver() + for row in self.files_store: + if row[4] and os.path.isfile(row[4]): + os.remove(row[4]) Gtk.main_quit() def forward_clicked(self, widget): @@ -631,6 +693,7 @@ def on_file_clicked(self, widget): Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) + dialog.set_select_multiple(True) downloads_dir = os.path.expanduser('~/Downloads') if os.path.isdir(downloads_dir): @@ -645,8 +708,9 @@ def on_file_clicked(self, widget): response = dialog.run() if response == Gtk.ResponseType.OK: print("Open clicked") - print("File selected: " + dialog.get_filename()) - self.select_file(dialog.get_filename()) + print("File selected:", dialog.get_filenames()) + self.queue_files(dialog.get_filenames()) + #self.select_file(dialog.get_filename()) elif response == Gtk.ResponseType.CANCEL: print("Cancel clicked") @@ -717,7 +781,6 @@ def f(): GLib.idle_add(f) return fn = os.path.abspath(fn) - self.file_button.set_label(os.path.basename(fn)) self.thumbnail_image.set_from_pixbuf(self.get_logo_pixbuf()) self.fn = fn self.subtitle_store.clear() @@ -726,8 +789,21 @@ def f(): self.subtitle_combo.set_active(0) if self.cast: self.cast.media_controller.stop() - threading.Thread(target=self.gen_thumbnail).start() threading.Thread(target=self.update_transcoder).start() + threading.Thread(target=self.update_subtitles).start() + def f(): + self.scrubber_adj.set_value(0) + for row in self.files_store: + thumbnail_fn = row[4] + if self.fn == row[1]: + if thumbnail_fn: + self.thumbnail_image.set_from_file(thumbnail_fn) + self.win.resize(1,1) + row[6] = 'media-playback-start' + self.duration = row[2] + else: + row[6] = None + GLib.idle_add(f) def update_transcoder(self): self.save_button.set_visible(False) @@ -742,34 +818,52 @@ def update_transcoder(self): self.transcoder = None GLib.idle_add(self.update_media_button_states) - def gen_thumbnail(self): - container = self.fn.lower().split(".")[-1] + def gen_thumbnail(self, fn): + container = fn.lower().split(".")[-1] thumbnail_fn = None - subtitle_ids = [] if container in ('aac','mp3','wav'): - cmd = ['ffmpeg', '-i', self.fn, '-f', 'ffmetadata', '-'] + cmd = ['ffmpeg', '-i', fn, '-f', 'ffmetadata', '-'] else: thumbnail_fn = tempfile.mkstemp(suffix='.jpg', prefix='gnomecast_thumbnail_')[1] os.remove(thumbnail_fn) - cmd = ['ffmpeg', '-y', '-i', self.fn, '-f', 'mjpeg', '-vframes', '1', '-ss', '27', '-vf', 'scale=600:-1', thumbnail_fn] + cmd = ['ffmpeg', '-y', '-i', fn, '-f', 'mjpeg', '-vframes', '1', '-ss', '27', '-vf', 'scale=600:-1', thumbnail_fn] self.ffmpeg_desc = output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + if os.path.isfile(thumbnail_fn): + for row in self.files_store: + if row[1]==fn: + row[4] = thumbnail_fn + def f(): + if self.fn == fn and thumbnail_fn: + self.thumbnail_image.set_from_file(thumbnail_fn) + self.win.resize(1,1) + self.update_status() + GLib.idle_add(f) + + def get_info(self, fn): + cmd = ['ffprobe', '-i', fn] + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) for line in output.decode().split('\n'): line = line.strip() if line.startswith('Duration:'): - self.duration = parse_ffmpeg_time(line.split()[1].strip(',')) + duration = parse_ffmpeg_time(line.split()[1].strip(',')) + if fn == self.fn: + self.duration = duration + for row in self.files_store: + if row[1]==fn: + row[2] = duration + row[3] = self.humanize_seconds(duration) + + def update_subtitles(self): + subtitle_ids = [] + cmd = ['ffprobe', '-i', self.fn] + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + for line in output.decode().split('\n'): + line = line.strip() if line.startswith('Stream') and 'Subtitle' in line: id = line.split()[1].strip('#').replace(':','.') id = id[:id.index('(')] subtitle_ids.append(id) print('subtitle_ids', subtitle_ids) - def f(): - if thumbnail_fn: - self.thumbnail_image.set_from_file(thumbnail_fn) - os.remove(thumbnail_fn) - self.win.resize(1,1) - self.scrubber_adj.set_value(0) - self.update_status() - GLib.idle_add(f) new_subtitles = [] for subtitle_id in subtitle_ids: srt_fn = tempfile.mkstemp(suffix='.srt', prefix='gnomecast_subtitles_')[1] From 23f8f89ec23b8891f1a2643a5a9066c841f0cfed Mon Sep 17 00:00:00 2001 From: Derek Anderson Date: Thu, 6 Sep 2018 12:39:04 -0700 Subject: [PATCH 2/7] more file queue support re #65 --- gnomecast.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/gnomecast.py b/gnomecast.py index 0f1b700..abb04db 100644 --- a/gnomecast.py +++ b/gnomecast.py @@ -313,7 +313,6 @@ def update_status(self, did_transcode=False): row[5] = 100 else: row[5] = self.transcoder.progress_seconds*100 // duration - print('Converting: %i%%' % (self.transcoder.progress_seconds*100 // duration)) elif duration: row[5] = 100 @@ -439,6 +438,7 @@ def build_gui(self): # list of queued files self.files_store = Gtk.ListStore(str, str, int, str, str, int, str) # name, path, duration, duration_str, thumbnail_fn, transcode_progress, status_icon self.files_view = Gtk.TreeView(self.files_store) + self.files_view.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) self.files_view.set_headers_visible(False) column = Gtk.TreeViewColumn("Name", Gtk.CellRendererText(), text=0) column.set_expand(True) @@ -476,7 +476,7 @@ def build_gui(self): hbox.pack_start(self.save_button, False, False, 0) self.remove_button = Gtk.Button(None, image=Gtk.Image(stock=Gtk.STOCK_REMOVE)) self.remove_button.set_tooltip_text('Overwrite original file with transcoded version.') - #self.remove_button.connect("clicked", self.save_transcoded_file) + self.remove_button.connect("clicked", self.remove_files) hbox.pack_start(self.remove_button, False, False, 0) self.subtitle_store = subtitle_store = Gtk.ListStore(str, int, str) @@ -551,6 +551,12 @@ def on_files_view_selection_changed(self, selection): model, treeiter = selection.get_selected() if treeiter is not None: print("You selected", model[treeiter]) + + def remove_files(self, w): + store, paths = self.files_view.get_selection().get_selected_rows() + for path in paths: + print('remove', path) + store.remove(store.get_iter(path)) def on_files_view_row_activated(self, widget, row, col): model = widget.get_model() @@ -562,20 +568,23 @@ def on_files_view_row_activated(self, widget, row, col): def queue_files(self, files): existing_files = set([row[1] for row in self.files_store]) + files = [f for f in files if f not in existing_files] for fn in files: - if fn in existing_files: continue display = os.path.basename(fn) MAX_LEN = 40 if len(display) > MAX_LEN: display = display[:MAX_LEN-10] + '...' + display[-10:] self.files_store.append([display, fn, None, '...', None, None, None]) - threading.Thread(target=self.gen_thumbnail, args=[fn]).start() threading.Thread(target=self.get_info, args=[fn]).start() + def gen_thumbnails(): + for fn in files: + self.gen_thumbnail(fn) + threading.Thread(target=gen_thumbnails).start() self.scrolled_window.set_visible(True) - self.scrolled_window.set_min_content_height(24*min(len(self.files_store),3)) + self.scrolled_window.set_min_content_height(24*min(len(self.files_store),4)) if len(files) and self.fn is None: self.select_file(files[0]) - + @throttle(seconds=1) def volume_moved(self, button, volume): if self.last_known_volume_level != volume: @@ -870,7 +879,7 @@ def update_subtitles(self): output = subprocess.check_output(['ffmpeg', '-y', '-i', self.fn, '-vn', '-an', '-codec:s:%s' % subtitle_id, 'srt', srt_fn], stderr=subprocess.STDOUT) with open(srt_fn) as f: caps = f.read() - print('caps', caps) + #print('caps', caps) converter = pycaption.CaptionConverter() converter.read(caps, pycaption.detect_format(caps)()) subtitles = converter.write(pycaption.WebVTTWriter()) From c0e07694b9a85d11a3bfa3d17f5c5857f0a6a3d8 Mon Sep 17 00:00:00 2001 From: Derek Anderson Date: Thu, 6 Sep 2018 13:48:11 -0700 Subject: [PATCH 3/7] functional queue support? re #65 --- gnomecast.py | 86 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 27 deletions(-) diff --git a/gnomecast.py b/gnomecast.py index abb04db..00dc46f 100644 --- a/gnomecast.py +++ b/gnomecast.py @@ -305,16 +305,14 @@ def update_status(self, did_transcode=False): # if self.last_known_player_state and self.last_known_player_state!='UNKNOWN': # notes.append('Cast: %s' % self.last_known_player_state) for row in self.files_store: - if row[1]!=self.fn: continue - row[6] = 'media-playback-start' duration = row[2] - if self.transcoder and duration: - if self.transcoder.done: - row[5] = 100 - else: - row[5] = self.transcoder.progress_seconds*100 // duration - elif duration: - row[5] = 100 + transcoder = row[7] + if transcoder: + if duration: + if transcoder.done: + row[5] = 100 + else: + row[5] = transcoder.progress_seconds*100 // duration def monitor_cast(self): while True: @@ -436,7 +434,7 @@ def build_gui(self): win.add(vbox_outer) # list of queued files - self.files_store = Gtk.ListStore(str, str, int, str, str, int, str) # name, path, duration, duration_str, thumbnail_fn, transcode_progress, status_icon + self.files_store = Gtk.ListStore(str, str, int, str, str, int, str, object) # name, path, duration, duration_str, thumbnail_fn, transcode_progress, status_icon, transcoder self.files_view = Gtk.TreeView(self.files_store) self.files_view.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) self.files_view.set_headers_visible(False) @@ -470,14 +468,14 @@ def build_gui(self): self.file_button.set_always_show_image(True) self.file_button.connect("clicked", self.on_file_clicked) hbox.pack_start(self.file_button, True, True, 0) - self.save_button = Gtk.Button(None, image=Gtk.Image(stock=Gtk.STOCK_SAVE)) - self.save_button.set_tooltip_text('Overwrite original file with transcoded version.') - self.save_button.connect("clicked", self.save_transcoded_file) - hbox.pack_start(self.save_button, False, False, 0) self.remove_button = Gtk.Button(None, image=Gtk.Image(stock=Gtk.STOCK_REMOVE)) self.remove_button.set_tooltip_text('Overwrite original file with transcoded version.') self.remove_button.connect("clicked", self.remove_files) hbox.pack_start(self.remove_button, False, False, 0) + self.save_button = Gtk.Button(None, image=Gtk.Image(stock=Gtk.STOCK_SAVE)) + self.save_button.set_tooltip_text('Overwrite original file with transcoded version.') + self.save_button.connect("clicked", self.save_transcoded_file) + hbox.pack_start(self.save_button, False, False, 0) self.subtitle_store = subtitle_store = Gtk.ListStore(str, int, str) subtitle_store.append(["No subtitles.", -1, None]) @@ -554,9 +552,17 @@ def on_files_view_selection_changed(self, selection): def remove_files(self, w): store, paths = self.files_view.get_selection().get_selected_rows() - for path in paths: + for path in reversed(paths): print('remove', path) - store.remove(store.get_iter(path)) + iterx = store.get_iter(path) + transcoder = store.get_value(iterx, 7) + if transcoder: + transcoder.destroy() + fn = store.get_value(iterx, 1) + store.remove(iterx) + if self.fn == fn: + self.unselect_file() + def on_files_view_row_activated(self, widget, row, col): model = widget.get_model() @@ -574,7 +580,7 @@ def queue_files(self, files): MAX_LEN = 40 if len(display) > MAX_LEN: display = display[:MAX_LEN-10] + '...' + display[-10:] - self.files_store.append([display, fn, None, '...', None, None, None]) + self.files_store.append([display, fn, None, '...', None, None, None, None]) threading.Thread(target=self.get_info, args=[fn]).start() def gen_thumbnails(): for fn in files: @@ -646,8 +652,10 @@ def get_logo_pixbuf(self, width=200, color=None): def quit(self, a=0, b=0): - if self.transcoder: - self.transcoder.destroy() + for row in self.files_store: + transcoder =row[7] + if transcoder: + transcoder.destroy() if self.cast: self.cast.media_controller.stop() self.restore_screensaver() @@ -780,6 +788,23 @@ def f(): self.subtitle_store.append([display_name, pos-2, self.subtitles]) self.subtitle_combo.set_active(pos) + def unselect_file(self): + self.thumbnail_image.set_from_pixbuf(self.get_logo_pixbuf()) + self.fn = None + self.subtitle_store.clear() + self.subtitle_store.append(["No subtitles.", -1, None]) + self.subtitle_combo.set_active(0) + self.transcoder = None + self.duration = None + if self.cast: + self.cast.media_controller.stop() + def f(): + self.scrubber_adj.set_value(0) + for row in self.files_store: + row[6] = None + self.win.resize(1,1) + GLib.idle_add(f) + def select_file(self, fn): if not os.path.isfile(fn): def f(): @@ -798,7 +823,7 @@ def f(): self.subtitle_combo.set_active(0) if self.cast: self.cast.media_controller.stop() - threading.Thread(target=self.update_transcoder).start() + threading.Thread(target=self.update_transcoders).start() threading.Thread(target=self.update_subtitles).start() def f(): self.scrubber_adj.set_value(0) @@ -814,17 +839,24 @@ def f(): row[6] = None GLib.idle_add(f) - def update_transcoder(self): + def update_transcoders(self): self.save_button.set_visible(False) if self.cast and self.fn: - self.transcoder = Transcoder(self.cast, self.fn, lambda did_transcode=None: GLib.idle_add(self.update_status, did_transcode), self.transcoder) + transcoder = None + for row in self.files_store: + if row[1]!=self.fn: continue + transcoder = row[7] + self.transcoder = Transcoder(self.cast, self.fn, lambda did_transcode=None: GLib.idle_add(self.update_status, did_transcode), transcoder) + row[7] = self.transcoder if self.autoplay: self.autoplay = False self.play_clicked(None) - else: - if self.transcoder: - self.transcoder.destroy() - self.transcoder = None + if not self.cast: + for row in self.files_store: + transcoder = row[7] + if transcoder: + transcoder.destroy() + row[7] = None GLib.idle_add(self.update_media_button_states) def gen_thumbnail(self, fn): @@ -918,7 +950,7 @@ def select_cast(self, cast): self.volume_button.set_value(cast.media_controller.status.volume_level) self.last_known_player_state = None self.update_media_button_states() - threading.Thread(target=self.update_transcoder).start() + threading.Thread(target=self.update_transcoders).start() def get_nonlocal_cast(self): From cf8d369a41fa79bbcc15e866c20901ec6c53fb74 Mon Sep 17 00:00:00 2001 From: Derek Anderson Date: Thu, 6 Sep 2018 14:15:31 -0700 Subject: [PATCH 4/7] prep next transcode in queue re #65 --- gnomecast.py | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/gnomecast.py b/gnomecast.py index 00dc46f..915c29b 100644 --- a/gnomecast.py +++ b/gnomecast.py @@ -302,17 +302,20 @@ def video(id, ext): def update_status(self, did_transcode=False): if did_transcode: self.save_button.set_visible(True) + self.prep_next_transcode() # if self.last_known_player_state and self.last_known_player_state!='UNKNOWN': # notes.append('Cast: %s' % self.last_known_player_state) - for row in self.files_store: - duration = row[2] - transcoder = row[7] - if transcoder: - if duration: - if transcoder.done: - row[5] = 100 - else: - row[5] = transcoder.progress_seconds*100 // duration + def f(): + for row in self.files_store: + duration = row[2] + transcoder = row[7] + if transcoder: + if duration: + if transcoder.done: + row[5] = 100 + else: + row[5] = transcoder.progress_seconds*100 // duration + GLib.idle_add(f) def monitor_cast(self): while True: @@ -700,6 +703,7 @@ def play_clicked(self, widget): mc.play_media('http://%s:%s/media/%s.%s' % (self.ip, self.port, hash(self.fn), ext), 'audio/%s'%ext if ext in AUDIO_EXTS else 'video/mp4', **kwargs) print(cast.status) print(mc.status) + self.prep_next_transcode() elif mc.status.player_state=='PLAYING': mc.pause() elif mc.status.player_state=='PAUSED': @@ -846,8 +850,9 @@ def update_transcoders(self): for row in self.files_store: if row[1]!=self.fn: continue transcoder = row[7] - self.transcoder = Transcoder(self.cast, self.fn, lambda did_transcode=None: GLib.idle_add(self.update_status, did_transcode), transcoder) - row[7] = self.transcoder + if not transcoder or self.cast != transcoder.cast or self.fn != transcoder.fn: + self.transcoder = Transcoder(self.cast, self.fn, lambda did_transcode=None: GLib.idle_add(self.update_status, did_transcode), transcoder) + row[7] = self.transcoder if self.autoplay: self.autoplay = False self.play_clicked(None) @@ -858,6 +863,19 @@ def update_transcoders(self): transcoder.destroy() row[7] = None GLib.idle_add(self.update_media_button_states) + + def prep_next_transcode(self): + transcode_next = False + for row in self.files_store: + fn = row[1] + transcoder = row[7] + if transcode_next and not transcoder: + print('prep_next_transcode', fn) + transcoder = Transcoder(self.cast, fn, lambda did_transcode=None: GLib.idle_add(self.update_status, did_transcode), transcoder) + row[7] = transcoder + transcode_next = False + if self.cast and self.fn and self.fn == fn and transcoder and transcoder.done: + transcode_next = True def gen_thumbnail(self, fn): container = fn.lower().split(".")[-1] From bcabf78df8e8b4e5113939e11aa80778fe4b2299 Mon Sep 17 00:00:00 2001 From: Derek Anderson Date: Thu, 6 Sep 2018 14:30:55 -0700 Subject: [PATCH 5/7] autoplay next item in queue re #65 --- gnomecast.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/gnomecast.py b/gnomecast.py index 915c29b..89a4c30 100644 --- a/gnomecast.py +++ b/gnomecast.py @@ -327,6 +327,8 @@ def monitor_cast(self): if mc.status.player_state != self.last_known_player_state: if mc.status.player_state=='PLAYING' and self.last_known_player_state=='BUFFERING' and seeking: self.seeking = False + if mc.status.player_state=='IDLE' and self.last_known_player_state=='PLAYING': + self.check_for_next_in_queue() if mc.status.player_state=='PLAYING': self.inhibit_screensaver() else: @@ -827,8 +829,6 @@ def f(): self.subtitle_combo.set_active(0) if self.cast: self.cast.media_controller.stop() - threading.Thread(target=self.update_transcoders).start() - threading.Thread(target=self.update_subtitles).start() def f(): self.scrubber_adj.set_value(0) for row in self.files_store: @@ -841,6 +841,8 @@ def f(): self.duration = row[2] else: row[6] = None + threading.Thread(target=self.update_transcoders).start() + threading.Thread(target=self.update_subtitles).start() GLib.idle_add(f) def update_transcoders(self): @@ -864,6 +866,18 @@ def update_transcoders(self): row[7] = None GLib.idle_add(self.update_media_button_states) + def check_for_next_in_queue(self): + next = False + for row in self.files_store: + fn = row[1] + if next: + print('check_for_next_in_queue', fn) + self.autoplay = True + self.select_file(fn) + next = False + if self.cast and self.fn and self.fn == fn: + next = True + def prep_next_transcode(self): transcode_next = False for row in self.files_store: From 32ff621cd5558fe0833e43b231138a547d24e9db Mon Sep 17 00:00:00 2001 From: Derek Anderson Date: Sat, 8 Sep 2018 18:46:41 -0700 Subject: [PATCH 6/7] up sudio bitrate re #65 --- gnomecast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnomecast.py b/gnomecast.py index 89a4c30..b546c05 100644 --- a/gnomecast.py +++ b/gnomecast.py @@ -127,7 +127,7 @@ def __init__(self, cast, fn, done_callback, prev_transcoder): self.trans_fn = tempfile.mkstemp(suffix='.mp4', prefix='gnomecast_', dir=dir)[1] os.remove(self.trans_fn) # flags = '''-c:v libx264 -profile:v high -level 5 -crf 18 -maxrate 10M -bufsize 16M -pix_fmt yuv420p -x264opts bframes=3:cabac=1 -movflags faststart -c:a libfdk_aac -b:a 320k''' # -vf "scale=iw*sar:ih, scale='if(gt(iw,ih),min(1920,iw),-1)':'if(gt(iw,ih),-1,min(1080,ih))'" - args = ['ffmpeg', '-i', self.source_fn, '-c:v', 'h264' if self.transcode_video else 'copy', '-c:a', 'mp3' if self.transcode_audio else 'copy', self.trans_fn] # '-movflags', 'faststart' + args = ['ffmpeg', '-i', self.source_fn, '-c:v', 'h264' if self.transcode_video else 'copy', '-c:a', 'mp3' if self.transcode_audio else 'copy'] + (['-b:a','256k'] if self.transcode_audio else []) + [self.trans_fn] # '-movflags', 'faststart' # args = ['ffmpeg', '-i', self.source_fn, '-c:v', 'libvpx', '-b:v', '5M', '-c:a', 'libvorbis', '-deadline','realtime', self.trans_fn] # args = ['ffmpeg', '-i', self.source_fn] + flags.split() + [self.trans_fn] print(args) From 86634b94ae1ad6d29cc901e70e15bd28e0a39f55 Mon Sep 17 00:00:00 2001 From: Derek Anderson Date: Thu, 27 Sep 2018 13:02:14 -0700 Subject: [PATCH 7/7] ui improvements --- gnomecast.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/gnomecast.py b/gnomecast.py index b546c05..0a67946 100644 --- a/gnomecast.py +++ b/gnomecast.py @@ -58,7 +58,7 @@ print(ERROR_MESSAGE.format(line,line)) sys.exit(1) -__version__ = '1.4.1' +__version__ = '1.5.0' if DEPS_MET: pycaption.WebVTTWriter._encode = lambda self, s: s @@ -446,10 +446,10 @@ def build_gui(self): column = Gtk.TreeViewColumn("Name", Gtk.CellRendererText(), text=0) column.set_expand(True) self.files_view.append_column(column) - r = Gtk.CellRendererText() + self.file_view_column_renderer = r = Gtk.CellRendererText() r.props.xalign = 1.0 self.files_view.append_column(Gtk.TreeViewColumn("Duration", r, text=3)) - column_progress = Gtk.TreeViewColumn("Progress", Gtk.CellRendererProgress(), value=5) + self.files_view_progress_column = column_progress = Gtk.TreeViewColumn("Progress", Gtk.CellRendererProgress(), value=5) self.files_view.append_column(column_progress) column_pixbuf = Gtk.TreeViewColumn("Playing", Gtk.CellRendererPixbuf(), icon_name=6) @@ -463,8 +463,6 @@ def build_gui(self): self.scrolled_window = Gtk.ScrolledWindow() self.scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.scrolled_window.add(self.files_view) - self.scrolled_window.set_min_content_height(24) - #self.scrolled_window.set_visible(False) vbox.pack_start(self.scrolled_window, True, True, 0) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8) @@ -540,6 +538,8 @@ def f(scale, s): win.connect("key_press_event", self.on_key_press) win.show_all() + self.scrolled_window.set_visible(False) + self.save_button.set_visible(False) win.resize(1,1) @@ -592,9 +592,14 @@ def gen_thumbnails(): self.gen_thumbnail(fn) threading.Thread(target=gen_thumbnails).start() self.scrolled_window.set_visible(True) - self.scrolled_window.set_min_content_height(24*min(len(self.files_store),4)) if len(files) and self.fn is None: self.select_file(files[0]) + path = Gtk.TreePath().new_first() + _1, _2, width, height = self.files_view_progress_column.cell_get_size() + height += self.file_view_column_renderer.get_padding().ypad*2 + height += 2 # measured - row lines? + self.scrolled_window.set_min_content_height(height*min(len(self.files_store),6)) + @throttle(seconds=1) def volume_moved(self, button, volume):