Skip to content

Commit

Permalink
refactor(anni): working on anni-cli for adding album
Browse files Browse the repository at this point in the history
  • Loading branch information
Yesterday17 committed Sep 6, 2024
1 parent 76dd00f commit 668e9d0
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 99 deletions.
8 changes: 8 additions & 0 deletions anni-metadata/src/annim/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ impl AnnimClient {
.collect(),
};

self.add_album_input(input, commit).await
}

pub async fn add_album_input(
&self,
input: mutation::add_album::AddAlbumInput<'_>,
commit: bool,
) -> anyhow::Result<query::album::AlbumFragment> {
let query =
mutation::add_album::AddAlbumMutation::build(mutation::add_album::AddAlbumVariables {
album: input,
Expand Down
41 changes: 41 additions & 0 deletions anni-metadata/src/annim/mutation/add_album.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,44 @@ pub struct CreateAlbumTrackInput<'a> {
#[cynic(rename = "type")]
pub type_: TrackTypeInput,
}

impl<'album, 'disc> From<crate::model::TrackRef<'album, 'disc>> for CreateAlbumTrackInput<'album>
where
'disc: 'album,
{
fn from(track: crate::model::TrackRef<'album, 'disc>) -> Self {
Self {
title: track.title(),
artist: track.artist(),
type_: track.track_type().into(),
}
}
}

impl<'a> From<&'a crate::model::Track> for CreateAlbumTrackInput<'a> {
fn from(track: &'a crate::model::Track) -> Self {
Self {
title: &track.title,
artist: track
.artist
.as_deref()
.unwrap_or(crate::model::UNKNOWN_ARTIST),
type_: track
.track_type
.as_ref()
.unwrap_or_else(|| &crate::model::TrackType::Normal)
.into(),
}
}
}

impl<'a> From<&'a crate::model::Disc> for CreateAlbumDiscInput<'a> {
fn from(value: &'a crate::model::Disc) -> Self {
Self {
title: value.title.as_deref(),
catalog: Some(value.catalog.as_str()),
artist: value.artist.as_deref(),
tracks: value.tracks.iter().map(Into::into).collect(),
}
}
}
2 changes: 1 addition & 1 deletion anni-metadata/src/model/album.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ impl DerefMut for Disc {
pub struct DiscInfo {
/// Disc title
#[serde(skip_serializing_if = "Option::is_none")]
title: Option<String>,
pub title: Option<String>,
/// Disc catalog
pub catalog: String,
/// Disc artist
Expand Down
81 changes: 2 additions & 79 deletions anni-workspace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ mod utils;

use crate::config::WorkspaceConfig;
use anni_common::fs;
use anni_metadata::model::{AnniDate, UNKNOWN_ARTIST};
use anni_metadata::model::AnniDate;
use anni_repo::library::file_name;
use anni_repo::models::{ApplyMetadata, RepoTrack};
use anni_repo::models::ApplyMetadata;
use anni_repo::RepositoryManager;
use config::LibraryConfig;
use std::borrow::Cow;
Expand Down Expand Up @@ -498,83 +498,6 @@ impl AnniWorkspace {
Ok(album_id)
}

/// Import tag from **committed** album.
pub fn import_tags<P, E>(
&self,
album_path: P,
extractor: E,
) -> Result<anni_metadata::model::Album, WorkspaceError>
where
P: AsRef<Path>,
E: FnOnce(&str) -> Option<ExtractedAlbumInfo>,
{
use anni_metadata::model::{Album, AlbumInfo, Disc, DiscInfo};

let album_id = self.get_album_id(album_path.as_ref())?;
let folder_name = file_name(&album_path)?;
let ExtractedAlbumInfo {
release_date,
catalog,
title,
edition,
..
} = extractor(&folder_name).ok_or_else(|| WorkspaceError::FailedToExtractAlbumInfo)?;

let album_path = self.get_album_controlled_path(&album_id)?;
let mut discs = Vec::new();
loop {
let disc_id = discs.len() + 1;
let disc_path = album_path.join(disc_id.to_string());
if !disc_path.exists() {
break;
}

let mut tracks = Vec::new();
loop {
let track_id = tracks.len() + 1;
let track_path = disc_path.join(format!("{track_id}.flac"));
if !track_path.exists() {
break;
}

let flac = anni_flac::FlacHeader::from_file(&track_path).map_err(|error| {
WorkspaceError::FlacError {
path: track_path,
error,
}
})?;
let track: RepoTrack = flac.into();
tracks.push(track.0)
}
discs.push(Disc::new(
DiscInfo::new(
catalog.to_string(),
None,
None,
None,
None,
Default::default(),
),
tracks,
));
}

let album = Album::new(
AlbumInfo {
album_id,
title: title.to_string(),
edition: edition.map(|c| c.to_string()),
artist: UNKNOWN_ARTIST.to_string(),
release_date,
catalog: catalog.to_string(),
..Default::default()
},
discs,
);

Ok(album)
}

pub fn revert<P>(&self, path: P) -> Result<(), WorkspaceError>
where
P: AsRef<Path>,
Expand Down
106 changes: 87 additions & 19 deletions anni/src/subcommands/workspace/add.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use crate::ll;
use anni_metadata::annim::mutation::add_album::AddAlbumInput;
use anni_metadata::annim::AnnimClient;
use anni_repo::library::AlbumFolderInfo;
use anni_workspace::{AnniWorkspace, ExtractedAlbumInfo, UntrackedWorkspaceAlbum};
use anni_metadata::model::{Album, AlbumInfo, Disc, DiscInfo, UNKNOWN_ARTIST};
use anni_repo::library::{file_name, AlbumFolderInfo};
use anni_repo::models::RepoTrack;
use anni_workspace::{AnniWorkspace, UntrackedWorkspaceAlbum, WorkspaceError};
use clap::Args;
use clap_handler::handler;
use colored::Colorize;
use inquire::Confirm;
use ptree::TreeBuilder;
use std::borrow::Cow;
use std::path::PathBuf;
use std::str::FromStr;

Expand Down Expand Up @@ -81,34 +83,100 @@ fn handle_workspace_add(me: WorkspaceAddAction) -> anyhow::Result<()> {

// import tags if necessary
if me.import_tags {
let album = workspace.import_tags(&album_path, |folder_name| {
let AlbumFolderInfo {
release_date,
catalog,
title,
edition,
..
} = AlbumFolderInfo::from_str(&folder_name).ok()?;
Some(ExtractedAlbumInfo {
title: Cow::Owned(title),
edition: edition.map(|e| Cow::Owned(e)),
catalog: Cow::Owned(catalog),
release_date,
})
})?;
let config = workspace.get_config()?;

let album_id = workspace.get_album_id(&album_path)?;
let folder_name = file_name(&album_path)?;

let album_path = workspace.get_album_controlled_path(&album_id)?;
let mut discs = Vec::new();
loop {
let disc_id = discs.len() + 1;
let disc_path = album_path.join(disc_id.to_string());
if !disc_path.exists() {
break;
}

let mut tracks = Vec::new();
loop {
let track_id = tracks.len() + 1;
let track_path = disc_path.join(format!("{track_id}.flac"));
if !track_path.exists() {
break;
}

let flac = anni_flac::FlacHeader::from_file(&track_path).map_err(|error| {
WorkspaceError::FlacError {
path: track_path,
error,
}
})?;
let track: RepoTrack = flac.into();
tracks.push(track.0)
}
discs.push(Disc::new(
DiscInfo::new(String::new(), None, None, None, None, Default::default()),
tracks,
));
}

match config.metadata() {
anni_workspace::config::WorkspaceMetadata::Repo => {
// TODO: do not enforce this folder name
let AlbumFolderInfo {
release_date,
catalog,
title,
edition,
..
} = AlbumFolderInfo::from_str(&folder_name)?;

for disc in discs.iter_mut() {
disc.catalog += &catalog;
}

let repo = workspace.to_repository_manager()?;
let album = Album::new(
AlbumInfo {
album_id,
title: title.to_string(),
edition: edition.map(|c| c.to_string()),
artist: UNKNOWN_ARTIST.to_string(),
release_date,
catalog: catalog.to_string(),
..Default::default()
},
discs,
);
repo.add_album(album, false)?;

if me.open_editor {
edit::edit_file(&album_path)?;
}
}
anni_workspace::config::WorkspaceMetadata::Remote { endpoint, token } => {
let AlbumFolderInfo {
release_date,
catalog,
title,
edition,
..
} = AlbumFolderInfo::from_str(&folder_name)?;

let client = AnnimClient::new(endpoint, token.as_deref());
client.add_album(&album, true).await?;
let input = AddAlbumInput {
album_id: Some(album_id),
title: &title,
edition: edition.as_deref(),
catalog: Some(catalog.as_ref()),
artist: UNKNOWN_ARTIST,
year: release_date.year() as i32,
month: release_date.month().map(i32::from),
day: release_date.day().map(i32::from),
extra: None,
discs: discs.iter().map(Into::into).collect(),
};
client.add_album_input(input, true).await?;
}
}
}
Expand Down

0 comments on commit 668e9d0

Please sign in to comment.