A tool to sync music with your favorite devices
0
fork

Configure Feed

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

gtkgui: use new Device paradigm

Gee Sawra bca36412 687ecc03

+91 -116
+91 -116
src/gtkgui/gtkgui.rs
··· 456 456 (dialog, count_label, title_label, artist_label, album_label) 457 457 } 458 458 459 + use std::path::PathBuf; 460 + use std::str::FromStr; 461 + 459 462 async fn perform_sync( 460 463 parent: impl IsA<gtk::Window>, 461 464 source_db: Instance, 462 - dest_db: Instance, 463 465 dest_dir: String, 464 466 ipod_mode: bool, 465 467 ) { ··· 576 578 577 579 println!("Perform Sync: Diffing..."); 578 580 579 - // Debug source count 580 - if let Ok(tracks) = source_db 581 - .tracks_by_state(crate::model::FileState::Copied) 582 - .await 583 - { 584 - println!("Source DB has {} copied tracks", tracks.len()); 581 + // Initialize Device 582 + let dest_path = PathBuf::from_str(&dest_dir).unwrap(); 583 + let dest: Result<Box<dyn crate::device::Device>> = if ipod_mode { 584 + crate::device::IPod::new(dest_path).await 585 585 } else { 586 - println!("Failed to get source tracks count"); 587 - } 586 + crate::device::Disk::new(dest_path).await 587 + }; 588 588 589 - match sync::diff_databases(&dest_db, &source_db, None, false).await { 590 - Ok(to_copy_ids) => { 591 - match sync::diff_databases(&source_db, &dest_db, None, false).await { 592 - Ok(to_delete_ids) => { 589 + match dest { 590 + Ok(dest) => { 591 + // Load filters 592 + let filters = match source_db.filter().await { 593 + Ok(Some(raw)) => crate::filter::evaluate(vec![raw]).ok(), 594 + _ => None, 595 + }; 596 + 597 + // Fetch tracks 598 + let local_tracks_res = source_db 599 + .tracks_by_state(crate::model::FileState::Copied) 600 + .await 601 + .map_err(|e| anyhow::anyhow!(e)); 602 + let dest_tracks_res = dest.list_by_state(crate::model::FileState::Copied).await; 603 + 604 + match (local_tracks_res, dest_tracks_res) { 605 + (Ok(local_tracks), Ok(dest_tracks)) => { 606 + // Filter local tracks 607 + let local_tracks = 608 + match sync::filter_tracks(local_tracks, filters.as_ref(), true) { 609 + Ok(t) => t, 610 + Err(e) => { 611 + eprintln!("Error filtering tracks: {}", e); 612 + vec![] 613 + } 614 + }; 615 + 593 616 println!( 594 - "Perform Sync: Copy {}, Delete {}", 595 - to_copy_ids.len(), 596 - to_delete_ids.len() 617 + "Source DB has {} copied tracks (after filter)", 618 + local_tracks.len() 597 619 ); 598 - let total = to_copy_ids.len() + to_delete_ids.len(); 599 - let mut current = 0; 600 - let start_time = std::time::Instant::now(); 601 620 602 - // Deletion 603 - match dest_db.tracks_by_id(to_delete_ids).await { 604 - Ok(tracks) => { 605 - if let Ok(tracks) = sync::filter_tracks(tracks, None, true) { 606 - for track in tracks { 607 - update_ui( 608 - current, 609 - total, 610 - start_time, 611 - "Deleting...".to_string(), 612 - track.title.clone(), 613 - track.artist.clone(), 614 - track.album.clone(), 615 - ); 621 + let diff_res = db::diff_vec(local_tracks.clone(), dest_tracks.clone()).await; 622 + let rev_diff_res = 623 + db::diff_vec(dest_tracks.clone(), local_tracks.clone()).await; 616 624 617 - // let _ = sync::delete(track, &dest_db, &dest_dir).await; 618 - current += 1; 619 - // Yield 620 - glib::timeout_future(std::time::Duration::from_millis(1)).await; 625 + match (diff_res, rev_diff_res) { 626 + (Ok(to_copy), Ok(to_delete)) => { 627 + println!( 628 + "Perform Sync: Copy {}, Delete {}", 629 + to_copy.len(), 630 + to_delete.len() 631 + ); 632 + let total = to_copy.len() + to_delete.len(); 633 + let total_deletes = to_delete.len(); 634 + let total_copies = to_copy.len(); 635 + let mut current = 0; 636 + let start_time = std::time::Instant::now(); 637 + 638 + // Deletion 639 + for (i, track) in to_delete.into_iter().enumerate() { 640 + update_ui( 641 + current, 642 + total, 643 + start_time, 644 + format!("Deleting ({}/{})", i + 1, total_deletes), 645 + track.title.clone(), 646 + track.artist.clone(), 647 + track.album.clone(), 648 + ); 649 + 650 + if let Err(e) = dest.delete(track).await { 651 + eprintln!("Error deleting track: {}", e); 621 652 } 653 + current += 1; 654 + glib::timeout_future(std::time::Duration::from_millis(1)).await; 622 655 } 623 - } 624 - Err(e) => eprintln!("Error fetching delete tracks: {}", e), 625 - } 626 656 627 - // Copying 628 - match source_db.tracks_by_id(to_copy_ids).await { 629 - Ok(tracks) => { 630 - if let Ok(tracks) = sync::filter_tracks(tracks, None, false) { 631 - let tr_settings = if !ipod_mode { 632 - dest_db.get_transcoding_settings().await.ok().flatten() 633 - } else { 634 - Some(crate::ffmpeg::Quality { 635 - bitrate: crate::ffmpeg::Bitrate::VBR("5".to_owned()), 636 - sampling_rate: Some(crate::ffmpeg::SamplingRate::Rate441K), 637 - codec: crate::ffmpeg::Codec::AAC, 638 - }) 639 - }; 640 - 641 - let mut ipod_manager = if ipod_mode { 642 - crate::gpod::Manager::new(dest_dir.clone()).ok() 643 - } else { 644 - None 645 - }; 657 + // Copying 658 + for (i, track) in to_copy.into_iter().enumerate() { 659 + update_ui( 660 + current, 661 + total, 662 + start_time, 663 + format!("Syncing ({}/{})", i + 1, total_copies), 664 + track.title.clone(), 665 + track.artist.clone(), 666 + track.album.clone(), 667 + ); 646 668 647 - for track in tracks { 648 - update_ui( 649 - current, 650 - total, 651 - start_time, 652 - "Copying...".to_string(), 653 - track.title.clone(), 654 - track.artist.clone(), 655 - track.album.clone(), 656 - ); 657 - 658 - let dest_path = if let Some(ref ipm) = ipod_manager { 659 - let mut fp: std::path::PathBuf = 660 - track.file_path.clone().into(); 661 - if track.is_lossless() { 662 - fp.set_extension(crate::ffmpeg::Codec::AAC.extension()); 663 - } 664 - ipm.path_for_file(fp.as_path()).unwrap() 665 - } else { 666 - track.storage_path(&dest_dir).into() 667 - }; 668 - 669 - // match sync::copy( 670 - // &track, 671 - // &dest_db, 672 - // dest_path.clone(), 673 - // tr_settings.clone(), 674 - // ) 675 - // .await 676 - // { 677 - // Ok((copied_track, tr_res)) => { 678 - // if let Some(ref mut ipm) = ipod_manager { 679 - // let _ = ipm.finalize_track( 680 - // &copied_track, 681 - // dest_path, 682 - // copied_track.extension.clone(), 683 - // 44100, 684 - // 256, 685 - // tr_res 686 - // .and_then(|r| r.replaygain) 687 - // .map(|r| r.soundcheck_value()), 688 - // ); 689 - // } 690 - // } 691 - // Err(e) => eprintln!("Error copying track: {}", e), 692 - // } 693 - current += 1; 694 - // Yield 695 - glib::timeout_future(std::time::Duration::from_millis(1)).await; 669 + if let Err(e) = dest.add(track).await { 670 + eprintln!("Error adding track: {}", e); 696 671 } 672 + current += 1; 673 + glib::timeout_future(std::time::Duration::from_millis(1)).await; 697 674 } 698 675 } 699 - Err(e) => eprintln!("Error fetching copy tracks: {}", e), 676 + (Err(e), _) | (_, Err(e)) => eprintln!("Error diffing: {}", e), 700 677 } 701 678 } 702 - Err(e) => eprintln!("Error diffing (delete): {}", e), 679 + (Err(e), _) | (_, Err(e)) => eprintln!("Error fetching tracks: {}", e), 703 680 } 704 681 } 705 - Err(e) => eprintln!("Error diffing (copy): {}", e), 682 + Err(e) => eprintln!("Error creating device: {}", e), 706 683 } 707 684 708 685 println!("Perform Sync: Done."); ··· 1205 1182 1206 1183 // Start Button Logic 1207 1184 let source_db_state = source_db_state.clone(); 1208 - let dest_db_state = dest_db_state.clone(); 1209 1185 let dialog_weak = dialog.downgrade(); 1210 1186 let ipod_row_weak = ipod_row.downgrade(); 1211 1187 let dest_row_weak = dest_row.downgrade(); ··· 1221 1197 start_button.connect_clicked(move |_| { 1222 1198 println!("Start button clicked"); 1223 1199 let source_db = { source_db_state.borrow().clone() }; 1224 - let dest_db = { dest_db_state.borrow().clone() }; 1225 1200 let dialog_weak = dialog_weak.clone(); 1226 1201 let ipod_mode = ipod_row_weak 1227 1202 .upgrade() ··· 1235 1210 // Upgrade weak ref immediately to keep it alive during setup 1236 1211 let parent_strong = parent_weak.upgrade(); 1237 1212 1238 - if let (Some(source_db), Some(dest_db)) = (source_db, dest_db) { 1213 + if let Some(source_db) = source_db { 1239 1214 println!("DBs loaded, closing dialog"); 1240 1215 // Close the config dialog 1241 1216 if let Some(dialog) = dialog_weak.upgrade() { ··· 1245 1220 glib::MainContext::default().spawn_local(async move { 1246 1221 if let Some(parent) = parent_strong { 1247 1222 println!("Starting perform_sync"); 1248 - perform_sync(parent, source_db, dest_db, dest_dir, ipod_mode).await; 1223 + perform_sync(parent, source_db, dest_dir, ipod_mode).await; 1249 1224 } else { 1250 1225 eprintln!("Cannot start sync: No parent window found (weak upgrade failed)."); 1251 1226 } 1252 1227 }); 1253 1228 } else { 1254 - eprintln!("Source or Dest DB missing"); 1229 + eprintln!("Source DB missing"); 1255 1230 } 1256 1231 }); 1257 1232