From 54e743b87651c0587522ee9bbd67b40355fce9c3 Mon Sep 17 00:00:00 2001 From: Elias Projahn Date: Sun, 1 Nov 2020 11:04:31 +0100 Subject: [PATCH] Store tracks from tracks editor --- .../2020-09-27-201047_initial_schema/down.sql | 4 ++- .../2020-09-27-201047_initial_schema/up.sql | 8 +++++ src/backend.rs | 26 +++++++++++++++ src/database/database.rs | 33 +++++++++++++++++++ src/database/models.rs | 16 ++++++++- src/database/schema.rs | 12 +++++++ src/database/tables.rs | 9 +++++ src/dialogs/track_editor.rs | 6 ++-- src/dialogs/tracks_editor.rs | 23 +++++++++---- 9 files changed, 126 insertions(+), 11 deletions(-) diff --git a/migrations/2020-09-27-201047_initial_schema/down.sql b/migrations/2020-09-27-201047_initial_schema/down.sql index d65f341..4a556b3 100644 --- a/migrations/2020-09-27-201047_initial_schema/down.sql +++ b/migrations/2020-09-27-201047_initial_schema/down.sql @@ -16,4 +16,6 @@ DROP TABLE ensembles; DROP TABLE recordings; -DROP TABLE performances; \ No newline at end of file +DROP TABLE performances; + +DROP TABLE tracks; \ No newline at end of file diff --git a/migrations/2020-09-27-201047_initial_schema/up.sql b/migrations/2020-09-27-201047_initial_schema/up.sql index 2ac9eef..d9f5f53 100644 --- a/migrations/2020-09-27-201047_initial_schema/up.sql +++ b/migrations/2020-09-27-201047_initial_schema/up.sql @@ -59,4 +59,12 @@ CREATE TABLE performances ( person BIGINT REFERENCES persons(id), ensemble BIGINT REFERENCES ensembles(id), role BIGINT REFERENCES instruments(id) +); + +CREATE TABLE tracks ( + id BIGINT NOT NULL PRIMARY KEY, + file_name TEXT NOT NULL, + recording BIGINT NOT NULL REFERENCES recordings(id) ON DELETE CASCADE, + track_index INTEGER NOT NULL, + work_parts TEXT NOT NULL ); \ No newline at end of file diff --git a/src/backend.rs b/src/backend.rs index a9db728..d57c1ba 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -34,6 +34,8 @@ enum BackendAction { GetRecordingsForPerson(i64, Sender>>), GetRecordingsForEnsemble(i64, Sender>>), GetRecordingsForWork(i64, Sender>>), + AddTracks(i64, Vec, Sender>), + GetTracks(i64, Sender>>), Stop, } @@ -212,6 +214,20 @@ impl Backend { receiver.await? } + pub async fn add_tracks(&self, recording_id: i64, tracks: Vec) -> Result<()> { + let (sender, receiver) = oneshot::channel(); + self.unwrap_action_sender()? + .send(AddTracks(recording_id, tracks, sender))?; + receiver.await? + } + + pub async fn get_tracks(&self, recording_id: i64) -> Result> { + let (sender, receiver) = oneshot::channel(); + self.unwrap_action_sender()? + .send(GetTracks(recording_id, sender))?; + receiver.await? + } + pub async fn set_music_library_path(&self, path: PathBuf) -> Result<()> { self.music_library_path.replace(Some(path.clone())); self.set_state(BackendState::Loading); @@ -369,6 +385,16 @@ impl Backend { .send(db.get_recordings_for_work(id)) .expect("Failed to send result from database thread!"); } + AddTracks(recording_id, tracks, sender) => { + sender + .send(db.add_tracks(recording_id, tracks)) + .expect("Failed to send result from database thread!"); + } + GetTracks(recording_id, sender) => { + sender + .send(db.get_tracks(recording_id)) + .expect("Failed to send result from database thread!"); + } Stop => { break; } diff --git a/src/database/database.rs b/src/database/database.rs index 5247312..97ce3e8 100644 --- a/src/database/database.rs +++ b/src/database/database.rs @@ -3,6 +3,7 @@ use super::schema::*; use super::tables::*; use anyhow::{anyhow, Error, Result}; use diesel::prelude::*; +use std::convert::TryInto; embed_migrations!(); @@ -399,6 +400,38 @@ impl Database { Ok(recordings) } + pub fn add_tracks(&self, recording_id: i64, tracks: Vec) -> Result<()> { + for (index, track_description) in tracks.iter().enumerate() { + let track = Track { + id: rand::random(), + file_name: track_description.file_name.clone(), + recording: recording_id, + track_index: index.try_into().unwrap(), + work_parts: track_description + .work_parts + .iter() + .map(|i| i.to_string()) + .collect::>() + .join(","), + }; + + diesel::insert_into(tracks::table) + .values(track) + .execute(&self.c)?; + } + + Ok(()) + } + + pub fn get_tracks(&self, recording_id: i64) -> Result> { + let tracks = tracks::table + .filter(tracks::recording.eq(recording_id)) + .order_by(tracks::track_index) + .load::(&self.c)?; + + Ok(tracks.iter().map(|track| track.clone().into()).collect()) + } + fn defer_foreign_keys(&self) { diesel::sql_query("PRAGMA defer_foreign_keys = ON;") .execute(&self.c) diff --git a/src/database/models.rs b/src/database/models.rs index f9fc117..e0a79d5 100644 --- a/src/database/models.rs +++ b/src/database/models.rs @@ -183,7 +183,21 @@ impl From for RecordingInsertion { } #[derive(Debug, Clone)] -pub struct Track { +pub struct TrackDescription { pub work_parts: Vec, pub file_name: String, } + +impl From for TrackDescription { + fn from(track: Track) -> Self { + let mut work_parts = Vec::::new(); + for part in track.work_parts.split(",") { + work_parts.push(part.parse().unwrap()); + } + + TrackDescription { + work_parts, + file_name: track.file_name, + } + } +} diff --git a/src/database/schema.rs b/src/database/schema.rs index ab1085b..f44ac19 100644 --- a/src/database/schema.rs +++ b/src/database/schema.rs @@ -54,6 +54,16 @@ table! { } } +table! { + tracks (id) { + id -> BigInt, + file_name -> Text, + recording -> BigInt, + track_index -> Integer, + work_parts -> Text, + } +} + table! { work_parts (id) { id -> BigInt, @@ -90,6 +100,7 @@ joinable!(performances -> instruments (role)); joinable!(performances -> persons (person)); joinable!(performances -> recordings (recording)); joinable!(recordings -> works (work)); +joinable!(tracks -> recordings (recording)); joinable!(work_parts -> persons (composer)); joinable!(work_parts -> works (work)); joinable!(work_sections -> works (work)); @@ -103,6 +114,7 @@ allow_tables_to_appear_in_same_query!( performances, persons, recordings, + tracks, work_parts, work_sections, works, diff --git a/src/database/tables.rs b/src/database/tables.rs index 342a724..894a0c3 100644 --- a/src/database/tables.rs +++ b/src/database/tables.rs @@ -83,3 +83,12 @@ pub struct Performance { pub ensemble: Option, pub role: Option, } + +#[derive(Insertable, Queryable, Debug, Clone)] +pub struct Track { + pub id: i64, + pub file_name: String, + pub recording: i64, + pub track_index: i32, + pub work_parts: String, +} diff --git a/src/dialogs/track_editor.rs b/src/dialogs/track_editor.rs index 62816aa..cd7ba5a 100644 --- a/src/dialogs/track_editor.rs +++ b/src/dialogs/track_editor.rs @@ -11,10 +11,10 @@ pub struct TrackEditor { } impl TrackEditor { - pub fn new(parent: &W, track: Track, work: WorkDescription, callback: F) -> Self + pub fn new(parent: &W, track: TrackDescription, work: WorkDescription, callback: F) -> Self where W: IsA, - F: Fn(Track) -> () + 'static, + F: Fn(TrackDescription) -> () + 'static, { let builder = gtk::Builder::from_resource("/de/johrpan/musicus_editor/ui/track_editor.ui"); @@ -37,7 +37,7 @@ impl TrackEditor { let mut work_parts = work_parts.borrow_mut(); work_parts.sort(); - callback(Track { + callback(TrackDescription { work_parts: work_parts.clone(), file_name: file_name.clone(), }); diff --git a/src/dialogs/tracks_editor.rs b/src/dialogs/tracks_editor.rs index 6460375..d1e39fb 100644 --- a/src/dialogs/tracks_editor.rs +++ b/src/dialogs/tracks_editor.rs @@ -41,10 +41,10 @@ impl TracksEditor { })); let recording = Rc::new(RefCell::new(None::)); - let tracks = Rc::new(RefCell::new(Vec::::new())); + let tracks = Rc::new(RefCell::new(Vec::::new())); let track_list = List::new( - clone!(@strong recording => move |track: &Track| { + clone!(@strong recording => move |track: &TrackDescription| { let mut title_parts = Vec::::new(); for part in &track.work_parts { if let Some(recording) = &*recording.borrow() { @@ -122,9 +122,20 @@ impl TracksEditor { } )); - save_button.connect_clicked(clone!(@strong window => move |_| { - window.close(); - callback(); + let callback = Rc::new(callback); + save_button.connect_clicked(clone!(@strong window, @strong backend, @strong recording, @strong tracks, @strong callback => move |_| { + let context = glib::MainContext::default(); + let window = window.clone(); + let backend = backend.clone(); + let recording = recording.clone(); + let tracks = tracks.clone(); + let callback = callback.clone(); + context.spawn_local(async move { + backend.add_tracks(recording.borrow().as_ref().unwrap().id, tracks.borrow().clone()).await.unwrap(); + callback(); + window.close(); + }); + })); add_track_button.connect_clicked(clone!(@strong window, @strong tracks, @strong track_list, @strong autofill_parts => move |_| { @@ -144,7 +155,7 @@ impl TracksEditor { let mut tracks = tracks.borrow_mut(); for file_name in dialog.get_filenames() { let file_name = file_name.strip_prefix(&music_library_path).unwrap(); - tracks.insert(index, Track { + tracks.insert(index, TrackDescription { work_parts: Vec::new(), file_name: String::from(file_name.to_str().unwrap()), });