Refactor
This commit is contained in:
parent
23fc436eaa
commit
3f16114d1b
@ -1,11 +1,26 @@
|
|||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required (VERSION 2.8)
|
||||||
|
|
||||||
project(MPDBliss C)
|
project (MPDBliss C)
|
||||||
|
|
||||||
add_subdirectory(bliss)
|
add_subdirectory (bliss)
|
||||||
|
|
||||||
file (GLOB MPDBLISS_SRC "src/*.c")
|
file (GLOB MPDBLISS_SRC "src/*.c")
|
||||||
include_directories("include/" "bliss/include")
|
|
||||||
|
# TODO \/
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(MULTIMEDIA REQUIRED libavformat libavutil libavcodec)
|
||||||
|
pkg_check_modules(RESAMPLE QUIET libswresample)
|
||||||
|
if(NOT RESAMPLE_FOUND)
|
||||||
|
pkg_check_modules(RESAMPLE REQUIRED libavresample)
|
||||||
|
set(AVRESAMPLE TRUE)
|
||||||
|
else()
|
||||||
|
set(AVRESAMPLE FALSE)
|
||||||
|
endif()
|
||||||
|
include_directories(${MULTIMEDIA_INCLUDE_DIRS} ${RESAMPLE_INCLUDE_DIRS} include/ bliss/include)
|
||||||
|
link_directories(${MULTIMEDIA_LIBRARY_DIRS} ${RESAMPLE_LIBRARY_DIRS})
|
||||||
|
add_definitions(${MULTIMEDIA_CFLAGS_OTHER} ${RESAMPLE_CFLAGS_OTHER})
|
||||||
|
add_definitions (-Wall -Wno-long-long -pedantic -std=c99)
|
||||||
|
# TODO /\
|
||||||
|
|
||||||
add_executable (mpdbliss
|
add_executable (mpdbliss
|
||||||
${MPDBLISS_SRC})
|
${MPDBLISS_SRC})
|
||||||
|
2
bliss
2
bliss
@ -1 +1 @@
|
|||||||
Subproject commit 0b289b9be7c9bbabef61c6131b629fc707b564e7
|
Subproject commit 39fe24d79f2fa4e253a29e66f5f7c0c33e4b84d5
|
36
include/analysis.h
Normal file
36
include/analysis.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef ANALYSIS_H
|
||||||
|
#define ANALYSIS_H
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
int _init_db(char* data_folder, char* db_path);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
int _parse_music_helper(
|
||||||
|
sqlite3* dbh,
|
||||||
|
const char *base_path,
|
||||||
|
const char *song_uri);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rescan errored files
|
||||||
|
*
|
||||||
|
* @param db_path Path to the db file to use.
|
||||||
|
* @param base_path Root directory of the MPD library.
|
||||||
|
* @return 0 on success. Non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int _rescan_errored(const char *db_path, const char *base_path);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
int _purge_db(const char* db_path);
|
||||||
|
|
||||||
|
#endif // ANALYSIS_H
|
15
include/utilities.h
Normal file
15
include/utilities.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef UTILITIES_H
|
||||||
|
#define UTILITIES_H
|
||||||
|
|
||||||
|
#define DEFAULT_STRING_LENGTH 1024
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip the trailing slash from a string.
|
||||||
|
*
|
||||||
|
* @param[in] str String to strip slash from.
|
||||||
|
* @param[out] str Stripped string.
|
||||||
|
*/
|
||||||
|
void strip_trailing_slash(char* str);
|
||||||
|
|
||||||
|
#endif // UTILITIES_H
|
BIN
src/.main.c.swp
Normal file
BIN
src/.main.c.swp
Normal file
Binary file not shown.
316
src/analysis.c
Normal file
316
src/analysis.c
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
#include "analysis.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <bliss.h>
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
|
||||||
|
int _init_db(char *data_folder, char* db_path)
|
||||||
|
{
|
||||||
|
data_folder[0] = '\0';
|
||||||
|
db_path[0] = '\0';
|
||||||
|
char *xdg_data_home_env = getenv("XDG_DATA_HOME");
|
||||||
|
if (NULL == xdg_data_home_env) {
|
||||||
|
strncat(data_folder, getenv("HOME"), DEFAULT_STRING_LENGTH);
|
||||||
|
strip_trailing_slash(data_folder);
|
||||||
|
strncat(data_folder, "/.local/share/mpdbliss", DEFAULT_STRING_LENGTH - strlen(data_folder));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strncpy(data_folder, xdg_data_home_env, DEFAULT_STRING_LENGTH);
|
||||||
|
strip_trailing_slash(data_folder);
|
||||||
|
strncat(data_folder, "/mpdbliss", DEFAULT_STRING_LENGTH - strlen(data_folder));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure data folder exists
|
||||||
|
mkdir(data_folder, 0700);
|
||||||
|
|
||||||
|
// Db path
|
||||||
|
strncat(db_path, data_folder, DEFAULT_STRING_LENGTH);
|
||||||
|
strncat(db_path, "/db.sqlite3", DEFAULT_STRING_LENGTH - strlen(db_path));
|
||||||
|
|
||||||
|
sqlite3 *dbh;
|
||||||
|
if (0 != sqlite3_open_v2(db_path, &dbh, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)) {
|
||||||
|
fprintf(stderr, "Unable to open SQLite db.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int dberr = sqlite3_exec(dbh, "PRAGMA foreign_keys = ON", NULL, NULL, NULL);
|
||||||
|
if (SQLITE_OK != dberr) {
|
||||||
|
fprintf(stderr, "Error creating db: %s.\n", sqlite3_errmsg(dbh));
|
||||||
|
sqlite3_close(dbh);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
dberr = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS songs( \
|
||||||
|
id INTEGER PRIMARY KEY, \
|
||||||
|
tempo REAL, \
|
||||||
|
amplitude REAL, \
|
||||||
|
frequency REAL, \
|
||||||
|
attack REAL, \
|
||||||
|
filename TEXT UNIQUE)",
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
if (SQLITE_OK != dberr) {
|
||||||
|
fprintf(stderr, "Error creating db: %s.\n", sqlite3_errmsg(dbh));
|
||||||
|
sqlite3_close(dbh);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
dberr = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS distances( \
|
||||||
|
song1 INTEGER, \
|
||||||
|
song2 INTEGER, \
|
||||||
|
distance REAL, \
|
||||||
|
FOREIGN KEY(song1) REFERENCES songs(id) ON DELETE CASCADE, \
|
||||||
|
FOREIGN KEY(song2) REFERENCES songs(id) ON DELETE CASCADE, \
|
||||||
|
UNIQUE (song1, song2))",
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
if (SQLITE_OK != dberr) {
|
||||||
|
fprintf(stderr, "Error creating db: %s.\n", sqlite3_errmsg(dbh));
|
||||||
|
sqlite3_close(dbh);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
dberr = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS errors( \
|
||||||
|
id INTEGER PRIMARY KEY, \
|
||||||
|
filename TEXT UNIQUE)", NULL, NULL, NULL);
|
||||||
|
if (SQLITE_OK != dberr) {
|
||||||
|
fprintf(stderr, "Error creating db: %s.\n", sqlite3_errmsg(dbh));
|
||||||
|
sqlite3_close(dbh);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sqlite3_close(dbh);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int _parse_music_helper(
|
||||||
|
sqlite3* dbh,
|
||||||
|
const char *base_path,
|
||||||
|
const char *song_uri)
|
||||||
|
{
|
||||||
|
sqlite3_stmt *res;
|
||||||
|
|
||||||
|
// Compute full uri
|
||||||
|
printf("\nAdding new song to db: %s\n", song_uri);
|
||||||
|
char song_full_uri[DEFAULT_STRING_LENGTH] = "";
|
||||||
|
strncat(song_full_uri, base_path, DEFAULT_STRING_LENGTH);
|
||||||
|
strncat(song_full_uri, song_uri, DEFAULT_STRING_LENGTH);
|
||||||
|
|
||||||
|
// Pass it to bliss
|
||||||
|
struct bl_song song_analysis;
|
||||||
|
bl_initialize_song(&song_analysis);
|
||||||
|
if (BL_UNEXPECTED == bl_analyze(song_full_uri, &song_analysis)) {
|
||||||
|
fprintf(stderr, "Error while parsing song: %s.\n\n", song_full_uri);
|
||||||
|
// Free song analysis
|
||||||
|
bl_free_song(&song_analysis);
|
||||||
|
// Store error in db
|
||||||
|
sqlite3_prepare_v2(dbh,
|
||||||
|
"INSERT INTO errors(filename) VALUES(?)",
|
||||||
|
-1, &res, 0);
|
||||||
|
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
||||||
|
sqlite3_step(res);
|
||||||
|
sqlite3_finalize(res);
|
||||||
|
// Pass file
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Insert into db
|
||||||
|
// Begin transaction
|
||||||
|
int dberr = sqlite3_exec(dbh, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||||
|
if (SQLITE_OK != dberr) {
|
||||||
|
fprintf(stderr, "Error while inserting data in db: %s\n\n", sqlite3_errmsg(dbh));
|
||||||
|
// Free song analysis
|
||||||
|
bl_free_song(&song_analysis);
|
||||||
|
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
||||||
|
// Store error in db
|
||||||
|
sqlite3_prepare_v2(dbh,
|
||||||
|
"INSERT INTO errors(filename) VALUES(?)",
|
||||||
|
-1, &res, 0);
|
||||||
|
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
||||||
|
sqlite3_step(res);
|
||||||
|
sqlite3_finalize(res);
|
||||||
|
// Pass file
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Insert song analysis in database
|
||||||
|
dberr = sqlite3_prepare_v2(dbh,
|
||||||
|
"INSERT INTO songs(tempo, amplitude, frequency, attack, filename) VALUES(?, ?, ?, ?, ?)",
|
||||||
|
-1, &res, 0);
|
||||||
|
if (SQLITE_OK != dberr) {
|
||||||
|
fprintf(stderr, "Error while inserting data in db: %s\n\n", sqlite3_errmsg(dbh));
|
||||||
|
// Free song analysis
|
||||||
|
bl_free_song(&song_analysis);
|
||||||
|
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
||||||
|
// Store error in db
|
||||||
|
sqlite3_prepare_v2(dbh,
|
||||||
|
"INSERT INTO errors(filename) VALUES(?)",
|
||||||
|
-1, &res, 0);
|
||||||
|
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
||||||
|
sqlite3_step(res);
|
||||||
|
sqlite3_finalize(res);
|
||||||
|
// Pass file
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sqlite3_bind_double(res, 1, song_analysis.force_vector.tempo);
|
||||||
|
sqlite3_bind_double(res, 2, song_analysis.force_vector.amplitude);
|
||||||
|
sqlite3_bind_double(res, 3, song_analysis.force_vector.frequency);
|
||||||
|
sqlite3_bind_double(res, 4, song_analysis.force_vector.attack);
|
||||||
|
sqlite3_bind_text(res, 5, song_uri, strlen(song_uri), SQLITE_STATIC);
|
||||||
|
sqlite3_step(res);
|
||||||
|
sqlite3_finalize(res);
|
||||||
|
int last_id = sqlite3_last_insert_rowid(dbh);
|
||||||
|
// Insert updated distances
|
||||||
|
dberr = sqlite3_prepare_v2(dbh, "SELECT id, tempo, amplitude, frequency, attack FROM songs", -1, &res, 0);
|
||||||
|
if (SQLITE_OK != dberr) {
|
||||||
|
fprintf(stderr, "Error while inserting data in db: %s\n\n", sqlite3_errmsg(dbh));
|
||||||
|
// Free song analysis
|
||||||
|
bl_free_song(&song_analysis);
|
||||||
|
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
||||||
|
// Store error in db
|
||||||
|
sqlite3_prepare_v2(dbh,
|
||||||
|
"INSERT INTO errors(filename) VALUES(?)",
|
||||||
|
-1, &res, 0);
|
||||||
|
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
||||||
|
sqlite3_step(res);
|
||||||
|
sqlite3_finalize(res);
|
||||||
|
// Pass file
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int dberr2 = SQLITE_OK;
|
||||||
|
while (sqlite3_step(res) == SQLITE_ROW) {
|
||||||
|
int id = sqlite3_column_int(res, 0);
|
||||||
|
if (id == last_id) {
|
||||||
|
// Skip last inserted item
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
struct force_vector_s song_db;
|
||||||
|
song_db.tempo = sqlite3_column_double(res, 1);
|
||||||
|
song_db.amplitude = sqlite3_column_double(res, 2);
|
||||||
|
song_db.frequency = sqlite3_column_double(res, 3);
|
||||||
|
song_db.attack = sqlite3_column_double(res, 4);
|
||||||
|
float distance = bl_distance(song_analysis.force_vector, song_db);
|
||||||
|
|
||||||
|
sqlite3_stmt *res2;
|
||||||
|
dberr2 = sqlite3_prepare_v2(dbh,
|
||||||
|
"INSERT INTO distances(song1, song2, distance) VALUES(?, ?, ?)",
|
||||||
|
-1, &res2, 0);
|
||||||
|
if (SQLITE_OK != dberr2) {
|
||||||
|
fprintf(stderr, "Error while inserting data in db: %s\n\n", sqlite3_errmsg(dbh));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sqlite3_bind_int(res2, 1, last_id);
|
||||||
|
sqlite3_bind_int(res2, 2, id);
|
||||||
|
sqlite3_bind_double(res2, 3, distance);
|
||||||
|
sqlite3_step(res2);
|
||||||
|
sqlite3_finalize(res2);
|
||||||
|
}
|
||||||
|
if (SQLITE_OK != dberr2) {
|
||||||
|
// Free song analysis
|
||||||
|
bl_free_song(&song_analysis);
|
||||||
|
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
||||||
|
// Store error in db
|
||||||
|
sqlite3_prepare_v2(dbh,
|
||||||
|
"INSERT INTO errors(filename) VALUES(?)",
|
||||||
|
-1, &res, 0);
|
||||||
|
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
||||||
|
sqlite3_step(res);
|
||||||
|
sqlite3_finalize(res);
|
||||||
|
// Pass file
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sqlite3_finalize(res);
|
||||||
|
// Commit transaction
|
||||||
|
dberr = sqlite3_exec(dbh, "COMMIT", NULL, NULL, NULL);
|
||||||
|
if (SQLITE_OK != dberr) {
|
||||||
|
fprintf(stderr, "Error while inserting data in db: %s\n\n", sqlite3_errmsg(dbh));
|
||||||
|
// Free song analysis
|
||||||
|
bl_free_song(&song_analysis);
|
||||||
|
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
||||||
|
// Store error in db
|
||||||
|
sqlite3_prepare_v2(dbh,
|
||||||
|
"INSERT INTO errors(filename) VALUES(?)",
|
||||||
|
-1, &res, 0);
|
||||||
|
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
||||||
|
sqlite3_step(res);
|
||||||
|
sqlite3_finalize(res);
|
||||||
|
// Pass file
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free song analysis
|
||||||
|
bl_free_song(&song_analysis);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int _rescan_errored(const char *db_path, const char *base_path)
|
||||||
|
{
|
||||||
|
// Connect to SQLite db
|
||||||
|
sqlite3 *dbh;
|
||||||
|
if (0 != sqlite3_open(db_path, &dbh)) {
|
||||||
|
fprintf(stderr, "Unable to open SQLite db.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the list of all the files to process
|
||||||
|
sqlite3_stmt *res = NULL;
|
||||||
|
int dberr = sqlite3_exec(dbh, "SELECT filename FROM errors", NULL, NULL, NULL);
|
||||||
|
if (SQLITE_OK != dberr) {
|
||||||
|
fprintf(stderr, "Error while fetching data in db: %s\n\n", sqlite3_errmsg(dbh));
|
||||||
|
sqlite3_close(dbh);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Handle the files
|
||||||
|
while (sqlite3_step(res) == SQLITE_ROW) {
|
||||||
|
const char* filename = (char*) sqlite3_column_text(res, 1);
|
||||||
|
|
||||||
|
// Delete it from errors list
|
||||||
|
sqlite3_stmt *res2;
|
||||||
|
int dberr2 = sqlite3_prepare_v2(dbh,
|
||||||
|
"DELETE FROM errors WHERE filename=?",
|
||||||
|
-1, &res2, 0);
|
||||||
|
if (SQLITE_OK != dberr2) {
|
||||||
|
fprintf(stderr, "Error while deleting error from db: %s\n\n", sqlite3_errmsg(dbh));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sqlite3_bind_text(res2, 1, filename, strlen(filename), SQLITE_STATIC);
|
||||||
|
sqlite3_step(res2);
|
||||||
|
sqlite3_finalize(res2);
|
||||||
|
|
||||||
|
// Try to import it back
|
||||||
|
if (1 == _parse_music_helper(dbh, base_path, filename)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlite3_finalize(res);
|
||||||
|
|
||||||
|
// Close SQLite connection
|
||||||
|
sqlite3_close(dbh);
|
||||||
|
|
||||||
|
printf("Done! :)\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int _purge_db(const char* db_path)
|
||||||
|
{
|
||||||
|
sqlite3 *dbh;
|
||||||
|
if (0 != sqlite3_open_v2(db_path, &dbh, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)) {
|
||||||
|
fprintf(stderr, "Unable to open SQLite db.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int dberr = sqlite3_exec(dbh, "PRAGMA foreign_keys = ON", NULL, NULL, NULL);
|
||||||
|
if (SQLITE_OK != dberr) {
|
||||||
|
fprintf(stderr, "Unable to open SQLite db.\n");
|
||||||
|
sqlite3_close(dbh);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
dberr = sqlite3_exec(dbh, "BEGIN TRANSACTION; DELETE FROM distances; DELETE FROM songs; DELETE FROM errors; COMMIT", NULL, NULL, NULL);
|
||||||
|
if (SQLITE_OK != dberr) {
|
||||||
|
fprintf(stderr, "Error purging existing data in db: %s.\n", sqlite3_errmsg(dbh));
|
||||||
|
sqlite3_close(dbh);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sqlite3_close(dbh);
|
||||||
|
return 0;
|
||||||
|
}
|
394
src/main.c
394
src/main.c
@ -1,30 +1,23 @@
|
|||||||
#include <math.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <mpd/client.h>
|
#include <mpd/client.h>
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
|
||||||
#include "bliss.h"
|
#include "analysis.h"
|
||||||
#include "cmdline.h"
|
#include "cmdline.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
// TODO: Handle deletions from db
|
// TODO: Handle deletions from db
|
||||||
|
|
||||||
#define DEFAULT_STRING_LENGTH 255
|
|
||||||
|
|
||||||
// Data file path to store latest seen mtimes and db
|
|
||||||
char mpdbliss_data_file[DEFAULT_STRING_LENGTH] = "";
|
|
||||||
char mpdbliss_data_db[DEFAULT_STRING_LENGTH] = "";
|
|
||||||
// IDLE loop control variable
|
// IDLE loop control variable
|
||||||
volatile bool mpd_run_idle_loop = true;
|
volatile bool mpd_run_idle_loop = true;
|
||||||
// MPD connection handler
|
// MPD connection handler
|
||||||
struct mpd_connection *conn;
|
struct mpd_connection *conn;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle interruption when waiting for MPD IDLE items.
|
* Handle interruption when waiting for MPD IDLE items.
|
||||||
*/
|
*/
|
||||||
@ -42,192 +35,18 @@ void sigint_catch_function(int signo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strip the trailing slash from a string.
|
|
||||||
*
|
|
||||||
* @param[in] str String to strip slash from.
|
|
||||||
* @param[out] str Stripped string.
|
|
||||||
*/
|
|
||||||
void strip_trailing_slash(char* str)
|
|
||||||
{
|
|
||||||
size_t length = strlen(str);
|
|
||||||
if ('/' == str[length - 1]) {
|
|
||||||
str[length - 1] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _parse_music_helper(
|
|
||||||
sqlite3* dbh,
|
|
||||||
const char *mpd_base_path,
|
|
||||||
const char *song_uri)
|
|
||||||
{
|
|
||||||
sqlite3_stmt *res;
|
|
||||||
|
|
||||||
// Compute full uri
|
|
||||||
printf("\nAdding new song to db: %s\n", song_uri);
|
|
||||||
char song_full_uri[DEFAULT_STRING_LENGTH] = "";
|
|
||||||
strncat(song_full_uri, mpd_base_path, DEFAULT_STRING_LENGTH);
|
|
||||||
strncat(song_full_uri, song_uri, DEFAULT_STRING_LENGTH);
|
|
||||||
|
|
||||||
// Pass it to bliss
|
|
||||||
struct bl_song song_analysis;
|
|
||||||
if (BL_UNEXPECTED == bl_analyze(song_full_uri, &song_analysis)) {
|
|
||||||
fprintf(stderr, "Error while parsing song: %s.\n\n", song_full_uri);
|
|
||||||
// Free song analysis
|
|
||||||
bl_free_song(&song_analysis);
|
|
||||||
// Store error in db
|
|
||||||
sqlite3_prepare_v2(dbh,
|
|
||||||
"INSERT INTO errors(filename) VALUES(?)",
|
|
||||||
-1, &res, 0);
|
|
||||||
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
|
||||||
sqlite3_step(res);
|
|
||||||
sqlite3_finalize(res);
|
|
||||||
// Pass file
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// Insert into db
|
|
||||||
// Begin transaction
|
|
||||||
int dberr = sqlite3_exec(dbh, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
|
||||||
if (SQLITE_OK != dberr) {
|
|
||||||
fprintf(stderr, "Error while inserting data in db: %s\n\n", sqlite3_errmsg(dbh));
|
|
||||||
// Free song analysis
|
|
||||||
bl_free_song(&song_analysis);
|
|
||||||
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
|
||||||
// Store error in db
|
|
||||||
sqlite3_prepare_v2(dbh,
|
|
||||||
"INSERT INTO errors(filename) VALUES(?)",
|
|
||||||
-1, &res, 0);
|
|
||||||
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
|
||||||
sqlite3_step(res);
|
|
||||||
sqlite3_finalize(res);
|
|
||||||
// Pass file
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// Insert song analysis in database
|
|
||||||
dberr = sqlite3_prepare_v2(dbh,
|
|
||||||
"INSERT INTO songs(tempo, amplitude, frequency, attack, filename) VALUES(?, ?, ?, ?, ?)",
|
|
||||||
-1, &res, 0);
|
|
||||||
if (SQLITE_OK != dberr) {
|
|
||||||
fprintf(stderr, "Error while inserting data in db: %s\n\n", sqlite3_errmsg(dbh));
|
|
||||||
// Free song analysis
|
|
||||||
bl_free_song(&song_analysis);
|
|
||||||
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
|
||||||
// Store error in db
|
|
||||||
sqlite3_prepare_v2(dbh,
|
|
||||||
"INSERT INTO errors(filename) VALUES(?)",
|
|
||||||
-1, &res, 0);
|
|
||||||
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
|
||||||
sqlite3_step(res);
|
|
||||||
sqlite3_finalize(res);
|
|
||||||
// Pass file
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
sqlite3_bind_double(res, 1, song_analysis.force_vector.tempo);
|
|
||||||
sqlite3_bind_double(res, 2, song_analysis.force_vector.amplitude);
|
|
||||||
sqlite3_bind_double(res, 3, song_analysis.force_vector.frequency);
|
|
||||||
sqlite3_bind_double(res, 4, song_analysis.force_vector.attack);
|
|
||||||
sqlite3_bind_text(res, 5, song_uri, strlen(song_uri), SQLITE_STATIC);
|
|
||||||
sqlite3_step(res);
|
|
||||||
sqlite3_finalize(res);
|
|
||||||
int last_id = sqlite3_last_insert_rowid(dbh);
|
|
||||||
// Insert updated distances
|
|
||||||
dberr = sqlite3_prepare_v2(dbh, "SELECT id, tempo, amplitude, frequency, attack FROM songs", -1, &res, 0);
|
|
||||||
if (SQLITE_OK != dberr) {
|
|
||||||
fprintf(stderr, "Error while inserting data in db: %s\n\n", sqlite3_errmsg(dbh));
|
|
||||||
// Free song analysis
|
|
||||||
bl_free_song(&song_analysis);
|
|
||||||
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
|
||||||
// Store error in db
|
|
||||||
sqlite3_prepare_v2(dbh,
|
|
||||||
"INSERT INTO errors(filename) VALUES(?)",
|
|
||||||
-1, &res, 0);
|
|
||||||
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
|
||||||
sqlite3_step(res);
|
|
||||||
sqlite3_finalize(res);
|
|
||||||
// Pass file
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
int dberr2 = SQLITE_OK;
|
|
||||||
while (sqlite3_step(res) == SQLITE_ROW) {
|
|
||||||
int id = sqlite3_column_int(res, 0);
|
|
||||||
if (id == last_id) {
|
|
||||||
// Skip last inserted item
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
struct force_vector_s song_db;
|
|
||||||
song_db.tempo = sqlite3_column_double(res, 1);
|
|
||||||
song_db.amplitude = sqlite3_column_double(res, 2);
|
|
||||||
song_db.frequency = sqlite3_column_double(res, 3);
|
|
||||||
song_db.attack = sqlite3_column_double(res, 4);
|
|
||||||
float distance = bl_distance(song_analysis.force_vector, song_db);
|
|
||||||
|
|
||||||
sqlite3_stmt *res2;
|
|
||||||
dberr2 = sqlite3_prepare_v2(dbh,
|
|
||||||
"INSERT INTO distances(song1, song2, distance) VALUES(?, ?, ?)",
|
|
||||||
-1, &res2, 0);
|
|
||||||
if (SQLITE_OK != dberr2) {
|
|
||||||
fprintf(stderr, "Error while inserting data in db: %s\n\n", sqlite3_errmsg(dbh));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sqlite3_bind_int(res2, 1, last_id);
|
|
||||||
sqlite3_bind_int(res2, 2, id);
|
|
||||||
sqlite3_bind_double(res2, 3, distance);
|
|
||||||
sqlite3_step(res2);
|
|
||||||
sqlite3_finalize(res2);
|
|
||||||
}
|
|
||||||
if (SQLITE_OK != dberr2) {
|
|
||||||
// Free song analysis
|
|
||||||
bl_free_song(&song_analysis);
|
|
||||||
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
|
||||||
// Store error in db
|
|
||||||
sqlite3_prepare_v2(dbh,
|
|
||||||
"INSERT INTO errors(filename) VALUES(?)",
|
|
||||||
-1, &res, 0);
|
|
||||||
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
|
||||||
sqlite3_step(res);
|
|
||||||
sqlite3_finalize(res);
|
|
||||||
// Pass file
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
sqlite3_finalize(res);
|
|
||||||
// Commit transaction
|
|
||||||
dberr = sqlite3_exec(dbh, "COMMIT", NULL, NULL, NULL);
|
|
||||||
if (SQLITE_OK != dberr) {
|
|
||||||
fprintf(stderr, "Error while inserting data in db: %s\n\n", sqlite3_errmsg(dbh));
|
|
||||||
// Free song analysis
|
|
||||||
bl_free_song(&song_analysis);
|
|
||||||
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
|
||||||
// Store error in db
|
|
||||||
sqlite3_prepare_v2(dbh,
|
|
||||||
"INSERT INTO errors(filename) VALUES(?)",
|
|
||||||
-1, &res, 0);
|
|
||||||
sqlite3_bind_text(res, 1, song_uri, strlen(song_uri), SQLITE_STATIC);
|
|
||||||
sqlite3_step(res);
|
|
||||||
sqlite3_finalize(res);
|
|
||||||
// Pass file
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free song analysis
|
|
||||||
bl_free_song(&song_analysis);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the database.
|
* Update the database.
|
||||||
*
|
*
|
||||||
* @param mpd_connection MPD connection object to use.
|
* @param mpd_connection MPD connection object to use.
|
||||||
* @param initial_mtime Initial mtime to use.
|
* @param initial_mtime Initial mtime to use.
|
||||||
* @param mpd_base_path Root directory of the MPD library.
|
* @param mpd_base_path Root directory of the MPD library.
|
||||||
|
* @param mpdbliss_data_db Path to the db to use.
|
||||||
*/
|
*/
|
||||||
void update_database(
|
long int update_database(
|
||||||
struct mpd_connection *conn,
|
|
||||||
time_t initial_mtime,
|
time_t initial_mtime,
|
||||||
const char *mpd_base_path
|
const char *mpd_base_path,
|
||||||
|
const char* mpdbliss_data_db
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Store latest mtime seen
|
// Store latest mtime seen
|
||||||
@ -237,25 +56,25 @@ void update_database(
|
|||||||
struct mpd_stats* stats = mpd_run_stats(conn);
|
struct mpd_stats* stats = mpd_run_stats(conn);
|
||||||
if (NULL == stats) {
|
if (NULL == stats) {
|
||||||
fprintf(stderr, "Unable to fetch number of songs in the db.\n");
|
fprintf(stderr, "Unable to fetch number of songs in the db.\n");
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
unsigned int n_songs = mpd_stats_get_number_of_songs(stats);
|
unsigned int n_songs = mpd_stats_get_number_of_songs(stats);
|
||||||
if (0 == n_songs) {
|
if (0 == n_songs) {
|
||||||
fprintf(stderr, "Unable to fetch number of songs in the db.\n");
|
fprintf(stderr, "Unable to fetch number of songs in the db.\n");
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the list of all the files to process
|
// Get the list of all the files to process
|
||||||
if (!mpd_send_list_all_meta(conn, NULL)) {
|
if (!mpd_send_list_all_meta(conn, NULL)) {
|
||||||
fprintf(stderr, "Unable to get a full list of items in the db.\n");
|
fprintf(stderr, "Unable to get a full list of items in the db.\n");
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect to SQLite db
|
// Connect to SQLite db
|
||||||
sqlite3 *dbh;
|
sqlite3 *dbh;
|
||||||
if (0 != sqlite3_open(mpdbliss_data_db, &dbh)) {
|
if (0 != sqlite3_open(mpdbliss_data_db, &dbh)) {
|
||||||
fprintf(stderr, "Unable to open SQLite db.\n");
|
fprintf(stderr, "Unable to open SQLite db.\n");
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the received list in memory, to prevent timeout
|
// Retrieve the received list in memory, to prevent timeout
|
||||||
@ -313,82 +132,20 @@ void update_database(
|
|||||||
// Check if exit was due to an error
|
// Check if exit was due to an error
|
||||||
if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {
|
if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {
|
||||||
printf("MPD Error: %s\n", mpd_connection_get_error_message(conn));
|
printf("MPD Error: %s\n", mpd_connection_get_error_message(conn));
|
||||||
return;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
// Update last_mtime, if no error occured.
|
|
||||||
FILE *fp = fopen(mpdbliss_data_file, "w+");
|
|
||||||
if (NULL != fp) {
|
|
||||||
fprintf(fp, "%d\n", latest_mtime);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "Unable to store latest mtime seen.\n");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(entities);
|
free(entities);
|
||||||
printf("Done! :)\n");
|
printf("Done! :)\n");
|
||||||
}
|
|
||||||
|
|
||||||
|
// Return last_mtime, if no error occured.
|
||||||
/**
|
return latest_mtime;
|
||||||
* Rescan errored files
|
|
||||||
*
|
|
||||||
* @param mpd_base_path Root directory of the MPD library.
|
|
||||||
*/
|
|
||||||
void rescan_errored(const char *mpd_base_path)
|
|
||||||
{
|
|
||||||
// Connect to SQLite db
|
|
||||||
sqlite3 *dbh;
|
|
||||||
if (0 != sqlite3_open(mpdbliss_data_db, &dbh)) {
|
|
||||||
fprintf(stderr, "Unable to open SQLite db.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the list of all the files to process
|
|
||||||
sqlite3_stmt *res;
|
|
||||||
int dberr = sqlite3_exec(dbh, "SELECT filename FROM errors", NULL, NULL, NULL);
|
|
||||||
if (SQLITE_OK != dberr) {
|
|
||||||
fprintf(stderr, "Error while fetching data in db: %s\n\n", sqlite3_errmsg(dbh));
|
|
||||||
sqlite3_close(dbh);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Handle the files
|
|
||||||
while (sqlite3_step(res) == SQLITE_ROW) {
|
|
||||||
const char* filename = sqlite3_column_text(res, 1);
|
|
||||||
|
|
||||||
// Delete it from errors list
|
|
||||||
sqlite3_stmt *res2;
|
|
||||||
int dberr2 = sqlite3_prepare_v2(dbh,
|
|
||||||
"DELETE FROM errors WHERE filename=?",
|
|
||||||
-1, &res2, 0);
|
|
||||||
if (SQLITE_OK != dberr2) {
|
|
||||||
fprintf(stderr, "Error while deleting error from db: %s\n\n", sqlite3_errmsg(dbh));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
sqlite3_bind_text(res2, 1, filename, strlen(filename), SQLITE_STATIC);
|
|
||||||
sqlite3_step(res2);
|
|
||||||
sqlite3_finalize(res2);
|
|
||||||
|
|
||||||
// Try to import it back
|
|
||||||
if (1 == _parse_music_helper(dbh, mpd_base_path, filename)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sqlite3_finalize(res);
|
|
||||||
|
|
||||||
// Close SQLite connection
|
|
||||||
sqlite3_close(dbh);
|
|
||||||
|
|
||||||
printf("Done! :)\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
struct gengetopt_args_info args_info;
|
|
||||||
|
|
||||||
// Scan arguments
|
// Scan arguments
|
||||||
|
struct gengetopt_args_info args_info;
|
||||||
if (0 != cmdline_parser(argc, argv, &args_info)) {
|
if (0 != cmdline_parser(argc, argv, &args_info)) {
|
||||||
exit(EXIT_FAILURE) ;
|
exit(EXIT_FAILURE) ;
|
||||||
}
|
}
|
||||||
@ -426,115 +183,65 @@ int main(int argc, char** argv) {
|
|||||||
char mpd_base_path[DEFAULT_STRING_LENGTH] = "";
|
char mpd_base_path[DEFAULT_STRING_LENGTH] = "";
|
||||||
strncat(mpd_base_path, args_info.mpd_root_arg, DEFAULT_STRING_LENGTH);
|
strncat(mpd_base_path, args_info.mpd_root_arg, DEFAULT_STRING_LENGTH);
|
||||||
strip_trailing_slash(mpd_base_path);
|
strip_trailing_slash(mpd_base_path);
|
||||||
strncat(mpd_base_path, "/", DEFAULT_STRING_LENGTH);
|
strncat(mpd_base_path, "/", DEFAULT_STRING_LENGTH - strlen(mpd_base_path));
|
||||||
|
|
||||||
// Get data directory
|
// Get data directory, init db file
|
||||||
char *xdg_data_home_env = getenv("XDG_DATA_HOME");
|
char mpdbliss_data_folder[DEFAULT_STRING_LENGTH] = "";
|
||||||
if (NULL == xdg_data_home_env) {
|
char mpdbliss_data_db[DEFAULT_STRING_LENGTH] = "";
|
||||||
strncat(mpdbliss_data_file, getenv("HOME"), DEFAULT_STRING_LENGTH);
|
if (0 != _init_db(mpdbliss_data_folder, mpdbliss_data_db)) {
|
||||||
strip_trailing_slash(mpdbliss_data_file);
|
exit(EXIT_FAILURE);
|
||||||
strncat(mpdbliss_data_file, "/.local/share/mpdbliss", DEFAULT_STRING_LENGTH);
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
strncpy(mpdbliss_data_file, xdg_data_home_env, DEFAULT_STRING_LENGTH);
|
|
||||||
strip_trailing_slash(mpdbliss_data_file);
|
|
||||||
strncat(mpdbliss_data_file, "/mpdbliss", DEFAULT_STRING_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure data folder exists
|
|
||||||
mkdir(mpdbliss_data_file, 0700);
|
|
||||||
|
|
||||||
// Set data file path
|
// Set data file path
|
||||||
strncat(mpdbliss_data_db, mpdbliss_data_file, DEFAULT_STRING_LENGTH);
|
char mpdbliss_data_file[DEFAULT_STRING_LENGTH] = "";
|
||||||
strncat(mpdbliss_data_db, "/db.sqlite3", DEFAULT_STRING_LENGTH);
|
strncat(mpdbliss_data_file, mpdbliss_data_folder, DEFAULT_STRING_LENGTH);
|
||||||
strncat(mpdbliss_data_file, "/latest_mtime.txt", DEFAULT_STRING_LENGTH);
|
strncat(mpdbliss_data_file, "/latest_mtime.txt", DEFAULT_STRING_LENGTH - strlen(mpdbliss_data_file));
|
||||||
|
|
||||||
// Get latest mtime
|
// Get latest mtime
|
||||||
time_t last_mtime = 0; // Set it to epoch by default
|
time_t last_mtime = 0; // Set it to epoch by default
|
||||||
FILE *fp = fopen(mpdbliss_data_file, "r");
|
FILE *fp = fopen(mpdbliss_data_file, "r");
|
||||||
if (NULL != fp) {
|
if (NULL != fp) {
|
||||||
// Read it from file if applicable
|
// Read it from file if applicable
|
||||||
fscanf(fp, "%d\n", &last_mtime);
|
fscanf(fp, "%ld\n", &last_mtime);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize database table
|
|
||||||
sqlite3 *dbh;
|
|
||||||
if (0 != sqlite3_open_v2(mpdbliss_data_db, &dbh, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)) {
|
|
||||||
fprintf(stderr, "Unable to open SQLite db.\n");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
int dberr = sqlite3_exec(dbh, "PRAGMA foreign_keys = ON", NULL, NULL, NULL);
|
|
||||||
if (SQLITE_OK != dberr) {
|
|
||||||
fprintf(stderr, "Error creating db: %s.\n", sqlite3_errmsg(dbh));
|
|
||||||
sqlite3_close(dbh);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
dberr = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS songs( \
|
|
||||||
id INTEGER PRIMARY KEY, \
|
|
||||||
tempo REAL, \
|
|
||||||
amplitude REAL, \
|
|
||||||
frequency REAL, \
|
|
||||||
attack REAL, \
|
|
||||||
filename TEXT UNIQUE)",
|
|
||||||
NULL, NULL, NULL);
|
|
||||||
if (SQLITE_OK != dberr) {
|
|
||||||
fprintf(stderr, "Error creating db: %s.\n", sqlite3_errmsg(dbh));
|
|
||||||
sqlite3_close(dbh);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
dberr = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS distances( \
|
|
||||||
song1 INTEGER, \
|
|
||||||
song2 INTEGER, \
|
|
||||||
distance REAL, \
|
|
||||||
FOREIGN KEY(song1) REFERENCES songs(id) ON DELETE CASCADE, \
|
|
||||||
FOREIGN KEY(song2) REFERENCES songs(id) ON DELETE CASCADE, \
|
|
||||||
UNIQUE (song1, song2))",
|
|
||||||
NULL, NULL, NULL);
|
|
||||||
if (SQLITE_OK != dberr) {
|
|
||||||
fprintf(stderr, "Error creating db: %s.\n", sqlite3_errmsg(dbh));
|
|
||||||
sqlite3_close(dbh);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
dberr = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS errors( \
|
|
||||||
id INTEGER PRIMARY KEY, \
|
|
||||||
filename TEXT UNIQUE)", NULL, NULL, NULL);
|
|
||||||
if (SQLITE_OK != dberr) {
|
|
||||||
fprintf(stderr, "Error creating db: %s.\n", sqlite3_errmsg(dbh));
|
|
||||||
sqlite3_close(dbh);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
// Purge db if a rescan is needed
|
// Purge db if a rescan is needed
|
||||||
if (1 == args_info.rescan_flag) {
|
if (1 == args_info.rescan_flag) {
|
||||||
dberr = sqlite3_exec(dbh, "BEGIN TRANSACTION; DELETE FROM distances; DELETE FROM songs; DELETE FROM errors; COMMIT", NULL, NULL, NULL);
|
if (0 != _purge_db(mpdbliss_data_db)) {
|
||||||
if (SQLITE_OK != dberr) {
|
exit(EXIT_FAILURE);
|
||||||
fprintf(stderr, "Error purging existing data in db: %s.\n", sqlite3_errmsg(dbh));
|
}
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
// Set last_mtime to 0
|
// Set last_mtime to 0
|
||||||
last_mtime = 0;
|
last_mtime = 0;
|
||||||
}
|
}
|
||||||
// Close db connection
|
|
||||||
sqlite3_close(dbh);
|
|
||||||
|
|
||||||
// Check if a full rescan is needed
|
// Check if a full rescan is needed
|
||||||
if (1 == args_info.rescan_flag) {
|
if (1 == args_info.rescan_flag) {
|
||||||
update_database(conn, last_mtime, mpd_base_path);
|
last_mtime = update_database(last_mtime, mpd_base_path, mpdbliss_data_db);
|
||||||
}
|
if (last_mtime < 0) {
|
||||||
|
fprintf(stderr, "An error occurred while scanning library.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Else, if we want to rescan errored files
|
// Else, if we want to rescan errored files
|
||||||
else if (1 == args_info.rescan_errors_flag) {
|
else if (1 == args_info.rescan_errors_flag) {
|
||||||
rescan_errored(mpd_base_path);
|
// Update last_mtime
|
||||||
|
_rescan_errored(mpdbliss_data_db, mpd_base_path);
|
||||||
}
|
}
|
||||||
// Else, if we requested an update of the db
|
// Else, if we requested an update of the db
|
||||||
else if (true == args_info.update_flag) {
|
else if (true == args_info.update_flag) {
|
||||||
// Rescan from last known mtime
|
// Rescan from last known mtime
|
||||||
update_database(conn, last_mtime, mpd_base_path);
|
last_mtime = update_database(last_mtime, mpd_base_path, mpdbliss_data_db);
|
||||||
|
if (last_mtime < 0) {
|
||||||
|
fprintf(stderr, "An error occurred while scanning library.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Setting signal handler
|
// Setting signal handler
|
||||||
if (signal(SIGINT, sigint_catch_function) == SIG_ERR) {
|
if (signal(SIGINT, sigint_catch_function) == SIG_ERR) {
|
||||||
fprintf(stderr, "An error occurred while setting a signal handler.\n");
|
fprintf(stderr, "An error occurred while setting a signal handler.\n");
|
||||||
return EXIT_FAILURE;
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (mpd_run_idle_loop) {
|
while (mpd_run_idle_loop) {
|
||||||
@ -542,12 +249,27 @@ int main(int argc, char** argv) {
|
|||||||
mpd_run_idle_mask(conn, MPD_IDLE_DATABASE);
|
mpd_run_idle_mask(conn, MPD_IDLE_DATABASE);
|
||||||
|
|
||||||
// Rescan from last known mtime
|
// Rescan from last known mtime
|
||||||
update_database(conn, last_mtime, mpd_base_path);
|
last_mtime = update_database(last_mtime, mpd_base_path, mpdbliss_data_db);
|
||||||
|
if (last_mtime < 0) {
|
||||||
|
fprintf(stderr, "An error occurred while scanning library.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// Stop listening to MPD IDLE
|
// Stop listening to MPD IDLE
|
||||||
mpd_run_noidle(conn);
|
mpd_run_noidle(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write last_mtime
|
||||||
|
fp = fopen(mpdbliss_data_file, "w+");
|
||||||
|
if (NULL != fp) {
|
||||||
|
fprintf(fp, "%ld\n", last_mtime);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Unable to store latest mtime seen.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
13
src/utilities.c
Normal file
13
src/utilities.c
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
|
||||||
|
void strip_trailing_slash(char* str)
|
||||||
|
{
|
||||||
|
size_t length = strlen(str);
|
||||||
|
if ('/' == str[length - 1]) {
|
||||||
|
str[length - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user