mirror of
https://github.com/CDrummond/bliss-analyser.git
synced 2025-04-08 05:00:02 +03:00
Add optio to just update tags.
This commit is contained in:
parent
b918cc6f83
commit
faedc0302b
@ -9,14 +9,14 @@
|
||||
use anyhow::{Result};
|
||||
use bliss_audio::{library::analyze_paths_streaming};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use lofty::{Accessor, Probe};
|
||||
use std::convert::TryInto;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use crate::db;
|
||||
use crate::tags;
|
||||
|
||||
const DONT_ANALYSE:&str = ".nomusic";
|
||||
|
||||
fn get_file_list(db:&mut db::Db, mpath:& Path, path: &Path, to_add:&mut Vec<String>) {
|
||||
fn get_file_list(db:&mut db::Db, mpath:&PathBuf, path:&PathBuf, track_paths:&mut Vec<String>) {
|
||||
if path.is_dir() {
|
||||
match path.read_dir() {
|
||||
Ok(items) => {
|
||||
@ -30,7 +30,7 @@ fn get_file_list(db:&mut db::Db, mpath:& Path, path: &Path, to_add:&mut Vec<Stri
|
||||
if check.exists() {
|
||||
log::error!("Skiping {}", pb.to_string_lossy());
|
||||
} else {
|
||||
get_file_list(db, mpath, &entry.path(), to_add);
|
||||
get_file_list(db, mpath, &entry.path(), track_paths);
|
||||
}
|
||||
} else if entry.path().is_file() {
|
||||
let e = pb.extension();
|
||||
@ -49,7 +49,7 @@ fn get_file_list(db:&mut db::Db, mpath:& Path, path: &Path, to_add:&mut Vec<Stri
|
||||
match db.get_rowid(&sname) {
|
||||
Ok(id) => {
|
||||
if id<=0 {
|
||||
to_add.push(String::from(pb.to_string_lossy()));
|
||||
track_paths.push(String::from(pb.to_string_lossy()));
|
||||
}
|
||||
},
|
||||
Err(_) => { }
|
||||
@ -71,47 +71,15 @@ fn get_file_list(db:&mut db::Db, mpath:& Path, path: &Path, to_add:&mut Vec<Stri
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_metadata(track:&String) -> db::Metadata {
|
||||
let mut meta = db::Metadata{
|
||||
title:String::new(),
|
||||
artist:String::new(),
|
||||
album:String::new(),
|
||||
genre:String::new(),
|
||||
duration:180
|
||||
};
|
||||
let path = Path::new(track);
|
||||
match Probe::open(path) {
|
||||
Ok(probe) => {
|
||||
match probe.read(true) {
|
||||
Ok(file) => {
|
||||
let tag = match file.primary_tag() {
|
||||
Some(primary_tag) => primary_tag,
|
||||
None => file.first_tag().expect("Error: No tags found!"),
|
||||
};
|
||||
|
||||
meta.title=tag.title().unwrap_or("").to_string();
|
||||
meta.artist=tag.artist().unwrap_or("").to_string();
|
||||
meta.album=tag.album().unwrap_or("").to_string();
|
||||
meta.genre=tag.genre().unwrap_or("").to_string();
|
||||
meta.duration=file.properties().duration().as_secs() as u32;
|
||||
},
|
||||
Err(_) => { }
|
||||
}
|
||||
},
|
||||
Err(_) => { }
|
||||
}
|
||||
meta
|
||||
}
|
||||
|
||||
pub fn analyse_new_files(db:&db::Db, mpath: &Path, to_add:Vec<String>) -> Result<()> {
|
||||
let total = to_add.len();
|
||||
pub fn analyse_new_files(db:&db::Db, mpath: &PathBuf, track_paths:Vec<String>) -> Result<()> {
|
||||
let total = track_paths.len();
|
||||
let pb = ProgressBar::new(total.try_into().unwrap());
|
||||
let style = ProgressStyle::default_bar()
|
||||
.template("[{elapsed_precise}] {bar:40} {pos:>7}/{len:7} {wide_msg}")
|
||||
.progress_chars("##-");
|
||||
pb.set_style(style);
|
||||
|
||||
let results = analyze_paths_streaming(to_add)?;
|
||||
let results = analyze_paths_streaming(track_paths)?;
|
||||
let mut analysed = 0;
|
||||
let mut failed = 0;
|
||||
let mut tag_error = 0;
|
||||
@ -120,7 +88,7 @@ pub fn analyse_new_files(db:&db::Db, mpath: &Path, to_add:Vec<String>) -> Result
|
||||
pb.set_message(format!("Analysing {}", path));
|
||||
match result {
|
||||
Ok(track) => {
|
||||
let meta = read_metadata(&path);
|
||||
let meta = tags::read(&path);
|
||||
let pb = PathBuf::from(path);
|
||||
if meta.title.is_empty() && meta.artist.is_empty() && meta.album.is_empty() && meta.genre.is_empty() {
|
||||
tag_error += 1;
|
||||
@ -145,20 +113,20 @@ pub fn analyse_new_files(db:&db::Db, mpath: &Path, to_add:Vec<String>) -> Result
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn analyse_files(db_path: &str, mpath: &Path, path: &Path, dry_run:bool, keep_old:bool) {
|
||||
let mut to_add:Vec<String> = Vec::new();
|
||||
pub fn analyse_files(db_path: &str, mpath: &PathBuf, dry_run:bool, keep_old:bool) {
|
||||
let mut track_paths:Vec<String> = Vec::new();
|
||||
let mut db = db::Db::new(&String::from(db_path));
|
||||
let cur = PathBuf::from(mpath);
|
||||
|
||||
db.init();
|
||||
get_file_list(&mut db, mpath, path, &mut to_add);
|
||||
log::info!("Num new tracks: {}", to_add.len());
|
||||
get_file_list(&mut db, mpath, &cur, &mut track_paths);
|
||||
log::info!("Num new tracks: {}", track_paths.len());
|
||||
if !keep_old {
|
||||
db.remove_old(mpath, dry_run);
|
||||
}
|
||||
if !dry_run {
|
||||
to_add.sort();
|
||||
if to_add.len()>0 {
|
||||
match analyse_new_files(&db, mpath, to_add) {
|
||||
if track_paths.len()>0 {
|
||||
match analyse_new_files(&db, mpath, track_paths) {
|
||||
Ok(_) => { },
|
||||
Err(_) => { }
|
||||
}
|
||||
@ -167,3 +135,10 @@ pub fn analyse_files(db_path: &str, mpath: &Path, path: &Path, dry_run:bool, kee
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
pub fn read_tags(db_path: &str, mpath: &PathBuf) {
|
||||
let db = db::Db::new(&String::from(db_path));
|
||||
db.init();
|
||||
db.update_tags(&mpath);
|
||||
db.close();
|
||||
}
|
41
src/db.rs
41
src/db.rs
@ -10,6 +10,17 @@ use bliss_audio::{Analysis, AnalysisIndex};
|
||||
use rusqlite::{Connection, params};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process;
|
||||
use crate::tags;
|
||||
|
||||
pub struct FileMetadata {
|
||||
pub rowid:usize,
|
||||
pub file:String,
|
||||
pub title:String,
|
||||
pub artist:String,
|
||||
pub album:String,
|
||||
pub genre:String,
|
||||
pub duration:u32
|
||||
}
|
||||
|
||||
pub struct Metadata {
|
||||
pub title:String,
|
||||
@ -145,7 +156,7 @@ impl Db {
|
||||
db_path = db_path.replace("/", "\\");
|
||||
}
|
||||
let path = mpath.join(PathBuf::from(db_path.clone()));
|
||||
|
||||
|
||||
if !path.exists() {
|
||||
to_remove.push(db_path);
|
||||
}
|
||||
@ -160,4 +171,32 @@ impl Db {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_tags(&self, mpath:&PathBuf) {
|
||||
let mut stmt = self.conn.prepare("SELECT rowid, File, Title, Artist, Album, Genre, Duration FROM Tracks;").unwrap();
|
||||
let track_iter = stmt.query_map([], |row| {
|
||||
Ok(FileMetadata {
|
||||
rowid: row.get(0)?,
|
||||
file: row.get(1)?,
|
||||
title: row.get(2)?,
|
||||
artist: row.get(3)?,
|
||||
album: row.get(4)?,
|
||||
genre: row.get(5)?,
|
||||
duration: row.get(6)?,
|
||||
})
|
||||
}).unwrap();
|
||||
|
||||
for tr in track_iter {
|
||||
let dtags = tr.unwrap();
|
||||
let path = String::from(mpath.join(&dtags.file).to_string_lossy());
|
||||
let ftags = tags::read(&path);
|
||||
if ftags.duration!=dtags.duration || ftags.title!=dtags.title || ftags.artist!=dtags.artist || ftags.album!=dtags.album || ftags.genre!=dtags.genre {
|
||||
match self.conn.execute("UPDATE Tracks SET Title=?, Artist=?, Album=?, Genre=?, Duration=? WHERE rowid=?);",
|
||||
params![ftags.title, ftags.artist, ftags.album, ftags.genre, ftags.duration, dtags.rowid]) {
|
||||
Ok(_) => { },
|
||||
Err(e) => { log::error!("Failed to update tags of '{}'. {}", dtags.file, e); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
14
src/main.rs
14
src/main.rs
@ -6,10 +6,11 @@
|
||||
*
|
||||
**/
|
||||
use argparse::{ArgumentParser, Store};
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
mod analyse;
|
||||
mod db;
|
||||
mod tags;
|
||||
|
||||
fn main() {
|
||||
let mut db_path = "bliss.db".to_string();
|
||||
@ -17,6 +18,7 @@ fn main() {
|
||||
let mut music_path = ".".to_string();
|
||||
let mut keep_old:bool = false;
|
||||
let mut dry_run:bool = false;
|
||||
let mut tags_only:bool = false;
|
||||
|
||||
{
|
||||
// arg_parse.refer 'borrows' db_path, etc, and can only have one
|
||||
@ -28,6 +30,7 @@ fn main() {
|
||||
arg_parse.refer(&mut logging).add_option(&["-l", "--logging"], Store, "Log level (trace, debug, info, warn, error)");
|
||||
arg_parse.refer(&mut keep_old).add_option(&["-k", "--keep-old"], Store, "Don't remove tracks from DB if they don't exist");
|
||||
arg_parse.refer(&mut dry_run).add_option(&["-r", "--dry-run"], Store, "Dry run, only show what needs to be done");
|
||||
arg_parse.refer(&mut tags_only).add_option(&["-t", "--tags-only"], Store, "Re-read tags");
|
||||
/*
|
||||
TODO:
|
||||
-i --ignore Update ignore column
|
||||
@ -49,13 +52,13 @@ fn main() {
|
||||
process::exit(-1);
|
||||
}
|
||||
|
||||
let path = Path::new(&db_path);
|
||||
let path = PathBuf::from(&db_path);
|
||||
if path.exists() && !path.is_file() {
|
||||
log::error!("DB path ({}) is not a file", db_path);
|
||||
process::exit(-1);
|
||||
}
|
||||
|
||||
let mpath = Path::new(&music_path);
|
||||
let mpath = PathBuf::from(&music_path);
|
||||
if !mpath.exists() {
|
||||
log::error!("Music path ({}) does not exist", music_path);
|
||||
process::exit(-1);
|
||||
@ -65,5 +68,8 @@ fn main() {
|
||||
process::exit(-1);
|
||||
}
|
||||
|
||||
analyse::analyse_files(&db_path, Path::new(&music_path), &mpath, dry_run, keep_old);
|
||||
if tags_only {
|
||||
analyse::read_tags(&db_path, &mpath);
|
||||
}
|
||||
analyse::analyse_files(&db_path, &mpath, dry_run, keep_old);
|
||||
}
|
||||
|
43
src/tags.rs
Normal file
43
src/tags.rs
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Analyse music with Bliss
|
||||
*
|
||||
* Copyright (c) 2022 Craig Drummond <craig.p.drummond@gmail.com>
|
||||
* GPLv3 license.
|
||||
*
|
||||
**/
|
||||
|
||||
use lofty::{Accessor, Probe};
|
||||
use std::path::Path;
|
||||
use crate::db;
|
||||
|
||||
pub fn read(track:&String) -> db::Metadata {
|
||||
let mut meta = db::Metadata{
|
||||
title:String::new(),
|
||||
artist:String::new(),
|
||||
album:String::new(),
|
||||
genre:String::new(),
|
||||
duration:180
|
||||
};
|
||||
let path = Path::new(track);
|
||||
match Probe::open(path) {
|
||||
Ok(probe) => {
|
||||
match probe.read(true) {
|
||||
Ok(file) => {
|
||||
let tag = match file.primary_tag() {
|
||||
Some(primary_tag) => primary_tag,
|
||||
None => file.first_tag().expect("Error: No tags found!"),
|
||||
};
|
||||
|
||||
meta.title=tag.title().unwrap_or("").to_string();
|
||||
meta.artist=tag.artist().unwrap_or("").to_string();
|
||||
meta.album=tag.album().unwrap_or("").to_string();
|
||||
meta.genre=tag.genre().unwrap_or("").to_string();
|
||||
meta.duration=file.properties().duration().as_secs() as u32;
|
||||
},
|
||||
Err(_) => { }
|
||||
}
|
||||
},
|
||||
Err(_) => { }
|
||||
}
|
||||
meta
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user