[READ-ONLY] Mirror of https://github.com/probablykasper/ferrum. Music library app for Mac, Linux and Windows ferrum.kasper.space
electron linux macos music music-library music-player napi windows
0

Configure Feed

Select the types of activity you want to include in your feed.

Make sorting faster

Kasper (Oct 6, 2024, 7:15 AM +0200) 1d4f6bf1 ca7f8cd7

+40 -33
+1
CHANGELOG.md
··· 20 20 - Respect user's locale time 21 21 - Allow pressing play to start the current playlist 22 22 - Make sidebar not focusable by mouse 23 + - Make sorting 3-4x faster 23 24 - Fix covers updates sometimes not being reflected in the queue panel 24 25 - Fix dragging tracks to up next/autoplay queue boundary 25 26 - Fix button edge not clickable due to zoom
+39 -33
src-native/sort.rs
··· 86 86 } 87 87 } 88 88 89 + struct SortItem<'a> { 90 + item_id: ItemId, 91 + track: &'a Track, 92 + } 93 + 89 94 pub fn sort(options: TracksPageOptions, library: &Library) -> Result<Vec<ItemId>> { 90 95 let now = Instant::now(); 91 96 92 97 let id_map = TRACK_ID_MAP.read().unwrap(); 98 + let tracks = library.get_tracks(); 93 99 94 - let mut item_ids = get_tracklist_item_ids(library, &options.playlist_id)?; 95 - let item_count = item_ids.len(); 100 + let mut items: Vec<_> = get_tracklist_item_ids(library, &options.playlist_id)? 101 + .into_iter() 102 + .map(|id| SortItem { 103 + item_id: id, 104 + track: tracks 105 + .get(&id_map[id as usize]) 106 + .expect("Track ID non-existant"), 107 + }) 108 + .collect(); 109 + let item_count = items.len(); 96 110 97 111 if options.sort_key == "index" { 98 112 // Note: Indexes descend from "first to last", unlike 99 113 // other numbers which ascend from "high to low" 100 114 if !options.sort_desc { 101 - item_ids.reverse(); 115 + items.reverse(); 102 116 } 103 - println!("Sort: {}ms", now.elapsed().as_millis()); 117 + println!("Sort: {:.3}ms", now.elapsed().as_secs_f32() * 1000.0); 118 + let item_ids = items.into_iter().map(|item| item.item_id).collect(); 104 119 return Ok(item_ids); 105 120 } 106 121 107 - let tracks = library.get_tracks(); 108 122 let field = get_track_field_type(&options.sort_key)?; 109 123 let group_album_tracks = options.group_album_tracks 110 124 && match options.sort_key.as_str() { 111 125 "dateAdded" | "albumName" | "comments" | "genre" | "year" | "artist" => true, 112 126 _ => false, 113 127 }; 114 - item_ids.sort_by(|&id_a, &id_b| { 115 - let track_id_a = &id_map[id_a as usize]; 116 - let track_id_b = &id_map[id_b as usize]; 117 - let track_a = tracks.get(track_id_a).expect("Track ID non-existant (1)"); 118 - let track_b = tracks.get(track_id_b).expect("Track ID non-existant (2)"); 119 - compare_track_field(track_a, track_b, &options.sort_key, &field) 128 + items.sort_by(|a, b| { 129 + return compare_track_field(a.track, b.track, &options.sort_key, &field); 120 130 }); 121 131 122 132 if options.sort_desc { 123 - item_ids.reverse(); 133 + items.reverse(); 124 134 } 125 135 126 136 if group_album_tracks { 127 - let mut grouped_track_ids: Vec<ItemId> = Vec::with_capacity(item_ids.len()); 128 - let mut item_ids_iter = item_ids.into_iter().peekable(); 137 + let mut post_grouped_items: Vec<_> = Vec::with_capacity(items.len()); 138 + let mut items_iter = items.into_iter().peekable(); 129 139 130 140 // Process the first track in the next album 131 - while let Some(first_item_id) = item_ids_iter.next() { 141 + while let Some(first_item) = items_iter.next() { 142 + let first_track = first_item.track; 132 143 // We need to get the first track to compare with the later tracks 133 - let first_track_id = &id_map[first_item_id as usize]; 134 - let first_track = tracks.get(first_track_id).unwrap(); 135 - let mut current_album_buffer: Vec<ItemId> = vec![first_item_id]; 144 + let mut current_album_buffer: Vec<SortItem> = vec![first_item]; 136 145 137 146 // Collect the rest of the tracks from the same album 138 - while let Some(item_id) = item_ids_iter.peek() { 139 - let track_id = &id_map[*item_id as usize]; 140 - let track = tracks.get(track_id).unwrap(); 141 - if !track.is_same_album(first_track) { 147 + while let Some(item) = items_iter.peek() { 148 + if !item.track.is_same_album(first_track) { 142 149 break; 143 150 } 144 - current_album_buffer.push(*item_id); 145 - item_ids_iter.next(); 151 + let item = items_iter.next().unwrap(); 152 + current_album_buffer.push(item); 146 153 } 147 154 148 155 // Sort album tracks by discNum, then trackNum 149 - current_album_buffer.sort_by(|&id_a, &id_b| { 150 - let track_a = tracks.get(&id_map[id_a as usize]).unwrap(); 151 - let track_b = tracks.get(&id_map[id_b as usize]).unwrap(); 152 - let mut order = compare_track_field(track_a, track_b, "discNum", &TrackField::U32); 156 + current_album_buffer.sort_by(|a, b| { 157 + let mut order = compare_track_field(a.track, b.track, "discNum", &TrackField::U32); 153 158 if order == Ordering::Equal { 154 - order = compare_track_field(track_a, track_b, "trackNum", &TrackField::U32); 159 + order = compare_track_field(a.track, b.track, "trackNum", &TrackField::U32); 155 160 } 156 161 order 157 162 }); 158 163 159 - grouped_track_ids.append(&mut current_album_buffer); 164 + post_grouped_items.append(&mut current_album_buffer); 160 165 } 161 166 162 - assert_eq!(item_count, grouped_track_ids.len()); 163 - item_ids = grouped_track_ids; 167 + assert_eq!(item_count, post_grouped_items.len()); 168 + items = post_grouped_items; 164 169 } 165 170 166 - println!("Sort group: {}ms", now.elapsed().as_millis()); 171 + println!("Sort: {}ms", now.elapsed().as_millis()); 172 + let item_ids = items.into_iter().map(|item| item.item_id).collect(); 167 173 return Ok(item_ids); 168 174 } 169 175