Merge lp:~submarine/unity-scope-gmusicbrowser/gmusicbrowser-previews into lp:unity-scope-gmusicbrowser

Proposed by Mark Tully
Status: Merged
Approved by: David Callé
Approved revision: 21
Merged at revision: 20
Proposed branch: lp:~submarine/unity-scope-gmusicbrowser/gmusicbrowser-previews
Merge into: lp:unity-scope-gmusicbrowser
Diff against target: 411 lines (+104/-167)
3 files modified
data/gmusicbrowser.scope.in (+3/-1)
src/unity_gmusicbrowser_daemon.py (+92/-157)
tests/test_gmusicbrowser.py (+9/-9)
To merge this branch: bzr merge lp:~submarine/unity-scope-gmusicbrowser/gmusicbrowser-previews
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
David Callé Approve
Review via email: mp+159935@code.launchpad.net

Commit message

Add Previews and Activation

Description of the change

Add Previews and Activation

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
David Callé (davidc3) wrote :

Works well. +1

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
21. By Mark Tully

Fixed tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'data/gmusicbrowser.scope.in'
--- data/gmusicbrowser.scope.in 2013-03-20 16:43:38 +0000
+++ data/gmusicbrowser.scope.in 2013-04-22 13:23:30 +0000
@@ -5,7 +5,9 @@
5QueryBinary=gmusicbrowser5QueryBinary=gmusicbrowser
6_Keywords=gmusicbrowser;6_Keywords=gmusicbrowser;
7RequiredMetadata=7RequiredMetadata=
8OptionalMetadata=8OptionalMetadata=album[s];artist[s];genre[s];year[i];track_length[i];track_number[i]
9Loader=/usr/share/unity-scopes/gmusicbrowser/unity_gmusicbrowser_daemon.py
10RemoteContent=false
9Type=music11Type=music
10_Name=Gmusicbrowser12_Name=Gmusicbrowser
11_Description=Find Gmusicbrowser items13_Description=Find Gmusicbrowser items
1214
=== modified file 'src/unity_gmusicbrowser_daemon.py'
--- src/unity_gmusicbrowser_daemon.py 2013-03-19 15:40:16 +0000
+++ src/unity_gmusicbrowser_daemon.py 2013-04-22 13:23:30 +0000
@@ -64,12 +64,13 @@
64m4 = {'id' :'year',64m4 = {'id' :'year',
65 'type' :'i',65 'type' :'i',
66 'field':Unity.SchemaFieldType.OPTIONAL}66 'field':Unity.SchemaFieldType.OPTIONAL}
67EXTRA_METADATA = [m1, m2, m3, m4]67m5 = {'id': 'track_length',
6868 'type': 'i',
69REFRESH_TIMEOUT = 30069 'field': Unity.SchemaFieldType.OPTIONAL}
70PREVIEW_PLAYER_DBUS_NAME = "com.canonical.Unity.Lens.Music.PreviewPlayer"70m6 = {'id': 'track_number',
71PREVIEW_PLAYER_DBUS_PATH = "/com/canonical/Unity/Lens/Music/PreviewPlayer"71 'type': 'i',
72PREVIEW_PLAYER_DBUS_IFACE = PREVIEW_PLAYER_DBUS_NAME72 'field': Unity.SchemaFieldType.OPTIONAL}
73EXTRA_METADATA = [m1, m2, m3, m4, m5, m6]
7374
74tracks = []75tracks = []
75albumart = []76albumart = []
@@ -77,6 +78,8 @@
7778
78def get_music_from_gmusicbrowser():79def get_music_from_gmusicbrowser():
79 """Parses GMusicBrowser's collection into a form we can use"""80 """Parses GMusicBrowser's collection into a form we can use"""
81 global tracks
82 global albumart
80 tracks = []83 tracks = []
81 albumart = []84 albumart = []
82 songlist = []85 songlist = []
@@ -95,7 +98,6 @@
95 albumstart = index98 albumstart = index
96 if item == '[artist]\n':99 if item == '[artist]\n':
97 artiststart = index100 artiststart = index
98 print(songstart)
99 except:101 except:
100 return tracks102 return tracks
101103
@@ -122,7 +124,7 @@
122 if track[7] == "":124 if track[7] == "":
123 track[7] = "0"125 track[7] = "0"
124 track[8] = 0 if fields[32] is None else fields[32]126 track[8] = 0 if fields[32] is None else fields[32]
125 track[9] = fields[32]127 track[9] = int(fields[32])
126 track[10] = fields[17]128 track[10] = fields[17]
127 tracks.append(track)129 tracks.append(track)
128 albumartlist = database[albumstart + 2:artiststart - 1]130 albumartlist = database[albumstart + 2:artiststart - 1]
@@ -135,7 +137,8 @@
135 albumarta[2] = fields[1]137 albumarta[2] = fields[1]
136 albumart.append(albumarta)138 albumart.append(albumarta)
137 print("Updated tracks from GMusicBrowser database")139 print("Updated tracks from GMusicBrowser database")
138140
141 tracks.sort(key=lambda track: track[9])
139 return albumart, tracks142 return albumart, tracks
140143
141144
@@ -149,6 +152,8 @@
149 '''152 '''
150 Search for help documents matching the search string153 Search for help documents matching the search string
151 '''154 '''
155 global tracks
156 global albumart
152 results = []157 results = []
153 albums, tracks = get_music_from_gmusicbrowser()158 albums, tracks = get_music_from_gmusicbrowser()
154 trackresults = []159 trackresults = []
@@ -162,166 +167,75 @@
162 albumartist = "" if track[5] is None else track[5]167 albumartist = "" if track[5] is None else track[5]
163 year = 0 if track[7] is None else int(track[7])168 year = 0 if track[7] is None else int(track[7])
164 genre = "" if track[6] is None else track[6]169 genre = "" if track[6] is None else track[6]
170 track_length = 0 if track[10] is None else int(track[10])
171 track_number = 0 if track[9] is None else int(track[9])
165 trackname = title + " - " + album + " - " + artist172 trackname = title + " - " + album + " - " + artist
166 if search.lower() in trackname.lower():173 if search.lower() in trackname.lower():
167 albumart = get_album_art(track, albums)174 albumart = 'file://' + get_album_art(track, albums).replace('\n', '')
168 albumuri = "album://" + albumartist + "/" + album175 albumuri = "album://" + albumartist + "/" + album
169 if track not in trackresults:176 if track not in trackresults:
170 results.append({'uri': uri,177 results.append({'uri': uri,
171 'icon': albumart,178 'icon': albumart,
172 'category': 0,179 'category': 0,
173 'mimetype': mimetype,
174 'title': title,180 'title': title,
175 'comment': artist,
176 'album':GLib.Variant('s', album),181 'album':GLib.Variant('s', album),
177 'artist':GLib.Variant('s', artist),182 'artist':GLib.Variant('s', artist),
178 'genre':GLib.Variant('s', genre),183 'genre':GLib.Variant('s', genre),
179 'year':GLib.Variant('i', year)})184 'year':GLib.Variant('i', year),
185 'track_length': GLib.Variant('i', track_length),
186 'track_number': GLib.Variant('i', track_number)})
180 trackresults.append(track)187 trackresults.append(track)
181188
182 if album not in albumresults:189 if album not in albumresults:
183 results.append({'uri': albumuri,190 results.append({'uri': albumuri,
184 'icon': albumart,191 'icon': albumart,
185 'category': 1,192 'category': 1,
186 'mimetype': mimetype,
187 'title': album,193 'title': album,
188 'comment': artist,
189 'album':GLib.Variant('s', album),194 'album':GLib.Variant('s', album),
190 'artist':GLib.Variant('s', artist),195 'artist':GLib.Variant('s', artist),
191 'genre':GLib.Variant('s', genre),196 'genre':GLib.Variant('s', genre),
192 'year':GLib.Variant('i', year)})197 'year':GLib.Variant('i', year),
198 'track_length': GLib.Variant('i', track_length),
199 'track_number': GLib.Variant('i', track_number)})
193 albumresults.append(album)200 albumresults.append(album)
194 return results201 return results
195202
196203
197def activate(scope, uri):204class Preview(Unity.ResultPreviewer):
198 import subprocess205
199 albumtracks = []206 def do_run(self):
200 albumtracks.append("gmusicbrowser")207 global tracks
201 albumtracks.append("-play")208 album = self.result.metadata['album'].get_string()
202 albumtracks.append("-playlist")209 artist = self.result.metadata['artist'].get_string()
203 # If uri starts with album:// then we need to play all the songs on it210 preview = Unity.MusicPreview.new(self.result.title, '', None)
204 if uri.startswith("album://"):211 preview.props.image_source_uri = self.result.icon_hint
205 trackdetails = []212 preview.props.subtitle = self.result.metadata['artist'].get_string()
206 for track in tracks:213 if self.result.uri.startswith("album://"):
207 trackdetail = []214 for track in tracks:
208 album = "album://" + track[5] + "/" + track[3]215 if album in track[3] and artist in track[2]:
209 if not album.find(uri) == -1:216 track = Unity.TrackMetadata.full(track[1],
210 albumtrack = track[1]217 int(track[9]),
211 trackdetail.append(albumtrack)218 track[0],
212 trackdetail.append(track[8])219 track[2],
213 trackdetails.append(trackdetail)220 track[3],
214 trackdetails.sort(key=lambda track: int(track[1]))221 int(track[10]))
215 for track in trackdetails:222 preview.add_track(track)
216 albumtracks.append(track[0])223 else:
217 subprocess.Popen(albumtracks)224 print(self.result.uri)
218 else:225 track = Unity.TrackMetadata.full('file://%s' % self.result.uri.replace(' ', '%20'),
219 albumtracks.append("file://" + uri)226 self.result.metadata['track_number'].get_int32(),
220 subprocess.Popen(albumtracks)227 self.result.title,
221 return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH, goto_uri='')228 self.result.metadata['artist'].get_string(),
222229 self.result.metadata['album'].get_string(),
223230 self.result.metadata['track_length'].get_int32())
224def show_in_folder(scope, uri):231 preview.add_track(track)
225 """ Shows the folder containing the selected track as requested from the Preview232
226 """233 view_action = Unity.PreviewAction.new("play", _("Play"), None)
227 if uri.startswith("album://"):234 preview.add_action(view_action)
228 for track in tracks:235 show_action = Unity.PreviewAction.new("show", _("Show in Folder"), None)
229 album = "album://" + track[2] + "/" + track[3]236 preview.add_action(show_action)
230 if not album.find(uri) == -1:237 return preview
231 filename = track[1]238
232 continue
233 else:
234 filename = uri
235 dirname = os.path.dirname(filename)
236 dirname = dirname.replace("%20", "\ ")
237 os.system("xdg-open '%s'" % str(dirname))
238 return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH, goto_uri='')
239
240
241def preview_uri(scope, uri):
242 """Preview request handler"""
243 albumtracks = []
244 isalbum = False
245 if uri.startswith("album://"):
246 isalbum = True
247 for track in tracks:
248 album = "album://" + track[2] + "/" + track[3]
249 if not album.find(uri) == -1:
250 albumtracks.append(track)
251 albumtracks.sort(key=lambda track: int(track[7]))
252 else:
253 for track in tracks:
254 album = "file://" + track[1]
255 if not album.find(uri) == -1:
256 albumtracks.append(track)
257 iteration = model.get_first_iter()
258 end_iter = model.get_last_iter()
259 while iteration != end_iter:
260 if model.get_value(iteration, 0) == uri:
261 title = model.get_value(iteration, 5)
262 description = model.get_value(iteration, 6)
263 if model.get_value(iteration, 1) == "musique":
264 image = "file:///usr/share/icons/hicolor/scalable/apps/audacious.svg"
265 else:
266 image = "file://%s" % model.get_value(iteration, 1)
267
268 preview = Unity.MusicPreview.new(title, description, None)
269 preview.props.image_source_uri = image
270 for albumtrack in albumtracks:
271 if isalbum:
272 track = Unity.TrackMetadata.full("file://" + urllib.parse.unquote(str(albumtrack[1])), # uri
273 int(albumtrack[7]), # track number
274 albumtrack[0], # track title
275 albumtrack[2], # artist
276 albumtrack[3], # album
277 int(albumtrack[8]) / 1000) # track length
278 else:
279 preview = Unity.MusicPreview.new(albumtrack[0], "", None)
280 preview.props.image_source_uri = image
281 track = Unity.TrackMetadata.full("file://" + urllib.parse.unquote(str(albumtrack[1])),
282 int(albumtrack[7]),
283 albumtrack[0],
284 albumtrack[2],
285 albumtrack[3],
286 int(albumtrack[8]) / 1000)
287 preview.add_track(track)
288
289 # Add the "Play" action
290 play_action = Unity.PreviewAction.new("activate_uri", "Play", None)
291 play_action.connect("activated", activate)
292 preview.add_action(play_action)
293
294 # Add the "Show in folder" action
295 show_action = Unity.PreviewAction.new("show_in_folder", "Show In Folder", None)
296 show_action.connect("activated", show_in_folder)
297 preview.add_action(show_action)
298
299 preview.connect("play", play)
300 preview.connect("pause", pause)
301 preview.connect("closed", closed)
302 break
303 iteration = model.next(iteration)
304 if preview is None:
305 print("Couldn't find model row for requested preview uri: '%s'", uri)
306 return preview
307
308
309def play(preview, uri):
310 """Plays the selected track as selected in the Preview"""
311 player = self.bus.get_object(PREVIEW_PLAYER_DBUS_NAME, PREVIEW_PLAYER_DBUS_PATH)
312 dbus.Interface(player, PREVIEW_PLAYER_DBUS_IFACE).Play(uri)
313
314
315def pause(preview, uri):
316 """Pauses the selected track as selected in the Preview"""
317 player = self.bus.get_object(PREVIEW_PLAYER_DBUS_NAME, PREVIEW_PLAYER_DBUS_PATH)
318 dbus.Interface(player, PREVIEW_PLAYER_DBUS_IFACE).Pause()
319
320
321def closed(preview):
322 """Stops playing when the previre is closed"""
323 player = self.bus.get_object(PREVIEW_PLAYER_DBUS_NAME, PREVIEW_PLAYER_DBUS_PATH)
324 dbus.Interface(player, PREVIEW_PLAYER_DBUS_IFACE).Close()
325239
326# Classes below this point establish communication240# Classes below this point establish communication
327# with Unity, you probably shouldn't modify them.241# with Unity, you probably shouldn't modify them.
@@ -356,19 +270,8 @@
356 i['comment'] = ''270 i['comment'] = ''
357 if not 'dnd_uri' in i or not i['dnd_uri'] or i['dnd_uri'] == '':271 if not 'dnd_uri' in i or not i['dnd_uri'] or i['dnd_uri'] == '':
358 i['dnd_uri'] = i['uri']272 i['dnd_uri'] = i['uri']
359 i['metadata'] = {}273 i['provider_credits'] = GLib.Variant('s', PROVIDER_CREDITS)
360 if EXTRA_METADATA:274 result_set.add_result(**i)
361 for e in i:
362 for m in EXTRA_METADATA:
363 if m['id'] == e:
364 i['metadata'][e] = i[e]
365 i['metadata']['provider_credits'] = GLib.Variant('s', PROVIDER_CREDITS)
366 result = Unity.ScopeResult.create(str(i['uri']), str(i['icon']),
367 i['category'], i['result_type'],
368 str(i['mimetype']), str(i['title']),
369 str(i['comment']), str(i['dnd_uri']),
370 i['metadata'])
371 result_set.add_result(result)
372 except Exception as error:275 except Exception as error:
373 print(error)276 print(error)
374277
@@ -424,6 +327,38 @@
424 se = MySearch(search_context)327 se = MySearch(search_context)
425 return se328 return se
426329
330 def do_activate(self, result, metadata, id):
331 album = result.metadata['album'].get_string()
332 artist = result.metadata['artist'].get_string()
333 global tracks
334 if id == 'show':
335 if result.uri.startswith("album://"):
336 for track in tracks:
337 if album in track[3] and artist in track[2]:
338 filename = tracks[1]
339 continue
340 else:
341 filename = result.uri
342 dirname = os.path.dirname(filename)
343 os.system("xdg-open '%s'" % str(dirname))
344 else:
345 albumtracks = ''
346 if result.uri.startswith('album://'):
347 for track in tracks:
348 if album in track[3] and artist in track[2]:
349 albumtracks = albumtracks + ' \'%s\'' % (track[1])
350 else:
351 albumtracks = '\'%s\'' % result.uri
352 os.system('gmusicbrowser -play -playlist %s' % albumtracks)
353
354 return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH, goto_uri=None)
355
356 def do_create_previewer(self, result, metadata):
357 rp = Preview()
358 rp.set_scope_result(result)
359 rp.set_search_metadata(metadata)
360 return rp
361
427362
428def load_scope():363def load_scope():
429 return Scope()364 return Scope()
430365
=== modified file 'tests/test_gmusicbrowser.py'
--- tests/test_gmusicbrowser.py 2013-03-03 19:20:19 +0000
+++ tests/test_gmusicbrowser.py 2013-04-22 13:23:30 +0000
@@ -11,17 +11,18 @@
11 self.results = []11 self.results = []
1212
13 def do_add_result(self, result):13 def do_add_result(self, result):
14 self.results.append({'uri':result.uri,14 self.results.append({'uri': result.uri,
15 'title':result.title,15 'title': result.title,
16 'comment':result.comment,16 'comment': result.comment,
17 'icon':result.icon_hint})17 'icon': result.icon_hint})
18
1819
19class ScopeTestCase(TestCase):20class ScopeTestCase(TestCase):
20 def init_scope(self, scope_path):21 def init_scope(self, scope_path):
21 self.scope_module = imp.load_source('scope', scope_path)22 self.scope_module = imp.load_source('scope', scope_path)
22 self.scope = self.scope_module.load_scope()23 self.scope = self.scope_module.load_scope()
2324
24 def perform_query(self, query, filter_set = Unity.FilterSet.new()):25 def perform_query(self, query, filter_set=Unity.FilterSet.new()):
25 result_set = ResultSet()26 result_set = ResultSet()
26 ctx = Unity.SearchContext.create(query, 0, filter_set,27 ctx = Unity.SearchContext.create(query, 0, filter_set,
27 None, result_set, None)28 None, result_set, None)
@@ -30,7 +31,7 @@
30 return result_set31 return result_set
3132
3233
33class TestAskUbuntu(ScopeTestCase):34class TestGmusicbrowser(ScopeTestCase):
34 def setUp(self):35 def setUp(self):
35 self.init_scope('src/unity_gmusicbrowser_daemon.py')36 self.init_scope('src/unity_gmusicbrowser_daemon.py')
3637
@@ -38,7 +39,7 @@
38 self.scope = None39 self.scope = None
39 self.scope_module = None40 self.scope_module = None
4041
41 def test_questions_search(self):42 def test_qsearch(self):
42 self.scope_module.GMUSICBROWSER_DBFILE = 'tests/data/mock_gmusicbrowser_pass'43 self.scope_module.GMUSICBROWSER_DBFILE = 'tests/data/mock_gmusicbrowser_pass'
43 expected_results = ["/home/mark/Music/Jacques Dutronc/En Vogue/02. Mini, Mini, Mini.mp3",44 expected_results = ["/home/mark/Music/Jacques Dutronc/En Vogue/02. Mini, Mini, Mini.mp3",
44 "Mini, Mini, Mini"]45 "Mini, Mini, Mini"]
@@ -49,8 +50,7 @@
49 results.append(result_set.results[0]['title'])50 results.append(result_set.results[0]['title'])
50 self.assertEqual(results, expected_results)51 self.assertEqual(results, expected_results)
5152
5253 def test_failing_search(self):
53 def test_questions_failing_search(self):
54 self.scope_module.GMUSICBROWSER_DBFILE = 'tests/data/mock_gmusicbrowser_fail'54 self.scope_module.GMUSICBROWSER_DBFILE = 'tests/data/mock_gmusicbrowser_fail'
55 for s in ['upnriitnyt']:55 for s in ['upnriitnyt']:
56 result_set = self.perform_query(s)56 result_set = self.perform_query(s)

Subscribers

People subscribed via source and target branches

to all changes: