mirror of
https://github.com/riwiwa/muzi.git
synced 2025-12-30 04:35:26 -08:00
spotify importing to db finished
This commit is contained in:
136
muzi.c
136
muzi.c
@@ -13,20 +13,16 @@
|
|||||||
|
|
||||||
#define MAX_FILENAME_SIZE 255
|
#define MAX_FILENAME_SIZE 255
|
||||||
|
|
||||||
// TODO:
|
enum Platform {
|
||||||
// - for each json entry {
|
SPOTIFY = 0,
|
||||||
// - add entry to postgresql db
|
LASTFM = 1,
|
||||||
// }
|
};
|
||||||
//
|
|
||||||
// - web ui
|
|
||||||
// - sql tables: "full history", "artists", "songs", "albums" (see ipad)
|
|
||||||
//
|
|
||||||
|
|
||||||
int extract(const char *path, const char *target);
|
int extract(const char *path, const char *target);
|
||||||
int get_artist_plays(const char *json_file, const char *artist);
|
int get_artist_plays(const char *json_file, const char *artist);
|
||||||
int import_spotify(void);
|
int import_spotify(void);
|
||||||
int add_dir_to_db(const char *path);
|
int add_dir_to_db(const char *path, int platform);
|
||||||
int json_to_db(const char *json_file);
|
int json_to_db(const char *json_file, int platform);
|
||||||
int create_db(void);
|
int create_db(void);
|
||||||
bool db_exists(void);
|
bool db_exists(void);
|
||||||
bool table_exists(const char *name, PGconn *conn);
|
bool table_exists(const char *name, PGconn *conn);
|
||||||
@@ -83,7 +79,6 @@ int create_db(void) {
|
|||||||
PQfinish(tmp_conn);
|
PQfinish(tmp_conn);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
printf("Database connection successful.\n");
|
|
||||||
if (PQresultStatus(PQexec(tmp_conn, "CREATE DATABASE muzi")) !=
|
if (PQresultStatus(PQexec(tmp_conn, "CREATE DATABASE muzi")) !=
|
||||||
PGRES_COMMAND_OK) {
|
PGRES_COMMAND_OK) {
|
||||||
printf("CREATE DATABASE muzi failed: %s\n", PQerrorMessage(tmp_conn));
|
printf("CREATE DATABASE muzi failed: %s\n", PQerrorMessage(tmp_conn));
|
||||||
@@ -95,7 +90,7 @@ int create_db(void) {
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int json_to_db(const char *json_file) {
|
int json_to_db(const char *json_file, int platform) {
|
||||||
if (db_exists() == false) {
|
if (db_exists() == false) {
|
||||||
create_db();
|
create_db();
|
||||||
}
|
}
|
||||||
@@ -107,34 +102,112 @@ int json_to_db(const char *json_file) {
|
|||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
printf("Database connection successful.\n");
|
|
||||||
|
|
||||||
bool e = table_exists("history", conn);
|
bool e = table_exists("history", conn);
|
||||||
if (e) {
|
if (!e) {
|
||||||
} else {
|
PGresult *result =
|
||||||
printf("Creating history table.\n");
|
PQexec(conn, "CREATE TABLE history ( ms_played INTEGER, timestamp "
|
||||||
PGresult *result = PQexec(
|
"TIMESTAMPTZ, song_name "
|
||||||
conn,
|
"TEXT, artist TEXT, "
|
||||||
"CREATE TABLE history ( id INT PRIMARY KEY GENERATED ALWAYS AS "
|
"album_name TEXT, PRIMARY KEY (timestamp, ms_played, "
|
||||||
"IDENTITY, year INT, month INT, day INT, time VARCHAR(10), timestamp "
|
"artist, song_name));");
|
||||||
"VARCHAR(20), song_name VARCHAR(100), artist VARCHAR(100), "
|
|
||||||
"album_artist VARCHAR(100), album_name VARCHAR(100));");
|
|
||||||
if (PQresultStatus(result) != PGRES_COMMAND_OK) {
|
if (PQresultStatus(result) != PGRES_COMMAND_OK) {
|
||||||
printf("History table creation failed: %s\n", PQerrorMessage(conn));
|
printf("History table creation failed: %s\n", PQerrorMessage(conn));
|
||||||
|
PQclear(result);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
printf("Created history table.\n");
|
||||||
|
PQclear(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// for json_entry in json_file {
|
FILE *fp = fopen(json_file, "r");
|
||||||
// add to database
|
if (fp == NULL) {
|
||||||
// }
|
printf("Error while opening file\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
long fileSize = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
|
char *buffer = (char *)malloc(fileSize + 1);
|
||||||
|
fread(buffer, 1, fileSize, fp);
|
||||||
|
buffer[fileSize] = '\0';
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
cJSON *json = cJSON_Parse(buffer);
|
||||||
|
if (json == NULL) {
|
||||||
|
const char *error_ptr = cJSON_GetErrorPtr();
|
||||||
|
if (error_ptr != NULL) {
|
||||||
|
printf("Error: %s\n", error_ptr);
|
||||||
|
}
|
||||||
|
cJSON_Delete(json);
|
||||||
|
free(buffer);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (platform == SPOTIFY) {
|
||||||
|
cJSON *play = NULL;
|
||||||
|
cJSON_ArrayForEach(play, json) {
|
||||||
|
// supports up to 2.7k hour long songs
|
||||||
|
char ms_played[10];
|
||||||
|
char *timestamp;
|
||||||
|
char *song_name;
|
||||||
|
char *album_artist;
|
||||||
|
char *album;
|
||||||
|
|
||||||
|
cJSON *ms_played_obj =
|
||||||
|
cJSON_GetObjectItemCaseSensitive(play, "ms_played");
|
||||||
|
if (cJSON_IsNumber(ms_played_obj)) {
|
||||||
|
sprintf(ms_played, "%d", ms_played_obj->valueint);
|
||||||
|
}
|
||||||
|
// do not add to database if played for only 20 seconds
|
||||||
|
if (ms_played_obj->valueint < 20000) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cJSON *timestamp_obj = cJSON_GetObjectItemCaseSensitive(play, "ts");
|
||||||
|
if (cJSON_IsString(timestamp_obj)) {
|
||||||
|
timestamp = timestamp_obj->valuestring;
|
||||||
|
}
|
||||||
|
cJSON *song_name_obj =
|
||||||
|
cJSON_GetObjectItemCaseSensitive(play, "master_metadata_track_name");
|
||||||
|
if (cJSON_IsString(song_name_obj)) {
|
||||||
|
song_name = song_name_obj->valuestring;
|
||||||
|
}
|
||||||
|
cJSON *artist_obj = cJSON_GetObjectItemCaseSensitive(
|
||||||
|
play, "master_metadata_album_artist_name");
|
||||||
|
if (cJSON_IsString(artist_obj)) {
|
||||||
|
album_artist = artist_obj->valuestring;
|
||||||
|
}
|
||||||
|
cJSON *album_obj = cJSON_GetObjectItemCaseSensitive(
|
||||||
|
play, "master_metadata_album_album_name");
|
||||||
|
if (cJSON_IsString(album_obj)) {
|
||||||
|
album = album_obj->valuestring;
|
||||||
|
}
|
||||||
|
const char *data[5] = {timestamp, song_name, album_artist, album,
|
||||||
|
ms_played};
|
||||||
|
PGresult *result =
|
||||||
|
PQexecParams(conn,
|
||||||
|
"INSERT INTO history (timestamp, song_name, artist, "
|
||||||
|
"album_name, ms_played) VALUES ($1, $2, $3, $4, $5);",
|
||||||
|
5, NULL, data, NULL, NULL, 0);
|
||||||
|
if (PQresultStatus(result) != PGRES_COMMAND_OK) {
|
||||||
|
printf("Attempt to insert data for track failed: %s\n",
|
||||||
|
PQerrorMessage(conn));
|
||||||
|
}
|
||||||
|
PQclear(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
|
cJSON_Delete(json);
|
||||||
|
free(buffer);
|
||||||
|
printf("Added file: '%s' to muzi database.\n", json_file);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int add_dir_to_db(const char *path) {
|
int add_dir_to_db(const char *path, int platform) {
|
||||||
DIR *dir = opendir(path);
|
DIR *dir = opendir(path);
|
||||||
struct dirent *data_dir = NULL;
|
struct dirent *data_dir = NULL;
|
||||||
|
|
||||||
@@ -155,13 +228,17 @@ int add_dir_to_db(const char *path) {
|
|||||||
if (json_file->d_type != DT_DIR) {
|
if (json_file->d_type != DT_DIR) {
|
||||||
char *ext = strrchr(json_file->d_name, '.');
|
char *ext = strrchr(json_file->d_name, '.');
|
||||||
if (strcmp(ext, ".json") == 0) {
|
if (strcmp(ext, ".json") == 0) {
|
||||||
|
// prevents parsing spotify video data that causes duplicates
|
||||||
|
if (platform == SPOTIFY && strstr(json_file->d_name, "Video")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
char json_file_path[MAX_FILENAME_SIZE];
|
char json_file_path[MAX_FILENAME_SIZE];
|
||||||
if (snprintf(json_file_path, MAX_FILENAME_SIZE, "%s/%s",
|
if (snprintf(json_file_path, MAX_FILENAME_SIZE, "%s/%s",
|
||||||
data_dir_path, json_file->d_name) < 0) {
|
data_dir_path, json_file->d_name) < 0) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
json_to_db(json_file_path);
|
json_to_db(json_file_path, platform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,13 +401,12 @@ int import_spotify(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
add_dir_to_db(target_base);
|
add_dir_to_db(target_base, SPOTIFY);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
// import_spotify();
|
import_spotify();
|
||||||
// add_dir_to_db("./spotify-data/extracted");
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user