Skip to main content

lr2_oxytabler/
lib.rs

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        // jounin.jp, where new overjoy and insane 2 tables are hosted, blocks requests with no
20        // user-agent.
21        .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    // === No errors from this point
87    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}