artifacts: make beets more forgiving, and handle errors with logs

This commit is contained in:
2026-06-11 21:41:29 +02:00
parent 5784c2440a
commit a049cdacdb
2 changed files with 22 additions and 13 deletions
+14 -12
View File
@@ -3,7 +3,7 @@ use std::process::{Command, Stdio};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::artifacts::{Artifact, Track}; use crate::artifacts::{Artifact, SourceID, Track};
#[derive(Debug, Default, Serialize, Deserialize, Clone, JsonSchema)] #[derive(Debug, Default, Serialize, Deserialize, Clone, JsonSchema)]
@@ -19,8 +19,8 @@ pub struct BeatsQueryArgs {
struct BeetsTrack { struct BeetsTrack {
album: String, album: String,
artist: String, artist: String,
genres: Vec<String>, genres: Option<Vec<String>>,
label: String, label: Option<String>,
title: String, title: String,
year: u32 year: u32
} }
@@ -29,18 +29,19 @@ impl Into<Artifact> for BeetsTrack {
fn into(self) -> Artifact { fn into(self) -> Artifact {
Artifact::Track(Track { Artifact::Track(Track {
title: self.title, title: self.title,
label: Some(self.label), label: self.label,
year: Some(self.year), year: Some(self.year),
genres: self.genres, genres: self.genres.unwrap_or_default(),
album: Some(self.album), album: Some(self.album),
artist: Some(self.artist), artist: Some(self.artist),
bpm: None bpm: None,
sources: vec![SourceID::Beets]
}) })
} }
} }
impl BeatsQueryArgs { impl BeatsQueryArgs {
pub fn execute(self) -> Result<Artifact, ()> { pub fn execute(self) -> Result<Vec<Artifact>, ()> {
let mut beets_cmd = Command::new("beet"); let mut beets_cmd = Command::new("beet");
beets_cmd.args(["export", "-f", "json", "-i", "title,label,year,genres,album,artist"]); beets_cmd.args(["export", "-f", "json", "-i", "title,label,year,genres,album,artist"]);
if let Some(artist) = self.artist { if let Some(artist) = self.artist {
@@ -61,11 +62,12 @@ impl BeatsQueryArgs {
log::debug!("Executing beets: {:?}", beets_cmd); log::debug!("Executing beets: {:?}", beets_cmd);
if let Ok(output) = beets_cmd.stdout(Stdio::piped()).spawn().unwrap().wait_with_output() { if let Ok(output) = beets_cmd.stdout(Stdio::piped()).spawn().unwrap().wait_with_output() {
if let Ok(track) = serde_json::from_str::<BeetsTrack>(str::from_utf8(&output.stdout).unwrap()) { match serde_json::from_str::<Vec<BeetsTrack>>(str::from_utf8(&output.stdout).unwrap()) {
Ok(track.into()) Ok(track) => Ok(track.into_iter().map(|t| { t.into()}).collect()),
} else { Err(err) => {
log::error!("Failed to decode beets json"); log::error!("Failed to decode beets json: {:?}", err);
Err(()) Err(())
}
} }
} else { } else {
log::error!("Unable to execute query!"); log::error!("Unable to execute query!");
+8 -1
View File
@@ -138,8 +138,15 @@ impl Session {
async fn tool_artifact_query(&mut self, args: BeatsQueryArgs) -> ToolResults { async fn tool_artifact_query(&mut self, args: BeatsQueryArgs) -> ToolResults {
let mut messages = vec![]; let mut messages = vec![];
messages.push(ConversationEntry::ShipComputer(format!("Executing archive query {:?}", args))); messages.push(ConversationEntry::ShipComputer(format!("Executing archive query {:?}", args)));
log::info!("Executing beets query {:?}", args);
if let Ok(output) = args.execute() { if let Ok(output) = args.execute() {
self.scenery.artifacts.push(output); for track in &output {
if let Some(merge_target) = self.scenery.artifacts.iter_mut().find(|a| { *a == track }) {
merge_target.merge(track.clone());
} else {
self.scenery.artifacts.push(track.clone());
}
}
} else { } else {
messages.push(ConversationEntry::ShipComputer("Unable to execute query!".into())); messages.push(ConversationEntry::ShipComputer("Unable to execute query!".into()));
}; };