Merge lp:~mhr3/unity-lens-music/rb-proper-album-handling into lp:unity-lens-music

Proposed by Michal Hruby
Status: Merged
Approved by: Gord Allott
Approved revision: 82
Merged at revision: 81
Proposed branch: lp:~mhr3/unity-lens-music/rb-proper-album-handling
Merge into: lp:unity-lens-music
Diff against target: 307 lines (+149/-30)
2 files modified
src/rhythmbox-collection.vala (+107/-11)
src/rhythmbox-scope.vala (+42/-19)
To merge this branch: bzr merge lp:~mhr3/unity-lens-music/rb-proper-album-handling
Reviewer Review Type Date Requested Status
Gord Allott (community) Approve
Alex Launi (community) code-only Approve
Review via email: mp+103527@code.launchpad.net

Commit message

Rhythmbox scope: Implement proper album handling

Description of the change

Clicking on music lens's rhythmbox album results plays only random song from the album instead of all songs from the album.

This branch implements proper album handling for rhythmbox, which was missing in the original merge when the scope was merged before beta2.

No tests, as this would require rhythmbox's database and we don't have the infrastructure setup for that. But FWIW this only builds on top of the data structures already present /and tested/ in the scope.

To post a comment you must log in.
Revision history for this message
Alex Launi (alexlauni) wrote :

+1. Looks fine, couldn't test it. RB doesn't work on my machine.

review: Approve (code-only)
Revision history for this message
Gord Allott (gordallott) wrote :

+1, seems okay here

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/rhythmbox-collection.vala'
2--- src/rhythmbox-collection.vala 2012-04-23 12:34:57 +0000
3+++ src/rhythmbox-collection.vala 2012-04-25 17:47:20 +0000
4@@ -43,10 +43,12 @@
5
6 class RhythmboxCollection : Object
7 {
8+ const string UNKNOWN_ALBUM = "Unknown";
9
10 SequenceModel all_tracks;
11 ModelTag<int> album_art_tag;
12 FilterModel tracks_by_play_count;
13+ HashTable<string, GenericArray<ModelIter>> album_to_tracks_map;
14
15 TDB.Database album_art_tdb;
16 FileMonitor tdb_monitor;
17@@ -153,6 +155,9 @@
18 case "album-artist":
19 if (current_data >= 0) current_data = -1;
20 break;
21+ case "hidden":
22+ if (processing_song) processing_song = false;
23+ break;
24 case "entry":
25 if (processing_song && current_track != null)
26 {
27@@ -212,6 +217,9 @@
28 "s", "s", "i", "i", "i");
29 assert (all_tracks.get_schema ().length == Columns.N_COLUMNS);
30 album_art_tag = new ModelTag<int> (all_tracks);
31+ album_to_tracks_map =
32+ new HashTable<string, GenericArray<ModelIter>> (str_hash,
33+ str_equal);
34
35 var filter = Dee.Filter.new_sort ((row1, row2) =>
36 {
37@@ -333,6 +341,22 @@
38 return null;
39 }
40
41+ public SList<unowned string> get_album_tracks (string album_key)
42+ {
43+ SList<unowned string> results = new SList<unowned string> ();
44+
45+ var iter_arr = album_to_tracks_map[album_key];
46+ if (iter_arr != null)
47+ {
48+ for (int i = iter_arr.length - 1; i >= 0; i--)
49+ {
50+ results.prepend (all_tracks.get_string (iter_arr[i], Columns.URI));
51+ }
52+ }
53+
54+ return results;
55+ }
56+
57 private Variant cached_variant_for_string (string? input)
58 {
59 unowned string text = input != null ? input : "";
60@@ -436,6 +460,7 @@
61 all_tracks.clear ();
62 initialize_index ();
63 current_album_art_tag = 0;
64+ album_to_tracks_map.remove_all ();
65
66 var parser = new XmlParser ();
67 parser.track_info_ready.connect ((track) =>
68@@ -448,7 +473,17 @@
69 track.artwork_path = "audio-x-generic";
70
71 prepare_row_buffer (track);
72- all_tracks.append_row (row_buffer);
73+ var iter = all_tracks.append_row (row_buffer);
74+
75+ if (track.album == UNKNOWN_ALBUM) return;
76+ var album_key = "%s - %s".printf (track.album, track.album_artist != null ? track.album_artist : track.artist);
77+ var arr = album_to_tracks_map[album_key];
78+ if (arr == null)
79+ {
80+ arr = new GenericArray<ModelIter> ();
81+ album_to_tracks_map[album_key] = arr;
82+ }
83+ arr.add (iter);
84 });
85
86 var file = File.new_for_path (path);
87@@ -468,10 +503,28 @@
88 {
89 warning ("Error while parsing rhythmbox DB: %s", err.message);
90 }
91+
92+ GLib.List<unowned string> all_albums = album_to_tracks_map.get_keys ();
93+ foreach (unowned string s in all_albums)
94+ {
95+ album_to_tracks_map[s].sort_with_data ((ref a, ref b) =>
96+ {
97+ var trackno1 = all_tracks.get_int32 (a, Columns.TRACK_NUMBER);
98+ var trackno2 = all_tracks.get_int32 (b, Columns.TRACK_NUMBER);
99+
100+ return trackno1 - trackno2;
101+ });
102+ }
103+ }
104+
105+ private enum ResultType
106+ {
107+ ALBUM,
108+ SONG
109 }
110
111 private void add_result (Model results_model, Model model,
112- ModelIter iter, Columns title_col,
113+ ModelIter iter, ResultType result_type,
114 uint category_id)
115 {
116 // check for updated album art
117@@ -503,13 +556,35 @@
118 album_art_tag[model, iter] = current_album_art_tag;
119 }
120
121- results_model.append (model.get_string (iter, Columns.URI),
122+ var title_col = result_type == ResultType.SONG ?
123+ Columns.TITLE : Columns.ALBUM;
124+ unowned string title = model.get_string (iter, title_col);
125+ var uri = model.get_string (iter, Columns.URI);
126+ var dnd_uri = model.get_string (iter, Columns.URI);
127+ if (result_type == ResultType.ALBUM)
128+ {
129+ if (title == UNKNOWN_ALBUM) return;
130+ unowned string artist = model.get_string (iter,
131+ Columns.ALBUM_ARTIST);
132+ if (artist == "")
133+ artist = model.get_string (iter, Columns.ARTIST);
134+ var album_key = "%s - %s".printf (title, artist);
135+ StringBuilder sb = new StringBuilder ();
136+ foreach (unowned string track_uri in get_album_tracks (album_key))
137+ {
138+ sb.append_printf ("%s\r\n", track_uri);
139+ }
140+ dnd_uri = (owned) sb.str;
141+ uri = "album://%s".printf (album_key);
142+ }
143+
144+ results_model.append (uri,
145 model.get_string (iter, Columns.ARTWORK),
146 category_id,
147 model.get_string (iter, Columns.MIMETYPE),
148- model.get_string (iter, title_col),
149+ title,
150 model.get_string (iter, Columns.ARTIST),
151- model.get_string (iter, Columns.URI));
152+ dnd_uri);
153 }
154
155 public void search (LensSearch search,
156@@ -528,6 +603,14 @@
157 get_decade_filter (filters, out min_year, out max_year);
158 var active_genres = get_genre_filter (filters);
159
160+ // we need this to be able to sort the albums properly
161+ var helper_model = search.results_model;
162+ if (category_override >= 0)
163+ {
164+ helper_model = new Dee.SequenceModel ();
165+ helper_model.set_schema_full (search.results_model.get_schema ());
166+ }
167+
168 if (empty_search)
169 {
170 // display a couple of most played songs
171@@ -568,14 +651,14 @@
172 category_override : Category.ALBUMS;
173
174 add_result (search.results_model, model, iter,
175- Columns.ALBUM, category_id);
176+ ResultType.ALBUM, category_id);
177 }
178
179 category_id = category_override >= 0 ?
180 category_override : Category.SONGS;
181
182- add_result (search.results_model, model, iter,
183- Columns.TITLE, category_id);
184+ add_result (helper_model, model, iter,
185+ ResultType.SONG, category_id);
186
187 num_results++;
188 if (max_results >= 0 && num_results >= max_results) break;
189@@ -660,20 +743,33 @@
190 category_override : Category.ALBUMS;
191
192 add_result (search.results_model, model, model_iter,
193- Columns.ALBUM, category_id);
194+ ResultType.ALBUM, category_id);
195 }
196
197 category_id = category_override >= 0 ?
198 category_override : Category.SONGS;
199
200- add_result (search.results_model, model, model_iter,
201- Columns.TITLE, category_id);
202+ add_result (helper_model, model, model_iter,
203+ ResultType.SONG, category_id);
204
205 num_results++;
206 if (max_results >= 0 && num_results >= max_results) break;
207
208 seq_iter = seq_iter.next ();
209 }
210+
211+ if (helper_model == search.results_model) return;
212+
213+ // we need to do this because the dash doesn't care about position
214+ // of a newly added rows in the model - it just appends it
215+ var iter = helper_model.get_first_iter ();
216+ var last = helper_model.get_last_iter ();
217+ while (iter != last)
218+ {
219+ var row = helper_model.get_row (iter);
220+ search.results_model.append_row (row);
221+ iter = helper_model.next (iter);
222+ }
223 }
224
225 private void get_decade_filter (GLib.List<FilterParser> filters,
226
227=== modified file 'src/rhythmbox-scope.vala'
228--- src/rhythmbox-scope.vala 2012-04-23 12:34:57 +0000
229+++ src/rhythmbox-scope.vala 2012-04-25 17:47:20 +0000
230@@ -45,35 +45,58 @@
231 protected override int num_results_global_search { get { return 20; } }
232 protected override int num_results_lens_search { get { return 50; } }
233
234+ private async void prepare_rhythmbox_play_queue (string[] main_exec)
235+ {
236+ Thread.create<void> (() =>
237+ {
238+ try
239+ {
240+ Process.spawn_command_line_sync ("rhythmbox-client --pause");
241+ Process.spawn_command_line_sync ("rhythmbox-client --clear-queue");
242+ Process.spawn_sync (null, main_exec, null, SpawnFlags.SEARCH_PATH,
243+ null, null);
244+ Process.spawn_command_line_sync ("rhythmbox-client --next");
245+ // make sure we're playing
246+ Process.spawn_command_line_sync ("rhythmbox-client --play");
247+ }
248+ catch (Error err)
249+ {
250+ warning ("%s", err.message);
251+ }
252+ Idle.add (prepare_rhythmbox_play_queue.callback);
253+ }, false);
254+ yield;
255+ }
256 /**
257 * Tells banshee to play the selected uri(s)
258 */
259 public Unity.ActivationResponse activate (string uri)
260 {
261- string[] exec = {"rhythmbox-client", "--play-uri"};
262+ string[] exec = {"rhythmbox-client"};
263
264- try {
265+ try
266+ {
267 if (Uri.parse_scheme (uri) == "album")
268- {
269- debug (@"searching for tracks for $uri");
270- string[] split = uri.split ("/");
271- string artist = split[2];
272- string title = split[3];
273-
274- Album album = new Album ();
275- album.artist = artist;
276- album.title = title;
277- // FIXME there must be a better way..
278-// foreach (string track in collection.get_track_uris (album))
279-// exec += track;
280- }
281+ {
282+ // this will be a bit crazy, let's do it in a separate thread
283+ exec += "--enqueue";
284+ string album_key = uri.substring (8);
285+ foreach (unowned string track_uri in collection.get_album_tracks (album_key))
286+ {
287+ exec += track_uri;
288+ }
289+ exec += null;
290+ prepare_rhythmbox_play_queue.begin (exec);
291+ return new Unity.ActivationResponse (Unity.HandledType.HIDE_DASH);
292+ }
293 else
294- {
295+ {
296+ exec += "--play-uri";
297 exec += uri;
298- }
299-
300+ }
301+
302 exec += null;
303-
304+
305 debug ("Spawning rb '%s'", string.joinv (" ", exec));
306 Process.spawn_async (null,
307 exec,

Subscribers

People subscribed via source and target branches

to all changes: