Merge lp:~chipaca/rhythmbox-ubuntuone/brown-paper-bags into lp:rhythmbox-ubuntuone

Proposed by John Lenton
Status: Merged
Merge reported by: Rodrigo Moya
Merged at revision: not available
Proposed branch: lp:~chipaca/rhythmbox-ubuntuone/brown-paper-bags
Merge into: lp:rhythmbox-ubuntuone
Diff against target: 424 lines (+6/-400)
1 file modified
umusicstore/__init__.py (+6/-400)
To merge this branch: bzr merge lp:~chipaca/rhythmbox-ubuntuone/brown-paper-bags
Reviewer Review Type Date Requested Status
Ubuntu One Control Tower Pending
Review via email: mp+30575@code.launchpad.net

Description of the change

resolved the conflict

To post a comment you must log in.
Revision history for this message
Rodrigo Moya (rodrigo-moya) wrote :

Sorry, didn't see this branch last night, so applied it manually to trunk and did a new release, so marking this as merged

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'umusicstore/__init__.py'
--- umusicstore/__init__.py 2010-06-08 15:19:02 +0000
+++ umusicstore/__init__.py 2010-07-21 20:25:57 +0000
@@ -16,29 +16,14 @@
16#16#
17# Authored by Stuart Langridge <stuart.langridge@canonical.com>17# Authored by Stuart Langridge <stuart.langridge@canonical.com>
1818
19import gtk, gobject, os, urllib, gconf, stat, urlparse, gio19
20import gst, gst.pbutils20import gconf
21import aptdaemon.client
22from aptdaemon.enums import *
23from aptdaemon.gtkwidgets import AptErrorDialog, \
24 AptProgressBar
25import rb, rhythmdb
26from ubuntuone.gtkwidgets import MusicStore as U1MusicStore
27from MusicStoreWidget import U1MusicStoreWidget21from MusicStoreWidget import U1MusicStoreWidget
28from U1MSLinks import U1MSLinkProvider22from U1MSLinks import U1MSLinkProvider
29import xdg.BaseDirectory23
30import dbus.exceptions24U1_FIRST_TIME_FLAG_ENTRY = "/apps/rhythmbox/plugins/umusicstore/first_time_flag"
3125
32import gettext26import rb
33from gettext import lgettext as _
34gettext.bindtextdomain("rhythmbox-ubuntuone-music-store", "/usr/share/locale")
35gettext.textdomain("rhythmbox-ubuntuone-music-store")
36
37MUSIC_STORE_WIDGET = U1MusicStore() # keep this around for later
38U1LIBRARYPATH = MUSIC_STORE_WIDGET.get_library_location()
39RB_LIBRARY_LOCATIONS = "/apps/rhythmbox/library_locations"
40U1_CONFIG_PATH = "/apps/rhythmbox/plugins/umusicstore"
41U1_FIRST_TIME_FLAG_ENTRY = U1_CONFIG_PATH + "/first_time_flag"
4227
43class U1MusicStorePlugin (rb.Plugin):28class U1MusicStorePlugin (rb.Plugin):
44 """The Ubuntu One Music Store."""29 """The Ubuntu One Music Store."""
@@ -67,384 +52,5 @@
6752
68 def deactivate(self, shell):53 def deactivate(self, shell):
69 """Plugin shutdown."""54 """Plugin shutdown."""
70<<<<<<< TREE
71 # remove source
72 self.source.delete_thyself()
73 # remove the library, if it's empty
74 try:
75 filecount = len(os.listdir(self.U1_LIBRARY_SYMLINK))
76 except OSError:
77 # symlink is dangling
78 # so they never downloaded anything
79 filecount = 0
80 if filecount == 0:
81 client = gconf.client_get_default()
82 libraries = client.get_list(RB_LIBRARY_LOCATIONS, gconf.VALUE_STRING)
83 if self.u1_library_path_url in libraries:
84 client.notify_remove(self.library_adder)
85 libraries.remove(self.u1_library_path_url)
86 client.set_list(RB_LIBRARY_LOCATIONS, gconf.VALUE_STRING, libraries)
87 # delete held references
88 del self.db
89 del self.source
90 del self.shell
91
92 def url_loaded(self, source, url):
93 """A URL is loaded in the plugin"""
94 print "URL loaded:", url
95 if urlparse.urlparse(url).scheme == "https":
96 pass
97 else:
98 pass
99
100 def _udf_path_to_library_uri(self, path):
101 """Calculate the path in the library.
102 Since the library is accessed via the created symlink, but the path
103 passed to us is to a file in the actual music store UDF, we need to
104 work out the path inside the library, i.e., what the path to that file
105 is via the symlink."""
106
107 if path.startswith(U1LIBRARYPATH):
108 subpath = path[len(U1LIBRARYPATH):]
109 else:
110 subpath = path
111 if subpath.startswith("/"): subpath = subpath[1:]
112 library_path = os.path.join(self.U1_LIBRARY_SYMLINK, subpath)
113 # convert path to URI. Don't use urllib for this; Python and
114 # glib escape URLs differently. gio does it the glib way.
115 library_uri = gio.File(library_path).get_uri()
116 return library_uri
117
118 def download_finished(self, source, path):
119 """A file is finished downloading"""
120 library_uri = self._udf_path_to_library_uri(path)
121 # Import the URI
122 if not self.shell.props.db.entry_lookup_by_location(library_uri):
123 self.db.add_uri(library_uri)
124
125 def play_library(self, source, path):
126 """Switch to and start playing a song from the library"""
127 uri = self._udf_path_to_library_uri(path)
128 entry = self.shell.props.db.entry_lookup_by_location(uri)
129 if not entry:
130 print "couldn't find entry", uri
131 return
132 libsrc = self.shell.props.library_source
133 genre_view, artist_view, album_view = libsrc.get_property_views()
134 song_view = libsrc.get_entry_view()
135 artist = self.shell.props.db.entry_get(entry, rhythmdb.PROP_ARTIST)
136 album = self.shell.props.db.entry_get(entry, rhythmdb.PROP_ALBUM)
137 self.shell.props.sourcelist.select(libsrc)
138 artist_view.set_selection([artist])
139 album_view.set_selection([album])
140 song_view.scroll_to_entry(entry)
141 player = self.shell.get_player()
142 player.stop()
143 player.play()
144 player.play_entry(entry, libsrc)
145
146 def play_preview_mp3(self, source, url, title):
147 """Play a passed mp3; signal handler for preview-mp3 signal."""
148 # create an entry, don't save it, and play it
149 entry = self.shell.props.db.entry_lookup_by_location(url)
150 if entry is None:
151 entry = self.shell.props.db.entry_new(self.entry_type, url)
152 self.shell.props.db.set(entry, rhythmdb.PROP_TITLE, title)
153 player = self.shell.get_player()
154 player.stop()
155 player.play()
156 player.play_entry(entry, self.source)
157 # FIXME delete this entry when it finishes playing. Don't know how yet.
158
159 def add_u1_library(self):
160 """Add the U1 library if not listed in RB and re-add if changed."""
161 u1_library_path_folder = xdg.BaseDirectory.save_data_path("ubuntuone")
162 # Ensure that we can write to the folder, because syncdaemon creates it
163 # with no write permissions
164 os.chmod(u1_library_path_folder,
165 os.stat(u1_library_path_folder)[stat.ST_MODE] | stat.S_IWUSR)
166 # Translators: this is the name under Music for U1 music in Rhythmbox
167 u1_library_path = os.path.join(u1_library_path_folder, _("Purchased from Ubuntu One"))
168 if not os.path.islink(u1_library_path):
169 if not os.path.exists(u1_library_path):
170 print "Attempting to symlink %s to %s" % (U1LIBRARYPATH,
171 u1_library_path)
172 os.symlink(U1LIBRARYPATH, u1_library_path)
173 else:
174 # something that isn't a symlink already exists. That's not
175 # supposed to happen.
176 # Write a warning and carry on.
177 print ("Warning: library location %s existed. It should have "
178 "been a symlink to %s, and it wasn't. This isn't supposed "
179 "to happen. Carrying on anyway, on the assumption that "
180 "you know what you're doing. If this is a problem, then "
181 "delete or rename %s.") % (u1_library_path, U1LIBRARYPATH,
182 u1_library_path)
183 self.u1_library_path_url = "file://%s" % urllib.quote(u1_library_path)
184 self.U1_LIBRARY_SYMLINK = u1_library_path
185 client = gconf.client_get_default()
186 self._add_u1_library_if_not_present(client)
187 self._remove_old_u1_library_if_present(client)
188 # Watch for changes to the gconf key and re-add the library
189 self.library_adder = client.notify_add(RB_LIBRARY_LOCATIONS,
190 self._add_u1_library_if_not_present)
191
192 def _add_u1_library_if_not_present(self, client, *args, **kwargs):
193 """Check for the U1 library and add to libraries list."""
194 libraries = client.get_list(RB_LIBRARY_LOCATIONS, gconf.VALUE_STRING)
195 if self.u1_library_path_url not in libraries:
196 libraries.append(self.u1_library_path_url)
197 client.set_list(RB_LIBRARY_LOCATIONS, gconf.VALUE_STRING, libraries)
198
199 def _remove_old_u1_library_if_present(self, client, *args, **kwargs):
200 """Check for the old U1 library and remove it from libraries list."""
201 libraries = client.get_list(RB_LIBRARY_LOCATIONS, gconf.VALUE_STRING)
202 removed = False
203 # originally, this was the library path. Someone might have this.
204 old_path = "file://%s" % os.path.expanduser("~/.ubuntuone/musicstore")
205 if old_path in libraries:
206 libraries.remove(old_path)
207 removed = True
208 # Then, this was the library path, which we put into gconf unescaped
209 actual_udf_path_unescaped = "file://%s" % U1LIBRARYPATH
210 if actual_udf_path_unescaped in libraries:
211 libraries.remove(actual_udf_path_unescaped)
212 removed = True
213 # In theory, no-one should have the escaped path, but let's check
214 actual_udf_path_escaped = "file://%s" % U1LIBRARYPATH
215 if actual_udf_path_escaped in libraries:
216 libraries.remove(actual_udf_path_escaped)
217 removed = True
218 # Also, remove any library which is in .local/share and *isn't*
219 # the current library. This caters for people who got the library
220 # created under one name (say, English) and then had it created
221 # under another (say, after a translation to Dutch)
222 u1_library_path_folder = xdg.BaseDirectory.save_data_path("ubuntuone")
223 u1_library_path_folder_url = "file://%s" % urllib.quote(u1_library_path_folder)
224 symlink_url = "file://" + urllib.quote(self.U1_LIBRARY_SYMLINK)
225 for l in libraries:
226 if l.startswith(u1_library_path_folder_url) and l != symlink_url:
227 libraries.remove(l)
228 # and delete the symlink itself
229 symlink_to_remove = urllib.unquote(l[7:])
230 os.unlink(symlink_to_remove)
231 removed = True
232 if removed:
233 client.set_list(RB_LIBRARY_LOCATIONS, gconf.VALUE_STRING, libraries)
234
235class U1Source(rb.Source):
236 """A Rhythmbox source widget for the U1 Music Store."""
237 # gproperties required so that rb.Source is instantiable
238 __gproperties__ = {
239 'plugin': (rb.Plugin, 'plugin', 'plugin',
240 gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY),
241 }
242 # we have the preview-mp3 signal; we receive it from the widget, and re-emit
243 # it so that the plugin gets it, because the plugin actually plays the mp3
244 __gsignals__ = {
245 "preview-mp3": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (str, str)),
246 "play-library": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (str,)),
247 "download-finished": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (str,)),
248 "url-loaded": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (str,)),
249 }
250
251 def __init__(self):
252 rb.Source.__init__(self, name=_("Ubuntu One"))
253 self.__activated = False
254
255 def do_impl_activate(self):
256 """Source startup."""
257 if self.__activated: return
258 self.__activated = True
259 self.test_can_play_mp3()
260 rb.Source.do_impl_activate (self)
261
262 def test_can_play_mp3(self):
263 """Can the user play mp3s? Start a GStreamer pipeline to check."""
264 mp3pth = os.path.realpath(os.path.join(
265 os.path.split(__file__)[0], "empty.mp3"))
266 uri = "file://%s" % urllib.quote("%s" % mp3pth)
267 self.install_pipeline = gst.parse_launch(
268 'uridecodebin uri=%s ! fakesink' % uri)
269 bus = self.install_pipeline.get_bus()
270 bus.add_signal_watch()
271 bus.connect("message::element", self._got_element_msg)
272 bus.connect("message::eos", self._got_end_of_stream)
273 self.install_pipeline.set_state(gst.STATE_PLAYING)
274
275 def _got_element_msg(self, bus, msg):
276 """Handler for element messages from the check-mp3 pipeline.
277 GStreamer throws a "plugin-missing" element message if the
278 user does not have the right codecs to play a file."""
279 plugin_missing = gst.pbutils.is_missing_plugin_message(msg)
280 if plugin_missing:
281 self.install_pipeline.set_state(gst.STATE_NULL)
282 self.install_mp3_playback()
283
284 def _got_end_of_stream(self, bus, msg):
285 """Handler for end of stream from the check-mp3 pipeline.
286 If we reach the end of the stream, mp3 playback is enabled."""
287 self.install_pipeline.set_state(gst.STATE_NULL)
288 if os.environ.has_key("U1INSTALLMP3ANYWAY"):
289 # override the decision not to install the package
290 self.install_mp3_playback()
291 else:
292 self.add_music_store_widget()
293
294 def install_mp3_playback(self):
295 """Use aptdaemon to install the Fluendo mp3 playback codec package."""
296 self.install_box = gtk.Alignment(xscale=0.0, yscale=0.0, xalign=0.5,
297 yalign=0.5)
298 self.install_vbox = gtk.VBox()
299 self.install_label_head = gtk.Label()
300 self.install_label_head.set_use_markup(True)
301 not_installed = _("MP3 plugins are not installed")
302 self.install_label_head.set_markup('<span weight="bold" size="larger">'
303 '%s</span>' % not_installed)
304 self.install_label_head.set_alignment(0.0, 0.5)
305 self.install_label_body = gtk.Label()
306 self.install_label_body.set_text(_('To listen to your purchased songs'
307 ', you need to install MP3 plugins. Click below to install them.'))
308 self.install_label_body.set_alignment(0.0, 0.5)
309 self.install_label_eula = gtk.Label()
310 # EULA text copied from /var/lib/dpkg/info/gstreamer0.10-fluendo-plugins-mp3-partner.templates
311 # The partner package shows the EULA itself on installations, but
312 # aptdaemon installations work like DEBIAN_FRONTEND=noninteractive
313 # so we show the EULA here. (This also avoids a popup window.)
314 # EULA text is not translatable; do not wrap it with gettext!
315 self.install_label_eula.set_markup(
316 "<small>MPEG Layer-3 audio decoding technology notice\n"
317 "MPEG Layer-3 audio decoding technology licensed "
318 "from Fraunhofer IIS and Thomson\n"
319 "This product cannot be installed in product other than Personal "
320 "Computers sold for general purpose usage, and not for set-top "
321 "boxes, embedded PC, PC which are sold and customized for "
322 "mainly audio or multimedia playback and/or registration, "
323 "unless the seller has received a license by Fraunhofer IIS"
324 "and Thomson and pay the relevant royalties to them.</small>")
325 self.install_label_eula.set_alignment(0.0, 0.5)
326 self.install_label_eula.set_size_request(400,200)
327 self.install_label_eula.set_line_wrap(True)
328 self.install_hbtn = gtk.HButtonBox()
329 self.install_hbtn.set_layout(gtk.BUTTONBOX_END)
330 self.install_button = gtk.Button(label=_("Install MP3 plugins"))
331 self.install_button.connect("clicked", self._start_mp3_install)
332 self.install_hbtn.add(self.install_button)
333 self.install_vbox.pack_start(self.install_label_head, expand=False)
334 self.install_vbox.pack_start(self.install_label_body, expand=False,
335 padding=12)
336 self.install_vbox.pack_start(self.install_hbtn, expand=False)
337 self.install_vbox.pack_start(self.install_label_eula, expand=False,
338 padding=12)
339 self.install_box.add(self.install_vbox)
340 self.install_box.show_all()
341 self.add(self.install_box)
342
343 def _start_mp3_install(self, btn):
344 """Add the 'partner' repository and update the package list from it."""
345 self.ac = aptdaemon.client.AptClient()
346 try:
347 self.ac.add_repository("deb","http://archive.canonical.com/", "lucid", ["partner"])
348 except dbus.exceptions.DBusException, e:
349 if e.get_dbus_name() == "org.freedesktop.PolicyKit.Error.NotAuthorized":
350 # user cancelled, so exit from here so they can press the button again
351 return
352 self.ac.update_cache(reply_handler=self._finish_updating_packages,
353 error_handler=self._on_error)
354
355 def _finish_updating_packages(self, transaction):
356 """Now that partner is added, install our mp3 codec package."""
357 self.update_progress = AptProgressBar(transaction)
358 self.update_progress.show()
359 self.install_label_head.set_text("")
360 self.install_label_body.set_text(_("Finding MP3 plugins"))
361 self.install_label_eula.hide()
362 self.install_hbtn.hide()
363 self.install_vbox.pack_start(self.update_progress, expand=False)
364 transaction.run(reply_handler=lambda: True,
365 error_handler=self._on_error)
366 self.ac.install_packages(["gstreamer0.10-fluendo-plugins-mp3-partner"],
367 reply_handler=self._run_transaction,
368 error_handler=self._on_error)
369
370 def _run_transaction(self, transaction):
371 """Show progress of aptdaemon package installation."""
372 self.update_progress.hide()
373 self.install_progress = AptProgressBar(transaction)
374 self.install_progress.show()
375 self.install_label_head.set_text("")
376 self.install_label_body.set_text(_("Installing MP3 plugins"))
377 self.install_label_eula.hide()
378 self.install_hbtn.hide()
379 self.install_vbox.pack_start(self.install_progress, expand=False)
380 transaction.run(reply_handler=lambda: True,
381 error_handler=self._on_error)
382 transaction.connect("finished", self._finished)
383
384 def _finished(self, trans, exit_code):
385 """Aptdaemon package installation finished; show music store."""
386 if exit_code == 0 or exit_code == 2: # 0: success, 2: already installed
387 self.remove(self.install_box)
388 gst.update_registry()
389 self.add_music_store_widget()
390 else:
391 self._on_error("Could not find the "
392 "gstreamer0.10-fluendo-plugins-mp3-partner package.")
393
394 def _on_error(self, error):
395 """Error handler for aptdaemon."""
396 print error
397 problem_installing = _("There was a problem installing, sorry")
398 self.install_label_head.set_markup('<span weight="bold" size="larger">'
399 '%s</span>' % problem_installing)
400 self.install_label_body.set_text(_('Check your internet connection and '
401 'try again.'))
402 if getattr(self, "install_progress"):
403 self.install_progress.hide()
404 self.install_hbtn.show()
405
406 def add_music_store_widget(self):
407 """Display the music store widget in Rhythmbox."""
408 self.browser = MUSIC_STORE_WIDGET
409 self.add(self.browser)
410 self.show_all()
411 self.browser.set_no_show_all(True)
412 self.browser.set_property("visible", True)
413 self.browser.connect("preview-mp3", self.re_emit_preview)
414 self.browser.connect("play-library", self.re_emit_playlibrary)
415 self.browser.connect("download-finished", self.re_emit_downloadfinished)
416 self.browser.connect("url-loaded", self.re_emit_urlloaded)
417
418 def do_impl_can_pause(self):
419 """Implementation can pause.
420 If we don't handle this, Rhythmbox segfaults."""
421 return True # so we can pause, else we segfault
422
423 def re_emit_preview(self, widget, url, title):
424 """Handle the preview-mp3 signal and re-emit it to the rb.Plugin."""
425 self.emit("preview-mp3", url, title)
426
427 def re_emit_playlibrary(self, widget, path):
428 """Handle the play-library signal and re-emit it to the rb.Plugin."""
429 self.emit("play-library", path)
430
431 def re_emit_downloadfinished(self, widget, path):
432 """Handle the download-finished signal and re-emit it to the rb.Plugin."""
433 self.emit("download-finished", path)
434
435 def re_emit_urlloaded(self, widget, url):
436 """Handle the url-loaded signal and re-emit it to the rb.Plugin."""
437 self.emit("url-loaded", url)
438
439 def do_set_property(self, property, value):
440 """Allow property settings to handle the plugin call."""
441 if property.name == 'plugin':
442 self.__plugin = value
443 else:
444 raise AttributeError, 'unknown property %s' % property.name
445
446=======
447 self.music_store_widget.deactivate(shell)55 self.music_store_widget.deactivate(shell)
448 self.music_store_links_provider.deactivate(shell)56 self.music_store_links_provider.deactivate(shell)
449>>>>>>> MERGE-SOURCE
450

Subscribers

People subscribed via source and target branches