Added auth
This commit is contained in:
@@ -60,26 +60,22 @@ impl fmt::Display for LibrarySummary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add an artist to the watchlist by expanding into individual track wanted items.
|
/// Add an artist to the watchlist by expanding into individual track wanted items.
|
||||||
///
|
|
||||||
/// Fetches the artist's discography from the provider, then for each release
|
|
||||||
/// fetches the tracklist and adds each track as a separate Wanted item.
|
|
||||||
pub async fn add_artist(
|
pub async fn add_artist(
|
||||||
conn: &DatabaseConnection,
|
conn: &DatabaseConnection,
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
musicbrainz_id: Option<&str>,
|
musicbrainz_id: Option<&str>,
|
||||||
provider: &impl MetadataProvider,
|
provider: &impl MetadataProvider,
|
||||||
|
user_id: Option<i32>,
|
||||||
) -> WatchResult<AddSummary> {
|
) -> WatchResult<AddSummary> {
|
||||||
let (resolved_name, resolved_mbid) =
|
let (resolved_name, resolved_mbid) =
|
||||||
resolve_artist_info(name, musicbrainz_id, provider).await?;
|
resolve_artist_info(name, musicbrainz_id, provider).await?;
|
||||||
|
|
||||||
let artist = queries::artists::upsert(conn, &resolved_name, resolved_mbid.as_deref()).await?;
|
let artist = queries::artists::upsert(conn, &resolved_name, resolved_mbid.as_deref()).await?;
|
||||||
|
|
||||||
// Get artist MBID — either provided or from the search
|
|
||||||
let artist_mbid = resolved_mbid.or_else(|| artist.musicbrainz_id.clone());
|
let artist_mbid = resolved_mbid.or_else(|| artist.musicbrainz_id.clone());
|
||||||
let artist_mbid = match artist_mbid {
|
let artist_mbid = match artist_mbid {
|
||||||
Some(mbid) => mbid,
|
Some(mbid) => mbid,
|
||||||
None => {
|
None => {
|
||||||
// Search for the artist to get MBID
|
|
||||||
let results = provider
|
let results = provider
|
||||||
.search_artist(&resolved_name, 1)
|
.search_artist(&resolved_name, 1)
|
||||||
.await
|
.await
|
||||||
@@ -95,7 +91,6 @@ pub async fn add_artist(
|
|||||||
|
|
||||||
tracing::info!(name = %resolved_name, mbid = %artist_mbid, "fetching discography");
|
tracing::info!(name = %resolved_name, mbid = %artist_mbid, "fetching discography");
|
||||||
|
|
||||||
// Fetch all releases
|
|
||||||
let releases = provider
|
let releases = provider
|
||||||
.get_artist_releases(&artist_mbid, 100)
|
.get_artist_releases(&artist_mbid, 100)
|
||||||
.await
|
.await
|
||||||
@@ -123,6 +118,7 @@ pub async fn add_artist(
|
|||||||
&resolved_name,
|
&resolved_name,
|
||||||
&track.title,
|
&track.title,
|
||||||
Some(&track.recording_mbid),
|
Some(&track.recording_mbid),
|
||||||
|
user_id,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@@ -141,19 +137,17 @@ pub async fn add_artist(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add an album to the watchlist by expanding into individual track wanted items.
|
/// Add an album to the watchlist by expanding into individual track wanted items.
|
||||||
///
|
|
||||||
/// Fetches the album's tracklist and adds each track as a separate Wanted item.
|
|
||||||
pub async fn add_album(
|
pub async fn add_album(
|
||||||
conn: &DatabaseConnection,
|
conn: &DatabaseConnection,
|
||||||
artist_name: Option<&str>,
|
artist_name: Option<&str>,
|
||||||
album_name: Option<&str>,
|
album_name: Option<&str>,
|
||||||
musicbrainz_id: Option<&str>,
|
musicbrainz_id: Option<&str>,
|
||||||
provider: &impl MetadataProvider,
|
provider: &impl MetadataProvider,
|
||||||
|
user_id: Option<i32>,
|
||||||
) -> WatchResult<AddSummary> {
|
) -> WatchResult<AddSummary> {
|
||||||
let (resolved_album, resolved_artist, resolved_mbid) =
|
let (resolved_album, resolved_artist, resolved_mbid) =
|
||||||
resolve_album_info(artist_name, album_name, musicbrainz_id, provider).await?;
|
resolve_album_info(artist_name, album_name, musicbrainz_id, provider).await?;
|
||||||
|
|
||||||
// Get release MBID
|
|
||||||
let release_mbid = match resolved_mbid {
|
let release_mbid = match resolved_mbid {
|
||||||
Some(mbid) => mbid,
|
Some(mbid) => mbid,
|
||||||
None => {
|
None => {
|
||||||
@@ -185,6 +179,7 @@ pub async fn add_album(
|
|||||||
&resolved_artist,
|
&resolved_artist,
|
||||||
&track.title,
|
&track.title,
|
||||||
Some(&track.recording_mbid),
|
Some(&track.recording_mbid),
|
||||||
|
user_id,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@@ -208,6 +203,7 @@ pub async fn add_track(
|
|||||||
title: Option<&str>,
|
title: Option<&str>,
|
||||||
musicbrainz_id: Option<&str>,
|
musicbrainz_id: Option<&str>,
|
||||||
provider: &impl MetadataProvider,
|
provider: &impl MetadataProvider,
|
||||||
|
user_id: Option<i32>,
|
||||||
) -> WatchResult<WatchListEntry> {
|
) -> WatchResult<WatchListEntry> {
|
||||||
let (resolved_title, resolved_artist, resolved_mbid) =
|
let (resolved_title, resolved_artist, resolved_mbid) =
|
||||||
resolve_track_info(artist_name, title, musicbrainz_id, provider).await?;
|
resolve_track_info(artist_name, title, musicbrainz_id, provider).await?;
|
||||||
@@ -217,12 +213,15 @@ pub async fn add_track(
|
|||||||
|
|
||||||
let item = queries::wanted::add(
|
let item = queries::wanted::add(
|
||||||
conn,
|
conn,
|
||||||
ItemType::Track,
|
queries::wanted::AddWantedItem {
|
||||||
&resolved_title,
|
item_type: ItemType::Track,
|
||||||
resolved_mbid.as_deref(),
|
name: &resolved_title,
|
||||||
Some(artist.id),
|
musicbrainz_id: resolved_mbid.as_deref(),
|
||||||
None,
|
artist_id: Some(artist.id),
|
||||||
None,
|
album_id: None,
|
||||||
|
track_id: None,
|
||||||
|
user_id,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -250,18 +249,22 @@ async fn add_track_inner(
|
|||||||
artist_name: &str,
|
artist_name: &str,
|
||||||
title: &str,
|
title: &str,
|
||||||
recording_mbid: Option<&str>,
|
recording_mbid: Option<&str>,
|
||||||
|
user_id: Option<i32>,
|
||||||
) -> WatchResult<bool> {
|
) -> WatchResult<bool> {
|
||||||
let artist = queries::artists::upsert(conn, artist_name, None).await?;
|
let artist = queries::artists::upsert(conn, artist_name, None).await?;
|
||||||
let is_owned = matching::track_is_owned(conn, artist_name, title).await?;
|
let is_owned = matching::track_is_owned(conn, artist_name, title).await?;
|
||||||
|
|
||||||
let item = queries::wanted::add(
|
let item = queries::wanted::add(
|
||||||
conn,
|
conn,
|
||||||
ItemType::Track,
|
queries::wanted::AddWantedItem {
|
||||||
title,
|
item_type: ItemType::Track,
|
||||||
recording_mbid,
|
name: title,
|
||||||
Some(artist.id),
|
musicbrainz_id: recording_mbid,
|
||||||
None,
|
artist_id: Some(artist.id),
|
||||||
None,
|
album_id: None,
|
||||||
|
track_id: None,
|
||||||
|
user_id,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -288,7 +291,6 @@ async fn resolve_artist_info(
|
|||||||
let mbid =
|
let mbid =
|
||||||
mbid.ok_or_else(|| WatchError::Other("either a name or --mbid is required".into()))?;
|
mbid.ok_or_else(|| WatchError::Other("either a name or --mbid is required".into()))?;
|
||||||
|
|
||||||
// Search for artist by MBID to get the name
|
|
||||||
let results = provider
|
let results = provider
|
||||||
.search_artist(mbid, 1)
|
.search_artist(mbid, 1)
|
||||||
.await
|
.await
|
||||||
@@ -385,12 +387,12 @@ pub async fn list_items(
|
|||||||
conn: &DatabaseConnection,
|
conn: &DatabaseConnection,
|
||||||
status_filter: Option<WantedStatus>,
|
status_filter: Option<WantedStatus>,
|
||||||
artist_filter: Option<&str>,
|
artist_filter: Option<&str>,
|
||||||
|
user_id: Option<i32>,
|
||||||
) -> WatchResult<Vec<WatchListEntry>> {
|
) -> WatchResult<Vec<WatchListEntry>> {
|
||||||
let items = queries::wanted::list(conn, status_filter).await?;
|
let items = queries::wanted::list(conn, status_filter, user_id).await?;
|
||||||
let mut entries = Vec::new();
|
let mut entries = Vec::new();
|
||||||
|
|
||||||
for item in items {
|
for item in items {
|
||||||
// Use the name field directly now
|
|
||||||
let artist_name = if let Some(id) = item.artist_id {
|
let artist_name = if let Some(id) = item.artist_id {
|
||||||
queries::artists::get_by_id(conn, id)
|
queries::artists::get_by_id(conn, id)
|
||||||
.await
|
.await
|
||||||
@@ -400,7 +402,6 @@ pub async fn list_items(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// Apply artist filter if provided
|
|
||||||
if let Some(filter) = artist_filter {
|
if let Some(filter) = artist_filter {
|
||||||
let filter_norm = matching::normalize(filter);
|
let filter_norm = matching::normalize(filter);
|
||||||
let matches = artist_name
|
let matches = artist_name
|
||||||
@@ -434,7 +435,7 @@ pub async fn remove_item(conn: &DatabaseConnection, id: i32) -> WatchResult<()>
|
|||||||
|
|
||||||
/// Get a summary of the library state.
|
/// Get a summary of the library state.
|
||||||
pub async fn library_summary(conn: &DatabaseConnection) -> WatchResult<LibrarySummary> {
|
pub async fn library_summary(conn: &DatabaseConnection) -> WatchResult<LibrarySummary> {
|
||||||
let all = queries::wanted::list(conn, None).await?;
|
let all = queries::wanted::list(conn, None, None).await?;
|
||||||
|
|
||||||
let mut summary = LibrarySummary::default();
|
let mut summary = LibrarySummary::default();
|
||||||
for item in &all {
|
for item in &all {
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
anyhow::bail!("provide either a name or --mbid");
|
anyhow::bail!("provide either a name or --mbid");
|
||||||
}
|
}
|
||||||
let summary =
|
let summary =
|
||||||
add_artist(db.conn(), name.as_deref(), mbid.as_deref(), &mb_client).await?;
|
add_artist(db.conn(), name.as_deref(), mbid.as_deref(), &mb_client, None).await?;
|
||||||
println!("Artist watch: {summary}");
|
println!("Artist watch: {summary}");
|
||||||
}
|
}
|
||||||
AddCommand::Album {
|
AddCommand::Album {
|
||||||
@@ -148,6 +148,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
album.as_deref(),
|
album.as_deref(),
|
||||||
mbid.as_deref(),
|
mbid.as_deref(),
|
||||||
&mb_client,
|
&mb_client,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
println!("Album watch: {summary}");
|
println!("Album watch: {summary}");
|
||||||
@@ -166,6 +167,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
title.as_deref(),
|
title.as_deref(),
|
||||||
mbid.as_deref(),
|
mbid.as_deref(),
|
||||||
&mb_client,
|
&mb_client,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
println!(
|
println!(
|
||||||
@@ -179,7 +181,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
},
|
},
|
||||||
Commands::List { status, artist } => {
|
Commands::List { status, artist } => {
|
||||||
let status_filter = status.as_deref().map(parse_status).transpose()?;
|
let status_filter = status.as_deref().map(parse_status).transpose()?;
|
||||||
let entries = list_items(db.conn(), status_filter, artist.as_deref()).await?;
|
let entries = list_items(db.conn(), status_filter, artist.as_deref(), None).await?;
|
||||||
|
|
||||||
if entries.is_empty() {
|
if entries.is_empty() {
|
||||||
println!("Watchlist is empty.");
|
println!("Watchlist is empty.");
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ async fn test_add_track_wanted() {
|
|||||||
let db = test_db().await;
|
let db = test_db().await;
|
||||||
let provider = MockProvider;
|
let provider = MockProvider;
|
||||||
|
|
||||||
let entry = add_track(db.conn(), Some("Radiohead"), Some("Creep"), None, &provider)
|
let entry = add_track(db.conn(), Some("Radiohead"), Some("Creep"), None, &provider, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(entry.item_type, ItemType::Track);
|
assert_eq!(entry.item_type, ItemType::Track);
|
||||||
@@ -133,7 +133,7 @@ async fn test_add_track_auto_owned() {
|
|||||||
|
|
||||||
insert_track(&db, "Pink Floyd", "Time", "DSOTM").await;
|
insert_track(&db, "Pink Floyd", "Time", "DSOTM").await;
|
||||||
|
|
||||||
let entry = add_track(db.conn(), Some("Pink Floyd"), Some("Time"), None, &provider)
|
let entry = add_track(db.conn(), Some("Pink Floyd"), Some("Time"), None, &provider, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(entry.status, WantedStatus::Owned);
|
assert_eq!(entry.status, WantedStatus::Owned);
|
||||||
@@ -150,12 +150,13 @@ async fn test_add_album_expands_to_tracks() {
|
|||||||
Some("Test Album"),
|
Some("Test Album"),
|
||||||
None,
|
None,
|
||||||
&provider,
|
&provider,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(summary.tracks_added, 2);
|
assert_eq!(summary.tracks_added, 2);
|
||||||
|
|
||||||
let items = list_items(db.conn(), Some(WantedStatus::Wanted), None)
|
let items = list_items(db.conn(), Some(WantedStatus::Wanted), None, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(items.len(), 2);
|
assert_eq!(items.len(), 2);
|
||||||
@@ -167,12 +168,12 @@ async fn test_add_artist_expands_to_tracks() {
|
|||||||
let db = test_db().await;
|
let db = test_db().await;
|
||||||
let provider = MockProvider;
|
let provider = MockProvider;
|
||||||
|
|
||||||
let summary = add_artist(db.conn(), Some("Test Artist"), None, &provider)
|
let summary = add_artist(db.conn(), Some("Test Artist"), None, &provider, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(summary.tracks_added, 2);
|
assert_eq!(summary.tracks_added, 2);
|
||||||
|
|
||||||
let items = list_items(db.conn(), None, None).await.unwrap();
|
let items = list_items(db.conn(), None, None, None).await.unwrap();
|
||||||
assert_eq!(items.len(), 2);
|
assert_eq!(items.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,22 +182,22 @@ async fn test_list_items_with_filters() {
|
|||||||
let db = test_db().await;
|
let db = test_db().await;
|
||||||
let provider = MockProvider;
|
let provider = MockProvider;
|
||||||
|
|
||||||
add_track(db.conn(), Some("Radiohead"), Some("Creep"), None, &provider)
|
add_track(db.conn(), Some("Radiohead"), Some("Creep"), None, &provider, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
add_track(db.conn(), Some("Tool"), Some("Lateralus"), None, &provider)
|
add_track(db.conn(), Some("Tool"), Some("Lateralus"), None, &provider, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let all = list_items(db.conn(), None, None).await.unwrap();
|
let all = list_items(db.conn(), None, None, None).await.unwrap();
|
||||||
assert_eq!(all.len(), 2);
|
assert_eq!(all.len(), 2);
|
||||||
|
|
||||||
let wanted = list_items(db.conn(), Some(WantedStatus::Wanted), None)
|
let wanted = list_items(db.conn(), Some(WantedStatus::Wanted), None, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(wanted.len(), 2);
|
assert_eq!(wanted.len(), 2);
|
||||||
|
|
||||||
let radiohead = list_items(db.conn(), None, Some("Radiohead"))
|
let radiohead = list_items(db.conn(), None, Some("Radiohead"), None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(radiohead.len(), 1);
|
assert_eq!(radiohead.len(), 1);
|
||||||
@@ -207,11 +208,11 @@ async fn test_remove_item() {
|
|||||||
let db = test_db().await;
|
let db = test_db().await;
|
||||||
let provider = MockProvider;
|
let provider = MockProvider;
|
||||||
|
|
||||||
let entry = add_track(db.conn(), Some("Radiohead"), Some("Creep"), None, &provider)
|
let entry = add_track(db.conn(), Some("Radiohead"), Some("Creep"), None, &provider, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
remove_item(db.conn(), entry.id).await.unwrap();
|
remove_item(db.conn(), entry.id).await.unwrap();
|
||||||
let all = list_items(db.conn(), None, None).await.unwrap();
|
let all = list_items(db.conn(), None, None, None).await.unwrap();
|
||||||
assert!(all.is_empty());
|
assert!(all.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,10 +223,10 @@ async fn test_library_summary() {
|
|||||||
|
|
||||||
insert_track(&db, "Pink Floyd", "Time", "DSOTM").await;
|
insert_track(&db, "Pink Floyd", "Time", "DSOTM").await;
|
||||||
|
|
||||||
add_track(db.conn(), Some("Radiohead"), Some("Creep"), None, &provider)
|
add_track(db.conn(), Some("Radiohead"), Some("Creep"), None, &provider, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
add_track(db.conn(), Some("Pink Floyd"), Some("Time"), None, &provider)
|
add_track(db.conn(), Some("Pink Floyd"), Some("Time"), None, &provider, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user