use crate::{
build_reqwest, changelog, fetch, open_db, output::OutputFolder, save_db, table::Table,
time::UnixEpochTs,
};
use anyhow::Result;
use std::{collections::HashMap, path::Path};
const TABLE_UPDATE_INTERVAL: UnixEpochTs = UnixEpochTs(60 * 60 * 12);
pub fn run(db: &Path, outputs: &[OutputFolder], write_tags: bool) -> Result<()> {
let (mut db, mut tables) = open_db(db, outputs)?;
let mut fallback_song_titles = HashMap::<String, String>::new();
let now = UnixEpochTs::now();
let client = build_reqwest()?;
let runtime = tokio::runtime::Runtime::new()?;
let tasks = tables
.iter()
.filter(|t| t.wants_updating(now, TABLE_UPDATE_INTERVAL))
.map(fetch::TableLocator::new_for_table)
.collect::<Vec<_>>();
log::info!("[1/3] fetching {} tables...", tasks.len());
let pb = indicatif::ProgressBar::new(tasks.len().try_into()?)
.with_style(indicatif::ProgressStyle::default_bar());
let updates = runtime.block_on(futures::future::join_all(tasks.into_iter().map(
|locator| {
let client = client.clone();
let pb = pb.clone();
async move {
let out = fetch::fetch_table(client, locator.web_url().clone()).await;
pb.inc(1);
(out, locator)
}
},
)));
pb.finish_and_clear();
log::info!("[2/3] applying updates...");
for update in updates {
match update {
(Ok((answer, new_song_titles)), locator) => {
fallback_song_titles.extend(new_song_titles);
Table::apply_update(
&changelog::SongNameAccessor::new(&db, &fallback_song_titles),
&mut tables,
answer,
&locator,
now,
)?;
}
(Err(e), locator) => {
log::warn!("table {locator}: fetch error: {e}");
log::debug!("full error: {e:?}");
}
}
}
log::info!("[3/3] saving...");
save_db(&mut db, outputs, &mut tables, write_tags)?;
log::info!("all done!");
Ok(())
}