use std::io::Write;
use anyhow::{Context, Result};
use doiget_core::store::{FsStore, Store};
use super::resolve_store_root;
const FETCHED_AT_FMT: &str = "%Y-%m-%dT%H:%M:%SZ";
pub fn run(
limit: usize,
missing_pdf: bool,
mode: super::output::OutputMode,
quiet_was_explicit: bool,
) -> Result<()> {
let store_root = resolve_store_root()?;
let store = FsStore::new(store_root)?;
let mut entries = store
.list_recent(limit)
.context("failed to list recent store entries")?;
if missing_pdf {
entries.retain(|e| !e.has_pdf());
}
if mode == super::output::OutputMode::Quiet && quiet_was_explicit {
return Ok(());
}
let stdout = std::io::stdout();
let mut out = stdout.lock();
if mode == super::output::OutputMode::Json {
let entries_json: Vec<serde_json::Value> = entries
.iter()
.map(|e| {
let mut v = serde_json::to_value(e)
.unwrap_or_else(|_| serde_json::json!({ "safekey": e.safekey.as_str() }));
if let Some(o) = v.as_object_mut() {
o.insert("has_pdf".into(), serde_json::json!(e.has_pdf()));
}
v
})
.collect();
let envelope = serde_json::json!({
"ok": true,
"count": entries_json.len(),
"entries": entries_json,
});
let s = serde_json::to_string_pretty(&envelope)
.context("failed to serialize list-recent entries to JSON")?;
writeln!(out, "{s}").context("failed to write list-recent JSON to stdout")?;
return Ok(());
}
writeln!(out, "safekey\tyear\ttitle\tfetched_at\tpdf")
.context("failed to write list-recent header to stdout")?;
for e in &entries {
let year = e.year.map(|y| y.to_string()).unwrap_or_else(|| "-".into());
let fetched = e
.fetched_at
.map(|t| t.format(FETCHED_AT_FMT).to_string())
.unwrap_or_else(|| "-".into());
writeln!(
out,
"{}\t{}\t{}\t{}\t{}",
e.safekey.as_str(),
year,
e.title,
fetched,
pdf_cell(e)
)
.context("failed to write list-recent row to stdout")?;
}
Ok(())
}
pub(crate) fn pdf_cell(e: &doiget_core::store::EntryInfo) -> String {
match e.size_bytes {
None => "?".to_string(),
Some(0) => "-".to_string(),
#[allow(clippy::cast_precision_loss)]
Some(n) if n >= 1_048_576 => format!("{:.1} MB", n as f64 / 1_048_576.0),
#[allow(clippy::cast_precision_loss)]
Some(n) if n >= 1024 => format!("{:.1} kB", n as f64 / 1024.0),
Some(n) => format!("{n} B"),
}
}