diff -Nru unity-scope-grooveshark-0.1/MANIFEST.in unity-scope-grooveshark-0.1/MANIFEST.in --- unity-scope-grooveshark-0.1/MANIFEST.in 2012-10-29 07:05:01.000000000 +0000 +++ unity-scope-grooveshark-0.1/MANIFEST.in 2012-11-05 17:24:36.000000000 +0000 @@ -3,3 +3,4 @@ include unity-scope-grooveshark.service include grooveshark.scope include src/unity-scope-grooveshark +include grooveshark.svg diff -Nru unity-scope-grooveshark-0.1/debian/bzr-builder.manifest unity-scope-grooveshark-0.1/debian/bzr-builder.manifest --- unity-scope-grooveshark-0.1/debian/bzr-builder.manifest 2012-10-29 07:05:01.000000000 +0000 +++ unity-scope-grooveshark-0.1/debian/bzr-builder.manifest 2012-11-05 17:24:36.000000000 +0000 @@ -1,2 +1,2 @@ -# bzr-builder format 0.3 deb-version {debupstream}-0~20 -lp:~davidc3/onehundredscopes/grooveshark-quantal revid:davidc@framli.eu-20121026063501-twu72tnnbn13uxnh +# bzr-builder format 0.3 deb-version {debupstream}-0~28 +lp:~davidc3/onehundredscopes/grooveshark revid:davidc@framli.eu-20121105170848-rii0d96pxa4eqb6x diff -Nru unity-scope-grooveshark-0.1/debian/changelog unity-scope-grooveshark-0.1/debian/changelog --- unity-scope-grooveshark-0.1/debian/changelog 2012-10-29 07:05:01.000000000 +0000 +++ unity-scope-grooveshark-0.1/debian/changelog 2012-11-05 17:24:36.000000000 +0000 @@ -1,8 +1,8 @@ -unity-scope-grooveshark (0.1-0~20~raring1) raring; urgency=low +unity-scope-grooveshark (0.1-0~28~raring1) raring; urgency=low * Auto build. - -- Launchpad Package Builder Mon, 29 Oct 2012 07:05:01 +0000 + -- David Callé Mon, 05 Nov 2012 17:24:36 +0000 unity-scope-grooveshark (0.1) oneiric; urgency=low diff -Nru unity-scope-grooveshark-0.1/grooveshark.svg unity-scope-grooveshark-0.1/grooveshark.svg --- unity-scope-grooveshark-0.1/grooveshark.svg 1970-01-01 00:00:00.000000000 +0000 +++ unity-scope-grooveshark-0.1/grooveshark.svg 2012-11-05 17:24:36.000000000 +0000 @@ -0,0 +1,69 @@ + + + +image/svg+xml \ No newline at end of file diff -Nru unity-scope-grooveshark-0.1/setup.py unity-scope-grooveshark-0.1/setup.py --- unity-scope-grooveshark-0.1/setup.py 2012-10-29 07:05:01.000000000 +0000 +++ unity-scope-grooveshark-0.1/setup.py 2012-11-05 17:24:36.000000000 +0000 @@ -11,6 +11,7 @@ license="GNU General Public License (GPL)", data_files=[ ('lib/unity-scope-grooveshark', ['src/unity-scope-grooveshark']), + ('lib/unity-scope-grooveshark', ['grooveshark.svg']), ('share/dbus-1/services', ['unity-scope-grooveshark.service']), ('share/unity/lenses/music', ['grooveshark.scope']), ], cmdclass={"build": build_extra.build_extra, }) diff -Nru unity-scope-grooveshark-0.1/src/unity-scope-grooveshark unity-scope-grooveshark-0.1/src/unity-scope-grooveshark --- unity-scope-grooveshark-0.1/src/unity-scope-grooveshark 2012-10-29 07:05:01.000000000 +0000 +++ unity-scope-grooveshark-0.1/src/unity-scope-grooveshark 2012-11-05 17:24:36.000000000 +0000 @@ -1,7 +1,8 @@ #! /usr/bin/python # -*- coding: latin-1 -*- -# Copyright (c) 2011 David Calle +# Copyright (c) 2012 Welton Rodrigo Torres Nascimento +# Copyright (c) 2012 David Calle # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -15,143 +16,213 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys, os + +import sys from gi.repository import GLib, GObject, Gio -from gi.repository import Dee -_m = dir(Dee.SequenceModel) from gi.repository import Unity -import socket +import random -socket.setdefaulttimeout(3) BUS_NAME = "net.launchpad.scope.music.grooveshark" class Daemon: - def __init__ (self): - self.scope = Unity.Scope.new ("/net/launchpad/scope/music/grooveshark") - self.scope.search_in_global = False - self.scope.connect ("search-changed", self.on_search_changed) - self.scope.connect ("filters-changed", lambda scope : self.scope.queue_search_changed(Unity.SearchType.DEFAULT)) - self.preferences = Unity.PreferencesManager.get_default() - self.preferences.connect("notify::remote-content-search", self._on_preference_changed) - self.scope.export() - - def _on_preference_changed (self, *_): - self.scope.queue_search_changed(Unity.SearchType.DEFAULT) - - - def on_search_changed (self, scope, search, search_type, *_): - model = self.scope.props.results_model - if self.preferences.props.remote_content_search != Unity.PreferencesManagerRemoteContent.ALL: - model.clear () - search.finished() - return - search_string = search.props.search_string.strip() - print 'Search changed to %s' % search_string - if search_type == Unity.SearchType.DEFAULT: - model.clear() - self.update_results_model (search_string, model) - model.flush_revision_queue () - search.finished() - - def update_results_model(self, search, model): - data_list = self.grooveshark(search) - if data_list: - for i in data_list: - model.append ( - str(i['uri']), - str(i['icon_hint']), - 0, - "text/html", - i['title'], - i['artistName'] + "\n" + i['album'], #comment - i['uri']) - - #Show this title's album on the album section - if 'album_uri' in i: - model.append ( - i['album_uri'], - i['icon_hint'], - 1, - "text/html", - i['album'], - i['artistName'] + i['album'], #comment - i['album_uri']) - - def grooveshark_search(self, q, key): - import urllib, urllib2, simplejson - if key == 1: - key = "5a71ca7fe5af04433b5c760f5960f477" - else: - key = "a4e7721f80f4cedde47e9e029cb0fcc3" - try: - query = urllib.quote(q) - if query != '' or query != 'q=' or query != 'q': - uri = ('http://tinysong.com/s/%s?format=json&key=%s&limit=32' - % (query, key)) - print uri - f = urllib2.urlopen(uri) - content = f.read() - results = simplejson.loads(content) - if results: - return results - else: - return - else: - return - except (IOError, urllib2.URLError, urllib2.HTTPError, simplejson.JSONDecodeError): - print "grooveshark_search_is_error" - return - - def grooveshark(self, search): - import urllib - if search: - data_grooveshark = self.grooveshark_search("%s" % search, 1) - data_list = [] - albums_seen = {} - - if data_grooveshark: - for i in data_grooveshark: - item_list = {} - - item_list['uri'] = str(i['Url']) - item_list['title'] = i['SongName'] - item_list['artistName'] = i['ArtistName'] - item_list['comment'] = i['ArtistName']+'\n'+i['AlbumName'] - item_list['icon_hint'] = 'http://beta.grooveshark.com/static/amazonart/m'+ str(i['AlbumID']) +'.jpg' - item_list['albumID'] = i['AlbumID'] - item_list['album'] = i['AlbumName'] - - if i['AlbumID'] not in albums_seen: - album_for_uri = urllib.quote(item_list['album'].encode('utf-8')) - print album_for_uri - item_list['album_uri'] = "http://grooveshark.com/#/album/"+ album_for_uri +"/"+ str(item_list['albumID']) - albums_seen[ item_list['albumID'] ] = 1 - - - data_list.append(item_list) - return data_list - else: - return [] - else: - return [] - + def __init__ (self): + self.scope = Unity.Scope.new ("/net/launchpad/scope/music/grooveshark") + self.scope.search_in_global = False + self.scope.connect ("search-changed", self.on_search_changed) + self.scope.connect ("filters-changed", lambda scope : self.scope.queue_search_changed(Unity.SearchType.DEFAULT)) + self.scope.connect ("activate_uri", self.on_activate) + self.scope.connect ("preview_uri", self.on_preview) + self.preferences = Unity.PreferencesManager.get_default() + self.preferences.connect("notify::remote-content-search", self._on_preference_changed) + self.scope.export() + + def _on_preference_changed (self, *_): + self.scope.queue_search_changed(Unity.SearchType.DEFAULT) + + + def on_search_changed (self, scope, search, search_type, cancellable): + if self.preferences.props.remote_content_search != Unity.PreferencesManagerRemoteContent.ALL: + self.scope.props.results_model.clear() + search.finished() + return + search_string = search.props.search_string.strip() + print 'Search changed to %s' % search_string + if search_type == Unity.SearchType.DEFAULT: + self.scope.props.results_model.clear() + # Randomize the choice of API key + key = random.randint(0,1) + # Dispatch an async call with callback on_grooveshark_search_finished + self.grooveshark_search(search_string, search, key, cancellable, self.on_grooveshark_search_finished) + else: + search.finished() + + def on_grooveshark_search_finished (self, search, cancellable, data_list): + model = search.props.results_model + model.clear() + + self.update_results_model(model, data_list, cancellable) + + model.flush_revision_queue() + search.finished() + + def update_results_model(self, model, data_list, cancellable): + import simplejson + + if data_list: + for i in data_list: + if(cancellable.is_cancelled()) : return + serialized = simplejson.dumps(i) + + if i['type'] == 'track': + category = 0 + else: # album + category = 1 + + model.append ( + serialized, + str(i['icon_hint']), + category, + "text/html", + i['title'], + i['artistName'] + "\n" + i['album'], #comment + i['uri']) + + def grooveshark_search (self, search_string, search, key, cancellable, callback): + import urllib, simplejson + if key == 1: + key = "5a71ca7fe5af04433b5c760f5960f477" + else: + key = "a4e7721f80f4cedde47e9e029cb0fcc3" + + query = urllib.quote(search_string) + print "Query is '%s'" % query + if query != '' and query != 'q=' and query != 'q': + uri = ('http://tinysong.com/s/%s?format=json&key=%s&limit=32' + % (query, key)) + print uri + + file = Gio.File.new_for_uri(uri) + + content = '' + def parse_json(gdaemonfile, result, *_): + try: + (ok, content, etag) = file.load_contents_finish(result) + + results = simplejson.loads(content) + data_list = self.grooveshark(results, cancellable) + callback(search, cancellable, data_list) + + except Exception as error: + print "grooveshark_search: %s" % error + + file.load_contents_async(cancellable, parse_json, None) + + def grooveshark(self, data_grooveshark, cancellable): + import urllib + if(cancellable.is_cancelled()) : return [] + data_list = [] + albums_seen = {} + + if data_grooveshark: + for i in data_grooveshark: + item_list = {} + + item_list['type'] = 'track' + item_list['uri'] = str(i['Url']) + item_list['title'] = i['SongName'] + item_list['artistName'] = i['ArtistName'] + item_list['comment'] = i['ArtistName']+"\n"+i['AlbumName'] + item_list['icon_hint'] = 'http://beta.grooveshark.com/static/amazonart/m'+ str(i['AlbumID']) +'.jpg' + item_list['albumID'] = i['AlbumID'] + item_list['album'] = i['AlbumName'] + + # URI for complete album + uri = urllib.quote(item_list['album'].encode('utf-8')) + item_list['album_uri'] = "http://grooveshark.com/#/album/%s/%s" % (uri, item_list['albumID']) + + # Append to the list. + data_list.append(item_list) + + # Create an entry on list for album too, but only first time we see it. + if i['AlbumID'] not in albums_seen: + + # Clone the item + album_item_list = item_list.copy() + + # Adjust fields + album_item_list['type'] = 'album' + album_item_list['title'] = album_item_list['album'] + album_item_list['uri'] = album_item_list['album_uri'] + + # Mark as seen + albums_seen[ album_item_list['albumID'] ] = 1 + + # Append an entry for this album. + data_list.append(album_item_list) + + return data_list + else: + return [] + + def _deserialize(self, stream): + import simplejson + + # De-serialize the item. + return simplejson.loads(stream) + + def on_activate(self, scope, stream): + item = self._deserialize(stream) + print "Stream is %s" % stream + + uri = '' + if item['type'] == 'track': + uri = item['uri'] + else: + uri = item['album_uri'] + + print "Type is %s" % item['type'] + print "URI is %s" % uri + + Gio.AppInfo.launch_default_for_uri(uri, None) + + return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH) + + def on_preview(self, scope, stream): + item = self._deserialize(stream) + preview = Unity.MusicPreview.new( + item['title'], item['artistName'], + Gio.FileIcon.new_for_string(item['icon_hint'])) + + gfile_icon = Gio.file_new_for_path("/usr/lib/unity-scope-grooveshark/grooveshark.svg") + gicon = Gio.FileIcon.new (gfile_icon) + play_action = Unity.PreviewAction.new("play_action", "Play", gicon) + play_action.connect("activated", self.play_action) + preview.add_action(play_action) + + return preview + + def play_action(self, scope, stream): + print "Clicked URI is %s" % self._deserialize(stream)['uri'] + return self.on_activate(scope, stream) + + if __name__ == "__main__": - session_bus_connection = Gio.bus_get_sync (Gio.BusType.SESSION, None) - session_bus = Gio.DBusProxy.new_sync (session_bus_connection, 0, None, - 'org.freedesktop.DBus', - '/org/freedesktop/DBus', - 'org.freedesktop.DBus', None) - result = session_bus.call_sync('RequestName', - GLib.Variant ("(su)", (BUS_NAME, 0x4)), - 0, -1, None) - - # Unpack variant response with signature "(u)". 1 means we got it. - result = result.unpack()[0] - - if result != 1 : - print >> sys.stderr, "Failed to own name %s. Bailing out." % BUS_NAME - raise SystemExit (1) - - daemon = Daemon() - GObject.MainLoop().run() + session_bus_connection = Gio.bus_get_sync (Gio.BusType.SESSION, None) + session_bus = Gio.DBusProxy.new_sync (session_bus_connection, 0, None, + 'org.freedesktop.DBus', + '/org/freedesktop/DBus', + 'org.freedesktop.DBus', None) + result = session_bus.call_sync('RequestName', + GLib.Variant ("(su)", (BUS_NAME, 0x4)), + 0, -1, None) + + # Unpack variant response with signature "(u)". 1 means we got it. + result = result.unpack()[0] + + if result != 1 : + print >> sys.stderr, "Failed to own name %s. Bailing out." % BUS_NAME + raise SystemExit (1) + + daemon = Daemon() + GObject.MainLoop().run()