mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 19:57:25 +01:00
Use track set for recording screen
This commit is contained in:
parent
aa6b5c6ac4
commit
f69cb38b57
6 changed files with 108 additions and 106 deletions
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue