Store errors in db and allow to pass them again
This commit is contained in:
parent
d8e86bf62d
commit
287e1ab0f4
@ -41,6 +41,8 @@ struct gengetopt_args_info
|
|||||||
const char *version_help; /**< @brief Print version and exit help description. */
|
const char *version_help; /**< @brief Print version and exit help description. */
|
||||||
int rescan_flag; /**< @brief Rescan the whole MPD database. (default=off). */
|
int rescan_flag; /**< @brief Rescan the whole MPD database. (default=off). */
|
||||||
const char *rescan_help; /**< @brief Rescan the whole MPD database. help description. */
|
const char *rescan_help; /**< @brief Rescan the whole MPD database. help description. */
|
||||||
|
int rescan_errors_flag; /**< @brief Rescan the errored files from the MPD database. (default=off). */
|
||||||
|
const char *rescan_errors_help; /**< @brief Rescan the errored files from the MPD database. help description. */
|
||||||
int update_flag; /**< @brief Trigger an update. (default=off). */
|
int update_flag; /**< @brief Trigger an update. (default=off). */
|
||||||
const char *update_help; /**< @brief Trigger an update. help description. */
|
const char *update_help; /**< @brief Trigger an update. help description. */
|
||||||
char * mpd_root_arg; /**< @brief MPD library base path.. */
|
char * mpd_root_arg; /**< @brief MPD library base path.. */
|
||||||
@ -56,6 +58,7 @@ struct gengetopt_args_info
|
|||||||
unsigned int help_given ; /**< @brief Whether help was given. */
|
unsigned int help_given ; /**< @brief Whether help was given. */
|
||||||
unsigned int version_given ; /**< @brief Whether version was given. */
|
unsigned int version_given ; /**< @brief Whether version was given. */
|
||||||
unsigned int rescan_given ; /**< @brief Whether rescan was given. */
|
unsigned int rescan_given ; /**< @brief Whether rescan was given. */
|
||||||
|
unsigned int rescan_errors_given ; /**< @brief Whether rescan-errors was given. */
|
||||||
unsigned int update_given ; /**< @brief Whether update was given. */
|
unsigned int update_given ; /**< @brief Whether update was given. */
|
||||||
unsigned int mpd_root_given ; /**< @brief Whether mpd_root was given. */
|
unsigned int mpd_root_given ; /**< @brief Whether mpd_root was given. */
|
||||||
unsigned int host_given ; /**< @brief Whether host was given. */
|
unsigned int host_given ; /**< @brief Whether host was given. */
|
||||||
|
@ -3,6 +3,7 @@ version "VERSION"
|
|||||||
purpose "Binding MPD and Bliss."
|
purpose "Binding MPD and Bliss."
|
||||||
|
|
||||||
option "rescan" r "Rescan the whole MPD database." flag off
|
option "rescan" r "Rescan the whole MPD database." flag off
|
||||||
|
option "rescan-errors" e "Rescan the errored files from the MPD database." flag off
|
||||||
option "update" u "Trigger an update." flag off
|
option "update" u "Trigger an update." flag off
|
||||||
option "mpd_root" - "MPD library base path." string
|
option "mpd_root" - "MPD library base path." string
|
||||||
option "host" - "MPD host." string default="" optional
|
option "host" - "MPD host." string default="" optional
|
||||||
|
@ -37,6 +37,7 @@ const char *gengetopt_args_info_help[] = {
|
|||||||
" -h, --help Print help and exit",
|
" -h, --help Print help and exit",
|
||||||
" -V, --version Print version and exit",
|
" -V, --version Print version and exit",
|
||||||
" -r, --rescan Rescan the whole MPD database. (default=off)",
|
" -r, --rescan Rescan the whole MPD database. (default=off)",
|
||||||
|
" -e, --rescan-errors Rescan the errored files from the MPD database.\n (default=off)",
|
||||||
" -u, --update Trigger an update. (default=off)",
|
" -u, --update Trigger an update. (default=off)",
|
||||||
" --mpd_root=STRING MPD library base path.",
|
" --mpd_root=STRING MPD library base path.",
|
||||||
" --host=STRING MPD host. (default=`')",
|
" --host=STRING MPD host. (default=`')",
|
||||||
@ -71,6 +72,7 @@ void clear_given (struct gengetopt_args_info *args_info)
|
|||||||
args_info->help_given = 0 ;
|
args_info->help_given = 0 ;
|
||||||
args_info->version_given = 0 ;
|
args_info->version_given = 0 ;
|
||||||
args_info->rescan_given = 0 ;
|
args_info->rescan_given = 0 ;
|
||||||
|
args_info->rescan_errors_given = 0 ;
|
||||||
args_info->update_given = 0 ;
|
args_info->update_given = 0 ;
|
||||||
args_info->mpd_root_given = 0 ;
|
args_info->mpd_root_given = 0 ;
|
||||||
args_info->host_given = 0 ;
|
args_info->host_given = 0 ;
|
||||||
@ -82,6 +84,7 @@ void clear_args (struct gengetopt_args_info *args_info)
|
|||||||
{
|
{
|
||||||
FIX_UNUSED (args_info);
|
FIX_UNUSED (args_info);
|
||||||
args_info->rescan_flag = 0;
|
args_info->rescan_flag = 0;
|
||||||
|
args_info->rescan_errors_flag = 0;
|
||||||
args_info->update_flag = 0;
|
args_info->update_flag = 0;
|
||||||
args_info->mpd_root_arg = NULL;
|
args_info->mpd_root_arg = NULL;
|
||||||
args_info->mpd_root_orig = NULL;
|
args_info->mpd_root_orig = NULL;
|
||||||
@ -100,10 +103,11 @@ void init_args_info(struct gengetopt_args_info *args_info)
|
|||||||
args_info->help_help = gengetopt_args_info_help[0] ;
|
args_info->help_help = gengetopt_args_info_help[0] ;
|
||||||
args_info->version_help = gengetopt_args_info_help[1] ;
|
args_info->version_help = gengetopt_args_info_help[1] ;
|
||||||
args_info->rescan_help = gengetopt_args_info_help[2] ;
|
args_info->rescan_help = gengetopt_args_info_help[2] ;
|
||||||
args_info->update_help = gengetopt_args_info_help[3] ;
|
args_info->rescan_errors_help = gengetopt_args_info_help[3] ;
|
||||||
args_info->mpd_root_help = gengetopt_args_info_help[4] ;
|
args_info->update_help = gengetopt_args_info_help[4] ;
|
||||||
args_info->host_help = gengetopt_args_info_help[5] ;
|
args_info->mpd_root_help = gengetopt_args_info_help[5] ;
|
||||||
args_info->port_help = gengetopt_args_info_help[6] ;
|
args_info->host_help = gengetopt_args_info_help[6] ;
|
||||||
|
args_info->port_help = gengetopt_args_info_help[7] ;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,6 +232,8 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info)
|
|||||||
write_into_file(outfile, "version", 0, 0 );
|
write_into_file(outfile, "version", 0, 0 );
|
||||||
if (args_info->rescan_given)
|
if (args_info->rescan_given)
|
||||||
write_into_file(outfile, "rescan", 0, 0 );
|
write_into_file(outfile, "rescan", 0, 0 );
|
||||||
|
if (args_info->rescan_errors_given)
|
||||||
|
write_into_file(outfile, "rescan-errors", 0, 0 );
|
||||||
if (args_info->update_given)
|
if (args_info->update_given)
|
||||||
write_into_file(outfile, "update", 0, 0 );
|
write_into_file(outfile, "update", 0, 0 );
|
||||||
if (args_info->mpd_root_given)
|
if (args_info->mpd_root_given)
|
||||||
@ -521,6 +527,7 @@ cmdline_parser_internal (
|
|||||||
{ "help", 0, NULL, 'h' },
|
{ "help", 0, NULL, 'h' },
|
||||||
{ "version", 0, NULL, 'V' },
|
{ "version", 0, NULL, 'V' },
|
||||||
{ "rescan", 0, NULL, 'r' },
|
{ "rescan", 0, NULL, 'r' },
|
||||||
|
{ "rescan-errors", 0, NULL, 'e' },
|
||||||
{ "update", 0, NULL, 'u' },
|
{ "update", 0, NULL, 'u' },
|
||||||
{ "mpd_root", 1, NULL, 0 },
|
{ "mpd_root", 1, NULL, 0 },
|
||||||
{ "host", 1, NULL, 0 },
|
{ "host", 1, NULL, 0 },
|
||||||
@ -528,7 +535,7 @@ cmdline_parser_internal (
|
|||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
c = getopt_long (argc, argv, "hVru", long_options, &option_index);
|
c = getopt_long (argc, argv, "hVreu", long_options, &option_index);
|
||||||
|
|
||||||
if (c == -1) break; /* Exit from `while (1)' loop. */
|
if (c == -1) break; /* Exit from `while (1)' loop. */
|
||||||
|
|
||||||
@ -553,6 +560,16 @@ cmdline_parser_internal (
|
|||||||
additional_error))
|
additional_error))
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'e': /* Rescan the errored files from the MPD database.. */
|
||||||
|
|
||||||
|
|
||||||
|
if (update_arg((void *)&(args_info->rescan_errors_flag), 0, &(args_info->rescan_errors_given),
|
||||||
|
&(local_args_info.rescan_errors_given), optarg, 0, 0, ARG_FLAG,
|
||||||
|
check_ambiguity, override, 1, 0, "rescan-errors", 'e',
|
||||||
|
additional_error))
|
||||||
|
goto failure;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'u': /* Trigger an update.. */
|
case 'u': /* Trigger an update.. */
|
||||||
|
|
||||||
|
310
src/main.c
310
src/main.c
@ -57,6 +57,151 @@ void strip_trailing_slash(char* str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
// 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));
|
||||||
|
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));
|
||||||
|
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));
|
||||||
|
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
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
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));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the database.
|
* Update the database.
|
||||||
*
|
*
|
||||||
@ -67,7 +212,7 @@ void strip_trailing_slash(char* str)
|
|||||||
void update_database(
|
void update_database(
|
||||||
struct mpd_connection *conn,
|
struct mpd_connection *conn,
|
||||||
time_t initial_mtime,
|
time_t initial_mtime,
|
||||||
char *mpd_base_path
|
const char *mpd_base_path
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Store latest mtime seen
|
// Store latest mtime seen
|
||||||
@ -111,86 +256,7 @@ void update_database(
|
|||||||
|
|
||||||
// Compute bl_analyze and store it
|
// Compute bl_analyze and store it
|
||||||
const char *song_uri = mpd_song_get_uri(song);
|
const char *song_uri = mpd_song_get_uri(song);
|
||||||
printf("\nAdding new song to db: %s\n", song_uri);
|
if (1 == _parse_music_helper(dbh, mpd_base_path, song_uri)) {
|
||||||
struct bl_song song_analysis;
|
|
||||||
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);
|
|
||||||
if (BL_UNEXPECTED == bl_analyze(song_full_uri, &song_analysis)) {
|
|
||||||
fprintf(stderr, "Error while parsing song: %s.\n\n", song_uri);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Insert into db
|
|
||||||
sqlite3_stmt *res;
|
|
||||||
// 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));
|
|
||||||
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 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));
|
|
||||||
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
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));
|
|
||||||
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
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));
|
|
||||||
sqlite3_exec(dbh, "ROLLBACK", NULL, NULL, NULL);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +286,57 @@ void update_database(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
struct gengetopt_args_info args_info;
|
struct gengetopt_args_info args_info;
|
||||||
|
|
||||||
@ -233,14 +350,29 @@ int main(int argc, char** argv) {
|
|||||||
if (strlen(args_info.host_arg) > 0) {
|
if (strlen(args_info.host_arg) > 0) {
|
||||||
mpd_host = args_info.host_arg;
|
mpd_host = args_info.host_arg;
|
||||||
}
|
}
|
||||||
conn = mpd_connection_new(
|
struct mpd_settings* conn_settings = mpd_settings_new(
|
||||||
mpd_host,
|
mpd_host,
|
||||||
args_info.port_arg,
|
args_info.port_arg,
|
||||||
30000);
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
// Connect
|
||||||
|
conn = mpd_connection_new(
|
||||||
|
mpd_settings_get_host(conn_settings),
|
||||||
|
mpd_settings_get_port(conn_settings),
|
||||||
|
mpd_settings_get_timeout_ms(conn_settings));
|
||||||
if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {
|
if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {
|
||||||
fprintf(stderr, "Unable to connect to the MPD server.\n");
|
fprintf(stderr, "Unable to connect to the MPD server.\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
// Handle passwords
|
||||||
|
const char* mpd_password = mpd_settings_get_password(conn_settings);
|
||||||
|
if (NULL != mpd_password) {
|
||||||
|
if (!mpd_run_password(conn, mpd_password)) {
|
||||||
|
fprintf(stderr, "Unable to send password to the MPD server.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char *mpd_base_path = args_info.mpd_root_arg;
|
char *mpd_base_path = args_info.mpd_root_arg;
|
||||||
|
|
||||||
@ -312,6 +444,14 @@ int main(int argc, char** argv) {
|
|||||||
sqlite3_close(dbh);
|
sqlite3_close(dbh);
|
||||||
return EXIT_FAILURE;
|
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; COMMIT", NULL, NULL, NULL);
|
dberr = sqlite3_exec(dbh, "BEGIN TRANSACTION; DELETE FROM distances; DELETE FROM songs; COMMIT", NULL, NULL, NULL);
|
||||||
@ -327,6 +467,10 @@ int main(int argc, char** argv) {
|
|||||||
if (1 == args_info.rescan_flag) {
|
if (1 == args_info.rescan_flag) {
|
||||||
update_database(conn, last_mtime, mpd_base_path);
|
update_database(conn, last_mtime, mpd_base_path);
|
||||||
}
|
}
|
||||||
|
// Else, if we want to rescan errored files
|
||||||
|
if (1 == args_info.rescan_errors_flag) {
|
||||||
|
rescan_errored(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
|
||||||
|
Loading…
Reference in New Issue
Block a user