CoverArt Browser
v2.0
Browse your cover-art albums in Rhythmbox
|
00001 # -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*- 00002 # 00003 # Copyright (C) 2012 - fossfreedom 00004 # Copyright (C) 2012 - Agustin Carrasco 00005 # 00006 # This program is free software; you can redistribute it and/or modify 00007 # it under the terms of the GNU General Public License as published by 00008 # the Free Software Foundation; either version 2, or (at your option) 00009 # any later version. 00010 # 00011 # This program is distributed in the hope that it will be useful, 00012 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 # GNU General Public License for more details. 00015 # 00016 # You should have received a copy of the GNU General Public License 00017 # along with this program; if not, write to the Free Software 00018 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 00019 00020 # define plugin 00021 from gi.repository import GObject 00022 from gi.repository import Gtk 00023 from gi.repository import RB 00024 from gi.repository import Peas 00025 from gi.repository import Gio 00026 from gi.repository import GLib 00027 00028 import rb 00029 from coverart_browser_prefs import GSetting 00030 from coverart_browser_prefs import CoverLocale 00031 from coverart_browser_prefs import Preferences 00032 from coverart_browser_source import CoverArtBrowserSource 00033 from coverart_listview import ListView 00034 from coverart_queueview import QueueView 00035 from coverart_playsourceview import PlaySourceView 00036 from coverart_toolbar import TopToolbar 00037 00038 class CoverArtBrowserEntryType(RB.RhythmDBEntryType): 00039 ''' 00040 Entry type for our source. 00041 ''' 00042 00043 def __init__(self): 00044 ''' 00045 Initializes the entry type. 00046 ''' 00047 RB.RhythmDBEntryType.__init__(self, name='CoverArtBrowserEntryType') 00048 00049 class CoverArtBrowserPlugin(GObject.Object, Peas.Activatable): 00050 ''' 00051 Main class of the plugin. Manages the activation and deactivation of the 00052 plugin. 00053 ''' 00054 __gtype_name = 'CoverArtBrowserPlugin' 00055 object = GObject.property(type=GObject.Object) 00056 00057 def __init__(self): 00058 ''' 00059 Initialises the plugin object. 00060 ''' 00061 GObject.Object.__init__(self) 00062 00063 def do_activate(self): 00064 ''' 00065 Called by Rhythmbox when the plugin is activated. It creates the 00066 plugin's source and connects signals to manage the plugin's 00067 preferences. 00068 ''' 00069 00070 print("CoverArtBrowser DEBUG - do_activate") 00071 self.shell = self.object 00072 self.db = self.shell.props.db 00073 00074 self.entry_type = CoverArtBrowserEntryType() 00075 self.db.register_entry_type(self.entry_type) 00076 00077 cl = CoverLocale() 00078 cl.switch_locale(cl.Locale.LOCALE_DOMAIN) 00079 00080 self.entry_type.category = RB.RhythmDBEntryCategory.NORMAL 00081 00082 group = RB.DisplayPageGroup.get_by_id('library') 00083 00084 # load plugin icon 00085 theme = Gtk.IconTheme.get_default() 00086 rb.append_plugin_source_path(theme, '/icons') 00087 00088 iconfile = Gio.File.new_for_path( 00089 rb.find_plugin_file(self, 'img/covermgr_rb3.png')) 00090 00091 self.source = CoverArtBrowserSource( 00092 shell=self.shell, 00093 name=_("CoverArt"), 00094 entry_type=self.entry_type, 00095 plugin=self, 00096 icon=Gio.FileIcon.new(iconfile), 00097 query_model=self.shell.props.library_source.props.base_query_model) 00098 00099 self.shell.register_entry_type_for_source(self.source, self.entry_type) 00100 self.shell.append_display_page(self.source, group) 00101 00102 self.source.props.query_model.connect('complete', self.load_complete) 00103 self._externalmenu = ExternalPluginMenu(self) 00104 00105 cl.switch_locale(cl.Locale.RB) 00106 print("CoverArtBrowser DEBUG - end do_activate") 00107 00108 def do_deactivate(self): 00109 ''' 00110 Called by Rhythmbox when the plugin is deactivated. It makes sure to 00111 free all the resources used by the plugin. 00112 ''' 00113 print("CoverArtBrowser DEBUG - do_deactivate") 00114 self.source.delete_thyself() 00115 if self._externalmenu: 00116 self._externalmenu.cleanup() 00117 del self.shell 00118 del self.db 00119 del self.source 00120 00121 print("CoverArtBrowser DEBUG - end do_deactivate") 00122 00123 def load_complete(self, *args, **kwargs): 00124 ''' 00125 Called by Rhythmbox when it has completed loading all data 00126 Used to automatically switch to the browser if the user 00127 has set in the preferences 00128 ''' 00129 gs = GSetting() 00130 setting = gs.get_setting(gs.Path.PLUGIN) 00131 00132 if setting[gs.PluginKey.AUTOSTART]: 00133 GLib.idle_add(self.shell.props.display_page_tree.select, 00134 self.source) 00135 00136 def _translation_helper(self): 00137 ''' 00138 a method just to help out with translation strings 00139 it is not meant to be called by itself 00140 ''' 00141 00142 # define .plugin text strings used for translation 00143 plugin = _('CoverArt Browser') 00144 desc = _('Browse and play your albums through their covers') 00145 00146 #. TRANSLATORS: This is the icon-grid view that the user sees 00147 tile = _('Tiles') 00148 00149 #. TRANSLATORS: This is the cover-flow view the user sees - they can swipe album covers from side-to-side 00150 artist = _('Flow') 00151 00152 #. TRANSLATORS: percentage size that the image will be expanded 00153 scale = _('Scale by %:') 00154 00155 # stop PyCharm removing the Preference import on optimisation 00156 pref = Preferences() 00157 00158 00159 class ExternalPluginMenu(GObject.Object): 00160 toolbar_pos = GObject.property(type=str, default=TopToolbar.name) 00161 00162 def __init__(self, plugin): 00163 super(ExternalPluginMenu, self).__init__() 00164 00165 self.plugin = plugin 00166 self.shell = plugin.shell 00167 self.source = plugin.source 00168 self.app_id = None 00169 from coverart_browser_source import Views 00170 00171 self._views = Views(self.shell) 00172 00173 self._connect_properties() 00174 self._connect_signals() 00175 00176 self._create_menu() 00177 00178 def _connect_signals(self): 00179 self.connect('notify::toolbar-pos', self._on_notify_toolbar_pos) 00180 self.shell.props.display_page_tree.connect( 00181 "selected", self.on_page_change 00182 ) 00183 00184 def _connect_properties(self): 00185 gs = GSetting() 00186 setting = gs.get_setting(gs.Path.PLUGIN) 00187 setting.bind(gs.PluginKey.TOOLBAR_POS, self, 'toolbar_pos', 00188 Gio.SettingsBindFlags.GET) 00189 00190 def _on_notify_toolbar_pos(self, *args): 00191 if self.toolbar_pos == TopToolbar.name: 00192 self._create_menu() 00193 else: 00194 self.cleanup() 00195 00196 def cleanup(self): 00197 if self.app_id: 00198 app = Gio.Application.get_default() 00199 for location in self.locations: 00200 app.remove_plugin_menu_item(location, self.app_id) 00201 self.app_id = None 00202 00203 def _create_menu(self): 00204 app = Gio.Application.get_default() 00205 self.app_id = 'coverart-browser' 00206 00207 self.locations = ['library-toolbar', 'queue-toolbar', 'playsource-toolbar'] 00208 action_name = 'coverart-browser-views' 00209 self.action = Gio.SimpleAction.new_stateful( 00210 action_name, GLib.VariantType.new('s'), 00211 self._views.get_action_name(ListView.name) 00212 ) 00213 self.action.connect("activate", self.view_change_cb) 00214 app.add_action(self.action) 00215 00216 menu_item = Gio.MenuItem() 00217 section = Gio.Menu() 00218 menu = Gio.Menu() 00219 toolbar_item = Gio.MenuItem() 00220 00221 for view_name in self._views.get_view_names(): 00222 menu_item.set_label(self._views.get_menu_name(view_name)) 00223 menu_item.set_action_and_target_value( 00224 'app.' + action_name, self._views.get_action_name(view_name) 00225 ) 00226 section.append_item(menu_item) 00227 00228 menu.append_section(None, section) 00229 00230 cl = CoverLocale() 00231 cl.switch_locale(cl.Locale.LOCALE_DOMAIN) 00232 toolbar_item.set_label(_('Views')) 00233 cl.switch_locale(cl.Locale.RB) 00234 00235 toolbar_item.set_submenu(menu) 00236 for location in self.locations: 00237 app.add_plugin_menu_item(location, self.app_id, toolbar_item) 00238 00239 00240 def on_page_change(self, display_page_tree, page): 00241 ''' 00242 Called when the display page changes. Grabs query models and sets the 00243 active view. 00244 ''' 00245 00246 if page == self.shell.props.library_source: 00247 self.action.set_state(self._views.get_action_name(ListView.name)) 00248 elif page == self.shell.props.queue_source: 00249 self.action.set_state(self._views.get_action_name(QueueView.name)) 00250 #elif page == self.source.playlist_source: 00251 # self.action.set_state(self._views.get_action_name(PlaySourceView.name)) 00252 00253 00254 def view_change_cb(self, action, current): 00255 ''' 00256 Called when the view state on a page is changed. Sets the new 00257 state. 00258 ''' 00259 action.set_state(current) 00260 view_name = self._views.get_view_name_for_action(current) 00261 if view_name != ListView.name and \ 00262 view_name != QueueView.name:# and \ 00263 #view_name != PlaySourceView.name: 00264 gs = GSetting() 00265 setting = gs.get_setting(gs.Path.PLUGIN) 00266 setting[gs.PluginKey.VIEW_NAME] = view_name 00267 GLib.idle_add(self.shell.props.display_page_tree.select, 00268 self.source) 00269 elif view_name == ListView.name: 00270 GLib.idle_add(self.shell.props.display_page_tree.select, 00271 self.shell.props.library_source) 00272 elif view_name == QueueView.name: 00273 GLib.idle_add(self.shell.props.display_page_tree.select, 00274 self.shell.props.queue_source) 00275 #elif view_name == PlaySourceView.name: 00276 # if not hasattr(self.source, 'playlist_source'): 00277 # return 00278 00279 # print ("test selectable") 00280 # path = self.shell.props.display_page_tree.props.model 00281 # #self.source.activate() 00282 # overlay = self.source.get_children()[0] 00283 00284 # GLib.idle_add(self.shell.props.display_page_tree.select, 00285 # self.source.playlist_source)