Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Alireza Ghassemi committed Aug 25, 2023
1 parent 026579e commit d428c00
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 92 deletions.
75 changes: 62 additions & 13 deletions src/body/merge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashSet;
use std::ops::Deref;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, TryRecvError::*};
use std::sync::mpsc::{channel, TryRecvError::*};
use std::thread;
use std::time::Duration;
use adw::glib::{ControlFlow::*, timeout_add_local};
Expand All @@ -13,9 +13,16 @@ use gtk::{Button, GestureClick, GestureZoom, Overlay, ProgressBar};
use gtk::EventSequenceState::Claimed;
use gtk::Orientation::Vertical;
use gtk::PropagationPhase::Capture;
use id3::{Tag, TagLike};
use id3::ErrorKind::NoTag;
use id3::v1v2::write_to_path;
use id3::Version::Id3v24;
use log::error;
use crate::body::collection::model::Collection;
use crate::common::state::State;
use crate::common::StyledWidget;
use crate::common::util::Plural;
use crate::song::{Song, WithPath};

pub(in crate::body) struct MergeState {
entity: &'static str,
Expand All @@ -40,16 +47,29 @@ impl MergeButton for Button {
}
}

#[derive(Copy, Clone)]
pub(in crate::body) enum EntityType {
Artist,
Album,
}

pub(in crate::body) struct Entity {
pub string: &'static str,
pub entity_type: EntityType,
}

impl MergeState {
pub(in crate::body) fn new<M: Fn(Vec<Arc<String>>, Arc<String>, bool, Sender<f64>) + Clone + Send + 'static>(
entity: &'static str, state: Rc<State>, title: Arc<String>, subtitle: Rc<String>, on_merge: M) -> Rc<Self> {
pub(in crate::body) fn new<G: Fn(Vec<Option<String>>, bool) -> Vec<(Song, Collection)> + Send + Clone + 'static,
M: Fn(Song, Arc<String>) + Send + Clone + 'static>(merge_entity: Entity, state: Rc<State>, title: Arc<String>,
subtitle: Rc<String>, get_songs: G, merge: M) -> Rc<Self> {
let cancel_button = Button::builder().label("Cancel").build();
let merge_button = Button::builder().label("Merge").build().suggested_action();
merge_button.disable();
let merge_menu_button = Button::builder().label(format!("Merge {}s", entity)).build();
let heading = format!("Choose the correct {} name", entity);
let Entity { string, entity_type } = merge_entity;
let merge_menu_button = Button::builder().label(format!("Merge {}s", string)).build();
let heading = format!("Choose the correct {} name", string);
let this = Rc::new(MergeState {
entity,
entity: string,
state: state.clone(),
title,
subtitle,
Expand Down Expand Up @@ -85,18 +105,49 @@ impl MergeState {
gtk_box.append(&button);
button.connect_clicked({
let overlay = overlay.clone();
let on_merge = on_merge.clone();
let get_songs = get_songs.clone();
let entities = entities.clone();
let merge = merge.clone();
let dialog = dialog.clone();
move |_| {
let progress_bar = ProgressBar::builder().hexpand(true).build().osd();
let progress_bar = ProgressBar::builder().hexpand(true).build();
overlay.add_overlay(&progress_bar);
let (sender, receiver) = channel::<f64>();
thread::spawn({
let on_merge = on_merge.clone();
let get_songs = get_songs.clone();
let entities = entities.clone();
let entity = entity.clone();
move || { on_merge(entities.clone(), entity.clone(), has_none, sender); }
let merge = merge.clone();
move || {
let song_collections = get_songs(entities.iter().filter_map(|it| {
(!Arc::ptr_eq(&it, &entity)).then_some(Some(it.to_string()))
}).collect::<Vec<_>>(), has_none);
let total = song_collections.len();
for (i, (song, collection)) in song_collections.into_iter().enumerate() {
let current_path = (&song, &collection).path();
let tag = match Tag::read_from_path(&current_path) {
Ok(tag) => { Some(tag) }
Err(error) => {
if let NoTag = error.kind {
Some(Tag::new())
} else {
error!("error reading tags on file {:?} while trying to set {} {}: {}",
current_path, string, entity.deref(), error);
None
}
}
};
if let Some(mut tag) = tag {
match entity_type {
EntityType::Artist => { tag.set_artist(entity.deref()); }
EntityType::Album => { tag.set_album(entity.deref()); }
}
write_to_path(current_path, &tag, Id3v24).unwrap();
merge(song, entity.clone());
}
sender.send(i as f64 / total as f64).unwrap();
}
}
});
timeout_add_local(Duration::from_millis(500), {
let dialog = dialog.clone();
Expand All @@ -112,9 +163,7 @@ impl MergeState {
Ok(fraction) => { merge_progress = Some(fraction); }
}
}
if let Some(fraction) = merge_progress {
progress_bar.set_fraction(fraction);
}
if let Some(fraction) = merge_progress { progress_bar.set_fraction(fraction); }
Continue
}
});
Expand Down
89 changes: 18 additions & 71 deletions src/body/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,9 @@ use diesel::{BoolExpressionMethods, ExpressionMethods, QueryDsl, RunQueryDsl, up
use diesel::dsl::{count_distinct, count_star, max, min};
use gtk::{CenterBox, GestureClick, Grid, Image, Label, Separator, Widget};
use gtk::Orientation::Vertical;
use id3::{Tag, TagLike, Version};
use id3::ErrorKind::NoTag;
use id3::v1v2::write_to_path;
use log::error;
use Version::Id3v24;
use crate::body::collection::add_collection_box;
use crate::body::collection::model::Collection;
use crate::body::merge::MergeState;
use crate::body::merge::{Entity, EntityType::*, MergeState};
use crate::common::{AdjustableScrolledWindow, ALBUM_ICON, ImagePathBuf, StyledLabelBuilder};
use crate::common::constant::INSENSITIVE_FG;
use crate::common::state::State;
Expand All @@ -28,7 +23,7 @@ use crate::schema::collections::path;
use crate::schema::config::dsl::config;
use crate::schema::songs::{album, artist, id, path as song_path, year};
use crate::schema::songs::dsl::songs;
use crate::song::{get_current_album, join_path, Song, WithCover, WithPath};
use crate::song::{get_current_album, join_path, Song, WithCover};

pub mod collection;
mod merge;
Expand Down Expand Up @@ -178,42 +173,18 @@ impl Body {
.get_results::<(Option<String>, i64, i64)>(&mut get_connection()).unwrap();
let title = Arc::new(String::from("Harborz"));
let subtitle = Rc::new(artists.len().number_plural(ARTIST));
let merge_state = MergeState::new(ARTIST, state.clone(), title.clone(), subtitle.clone(),
|artists, artist_string, has_none, sender| {
let in_filter = artist.eq_any(artists.iter().filter_map(|it| {
(!Arc::ptr_eq(&it, &artist_string)).then_some(Some(it.to_string()))
}).collect::<Vec<_>>());
let merge_state = MergeState::new(Entity { string: ARTIST, entity_type: Artist }, state.clone(), title.clone(),
subtitle.clone(), |artists, has_none| {
let in_filter = artist.eq_any(artists);
let statement = songs.inner_join(collections).into_boxed();
let filtered_statement = if has_none {
if has_none {
statement.filter(in_filter.or(artist.is_null()))
} else {
statement.filter(in_filter)
};
let song_collections = filtered_statement.get_results::<(Song, Collection)>(&mut get_connection())
.unwrap();
let total = song_collections.len();
for (i, (song, collection)) in song_collections.into_iter().enumerate() {
let current_path = (&song, &collection).path();
let tag = match Tag::read_from_path(&current_path) {
Ok(tag) => { Some(tag) }
Err(error) => {
if let NoTag = error.kind {
Some(Tag::new())
} else {
error!("error reading tags on file {:?} while trying to set artist {}: {}",
current_path, artist_string.deref(), error);
None
}
}
};
if let Some(mut tag) = tag {
tag.set_artist(artist_string.deref());
write_to_path(current_path, &tag, Id3v24).unwrap();
update(songs.filter(id.eq(song.id))).set(artist.eq(Some(artist_string.to_string())))
.execute(&mut get_connection()).unwrap();
}
sender.send(i as f64 / total as f64).unwrap();
}
}.get_results::<(Song, Collection)>(&mut get_connection()).unwrap()
}, |song, artist_string| {
update(songs.filter(id.eq(song.id))).set(artist.eq(Some(artist_string.to_string())))
.execute(&mut get_connection()).unwrap();
},
);
Self {
Expand Down Expand Up @@ -275,42 +246,18 @@ impl Body {
.unwrap();
let title = or_none_arc(artist_string.clone());
let subtitle = Rc::new(albums.len().number_plural(ALBUM));
let merge_state = MergeState::new(ALBUM, state.clone(), title.clone(), subtitle.clone(),
|albums, album_string, has_none, sender| {
let in_filter = album.eq_any(albums.iter().filter_map(|it| {
(!Arc::ptr_eq(&it, &album_string)).then_some(Some(it.to_string()))
}).collect::<Vec<_>>());
let merge_state = MergeState::new(Entity { string: ALBUM, entity_type: Album }, state.clone(), title.clone(),
subtitle.clone(), |albums, has_none| {
let in_filter = album.eq_any(albums);
let statement = songs.inner_join(collections).into_boxed();
let filtered_statement = if has_none {
if has_none {
statement.filter(in_filter.or(album.is_null()))
} else {
statement.filter(in_filter)
};
let song_collections = filtered_statement.get_results::<(Song, Collection)>(&mut get_connection())
.unwrap();
let total = song_collections.len();
for (i, (song, collection)) in song_collections.into_iter().enumerate() {
let current_path = (&song, &collection).path();
let tag = match Tag::read_from_path(&current_path) {
Ok(tag) => { Some(tag) }
Err(error) => {
if let NoTag = error.kind {
Some(Tag::new())
} else {
error!("error reading tags on file {:?} while trying to set album {}: {}",
current_path, album_string.deref(), error);
None
}
}
};
if let Some(mut tag) = tag {
tag.set_album(album_string.deref());
write_to_path(current_path, &tag, Id3v24).unwrap();
update(songs.filter(id.eq(song.id))).set(album.eq(Some(album_string.to_string())))
.execute(&mut get_connection()).unwrap();
}
sender.send(i as f64 / total as f64).unwrap();
}
}.get_results::<(Song, Collection)>(&mut get_connection()).unwrap()
}, |song, album_string| {
update(songs.filter(id.eq(song.id))).set(album.eq(Some(album_string.to_string())))
.execute(&mut get_connection()).unwrap();
},
);
Self {
Expand Down
3 changes: 1 addition & 2 deletions src/now_playing/playbin.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::cell::RefCell;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use std::time::Duration;
use diesel::{Connection, QueryDsl, RunQueryDsl};
use gstreamer::{ClockTime, ElementFactory, Pipeline, SeekFlags};
Expand Down Expand Up @@ -76,7 +75,7 @@ impl Playbin for Pipeline {
.select((current_song_id, artist, album))
.get_result::<(Option<i32>, Option<String>, Option<String>)>(connection) {
let song_collections
= get_current_album(artist_string.map(Arc::new), album_string.map(Arc::new), connection);
= get_current_album(artist_string.map(Rc::new), album_string.map(Rc::new), connection);
let delta_song_index = song_collections.iter().position(|(song, _)| { song.id == current_song_id_int })
.unwrap() as i32 + delta;
if delta_song_index >= 0 && delta_song_index < song_collections.len() as i32 {
Expand Down
11 changes: 5 additions & 6 deletions src/song/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::Sender;
use std::time::{Duration, SystemTime};
use adw::glib::{ControlFlow, timeout_add};
use diesel::{ExpressionMethods, insert_or_ignore_into, QueryDsl, QueryResult, RunQueryDsl, SqliteConnection};
use diesel::r2d2::{ConnectionManager, PooledConnection};
use diesel::result::Error;
use diesel::result::Error::NotFound;
use gstreamer::ClockTime;
use gstreamer::tags::*;
use gstreamer_pbutils::Discoverer;
Expand Down Expand Up @@ -101,7 +100,7 @@ pub fn import_songs(collection: &Collection, sender: Sender<ImportProgress>,
if discoverer_info.video_streams().is_empty() && !discoverer_info.audio_streams().is_empty() {
let tag_list = discoverer_info.tags().unwrap();
let tag_list_ref = tag_list.as_ref();
if let Err(Error::NotFound) = insert_or_ignore_into(songs).values((
if let Err(NotFound) = insert_or_ignore_into(songs).values((
path.eq(entry.path().strip_prefix(&collection.path)?.to_str().unwrap()),
title.eq(tag_list_ref.get::<Title>().map(|it| { it.get().to_string() })),
artist.eq(tag_list_ref.get::<Artist>().map(|it| { it.get().to_string() })),
Expand Down Expand Up @@ -135,16 +134,16 @@ pub fn get_current_song(connection: &mut PooledConnection<ConnectionManager<Sqli
Ok(songs.inner_join(config).inner_join(collections).get_result::<(Song, Config, Collection)>(connection)?)
}

pub fn get_current_album(artist_string: Option<Arc<String>>, album_string: Option<Arc<String>>,
pub fn get_current_album(artist_string: Option<impl AsRef<String>>, album_string: Option<impl AsRef<String>>,
connection: &mut PooledConnection<ConnectionManager<SqliteConnection>>) -> Vec<(Song, Collection)> {
let statement = songs.inner_join(collections).order_by((track_number, id)).into_boxed();
let artist_filtered_statement = if let Some(artist_string) = artist_string {
statement.filter(artist.eq(artist_string.deref().to_owned()))
statement.filter(artist.eq(artist_string.as_ref().to_owned()))
} else {
statement.filter(artist.is_null())
};
if let Some(album_string) = album_string {
artist_filtered_statement.filter(album.eq(album_string.deref().to_owned()))
artist_filtered_statement.filter(album.eq(album_string.as_ref().to_owned()))
} else {
artist_filtered_statement.filter(album.is_null())
}.get_results::<(Song, Collection)>(connection).unwrap()
Expand Down

0 comments on commit d428c00

Please sign in to comment.