feat: scanning somewhat cromulent

now to make sure it can play again ;3
This commit is contained in:
Lys 2023-10-10 22:26:42 +03:00
parent 71b7eca0b9
commit 56bc015b7a
Signed by: lyssieth
GPG key ID: C9CF3D614FAA3940
2 changed files with 58 additions and 65 deletions

View file

@ -9,6 +9,6 @@ mount:
run: mount run: mount
RAVE_STORAGE_DIR=/tmp/media-for-rave cargo r RAVE_STORAGE_DIR=/tmp/media-for-rave cargo r
update-db: refresh:
sea migrate fresh sea migrate fresh
sea generate entity -o ./entities/src --with-serde both --date-time-crate time --lib sea generate entity -o ./entities/src --with-serde both --date-time-crate time --lib

View file

@ -83,7 +83,9 @@ async fn scan() {
continue; continue;
}; };
tokio::spawn(do_entry(de, txn, state.clone())); // tokio::spawn(do_entry(de, txn, state.clone())); // multithreading version
do_entry(de, txn, state.clone()).await; // test without multithreading
} }
{ {
@ -96,11 +98,13 @@ async fn scan() {
const VALID_EXTENSIONS: &[&str] = &["mp3"]; const VALID_EXTENSIONS: &[&str] = &["mp3"];
async fn do_entry(de: walk::DirEntry, txn: DatabaseTransaction, state: Arc<RwLock<ScanState>>) { async fn do_entry(de: walk::DirEntry, txn: DatabaseTransaction, state: Arc<RwLock<ScanState>>) {
if let Err(e) = handle_entry(&txn, de, state).await { if let Err(e) = handle_entry(&txn, de.clone(), state).await {
let _ = txn.rollback().await; let _ = txn.rollback().await;
let path = de.path();
let path = path.to_string_lossy();
error!( error!(
error = e.root_cause(), error = e.root_cause(),
"Failed to handle directory entry: {e}" "Failed to handle directory entry `{path}`: {e}"
); );
{ {
@ -175,20 +179,11 @@ async fn handle_entry(
let meta = { File::open(&path).await?.metadata().await? }; let meta = { File::open(&path).await?.metadata().await? };
let current_album = { state.read().await.album_id };
let tag = Tag::async_read_from_path(&path).await?; let tag = Tag::async_read_from_path(&path).await?;
let artist = find_artist(tx, &tag).await?; let artist = find_artist(tx, &tag).await?;
let album = find_album( let album = find_album(tx, artist.as_ref().map(|c| c.id), &tag, state.clone()).await?;
tx,
current_album,
artist.as_ref().map(|c| c.id),
&tag,
state.clone(),
)
.await?;
let mut am = track::ActiveModel::new(); let mut am = track::ActiveModel::new();
@ -219,35 +214,33 @@ async fn handle_entry(
#[instrument(skip(tx, tag, state))] #[instrument(skip(tx, tag, state))]
async fn find_album( async fn find_album(
tx: &DatabaseTransaction, tx: &DatabaseTransaction,
current_album: Option<i64>,
artist_id: Option<i64>, artist_id: Option<i64>,
tag: &Tag, tag: &Tag,
state: Arc<RwLock<ScanState>>, state: Arc<RwLock<ScanState>>,
) -> Result<album::Model, Report> { ) -> Result<album::Model, Report> {
if let Some(current_album) = current_album { let Some(album_name) = tag.album() else {
let album = Album::find_by_id(current_album).one(tx).await?; return Err(Report::msg("Couldn't get album name from tag"));
let Some(album) = album else {
error!("Couldn't find album with id {current_album}");
return Err(Report::msg(format!(
"Couldn't find album with id {current_album}"
)));
}; };
Ok(album) // if not, search by name
} else { let search = Album::find()
let mut am = album::ActiveModel::new(); .filter(album::Column::Name.like(album_name))
.one(tx)
.await?;
if let Some(tag_album) = tag.album() { // if we found one, return it
am.name = Set(tag_album.to_string()); if let Some(search) = search {
} else { return Ok(search);
am.name = Set("Unknown Album".to_string());
} }
// otherwise, create it
let mut am = album::ActiveModel::new();
am.name = Set(album_name.to_string());
am.music_folder_id = Set(state.read().await.music_folder_id); am.music_folder_id = Set(state.read().await.music_folder_id);
am.artist_id = Set(artist_id); am.artist_id = Set(artist_id);
am.year = Set(tag.year()); am.year = Set(tag.year());
let genre = tag.genre_parsed(); let genre = tag.genre_parsed();
if let Some(genre) = genre { if let Some(genre) = genre {
let genre_id = find_or_create_genre(tx, genre.as_ref()).await?; let genre_id = find_or_create_genre(tx, genre.as_ref()).await?;
@ -262,6 +255,7 @@ async fn find_album(
let model = Album::insert(am).exec_with_returning(tx).await; let model = Album::insert(am).exec_with_returning(tx).await;
// if we failed to insert, return the error
let Ok(model) = model else { let Ok(model) = model else {
let err = model.expect_err("somehow not err"); let err = model.expect_err("somehow not err");
error!( error!(
@ -274,7 +268,6 @@ async fn find_album(
Ok(model) Ok(model)
} }
}
#[instrument(skip(tx))] #[instrument(skip(tx))]
async fn find_or_create_genre(tx: &DatabaseTransaction, name: &str) -> Result<i64, Report> { async fn find_or_create_genre(tx: &DatabaseTransaction, name: &str) -> Result<i64, Report> {
@ -327,8 +320,9 @@ async fn find_artist(tx: &DatabaseTransaction, tag: &Tag) -> Result<Option<artis
match &artist_to_search { match &artist_to_search {
Some(artist_to_search) => { Some(artist_to_search) => {
let artist_to_search = artist_to_search.trim();
let attempt = Artist::find() let attempt = Artist::find()
.filter(artist::Column::Name.contains(artist_to_search)) .filter(artist::Column::Name.like(artist_to_search))
.one(tx) .one(tx)
.await?; .await?;
@ -336,7 +330,7 @@ async fn find_artist(tx: &DatabaseTransaction, tag: &Tag) -> Result<Option<artis
Ok(Some(attempt)) Ok(Some(attempt))
} else { } else {
let am = artist::ActiveModel { let am = artist::ActiveModel {
name: Set(artist_to_search.clone()), name: Set(artist_to_search.to_string()),
..Default::default() ..Default::default()
}; };
let model = Artist::insert(am).exec_with_returning(tx).await; let model = Artist::insert(am).exec_with_returning(tx).await;
@ -361,7 +355,6 @@ async fn find_artist(tx: &DatabaseTransaction, tag: &Tag) -> Result<Option<artis
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct ScanState { struct ScanState {
pub music_folder_id: i64, pub music_folder_id: i64,
pub album_id: Option<i64>,
} }
#[instrument(skip(dbc, state))] #[instrument(skip(dbc, state))]