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

Proposed by Mark Tully
Status: Merged
Approved by: David Callé
Approved revision: 29
Merged at revision: 28
Proposed branch: lp:~submarine/unity-scope-audacious/audacious-previews
Merge into: lp:unity-scope-audacious
Diff against target: 401 lines (+111/-168)
3 files modified
data/audacious.scope.in (+1/-1)
src/unity_audacious_daemon.py (+101/-158)
tests/test_audacious.py (+9/-9)
To merge this branch: bzr merge lp:~submarine/unity-scope-audacious/audacious-previews
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
David Callé Approve
Review via email: mp+159941@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 :

+1

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

Subscribers

People subscribed via source and target branches

to all changes: