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