Use track set for recording screen

This commit is contained in:
Elias Projahn 2021-01-16 15:08:12 +01:00
parent aa6b5c6ac4
commit f69cb38b57
6 changed files with 108 additions and 106 deletions

View file

@ -175,33 +175,22 @@ impl Database {
Ok(()) Ok(())
} }
/// Get all tracks for a recording. /// Get all available track sets for a recording.
pub fn get_tracks(&self, recording_id: &str) -> Result<Vec<Track>> { pub fn get_track_sets(&self, recording_id: &str) -> Result<Vec<TrackSet>> {
let mut tracks: Vec<Track> = Vec::new(); let mut track_sets: Vec<TrackSet> = Vec::new();
let rows = tracks::table let rows = track_sets::table
.inner_join(track_sets::table.on(track_sets::id.eq(tracks::track_set)))
.inner_join(recordings::table.on(recordings::id.eq(track_sets::recording))) .inner_join(recordings::table.on(recordings::id.eq(track_sets::recording)))
.filter(recordings::id.eq(recording_id)) .filter(recordings::id.eq(recording_id))
.select(tracks::table::all_columns()) .select(track_sets::table::all_columns())
.load::<TrackRow>(&self.connection)?; .load::<TrackSetRow>(&self.connection)?;
for row in rows { for row in rows {
let work_parts = row let track_set = self.get_track_set_from_row(row)?;
.work_parts track_sets.push(track_set);
.split(',')
.map(|part_index| Ok(str::parse(part_index)?))
.collect::<Result<Vec<usize>>>()?;
let track = Track {
work_parts,
path: row.path.clone(),
};
tracks.push(track);
} }
Ok(tracks) Ok(track_sets)
} }
/// Retrieve all available information on a medium from related tables. /// Retrieve all available information on a medium from related tables.
@ -214,36 +203,7 @@ impl Database {
let mut track_sets = Vec::new(); let mut track_sets = Vec::new();
for track_set_row in track_set_rows { for track_set_row in track_set_rows {
let recording_id = &track_set_row.recording; let track_set = self.get_track_set_from_row(track_set_row)?;
let recording = self
.get_recording(recording_id)?
.ok_or_else(|| anyhow!("No recording with ID: {}", recording_id))?;
let track_rows = tracks::table
.filter(tracks::id.eq(&track_set_row.id))
.order_by(tracks::index)
.load::<TrackRow>(&self.connection)?;
let mut tracks = Vec::new();
for track_row in track_rows {
let work_parts = track_row
.work_parts
.split(',')
.map(|part_index| Ok(str::parse(part_index)?))
.collect::<Result<Vec<usize>>>()?;
let track = Track {
work_parts,
path: track_row.path.clone(),
};
tracks.push(track);
}
let track_set = TrackSet { recording, tracks };
track_sets.push(track_set); track_sets.push(track_set);
} }
@ -256,4 +216,39 @@ impl Database {
Ok(medium) Ok(medium)
} }
/// Convert a track set row from the database to an actual track set.
fn get_track_set_from_row(&self, row: TrackSetRow) -> Result<TrackSet> {
let recording_id = row.recording;
let recording = self
.get_recording(&recording_id)?
.ok_or_else(|| anyhow!("No recording with ID: {}", recording_id))?;
let track_rows = tracks::table
.filter(tracks::track_set.eq(row.id))
.order_by(tracks::index)
.load::<TrackRow>(&self.connection)?;
let mut tracks = Vec::new();
for track_row in track_rows {
let work_parts = track_row
.work_parts
.split(',')
.map(|part_index| Ok(str::parse(part_index)?))
.collect::<Result<Vec<usize>>>()?;
let track = Track {
work_parts,
path: track_row.path,
};
tracks.push(track);
}
let track_set = TrackSet { recording, tracks };
Ok(track_set)
}
} }

View file

@ -31,7 +31,7 @@ enum Action {
UpdateMedium(Medium, Sender<Result<()>>), UpdateMedium(Medium, Sender<Result<()>>),
GetMedium(String, Sender<Result<Option<Medium>>>), GetMedium(String, Sender<Result<Option<Medium>>>),
DeleteMedium(String, Sender<Result<()>>), DeleteMedium(String, Sender<Result<()>>),
GetTracks(String, Sender<Result<Vec<Track>>>), GetTrackSets(String, Sender<Result<Vec<TrackSet>>>),
Stop(Sender<()>), Stop(Sender<()>),
} }
@ -134,8 +134,8 @@ impl DbThread {
DeleteMedium(id, sender) => { DeleteMedium(id, sender) => {
sender.send(db.delete_medium(&id)).unwrap(); sender.send(db.delete_medium(&id)).unwrap();
} }
GetTracks(recording_id, sender) => { GetTrackSets(recording_id, sender) => {
sender.send(db.get_tracks(&recording_id)).unwrap(); sender.send(db.get_track_sets(&recording_id)).unwrap();
} }
Stop(sender) => { Stop(sender) => {
sender.send(()).unwrap(); sender.send(()).unwrap();
@ -339,10 +339,10 @@ impl DbThread {
receiver.await? receiver.await?
} }
/// Get all tracks for a recording. /// Get all track sets for a recording.
pub async fn get_tracks(&self, recording_id: &str) -> Result<Vec<Track>> { pub async fn get_track_sets(&self, recording_id: &str) -> Result<Vec<TrackSet>> {
let (sender, receiver) = oneshot::channel(); let (sender, receiver) = oneshot::channel();
self.action_sender.send(GetTracks(recording_id.to_owned(), sender))?; self.action_sender.send(GetTrackSets(recording_id.to_owned(), sender))?;
receiver.await? receiver.await?
} }

View file

@ -8,8 +8,7 @@ use std::rc::Rc;
#[derive(Clone)] #[derive(Clone)]
pub struct PlaylistItem { pub struct PlaylistItem {
pub tracks: TrackSet, pub track_set: TrackSet,
pub file_names: Vec<String>,
pub indices: Vec<usize>, pub indices: Vec<usize>,
} }
@ -249,7 +248,7 @@ impl Player {
"file://{}", "file://{}",
self.music_library_path self.music_library_path
.join( .join(
self.playlist.borrow()[current_item].file_names[current_track].clone(), self.playlist.borrow()[current_item].track_set.tracks[current_track].path.clone(),
) )
.to_str() .to_str()
.unwrap(), .unwrap(),

View file

@ -215,17 +215,17 @@ impl PlayerScreen {
elements.push(PlaylistElement { elements.push(PlaylistElement {
item: item_index, item: item_index,
track: 0, track: 0,
title: item.tracks.recording.work.get_title(), title: item.track_set.recording.work.get_title(),
subtitle: Some(item.tracks.recording.get_performers()), subtitle: Some(item.track_set.recording.get_performers()),
playable: false, playable: false,
}); });
for track_index in &item.indices { for track_index in &item.indices {
let track = &item.tracks.tracks[*track_index]; let track = &item.track_set.tracks[*track_index];
let mut parts = Vec::<String>::new(); let mut parts = Vec::<String>::new();
for part in &track.work_parts { for part in &track.work_parts {
parts.push(item.tracks.recording.work.parts[*part].title.clone()); parts.push(item.track_set.recording.work.parts[*part].title.clone());
} }
let title = if parts.is_empty() { let title = if parts.is_empty() {
@ -264,20 +264,20 @@ impl PlayerScreen {
next_button.set_sensitive(player.has_next()); next_button.set_sensitive(player.has_next());
let item = &playlist.borrow()[current_item]; let item = &playlist.borrow()[current_item];
let track = &item.tracks.tracks[current_track]; let track = &item.track_set.tracks[current_track];
let mut parts = Vec::<String>::new(); let mut parts = Vec::<String>::new();
for part in &track.work_parts { for part in &track.work_parts {
parts.push(item.tracks.recording.work.parts[*part].title.clone()); parts.push(item.track_set.recording.work.parts[*part].title.clone());
} }
let mut title = item.tracks.recording.work.get_title(); let mut title = item.track_set.recording.work.get_title();
if !parts.is_empty() { if !parts.is_empty() {
title = format!("{}: {}", title, parts.join(", ")); title = format!("{}: {}", title, parts.join(", "));
} }
title_label.set_text(&title); title_label.set_text(&title);
subtitle_label.set_text(&item.tracks.recording.get_performers()); subtitle_label.set_text(&item.track_set.recording.get_performers());
position_label.set_text("0:00"); position_label.set_text("0:00");
self_item.replace(current_item); self_item.replace(current_item);

View file

@ -17,7 +17,7 @@ pub struct RecordingScreen {
recording: Recording, recording: Recording,
widget: gtk::Box, widget: gtk::Box,
stack: gtk::Stack, stack: gtk::Stack,
tracks: RefCell<Vec<Track>>, track_sets: RefCell<Vec<TrackSet>>,
navigator: RefCell<Option<Rc<Navigator>>>, navigator: RefCell<Option<Rc<Navigator>>>,
} }
@ -56,35 +56,43 @@ impl RecordingScreen {
recording, recording,
widget, widget,
stack, stack,
tracks: RefCell::new(Vec::new()), track_sets: RefCell::new(Vec::new()),
navigator: RefCell::new(None), navigator: RefCell::new(None),
}); });
list.set_make_widget(clone!(@strong result => move |track: &Track| { list.set_make_widget(clone!(@strong result => move |track_set: &TrackSet| {
let mut title_parts = Vec::<String>::new();
for part in &track.work_parts {
title_parts.push(result.recording.work.parts[*part].title.clone());
}
let title = if title_parts.is_empty() {
gettext("Unknown")
} else {
title_parts.join(", ")
};
let title_label = gtk::Label::new(Some(&title));
title_label.set_ellipsize(pango::EllipsizeMode::End);
title_label.set_halign(gtk::Align::Start);
let file_name_label = gtk::Label::new(Some(&track.path));
file_name_label.set_ellipsize(pango::EllipsizeMode::End);
file_name_label.set_opacity(0.5);
file_name_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0); let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.set_border_width(6); vbox.set_border_width(6);
vbox.add(&title_label); vbox.set_spacing(6);
vbox.add(&file_name_label);
for track in &track_set.tracks {
let track_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
let mut title_parts = Vec::<String>::new();
for part in &track.work_parts {
title_parts.push(result.recording.work.parts[*part].title.clone());
}
let title = if title_parts.is_empty() {
gettext("Unknown")
} else {
title_parts.join(", ")
};
let title_label = gtk::Label::new(Some(&title));
title_label.set_ellipsize(pango::EllipsizeMode::End);
title_label.set_halign(gtk::Align::Start);
let file_name_label = gtk::Label::new(Some(&track.path));
file_name_label.set_ellipsize(pango::EllipsizeMode::End);
file_name_label.set_opacity(0.5);
file_name_label.set_halign(gtk::Align::Start);
track_box.add(&title_label);
track_box.add(&file_name_label);
vbox.add(&track_box);
}
vbox.upcast() vbox.upcast()
})); }));
@ -97,12 +105,12 @@ impl RecordingScreen {
})); }));
add_to_playlist_button.connect_clicked(clone!(@strong result => move |_| { add_to_playlist_button.connect_clicked(clone!(@strong result => move |_| {
if let Some(player) = result.backend.get_player() { // if let Some(player) = result.backend.get_player() {
// player.add_item(PlaylistItem { // player.add_item(PlaylistItem {
// recording: result.recording.clone(), // track_set: result.track_sets.get(0).unwrap().clone(),
// tracks: result.tracks.borrow().clone(), // indices: result.tracks.borrow().clone(),
// }).unwrap(); // }).unwrap();
} // }
})); }));
edit_action.connect_activate(clone!(@strong result => move |_, _| { edit_action.connect_activate(clone!(@strong result => move |_, _| {
@ -138,16 +146,16 @@ impl RecordingScreen {
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let clone = result.clone(); let clone = result.clone();
context.spawn_local(async move { context.spawn_local(async move {
let tracks = clone let track_sets = clone
.backend .backend
.db() .db()
.get_tracks(&clone.recording.id) .get_track_sets(&clone.recording.id)
.await .await
.unwrap(); .unwrap();
list.show_items(tracks.clone()); list.show_items(track_sets.clone());
clone.stack.set_visible_child_name("content"); clone.stack.set_visible_child_name("content");
clone.tracks.replace(tracks); clone.track_sets.replace(track_sets);
}); });
result result

View file

@ -112,20 +112,20 @@ impl PlayerBar {
next_button.set_sensitive(player.has_next()); next_button.set_sensitive(player.has_next());
let item = &playlist.borrow()[current_item]; let item = &playlist.borrow()[current_item];
let track = &item.tracks.tracks[current_track]; let track = &item.track_set.tracks[current_track];
let mut parts = Vec::<String>::new(); let mut parts = Vec::<String>::new();
for part in &track.work_parts { for part in &track.work_parts {
parts.push(item.tracks.recording.work.parts[*part].title.clone()); parts.push(item.track_set.recording.work.parts[*part].title.clone());
} }
let mut title = item.tracks.recording.work.get_title(); let mut title = item.track_set.recording.work.get_title();
if !parts.is_empty() { if !parts.is_empty() {
title = format!("{}: {}", title, parts.join(", ")); title = format!("{}: {}", title, parts.join(", "));
} }
title_label.set_text(&title); title_label.set_text(&title);
subtitle_label.set_text(&item.tracks.recording.get_performers()); subtitle_label.set_text(&item.track_set.recording.get_performers());
position_label.set_text("0:00"); position_label.set_text("0:00");
} }
)); ));