···2020- Respect user's locale time
2121- Allow pressing play to start the current playlist
2222- Make sidebar not focusable by mouse
2323+- Make sorting 3-4x faster
2324- Fix covers updates sometimes not being reflected in the queue panel
2425- Fix dragging tracks to up next/autoplay queue boundary
2526- Fix button edge not clickable due to zoom
+39-33
src-native/sort.rs
···8686 }
8787}
88888989+struct SortItem<'a> {
9090+ item_id: ItemId,
9191+ track: &'a Track,
9292+}
9393+8994pub fn sort(options: TracksPageOptions, library: &Library) -> Result<Vec<ItemId>> {
9095 let now = Instant::now();
91969297 let id_map = TRACK_ID_MAP.read().unwrap();
9898+ let tracks = library.get_tracks();
93999494- let mut item_ids = get_tracklist_item_ids(library, &options.playlist_id)?;
9595- let item_count = item_ids.len();
100100+ let mut items: Vec<_> = get_tracklist_item_ids(library, &options.playlist_id)?
101101+ .into_iter()
102102+ .map(|id| SortItem {
103103+ item_id: id,
104104+ track: tracks
105105+ .get(&id_map[id as usize])
106106+ .expect("Track ID non-existant"),
107107+ })
108108+ .collect();
109109+ let item_count = items.len();
9611097111 if options.sort_key == "index" {
98112 // Note: Indexes descend from "first to last", unlike
99113 // other numbers which ascend from "high to low"
100114 if !options.sort_desc {
101101- item_ids.reverse();
115115+ items.reverse();
102116 }
103103- println!("Sort: {}ms", now.elapsed().as_millis());
117117+ println!("Sort: {:.3}ms", now.elapsed().as_secs_f32() * 1000.0);
118118+ let item_ids = items.into_iter().map(|item| item.item_id).collect();
104119 return Ok(item_ids);
105120 }
106121107107- let tracks = library.get_tracks();
108122 let field = get_track_field_type(&options.sort_key)?;
109123 let group_album_tracks = options.group_album_tracks
110124 && match options.sort_key.as_str() {
111125 "dateAdded" | "albumName" | "comments" | "genre" | "year" | "artist" => true,
112126 _ => false,
113127 };
114114- item_ids.sort_by(|&id_a, &id_b| {
115115- let track_id_a = &id_map[id_a as usize];
116116- let track_id_b = &id_map[id_b as usize];
117117- let track_a = tracks.get(track_id_a).expect("Track ID non-existant (1)");
118118- let track_b = tracks.get(track_id_b).expect("Track ID non-existant (2)");
119119- compare_track_field(track_a, track_b, &options.sort_key, &field)
128128+ items.sort_by(|a, b| {
129129+ return compare_track_field(a.track, b.track, &options.sort_key, &field);
120130 });
121131122132 if options.sort_desc {
123123- item_ids.reverse();
133133+ items.reverse();
124134 }
125135126136 if group_album_tracks {
127127- let mut grouped_track_ids: Vec<ItemId> = Vec::with_capacity(item_ids.len());
128128- let mut item_ids_iter = item_ids.into_iter().peekable();
137137+ let mut post_grouped_items: Vec<_> = Vec::with_capacity(items.len());
138138+ let mut items_iter = items.into_iter().peekable();
129139130140 // Process the first track in the next album
131131- while let Some(first_item_id) = item_ids_iter.next() {
141141+ while let Some(first_item) = items_iter.next() {
142142+ let first_track = first_item.track;
132143 // We need to get the first track to compare with the later tracks
133133- let first_track_id = &id_map[first_item_id as usize];
134134- let first_track = tracks.get(first_track_id).unwrap();
135135- let mut current_album_buffer: Vec<ItemId> = vec![first_item_id];
144144+ let mut current_album_buffer: Vec<SortItem> = vec![first_item];
136145137146 // Collect the rest of the tracks from the same album
138138- while let Some(item_id) = item_ids_iter.peek() {
139139- let track_id = &id_map[*item_id as usize];
140140- let track = tracks.get(track_id).unwrap();
141141- if !track.is_same_album(first_track) {
147147+ while let Some(item) = items_iter.peek() {
148148+ if !item.track.is_same_album(first_track) {
142149 break;
143150 }
144144- current_album_buffer.push(*item_id);
145145- item_ids_iter.next();
151151+ let item = items_iter.next().unwrap();
152152+ current_album_buffer.push(item);
146153 }
147154148155 // Sort album tracks by discNum, then trackNum
149149- current_album_buffer.sort_by(|&id_a, &id_b| {
150150- let track_a = tracks.get(&id_map[id_a as usize]).unwrap();
151151- let track_b = tracks.get(&id_map[id_b as usize]).unwrap();
152152- let mut order = compare_track_field(track_a, track_b, "discNum", &TrackField::U32);
156156+ current_album_buffer.sort_by(|a, b| {
157157+ let mut order = compare_track_field(a.track, b.track, "discNum", &TrackField::U32);
153158 if order == Ordering::Equal {
154154- order = compare_track_field(track_a, track_b, "trackNum", &TrackField::U32);
159159+ order = compare_track_field(a.track, b.track, "trackNum", &TrackField::U32);
155160 }
156161 order
157162 });
158163159159- grouped_track_ids.append(&mut current_album_buffer);
164164+ post_grouped_items.append(&mut current_album_buffer);
160165 }
161166162162- assert_eq!(item_count, grouped_track_ids.len());
163163- item_ids = grouped_track_ids;
167167+ assert_eq!(item_count, post_grouped_items.len());
168168+ items = post_grouped_items;
164169 }
165170166166- println!("Sort group: {}ms", now.elapsed().as_millis());
171171+ println!("Sort: {}ms", now.elapsed().as_millis());
172172+ let item_ids = items.into_iter().map(|item| item.item_id).collect();
167173 return Ok(item_ids);
168174}
169175