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
1=== modified file 'data/gmusicbrowser.scope.in'
2--- data/gmusicbrowser.scope.in 2013-03-20 16:43:38 +0000
3+++ data/gmusicbrowser.scope.in 2013-04-22 13:23:30 +0000
4@@ -5,7 +5,9 @@
5 QueryBinary=gmusicbrowser
6 _Keywords=gmusicbrowser;
7 RequiredMetadata=
8-OptionalMetadata=
9+OptionalMetadata=album[s];artist[s];genre[s];year[i];track_length[i];track_number[i]
10+Loader=/usr/share/unity-scopes/gmusicbrowser/unity_gmusicbrowser_daemon.py
11+RemoteContent=false
12 Type=music
13 _Name=Gmusicbrowser
14 _Description=Find Gmusicbrowser items
15
16=== modified file 'src/unity_gmusicbrowser_daemon.py'
17--- src/unity_gmusicbrowser_daemon.py 2013-03-19 15:40:16 +0000
18+++ src/unity_gmusicbrowser_daemon.py 2013-04-22 13:23:30 +0000
19@@ -64,12 +64,13 @@
20 m4 = {'id' :'year',
21 'type' :'i',
22 'field':Unity.SchemaFieldType.OPTIONAL}
23-EXTRA_METADATA = [m1, m2, m3, m4]
24-
25-REFRESH_TIMEOUT = 300
26-PREVIEW_PLAYER_DBUS_NAME = "com.canonical.Unity.Lens.Music.PreviewPlayer"
27-PREVIEW_PLAYER_DBUS_PATH = "/com/canonical/Unity/Lens/Music/PreviewPlayer"
28-PREVIEW_PLAYER_DBUS_IFACE = PREVIEW_PLAYER_DBUS_NAME
29+m5 = {'id': 'track_length',
30+ 'type': 'i',
31+ 'field': Unity.SchemaFieldType.OPTIONAL}
32+m6 = {'id': 'track_number',
33+ 'type': 'i',
34+ 'field': Unity.SchemaFieldType.OPTIONAL}
35+EXTRA_METADATA = [m1, m2, m3, m4, m5, m6]
36
37 tracks = []
38 albumart = []
39@@ -77,6 +78,8 @@
40
41 def get_music_from_gmusicbrowser():
42 """Parses GMusicBrowser's collection into a form we can use"""
43+ global tracks
44+ global albumart
45 tracks = []
46 albumart = []
47 songlist = []
48@@ -95,7 +98,6 @@
49 albumstart = index
50 if item == '[artist]\n':
51 artiststart = index
52- print(songstart)
53 except:
54 return tracks
55
56@@ -122,7 +124,7 @@
57 if track[7] == "":
58 track[7] = "0"
59 track[8] = 0 if fields[32] is None else fields[32]
60- track[9] = fields[32]
61+ track[9] = int(fields[32])
62 track[10] = fields[17]
63 tracks.append(track)
64 albumartlist = database[albumstart + 2:artiststart - 1]
65@@ -135,7 +137,8 @@
66 albumarta[2] = fields[1]
67 albumart.append(albumarta)
68 print("Updated tracks from GMusicBrowser database")
69-
70+
71+ tracks.sort(key=lambda track: track[9])
72 return albumart, tracks
73
74
75@@ -149,6 +152,8 @@
76 '''
77 Search for help documents matching the search string
78 '''
79+ global tracks
80+ global albumart
81 results = []
82 albums, tracks = get_music_from_gmusicbrowser()
83 trackresults = []
84@@ -162,166 +167,75 @@
85 albumartist = "" if track[5] is None else track[5]
86 year = 0 if track[7] is None else int(track[7])
87 genre = "" if track[6] is None else track[6]
88+ track_length = 0 if track[10] is None else int(track[10])
89+ track_number = 0 if track[9] is None else int(track[9])
90 trackname = title + " - " + album + " - " + artist
91 if search.lower() in trackname.lower():
92- albumart = get_album_art(track, albums)
93+ albumart = 'file://' + get_album_art(track, albums).replace('\n', '')
94 albumuri = "album://" + albumartist + "/" + album
95 if track not in trackresults:
96 results.append({'uri': uri,
97 'icon': albumart,
98 'category': 0,
99- 'mimetype': mimetype,
100 'title': title,
101- 'comment': artist,
102 'album':GLib.Variant('s', album),
103 'artist':GLib.Variant('s', artist),
104 'genre':GLib.Variant('s', genre),
105- 'year':GLib.Variant('i', year)})
106+ 'year':GLib.Variant('i', year),
107+ 'track_length': GLib.Variant('i', track_length),
108+ 'track_number': GLib.Variant('i', track_number)})
109 trackresults.append(track)
110
111 if album not in albumresults:
112 results.append({'uri': albumuri,
113 'icon': albumart,
114 'category': 1,
115- 'mimetype': mimetype,
116 'title': album,
117- 'comment': artist,
118 'album':GLib.Variant('s', album),
119 'artist':GLib.Variant('s', artist),
120 'genre':GLib.Variant('s', genre),
121- 'year':GLib.Variant('i', year)})
122+ 'year':GLib.Variant('i', year),
123+ 'track_length': GLib.Variant('i', track_length),
124+ 'track_number': GLib.Variant('i', track_number)})
125 albumresults.append(album)
126 return results
127
128
129-def activate(scope, uri):
130- import subprocess
131- albumtracks = []
132- albumtracks.append("gmusicbrowser")
133- albumtracks.append("-play")
134- albumtracks.append("-playlist")
135- # If uri starts with album:// then we need to play all the songs on it
136- if uri.startswith("album://"):
137- trackdetails = []
138- for track in tracks:
139- trackdetail = []
140- album = "album://" + track[5] + "/" + track[3]
141- if not album.find(uri) == -1:
142- albumtrack = track[1]
143- trackdetail.append(albumtrack)
144- trackdetail.append(track[8])
145- trackdetails.append(trackdetail)
146- trackdetails.sort(key=lambda track: int(track[1]))
147- for track in trackdetails:
148- albumtracks.append(track[0])
149- subprocess.Popen(albumtracks)
150- else:
151- albumtracks.append("file://" + uri)
152- subprocess.Popen(albumtracks)
153- return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH, goto_uri='')
154-
155-
156-def show_in_folder(scope, uri):
157- """ Shows the folder containing the selected track as requested from the Preview
158- """
159- if uri.startswith("album://"):
160- for track in tracks:
161- album = "album://" + track[2] + "/" + track[3]
162- if not album.find(uri) == -1:
163- filename = track[1]
164- continue
165- else:
166- filename = uri
167- dirname = os.path.dirname(filename)
168- dirname = dirname.replace("%20", "\ ")
169- os.system("xdg-open '%s'" % str(dirname))
170- return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH, goto_uri='')
171-
172-
173-def preview_uri(scope, uri):
174- """Preview request handler"""
175- albumtracks = []
176- isalbum = False
177- if uri.startswith("album://"):
178- isalbum = True
179- for track in tracks:
180- album = "album://" + track[2] + "/" + track[3]
181- if not album.find(uri) == -1:
182- albumtracks.append(track)
183- albumtracks.sort(key=lambda track: int(track[7]))
184- else:
185- for track in tracks:
186- album = "file://" + track[1]
187- if not album.find(uri) == -1:
188- albumtracks.append(track)
189- iteration = model.get_first_iter()
190- end_iter = model.get_last_iter()
191- while iteration != end_iter:
192- if model.get_value(iteration, 0) == uri:
193- title = model.get_value(iteration, 5)
194- description = model.get_value(iteration, 6)
195- if model.get_value(iteration, 1) == "musique":
196- image = "file:///usr/share/icons/hicolor/scalable/apps/audacious.svg"
197- else:
198- image = "file://%s" % model.get_value(iteration, 1)
199-
200- preview = Unity.MusicPreview.new(title, description, None)
201- preview.props.image_source_uri = image
202- for albumtrack in albumtracks:
203- if isalbum:
204- track = Unity.TrackMetadata.full("file://" + urllib.parse.unquote(str(albumtrack[1])), # uri
205- int(albumtrack[7]), # track number
206- albumtrack[0], # track title
207- albumtrack[2], # artist
208- albumtrack[3], # album
209- int(albumtrack[8]) / 1000) # track length
210- else:
211- preview = Unity.MusicPreview.new(albumtrack[0], "", None)
212- preview.props.image_source_uri = image
213- track = Unity.TrackMetadata.full("file://" + urllib.parse.unquote(str(albumtrack[1])),
214- int(albumtrack[7]),
215- albumtrack[0],
216- albumtrack[2],
217- albumtrack[3],
218- int(albumtrack[8]) / 1000)
219- preview.add_track(track)
220-
221- # Add the "Play" action
222- play_action = Unity.PreviewAction.new("activate_uri", "Play", None)
223- play_action.connect("activated", activate)
224- preview.add_action(play_action)
225-
226- # Add the "Show in folder" action
227- show_action = Unity.PreviewAction.new("show_in_folder", "Show In Folder", None)
228- show_action.connect("activated", show_in_folder)
229- preview.add_action(show_action)
230-
231- preview.connect("play", play)
232- preview.connect("pause", pause)
233- preview.connect("closed", closed)
234- break
235- iteration = model.next(iteration)
236- if preview is None:
237- print("Couldn't find model row for requested preview uri: '%s'", uri)
238- return preview
239-
240-
241-def play(preview, uri):
242- """Plays the selected track as selected in the Preview"""
243- player = self.bus.get_object(PREVIEW_PLAYER_DBUS_NAME, PREVIEW_PLAYER_DBUS_PATH)
244- dbus.Interface(player, PREVIEW_PLAYER_DBUS_IFACE).Play(uri)
245-
246-
247-def pause(preview, uri):
248- """Pauses the selected track as selected in the Preview"""
249- player = self.bus.get_object(PREVIEW_PLAYER_DBUS_NAME, PREVIEW_PLAYER_DBUS_PATH)
250- dbus.Interface(player, PREVIEW_PLAYER_DBUS_IFACE).Pause()
251-
252-
253-def closed(preview):
254- """Stops playing when the previre is closed"""
255- player = self.bus.get_object(PREVIEW_PLAYER_DBUS_NAME, PREVIEW_PLAYER_DBUS_PATH)
256- dbus.Interface(player, PREVIEW_PLAYER_DBUS_IFACE).Close()
257+class Preview(Unity.ResultPreviewer):
258+
259+ def do_run(self):
260+ global tracks
261+ album = self.result.metadata['album'].get_string()
262+ artist = self.result.metadata['artist'].get_string()
263+ preview = Unity.MusicPreview.new(self.result.title, '', None)
264+ preview.props.image_source_uri = self.result.icon_hint
265+ preview.props.subtitle = self.result.metadata['artist'].get_string()
266+ if self.result.uri.startswith("album://"):
267+ for track in tracks:
268+ if album in track[3] and artist in track[2]:
269+ track = Unity.TrackMetadata.full(track[1],
270+ int(track[9]),
271+ track[0],
272+ track[2],
273+ track[3],
274+ int(track[10]))
275+ preview.add_track(track)
276+ else:
277+ print(self.result.uri)
278+ track = Unity.TrackMetadata.full('file://%s' % self.result.uri.replace(' ', '%20'),
279+ self.result.metadata['track_number'].get_int32(),
280+ self.result.title,
281+ self.result.metadata['artist'].get_string(),
282+ self.result.metadata['album'].get_string(),
283+ self.result.metadata['track_length'].get_int32())
284+ preview.add_track(track)
285+
286+ view_action = Unity.PreviewAction.new("play", _("Play"), None)
287+ preview.add_action(view_action)
288+ show_action = Unity.PreviewAction.new("show", _("Show in Folder"), None)
289+ preview.add_action(show_action)
290+ return preview
291+
292
293 # Classes below this point establish communication
294 # with Unity, you probably shouldn't modify them.
295@@ -356,19 +270,8 @@
296 i['comment'] = ''
297 if not 'dnd_uri' in i or not i['dnd_uri'] or i['dnd_uri'] == '':
298 i['dnd_uri'] = i['uri']
299- i['metadata'] = {}
300- if EXTRA_METADATA:
301- for e in i:
302- for m in EXTRA_METADATA:
303- if m['id'] == e:
304- i['metadata'][e] = i[e]
305- i['metadata']['provider_credits'] = GLib.Variant('s', PROVIDER_CREDITS)
306- result = Unity.ScopeResult.create(str(i['uri']), str(i['icon']),
307- i['category'], i['result_type'],
308- str(i['mimetype']), str(i['title']),
309- str(i['comment']), str(i['dnd_uri']),
310- i['metadata'])
311- result_set.add_result(result)
312+ i['provider_credits'] = GLib.Variant('s', PROVIDER_CREDITS)
313+ result_set.add_result(**i)
314 except Exception as error:
315 print(error)
316
317@@ -424,6 +327,38 @@
318 se = MySearch(search_context)
319 return se
320
321+ def do_activate(self, result, metadata, id):
322+ album = result.metadata['album'].get_string()
323+ artist = result.metadata['artist'].get_string()
324+ global tracks
325+ if id == 'show':
326+ if result.uri.startswith("album://"):
327+ for track in tracks:
328+ if album in track[3] and artist in track[2]:
329+ filename = tracks[1]
330+ continue
331+ else:
332+ filename = result.uri
333+ dirname = os.path.dirname(filename)
334+ os.system("xdg-open '%s'" % str(dirname))
335+ else:
336+ albumtracks = ''
337+ if result.uri.startswith('album://'):
338+ for track in tracks:
339+ if album in track[3] and artist in track[2]:
340+ albumtracks = albumtracks + ' \'%s\'' % (track[1])
341+ else:
342+ albumtracks = '\'%s\'' % result.uri
343+ os.system('gmusicbrowser -play -playlist %s' % albumtracks)
344+
345+ return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH, goto_uri=None)
346+
347+ def do_create_previewer(self, result, metadata):
348+ rp = Preview()
349+ rp.set_scope_result(result)
350+ rp.set_search_metadata(metadata)
351+ return rp
352+
353
354 def load_scope():
355 return Scope()
356
357=== modified file 'tests/test_gmusicbrowser.py'
358--- tests/test_gmusicbrowser.py 2013-03-03 19:20:19 +0000
359+++ tests/test_gmusicbrowser.py 2013-04-22 13:23:30 +0000
360@@ -11,17 +11,18 @@
361 self.results = []
362
363 def do_add_result(self, result):
364- self.results.append({'uri':result.uri,
365- 'title':result.title,
366- 'comment':result.comment,
367- 'icon':result.icon_hint})
368+ self.results.append({'uri': result.uri,
369+ 'title': result.title,
370+ 'comment': result.comment,
371+ 'icon': result.icon_hint})
372+
373
374 class ScopeTestCase(TestCase):
375 def init_scope(self, scope_path):
376 self.scope_module = imp.load_source('scope', scope_path)
377 self.scope = self.scope_module.load_scope()
378
379- def perform_query(self, query, filter_set = Unity.FilterSet.new()):
380+ def perform_query(self, query, filter_set=Unity.FilterSet.new()):
381 result_set = ResultSet()
382 ctx = Unity.SearchContext.create(query, 0, filter_set,
383 None, result_set, None)
384@@ -30,7 +31,7 @@
385 return result_set
386
387
388-class TestAskUbuntu(ScopeTestCase):
389+class TestGmusicbrowser(ScopeTestCase):
390 def setUp(self):
391 self.init_scope('src/unity_gmusicbrowser_daemon.py')
392
393@@ -38,7 +39,7 @@
394 self.scope = None
395 self.scope_module = None
396
397- def test_questions_search(self):
398+ def test_qsearch(self):
399 self.scope_module.GMUSICBROWSER_DBFILE = 'tests/data/mock_gmusicbrowser_pass'
400 expected_results = ["/home/mark/Music/Jacques Dutronc/En Vogue/02. Mini, Mini, Mini.mp3",
401 "Mini, Mini, Mini"]
402@@ -49,8 +50,7 @@
403 results.append(result_set.results[0]['title'])
404 self.assertEqual(results, expected_results)
405
406-
407- def test_questions_failing_search(self):
408+ def test_failing_search(self):
409 self.scope_module.GMUSICBROWSER_DBFILE = 'tests/data/mock_gmusicbrowser_fail'
410 for s in ['upnriitnyt']:
411 result_set = self.perform_query(s)

Subscribers

People subscribed via source and target branches

to all changes: