From 17bb41d2dea86394d0f9c8d0952ccd135bf7038c Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Thu, 01 Nov 2012 15:09:32 +0000 Subject: Media not found SL #3709 - Show an Alert message at startup when there are some media files that couldn't be reached. - Show full information (media paths) in the main canvas of those files that weren't found. - Listen "Mount" and "Unmount" events to check the availability of all media files in the playlist. Signed-off-by: Manuel Kaufmann --- diff --git a/jukeboxactivity.py b/jukeboxactivity.py index 48a5aa8..f106dd8 100644 --- a/jukeboxactivity.py +++ b/jukeboxactivity.py @@ -37,6 +37,7 @@ from sugar3.graphics.toolbarbox import ToolbarButton from sugar3.activity.widgets import StopButton from sugar3.activity.widgets import ActivityToolbarButton from sugar3.graphics.alert import ErrorAlert +from sugar3.graphics.alert import Alert import gi gi.require_version('Gtk', '3.0') @@ -46,6 +47,7 @@ from gi.repository import GObject from gi.repository import Gdk from gi.repository import Gtk from gi.repository import Gst +from gi.repository import Gio # Needed for window.get_xid(), xvimagesink.set_window_handle(), # respectively: @@ -88,6 +90,10 @@ class JukeboxActivity(activity.Activity): # FIXME: I don't know what is the mission of this line # activity_toolbar.stop.hide() + self.volume_monitor = Gio.VolumeMonitor.get() + self.volume_monitor.connect('mount-added', self._mount_added_cb) + self.volume_monitor.connect('mount-removed', self._mount_removed_cb) + _view_toolbar = ViewToolbar() _view_toolbar.connect('go-fullscreen', self.__go_fullscreen_cb) @@ -137,6 +143,7 @@ class JukeboxActivity(activity.Activity): self.playpath = None self.currentplaying = None self.playflag = False + self._not_found_files = 0 # README: I changed this because I was getting an error when I # tried to modify self.bin with something different than @@ -304,6 +311,42 @@ class JukeboxActivity(activity.Activity): alert.connect('response', self._alert_cancel_cb) alert.show() + def _mount_added_cb(self, volume_monitor, device): + self.playlist_widget.update(self.playlist) + + def _mount_removed_cb(self, volume_monitor, device): + self.playlist_widget.update(self.playlist) + + def _show_missing_tracks_alert(self, nro): + alert = Alert() + title = _('%s tracks not found.') % nro + alert.props.title = title + alert.add_button(Gtk.ResponseType.APPLY, _('Details')) + self.add_alert(alert) + alert.connect('response', self.__missing_tracks_alert_response_cb) + + def __missing_tracks_alert_response_cb(self, alert, response_id): + vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + vbox.props.valign = Gtk.Align.CENTER + label = Gtk.Label(label='') + label.set_markup(_('Missing tracks')) + vbox.pack_start(label, False, False, 15) + + for track in self.playlist_widget.get_missing_tracks(): + path = track['url'].replace('journal://', '')\ + .replace('file://', '') + label = Gtk.Label(label=path) + vbox.add(label) + + _missing_tracks = Gtk.ScrolledWindow() + _missing_tracks.add_with_viewport(vbox) + _missing_tracks.show_all() + + self.view_area.append_page(_missing_tracks, None) + + self.view_area.set_current_page(2) + self.remove_alert(alert) + def _alert_cancel_cb(self, alert, response_id): self.remove_alert(alert) @@ -364,12 +407,18 @@ class JukeboxActivity(activity.Activity): if mimetype == 'audio/x-mpegurl': # is a M3U playlist: for uri in self._read_m3u_playlist(file_path): + if not self.playlist_widget.check_available_media(uri['url']): + self._not_found_files += 1 + GObject.idle_add(self._start, uri['url'], uri['title'], uri['object_id']) else: # is another media file: GObject.idle_add(self._start, self.uri, title, object_id) + if self._not_found_files > 0: + self._show_missing_tracks_alert(self._not_found_files) + def _create_playlist_jobject(self): """Create an object in the Journal to store the playlist. @@ -451,6 +500,7 @@ class JukeboxActivity(activity.Activity): self.playpath = os.path.dirname(uri) if not uri: return False + if title is not None: title = title.strip() if object_id is not None: diff --git a/widgets.py b/widgets.py index 2dd5742..fbbd9c5 100644 --- a/widgets.py +++ b/widgets.py @@ -14,6 +14,7 @@ # USA import logging +import os from gettext import gettext as _ import gi @@ -23,8 +24,10 @@ from gi.repository import GObject from gi.repository import Gtk from gi.repository import Pango +from sugar3.graphics.icon import CellRendererIcon -COLUMNS_NAME = ('index', 'media') + +COLUMNS_NAME = ('index', 'media', 'available') COLUMNS = dict((name, i) for i, name in enumerate(COLUMNS_NAME)) @@ -37,11 +40,21 @@ class PlayListWidget(Gtk.ScrolledWindow): vadjustment=None) self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.listview = Gtk.TreeView() - self.treemodel = Gtk.ListStore(int, object) + self.treemodel = Gtk.ListStore(int, object, bool) self.listview.set_model(self.treemodel) selection = self.listview.get_selection() selection.set_mode(Gtk.SelectionMode.SINGLE) + renderer_icon = CellRendererIcon(self.listview) + renderer_icon.props.icon_name = 'emblem-notification' + renderer_icon.props.width = 20 + renderer_icon.props.height = 20 + renderer_icon.props.size = 20 + treecol_icon = Gtk.TreeViewColumn() + treecol_icon.pack_start(renderer_icon, False) + treecol_icon.set_cell_data_func(renderer_icon, self._set_icon) + self.listview.append_column(treecol_icon) + renderer_idx = Gtk.CellRendererText() treecol_idx = Gtk.TreeViewColumn(_('No.')) treecol_idx.pack_start(renderer_idx, True) @@ -75,15 +88,27 @@ class PlayListWidget(Gtk.ScrolledWindow): def _set_title(self, column, cell, model, it, data): playlist_item = model.get_value(it, COLUMNS['media']) + available = model.get_value(it, COLUMNS['available']) + cell.set_property('text', playlist_item['title']) + sensitive = True + if not available: + sensitive = False + cell.set_property('sensitive', sensitive) + + def _set_icon(self, column, cell, model, it, data): + available = model.get_value(it, COLUMNS['available']) + cell.set_property('visible', not available) def update(self, playlist): self.treemodel.clear() self._playlist = playlist pl = list(enumerate(playlist)) for i, media in pl: - self.treemodel.append((i, media)) - self.set_cursor(0) + available = self.check_available_media(media['url']) + media['available'] = available + self.treemodel.append((i, media, available)) + #self.set_cursor(0) def set_cursor(self, index): self.listview.set_cursor((index,)) @@ -96,3 +121,17 @@ class PlayListWidget(Gtk.ScrolledWindow): self._playlist.pop(index) self.treemodel.remove(self.treemodel.get_iter(row)) self.update(self._playlist) + + def check_available_media(self, uri): + path = uri.replace('journal://', '').replace('file://', '') + if os.path.exists(path): + return True + else: + return False + + def get_missing_tracks(self): + missing_tracks = [] + for track in self._playlist: + if not track['available']: + missing_tracks.append(track) + return missing_tracks -- cgit v0.9.1