1use crate::{output::OutputFolder, output::OutputFolderKey, time::UnixEpochTs};
2use anyhow::{Context as _, Result, ensure};
3use std::path::Path;
4
5pub mod changelog;
6pub mod db;
7pub mod fetch;
8pub mod lr2folder;
9pub mod mass_edit;
10pub mod migrations;
11pub mod output;
12pub mod table;
13pub mod time;
14pub mod url;
15
16pub fn build_reqwest() -> Result<reqwest::Client> {
17 const APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
18 reqwest::ClientBuilder::new()
19 .user_agent(APP_USER_AGENT)
22 .build()
23 .context("failed to build reqwest client")
24}
25
26pub fn open_db(
27 path: &Path,
28 outputs: &[OutputFolder],
29) -> Result<(rusqlite::Connection, Vec<table::Table>)> {
30 fn validate_good_outputs(outputs: &[OutputFolder]) -> Result<()> {
31 if let Some(p) = OutputFolder::is_any_parent_of_another(outputs) {
32 anyhow::bail!(
33 "intersecting output paths found: '{}:{}' and '{}:{}'",
34 p.0.0,
35 p.0.1.display(),
36 p.1.0,
37 p.1.1.display()
38 );
39 }
40
41 for OutputFolder(_key, path) in outputs {
42 lr2folder::validate_good_playlists_folder(path)
43 .context("bad playlists folder selected")?;
44 }
45
46 Ok(())
47 }
48
49 fn validate_outputs_for_tables(
50 tables: &[table::Table],
51 outputs: &[OutputFolder],
52 ) -> Result<()> {
53 for table::Table(table, add_data) in tables {
54 ensure!(
55 outputs.iter().any(|o| o.0 == add_data.output),
56 "missing --output '{}' required for table '{}'",
57 add_data.output.0,
58 table.name,
59 );
60 }
61 Ok(())
62 }
63
64 validate_good_outputs(outputs)?;
65 let (db, tables) = db::open_from_file(path)?;
66 validate_outputs_for_tables(&tables, outputs)?;
67 Ok((db, tables))
68}
69
70pub fn save_db(
71 db: &mut rusqlite::Connection,
72 outputs: &[OutputFolder],
73 tables: &mut [table::Table],
74 write_tags: bool,
75) -> Result<()> {
76 let tx = db
77 .transaction()
78 .context("failed to start transaction for updating db")?;
79 let table_ids = db::save_db_raw(&tx, tables)?;
80 if write_tags {
81 db::update_tags_inplace(&tx)?;
82 }
83 lr2folder::write_files(outputs, tables, &table_ids)?;
84 tx.commit()
85 .context("failed to commit after writing playlists")?;
86 for (table, id) in tables.iter_mut().zip(table_ids) {
88 table.1.playlist_id = Some(id);
89 }
90 for table in tables.iter_mut() {
91 table.1.entry_diff_to_save_to_db.clear();
92 }
93 Ok(())
94}