Hi all, currently, if you use multiple library locations, browser state for additional library sources is lost when rhythmbox is restarted. I made a patch making additional library sources preserve state across restarts[1].
Until now, additional library sources can only be added by editing the gconf key "/apps/rhythmbox/library_locations" using e.g. gconf-editor - so I am planing to edit the preferences dialog to allow selection of multiple library locations (see attached python demo). There are some implementation details that have to be decided upon: * If you have configured multiple library locations, and you choose to remove one of them, what should happen to the songs from the removed location? Should they be removed from the library or should they be kept? If they are removed, what about the metadata (play counts, ratings, etc.)? Currently, if you remove a song from the library (by right-clicking a song and selecting "Remove"), the removal time is recorded in RhythmDB and metadata is kept for a certain time (configurable via the gconf key "/apps/rhythmbox/grace_period"). So if you add the song again to your library during grace_time, metadata will still be there. Should this apply to songs from a removed library location as well? * If you rip a CD using rb, where should the files be saved? Currently, they are put in the first library location. Should there be some ui to choose where to put them? * Should there be drag and drop support, allowing to move files between different library sources within rb? Please try the patch from [1] and the attached python demo of the new preferences dialog I have in mind, and tell me your thoughts. Regards, Chris [1] http://bugzilla.gnome.org/show_bug.cgi?id=523162
#!/usr/bin/python import gobject import gtk import gtk.glade import urlparse LIBRARY_PREFS_GLADE = "library-prefs-example.glade" COL_LIBRARY_LOCATION = 0 COL_NEW_FILES_LOCATION = 1 class UI: def __init__ (self): self.gladeXML = gtk.glade.XML (LIBRARY_PREFS_GLADE) self.gladeXML.signal_autoconnect (self) locations_tv = self.gladeXML.get_widget ("library_locations_treeview") self.library_locations_filechooserdialog = self.gladeXML.get_widget ("library_locations_filechooserdialog") self.remove_library_location_messagedialog = self.gladeXML.get_widget ("remove_library_location_messagedialog") self.keep_metadata_checkbutton = self.gladeXML.get_widget ("keep_metadata_checkbutton") self.locations = gtk.ListStore (gobject.TYPE_STRING, gobject.TYPE_BOOLEAN) self.locations_tree_selection = locations_tv.get_selection () self.locations_tree_selection.set_mode (gtk.SELECTION_MULTIPLE) locations_tv.set_model (self.locations) locations_column = gtk.TreeViewColumn ("Library Locations") locations_column.set_expand (True) locations_tv.append_column (locations_column) cr = gtk.CellRendererText () locations_column.pack_start (cr, True) locations_column.add_attribute (cr, 'text', COL_LIBRARY_LOCATION) new_files_column = gtk.TreeViewColumn ("Put new files here") new_files_column.set_expand (False) locations_tv.append_column (new_files_column) cr = gtk.CellRendererToggle () cr.set_radio (True) cr.connect ("toggled", self.on_new_files_location_toggled) new_files_column.pack_start (cr, True) new_files_column.add_attribute (cr, 'active', COL_NEW_FILES_LOCATION) def run (self): gtk.main () def run_library_locations_filechooserdialog (self): locations = [] resp = self.library_locations_filechooserdialog.run () if resp == gtk.RESPONSE_OK: locations = self.library_locations_filechooserdialog.get_uris () self.library_locations_filechooserdialog.hide () return locations def new_files_location_toggled_foreach_func (self, model, path, it, toggled): if int (path[0]) == int (toggled): model.set_value (it, COL_NEW_FILES_LOCATION, True) else: model.set_value (it, COL_NEW_FILES_LOCATION, False) return False def on_new_files_location_toggled (self, cr, path): self.locations.foreach (self.new_files_location_toggled_foreach_func, path) return False def on_quit (self, *args, **kwargs): gtk.main_quit () def location_is_valid_foreach_func (self, model, path, it, data): loc = urlparse.urlsplit (model.get_value (it, COL_LIBRARY_LOCATION)) new = data[0] if new.scheme == loc.scheme: if new.path == loc.path or new.path.startswith (loc.path) or loc.path.startswith (new.path): data[1] = False return True def location_is_valid (self, location): data = [urlparse.urlsplit (location), True] self.locations.foreach (self.location_is_valid_foreach_func, data) return data[1] def update_new_files_location_foreach_func (self, model, path, it, found): if model.get_value (it, COL_NEW_FILES_LOCATION): found[0] = it return False def update_new_files_location (self): found = [None] self.locations.foreach (self.update_new_files_location_foreach_func, found) if not found[0]: gobject.idle_add (self.on_new_files_location_toggled, None, 0) return False def on_button_add_clicked (self, button): locations = self.run_library_locations_filechooserdialog () location_added = False invalid_locations = [] for loc in locations: if self.location_is_valid (loc): self.locations.append ([loc, False]) location_added = True else: invalid_locations.append (loc) if location_added: gobject.idle_add (self.update_new_files_location) if invalid_locations: dlg = gtk.MessageDialog (parent=self.gladeXML.get_widget ("window1"), flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK, message_format="Some location(s) could not be added") dlg.format_secondary_text ("The following location(s) could not be added to the list of library locations:\n\n" "%s\n\n" "Possible reasons: either the location itself, " "one of its subfolders, or one of its parent folders is already added.\n" "Nested folders can not be added as library locations." % "\n".join (invalid_locations)) dlg.run () dlg.destroy () def on_button_remove_clicked (self, button): resp = self.remove_library_location_messagedialog.run () if resp == gtk.RESPONSE_OK: keep_metadata = self.keep_metadata_checkbutton.get_active () if keep_metadata: print "Would remove songs from library, keeping metadata in rhythmdb." else: print "Would remove songs from library, removing metadata from rhythmdb." (model, pathlist) = self.locations_tree_selection.get_selected_rows () pathlist.reverse () new_files_location_removed = False for path in pathlist: it = model.get_iter (path) new_files_location_removed = (new_files_location_removed or model.get_value (it, COL_NEW_FILES_LOCATION)) model.remove (it) if new_files_location_removed: gobject.idle_add (self.update_new_files_location) self.remove_library_location_messagedialog.hide () if __name__ == '__main__': ui = UI () ui.run ()
library-prefs-example.glade
Description: application/glade
_______________________________________________ rhythmbox-devel mailing list rhythmbox-devel@gnome.org http://mail.gnome.org/mailman/listinfo/rhythmbox-devel