[feat]: Song importing works now
This means we have a decent flow for creating and importing songs. By default this will use Genius as the lyric backend. In the future we will support more options, but for now this means you can get the lyrics you need and start building songs rather fast.
This commit is contained in:
parent
d043caae27
commit
e7d4c10ad6
5 changed files with 104 additions and 3 deletions
|
|
@ -81,11 +81,29 @@ impl From<OnlineSong> for Song {
|
|||
.or_insert(online_song.lyrics);
|
||||
Some(map)
|
||||
};
|
||||
let lyrics = ron::ser::to_string(&map).ok();
|
||||
|
||||
let verse_order: Option<Vec<String>> =
|
||||
if let Some(map) = map.as_ref() {
|
||||
Some(map.keys().map(|v| v.get_name()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let verses: Option<Vec<VerseName>> =
|
||||
if let Some(map) = map.as_ref() {
|
||||
Some(map.keys().map(|v| v.to_owned()).collect())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Self {
|
||||
title: online_song.title,
|
||||
author: Some(online_song.author),
|
||||
verse_map: map,
|
||||
lyrics,
|
||||
verse_order,
|
||||
verses,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -788,6 +788,54 @@ pub async fn remove_song(
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn insert_song(
|
||||
mut song: Song,
|
||||
mut songs: Vec<Song>,
|
||||
db: Arc<SqlitePool>,
|
||||
) -> Result<Vec<Song>> {
|
||||
let verse_order = {
|
||||
song.verse_order.clone().map_or_else(String::new, |vo| {
|
||||
vo.into_iter()
|
||||
.map(|mut s| {
|
||||
s.push(' ');
|
||||
s
|
||||
})
|
||||
.collect::<String>()
|
||||
})
|
||||
};
|
||||
|
||||
let audio = song
|
||||
.audio
|
||||
.clone()
|
||||
.map(|a| a.to_str().unwrap_or_default().to_string());
|
||||
|
||||
let background = song
|
||||
.background
|
||||
.clone()
|
||||
.map(|b| b.path.to_str().unwrap_or_default().to_string());
|
||||
|
||||
let res = query!(
|
||||
r#"INSERT INTO songs (title, lyrics, author, ccli, verse_order, audio, font, font_size, background) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)"#,
|
||||
song.title,
|
||||
song.lyrics,
|
||||
song.author,
|
||||
song.ccli,
|
||||
verse_order,
|
||||
audio,
|
||||
song.font,
|
||||
song.font_size,
|
||||
background
|
||||
)
|
||||
.execute(&*db)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
song.id = i32::try_from(res.last_insert_rowid()).expect(
|
||||
"Fairly confident that this number won't get that high",
|
||||
);
|
||||
songs.push(song);
|
||||
Ok(songs)
|
||||
}
|
||||
|
||||
pub async fn add_song(
|
||||
mut songs: Vec<Song>,
|
||||
db: Arc<SqlitePool>,
|
||||
|
|
|
|||
11
src/main.rs
11
src/main.rs
|
|
@ -958,6 +958,17 @@ impl cosmic::Application for App {
|
|||
Task::none()
|
||||
}
|
||||
}
|
||||
song_editor::Action::AddSong(song) => {
|
||||
if self.library.is_some() {
|
||||
self.update(Message::Library(
|
||||
library::Message::AddSongFromEditor(
|
||||
song,
|
||||
),
|
||||
))
|
||||
} else {
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
song_editor::Action::None => Task::none(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use crate::core::kinds::ServiceItemKind;
|
|||
use crate::core::model::{KindWrapper, LibraryKind, Model};
|
||||
use crate::core::presentations::{self, Presentation};
|
||||
use crate::core::service_items::ServiceItem;
|
||||
use crate::core::songs::{self, Song};
|
||||
use crate::core::songs::{self, Song, insert_song};
|
||||
use crate::core::videos::{self, Video};
|
||||
|
||||
#[allow(clippy::struct_field_names)]
|
||||
|
|
@ -110,6 +110,7 @@ pub enum Message {
|
|||
ReaddVideos(Vec<Video>),
|
||||
ReaddPres(Vec<Presentation>),
|
||||
ToService((LibraryKind, i32)),
|
||||
AddSongFromEditor(Song),
|
||||
}
|
||||
|
||||
impl<'a> Library {
|
||||
|
|
@ -185,6 +186,25 @@ impl<'a> Library {
|
|||
Message::AddSong => {
|
||||
return Action::CreateSong;
|
||||
}
|
||||
Message::AddSongFromEditor(song) => {
|
||||
let after_task =
|
||||
Task::done(Message::OpenItem(Some((
|
||||
LibraryKind::Song,
|
||||
self.song_library.items.len() as i32,
|
||||
))));
|
||||
debug!(?song);
|
||||
let task = Task::perform(
|
||||
insert_song(
|
||||
song,
|
||||
self.song_library.items.clone(),
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
|res| {
|
||||
res.map_or(Message::None, Message::ReaddSongs)
|
||||
},
|
||||
);
|
||||
return Action::Task(task.chain(after_task));
|
||||
}
|
||||
Message::AddItem => {
|
||||
let kind =
|
||||
self.library_open.unwrap_or(LibraryKind::Song);
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ pub struct SongEditor {
|
|||
pub enum Action {
|
||||
Task(Task<Message>),
|
||||
UpdateSong(Song),
|
||||
AddSong(Song),
|
||||
None,
|
||||
}
|
||||
|
||||
|
|
@ -974,7 +975,8 @@ impl SongEditor {
|
|||
}
|
||||
Message::AddSong(song) => {
|
||||
let song = Song::from(song);
|
||||
return self.update(Message::ChangeSong(song));
|
||||
self.importing = false;
|
||||
return Action::AddSong(song);
|
||||
}
|
||||
Message::HoverSong(index) => {
|
||||
self.hovered_online_song = index;
|
||||
|
|
@ -1997,8 +1999,8 @@ impl SongEditor {
|
|||
provider
|
||||
]
|
||||
.spacing(space_s)
|
||||
.padding(space_m)
|
||||
.apply(container)
|
||||
.padding(space_m)
|
||||
.style(move |theme| {
|
||||
container::Style::default()
|
||||
.background(
|
||||
|
|
@ -2061,8 +2063,10 @@ impl SongEditor {
|
|||
.collect();
|
||||
|
||||
column::with_children(songs)
|
||||
.padding([space_s, space_l, space_s, space_s])
|
||||
.spacing(space_s)
|
||||
.apply(scrollable)
|
||||
.scrollbar_padding(space_s)
|
||||
.apply(container)
|
||||
},
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue