summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjakka <jakka@jakka.su>2025-09-30 17:00:59 +0300
committerjakka <jakka@jakka.su>2025-09-30 17:00:59 +0300
commitd531f8909d3ee47ea11a7a0dc60ea70819c16032 (patch)
treeb0faba9c6f8ee0686358c2a8252709f1ed6ef540 /src
parent9e4796570baf97d2193745a350e9611fa21d6a78 (diff)
removed useless trait, reorganized code, isolated modules
Diffstat (limited to 'src')
-rw-r--r--src/db.rs203
-rw-r--r--src/files.rs50
-rw-r--r--src/flac.rs4
-rw-r--r--src/main.rs7
4 files changed, 125 insertions, 139 deletions
diff --git a/src/db.rs b/src/db.rs
index 809e5e0..ba14c1a 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -20,126 +20,109 @@ const DEDUPE_DB: &str =
"DELETE FROM flacs WHERE rowid NOT IN (SELECT MAX(rowid) FROM flacs GROUP BY path)";
const GET_MODTIME: &str = "SELECT modtime FROM flacs WHERE path = ?1";
-pub trait Database {
- type Conn;
- fn new(path: Option<&PathBuf>) -> Result<Self::Conn>;
- fn insert_file(&self, filename: &Path) -> Result<()>;
- fn update_file(&self, filename: &Path) -> Result<()>;
- fn check_file(&self, filename: &Path) -> Result<bool>;
- fn init_clean_files(&self) -> Result<Vec<PathBuf>, rusqlite::Error>;
- fn remove_file(&self, filename: &Path) -> Result<()>;
- fn get_toencode_files(&self) -> Result<Vec<PathBuf>, rusqlite::Error>;
- fn get_toencode_number(&self) -> Result<u64, rusqlite::Error>;
- fn get_modtime(&self, file: &Path) -> Result<u64>;
- fn vacuum(&self) -> Result<()>;
+pub(crate) fn init_connection(path: Option<&PathBuf>) -> Result<Connection> {
+ let conn = if let Some(file) = path {
+ Connection::open(file)?
+ } else if let Some(base_dir) = BaseDirs::new() {
+ let file = Path::new(base_dir.data_dir()).join("reencoder.db");
+ Connection::open(file)?
+ } else {
+ return Err(anyhow!("Failed to locate data directory"));
+ };
+ conn.execute(TABLE_CREATE, ())?;
+ Ok(conn)
}
-impl Database for Connection {
- type Conn = Connection;
- fn new(path: Option<&PathBuf>) -> Result<Self> {
- let conn = if let Some(file) = path {
- Connection::open(file)?
- } else if let Some(base_dir) = BaseDirs::new() {
- let file = Path::new(base_dir.data_dir()).join("reencoder.db");
- Connection::open(file)?
- } else {
- return Err(anyhow!("Failed to locate data directory"));
- };
- conn.execute(TABLE_CREATE, ())?;
- Ok(conn)
- }
-
- fn insert_file(&self, filename: &Path) -> Result<()> {
- let toencode = !matches!(get_vendor(filename)?.as_str(), CURRENT_VENDOR);
+pub(crate) fn insert_file(conn: &Connection, filename: &Path) -> Result<()> {
+ let toencode = !matches!(get_vendor(filename)?.as_str(), CURRENT_VENDOR);
- let modtime = filename
- .metadata()?
- .modified()?
- .duration_since(UNIX_EPOCH)?
- .as_secs();
+ let modtime = filename
+ .metadata()?
+ .modified()?
+ .duration_since(UNIX_EPOCH)?
+ .as_secs();
- self.execute(
- ADD_ITEM,
- params![filename.to_str().unwrap(), toencode, modtime],
- )?;
+ conn.execute(
+ ADD_ITEM,
+ params![filename.to_str().unwrap(), toencode, modtime],
+ )?;
- Ok(())
- }
+ Ok(())
+}
- fn update_file(&self, filename: &Path) -> Result<()> {
- let modtime = filename
- .metadata()?
- .modified()?
- .duration_since(UNIX_EPOCH)?
- .as_secs();
+pub(crate) fn update_file(conn: &Connection, filename: &Path) -> Result<()> {
+ let modtime = filename
+ .metadata()?
+ .modified()?
+ .duration_since(UNIX_EPOCH)?
+ .as_secs();
- self.execute(
- UPDATE_ITEM,
- params![filename.to_str().unwrap(), false, modtime],
- )?;
+ conn.execute(
+ UPDATE_ITEM,
+ params![filename.to_str().unwrap(), false, modtime],
+ )?;
- Ok(())
- }
+ Ok(())
+}
- fn check_file(&self, filename: &Path) -> Result<bool> {
- if self.query_one(CHECK_FILE, params!(filename.to_str().unwrap()), |row| {
- let num: bool = row.get(0)?;
- Ok(num)
- })? {
- Ok(true)
- } else {
- Ok(false)
- }
+pub(crate) fn check_file(conn: &Connection, filename: &Path) -> Result<bool> {
+ if conn.query_one(CHECK_FILE, params!(filename.to_str().unwrap()), |row| {
+ let num: bool = row.get(0)?;
+ Ok(num)
+ })? {
+ Ok(true)
+ } else {
+ Ok(false)
}
+}
- fn init_clean_files(&self) -> Result<Vec<PathBuf>, rusqlite::Error> {
- self.execute(DEDUPE_DB, ())?;
- let mut stmt = self.prepare(FETCH_FILES)?;
- let mut rows = stmt.query(())?;
- let mut files = Vec::new();
- while let Ok(Some(row)) = rows.next() {
- let path: String = row.get(0)?;
- files.push(PathBuf::from(path));
- }
- Ok(files)
+pub(crate) fn init_clean_files(conn: &Connection) -> Result<Vec<PathBuf>, rusqlite::Error> {
+ conn.execute(DEDUPE_DB, ())?;
+ let mut stmt = conn.prepare(FETCH_FILES)?;
+ let mut rows = stmt.query(())?;
+ let mut files = Vec::new();
+ while let Ok(Some(row)) = rows.next() {
+ let path: String = row.get(0)?;
+ files.push(PathBuf::from(path));
}
+ Ok(files)
+}
- fn remove_file(&self, filename: &Path) -> Result<()> {
- self.execute(REMOVE_FILE, params!(filename.to_str().unwrap()))?;
- Ok(())
- }
+pub(crate) fn remove_file(conn: &Connection, filename: &Path) -> Result<()> {
+ conn.execute(REMOVE_FILE, params!(filename.to_str().unwrap()))?;
+ Ok(())
+}
- fn get_toencode_files(&self) -> Result<Vec<PathBuf>, rusqlite::Error> {
- let mut stmt = self.prepare(TOENCODE_PATHS)?;
- let mut rows = stmt.query(())?;
- let mut files: Vec<PathBuf> = Vec::new();
- while let Ok(Some(row)) = rows.next() {
- let path: String = row.get(0)?;
- files.push(PathBuf::from(path));
- }
- Ok(files)
+pub(crate) fn get_toencode_files(conn: &Connection) -> Result<Vec<PathBuf>, rusqlite::Error> {
+ let mut stmt = conn.prepare(TOENCODE_PATHS)?;
+ let mut rows = stmt.query(())?;
+ let mut files: Vec<PathBuf> = Vec::new();
+ while let Ok(Some(row)) = rows.next() {
+ let path: String = row.get(0)?;
+ files.push(PathBuf::from(path));
}
+ Ok(files)
+}
- fn get_toencode_number(&self) -> Result<u64, rusqlite::Error> {
- self.query_one(TOENCODE_NUMBER, (), |row| {
- let num: u64 = row.get(0)?;
- Ok(num)
- })
- }
+pub(crate) fn get_toencode_number(conn: &Connection) -> Result<u64, rusqlite::Error> {
+ conn.query_one(TOENCODE_NUMBER, (), |row| {
+ let num: u64 = row.get(0)?;
+ Ok(num)
+ })
+}
- fn get_modtime(&self, file: &Path) -> Result<u64> {
- Ok(
- self.query_one(GET_MODTIME, params![file.to_str().unwrap()], |row| {
- let modtime: u64 = row.get(0)?;
- Ok(modtime)
- })?,
- )
- }
+pub(crate) fn get_modtime(conn: &Connection, file: &Path) -> Result<u64> {
+ Ok(
+ conn.query_one(GET_MODTIME, params![file.to_str().unwrap()], |row| {
+ let modtime: u64 = row.get(0)?;
+ Ok(modtime)
+ })?,
+ )
+}
- fn vacuum(&self) -> Result<()> {
- self.execute("VACUUM", ())?;
- Ok(())
- }
+pub(crate) fn vacuum(conn: &Connection) -> Result<()> {
+ conn.execute("VACUUM", ())?;
+ Ok(())
}
#[cfg(test)]
@@ -156,10 +139,10 @@ mod tests {
"./samples/32bit.flac",
];
let mut counter = 0;
- let conn = Connection::new(Some(&dbname)).unwrap();
+ let conn = init_connection(Some(&dbname)).unwrap();
for file in filenames {
let filename = PathBuf::from(file);
- conn.insert_file(&filename).unwrap();
+ insert_file(&conn, &filename).unwrap();
}
let mut stmt = conn.prepare(TOENCODE_PATHS).unwrap();
let mut returned = stmt.query(()).unwrap();
@@ -179,10 +162,9 @@ mod tests {
"./samples/24bit.flac",
"./samples/32bit.flac",
];
- let conn = Connection::new(Some(&dbname)).unwrap();
+ let conn = init_connection(Some(&dbname)).unwrap();
for file in filenames {
- conn.insert_file(&Path::new(file).canonicalize().unwrap())
- .unwrap();
+ insert_file(&conn, &Path::new(file).canonicalize().unwrap()).unwrap();
}
conn.execute(
@@ -199,8 +181,11 @@ mod tests {
)
.unwrap();
- conn.update_file(&Path::new("./samples/16bit.flac").canonicalize().unwrap())
- .unwrap();
+ update_file(
+ &conn,
+ &Path::new("./samples/16bit.flac").canonicalize().unwrap(),
+ )
+ .unwrap();
let mut stmt = conn.prepare(TOENCODE_PATHS).unwrap();
let mut returned = stmt.query(()).unwrap();
diff --git a/src/files.rs b/src/files.rs
index afb42d7..3b00de1 100644
--- a/src/files.rs
+++ b/src/files.rs
@@ -1,3 +1,5 @@
+use crate::db;
+use crate::flac::handle_encode;
use anyhow::{Result, anyhow};
#[cfg(not(test))]
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
@@ -15,8 +17,6 @@ use std::{
};
use walkdir::WalkDir;
-use crate::{db::Database, flac::handle_encode};
-
#[cfg(not(test))]
const BAR_TEMPLATE: &str = "{msg:<} [{wide_bar:.green/cyan}] Elapsed: {elapsed} {pos:>7}/{len:7}";
#[cfg(not(test))]
@@ -51,25 +51,25 @@ impl Display for FileError {
impl Error for FileError {}
fn handle_file(file: &Path, conn: &Connection) -> Result<()> {
- if conn.check_file(file)? {
+ if db::check_file(conn, file)? {
let modtime = file
.metadata()?
.modified()?
.duration_since(UNIX_EPOCH)?
.as_secs();
- let db_modtime = conn.get_modtime(file)?;
+ let db_modtime = db::get_modtime(conn, file)?;
if modtime != db_modtime {
- conn.update_file(file)?;
+ db::update_file(conn, file)?;
}
return Ok(());
}
- conn.insert_file(file)?;
+ db::insert_file(conn, file)?;
Ok(())
}
-pub fn index_files_recursively(
+pub(crate) fn index_files_recursively(
path: &Path,
conn: &Connection,
handler: Arc<AtomicBool>,
@@ -129,16 +129,20 @@ pub fn index_files_recursively(
Ok(())
}
-pub fn reencode_files(conn: Connection, handler: Arc<AtomicBool>, threads: usize) -> Result<()> {
+pub(crate) fn reencode_files(
+ conn: Connection,
+ handler: Arc<AtomicBool>,
+ threads: usize,
+) -> Result<()> {
#[cfg(not(test))]
let bar = ProgressBar::with_draw_target(
- Some(conn.get_toencode_number()?),
+ Some(db::get_toencode_number(&conn)?),
ProgressDrawTarget::stdout_with_hz(60),
)
.with_style(ProgressStyle::with_template(BAR_TEMPLATE)?.progress_chars("#>-"))
.with_message("Reencoding");
- let mut files = conn.get_toencode_files()?.into_iter();
+ let mut files = db::get_toencode_files(&conn)?.into_iter();
let lock = Arc::new(Mutex::new(conn));
@@ -170,7 +174,7 @@ pub fn reencode_files(conn: Connection, handler: Arc<AtomicBool>, threads: usize
match handle_encode(&file, handler) {
Err(error) => eprintln!("{}", FileError::new(&file, error)),
Ok(false) => {
- if let Err(error) = lock.lock().unwrap().update_file(&file) {
+ if let Err(error) = db::update_file(&lock.lock().unwrap(), &file) {
eprintln!("{}", FileError::new(&file, error));
}
#[cfg(not(test))]
@@ -194,8 +198,8 @@ pub fn reencode_files(conn: Connection, handler: Arc<AtomicBool>, threads: usize
Ok(())
}
-pub fn clean_files(conn: &Connection, handler: Arc<AtomicBool>) -> Result<()> {
- let files = conn.init_clean_files()?;
+pub(crate) fn clean_files(conn: &Connection, handler: Arc<AtomicBool>) -> Result<()> {
+ let files = db::init_clean_files(conn)?;
#[cfg(not(test))]
let spinner = ProgressBar::with_draw_target(None, ProgressDrawTarget::stdout_with_hz(60))
@@ -206,7 +210,7 @@ pub fn clean_files(conn: &Connection, handler: Arc<AtomicBool>) -> Result<()> {
files.iter().for_each(|file| {
#[allow(clippy::collapsible_if)]
if handler.load(Ordering::SeqCst) && !file.exists() {
- if let Err(error) = conn.remove_file(file) {
+ if let Err(error) = db::remove_file(conn, file) {
eprintln!("{}", FileError::new(file, error))
};
#[cfg(not(test))]
@@ -216,7 +220,7 @@ pub fn clean_files(conn: &Connection, handler: Arc<AtomicBool>) -> Result<()> {
#[cfg(not(test))]
spinner.finish();
- conn.vacuum()?;
+ db::vacuum(conn)?;
Ok(())
}
@@ -229,7 +233,7 @@ mod tests {
fn test_index_lots_of_files() {
let dbname = PathBuf::from("temp3.db");
let handler = Arc::new(AtomicBool::new(true));
- let conn = Connection::new(Some(&dbname)).unwrap();
+ let conn = db::init_connection(Some(&dbname)).unwrap();
index_files_recursively(Path::new("./testfiles"), &conn, handler).unwrap();
std::fs::remove_file(dbname).unwrap();
}
@@ -238,7 +242,7 @@ mod tests {
fn test_clean_files() {
let dbname = PathBuf::from("temp4.db");
let handler = Arc::new(AtomicBool::new(true));
- let conn = Connection::new(Some(&dbname)).unwrap();
+ let conn = db::init_connection(Some(&dbname)).unwrap();
let filenames = [
"./samples/16bit.flac",
"./samples/24bit.flac",
@@ -248,13 +252,13 @@ mod tests {
std::fs::copy("./samples/32bit.flac", "./samples/nonexisting.flac").unwrap();
for file in filenames {
let filename = PathBuf::from(file);
- conn.insert_file(&filename).unwrap();
+ db::insert_file(&conn, &filename).unwrap();
}
std::fs::remove_file("./samples/nonexisting.flac").unwrap();
clean_files(&conn, handler).unwrap();
- let counter = conn.init_clean_files().unwrap().len();
+ let counter = db::init_clean_files(&conn).unwrap().len();
std::fs::remove_file(dbname).unwrap();
assert!(counter == 3)
}
@@ -263,13 +267,13 @@ mod tests {
fn test_reencode_lots_of_files() {
let dbname = PathBuf::from("temp5.db");
let handler = Arc::new(AtomicBool::new(true));
- let conn = Connection::new(Some(&dbname)).unwrap();
+ let conn = db::init_connection(Some(&dbname)).unwrap();
let temp = handler.clone();
index_files_recursively(Path::new("./testfiles"), &conn, temp).unwrap();
- println!("\n{}", conn.get_toencode_number().unwrap());
+ println!("\n{}", db::get_toencode_number(&conn).unwrap());
reencode_files(conn, handler, 4).unwrap();
- let conn = Connection::new(Some(&dbname)).unwrap();
- println!("\n{}", conn.get_toencode_number().unwrap());
+ let conn = db::init_connection(Some(&dbname)).unwrap();
+ println!("\n{}", db::get_toencode_number(&conn).unwrap());
std::fs::remove_file(dbname).unwrap();
}
}
diff --git a/src/flac.rs b/src/flac.rs
index e882cd7..eb603d7 100644
--- a/src/flac.rs
+++ b/src/flac.rs
@@ -141,7 +141,7 @@ fn encode_file(filename: &Path, handler: Arc<AtomicBool>) -> Result<bool> {
Ok(false)
}
-pub fn handle_encode(filename: &Path, handler: Arc<AtomicBool>) -> Result<bool> {
+pub(crate) fn handle_encode(filename: &Path, handler: Arc<AtomicBool>) -> Result<bool> {
match encode_file(filename, handler) {
Err(error) => {
let _ = std::fs::remove_file(filename.with_extension("tmp"));
@@ -151,7 +151,7 @@ pub fn handle_encode(filename: &Path, handler: Arc<AtomicBool>) -> Result<bool>
}
}
-pub fn get_vendor(file: &Path) -> Result<String> {
+pub(crate) fn get_vendor(file: &Path) -> Result<String> {
let blocklist = metadata::BlockList::open(file)?;
if let Some(data) = blocklist.get::<metadata::VorbisComment>() {
Ok(data.vendor_string.to_owned())
diff --git a/src/main.rs b/src/main.rs
index d1e4562..de3da62 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,7 +5,6 @@ use anyhow::Result;
use clap::{Arg, ArgAction, Command, ValueHint, command, value_parser};
use clap_complete::{Generator, Shell, generate};
use console::style;
-use rusqlite::Connection;
use std::{
path::PathBuf,
sync::{
@@ -14,8 +13,6 @@ use std::{
},
};
-use crate::db::Database;
-
fn build_cli() -> Command {
command!()
.arg(
@@ -93,12 +90,12 @@ fn main() -> Result<()> {
r.store(false, Ordering::SeqCst);
})?;
- let conn = Connection::new(args.get_one::<PathBuf>("db"))?;
+ let conn = db::init_connection(args.get_one::<PathBuf>("db"))?;
let path = args.get_one::<PathBuf>("path");
if path.is_none() && !args.get_flag("clean") && !args.get_flag("doit") {
- let count = conn.get_toencode_number()?;
+ let count = db::get_toencode_number(&conn)?;
println!("Files to reencode:\t{}", style(count).green());
return Ok(());
}