gonk_core/
lib.rs

1pub use crate::{
2    index::Index,
3    song::Song,
4    sqlite::{Database, State},
5    toml::{Bind, Colors, GlobalHotkey, Hotkey, Key, Modifier, Toml},
6};
7use static_init::dynamic;
8use std::path::PathBuf;
9
10mod index;
11mod song;
12mod toml;
13
14pub mod sqlite;
15
16#[dynamic]
17pub static GONK_DIR: PathBuf = {
18    let gonk = dirs::config_dir().unwrap().join("gonk");
19    if !gonk.exists() {
20        std::fs::create_dir_all(&gonk).unwrap();
21    }
22    gonk
23};
24
25#[dynamic]
26pub static DB_DIR: PathBuf = GONK_DIR.join("gonk.db");
27
28#[dynamic]
29pub static TOML_DIR: PathBuf = GONK_DIR.join("gonk.toml");
30
31#[cfg(test)]
32mod tests {
33    /*
34        cargo test --release --lib -- tests::bench_adding --exact
35        hyperfine 'cargo test --release --lib -- tests::bench_adding --exact' -w 5 -r 50
36    */
37
38    #[test]
39    fn bench_adding() {
40        use crate::sqlite;
41        use crate::sqlite::conn;
42        use crate::Song;
43        use jwalk::WalkDir;
44        use rayon::iter::{IntoParallelIterator, ParallelIterator};
45        use std::path::PathBuf;
46
47        unsafe {
48            sqlite::CONN = sqlite::open_database();
49        }
50
51        let paths: Vec<PathBuf> = WalkDir::new("D:\\Music")
52            .into_iter()
53            .flatten()
54            .map(|dir| dir.path())
55            .filter(|path| match path.extension() {
56                Some(ex) => {
57                    matches!(ex.to_str(), Some("flac" | "mp3" | "ogg" | "wav" | "m4a"))
58                }
59                None => false,
60            })
61            .collect();
62
63        let songs: Vec<Song> = paths
64            .into_par_iter()
65            .map(|dir| Song::from(&dir))
66            .flatten()
67            .collect();
68
69        if songs.is_empty() {
70            return;
71        }
72
73        let mut stmt = String::from("BEGIN;\n");
74        stmt.push_str(&songs.iter()
75                .map(|song| {
76                    let artist = song.artist.replace('\'', r"''");
77                    let album = song.album.replace('\'', r"''");
78                    let name = song.name.replace('\'', r"''");
79                    let path = song.path.to_string_lossy().replace('\'', r"''");
80                    let parent = "D:\\Music";
81                    format!("INSERT OR IGNORE INTO song (number, disc, name, album, artist, path, duration, track_gain, parent) VALUES ('{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}');",
82                                song.number, song.disc, name, album, artist,path, song.duration.as_secs_f64(), song.track_gain, parent)
83                })
84                .collect::<Vec<_>>().join("\n"));
85
86        stmt.push_str("COMMIT;\n");
87
88        conn().execute_batch(&stmt).unwrap();
89    }
90
91    /*
92    cargo test --release --lib -- tests::bench_query --exact --nocapture
93    */
94
95    #[test]
96    fn bench_query() {
97        use crate::sqlite;
98
99        unsafe {
100            sqlite::CONN = sqlite::open_database();
101        }
102
103        let t = std::time::Instant::now();
104
105        for _ in 0..10 {
106            let artists = sqlite::get_all_artists();
107            for artist in artists {
108                let albums = sqlite::get_all_albums_by_artist(&artist);
109                for album in albums {
110                    let songs = sqlite::get_all_songs_from_album(&album, &artist);
111                    assert!(!songs.is_empty());
112                }
113            }
114        }
115        eprintln!("{:0.2?}", t.elapsed())
116    }
117
118    #[cfg(windows)]
119    #[test]
120    fn windows_keybindings() {
121        use crate::{Bind, Key, Modifier};
122        use global_hotkeys::{keys, modifiers};
123
124        let b = Bind {
125            key: Key::from("A"),
126            modifiers: Some(vec![Modifier::ALT, Modifier::SHIFT]),
127        };
128        assert_eq!(Bind::new("A").key(), 'A' as u32);
129        assert_eq!(Bind::new("TAB").key(), keys::TAB);
130        assert_eq!(b.modifiers(), modifiers::ALT | modifiers::SHIFT);
131    }
132}