/** * Copyright 2014 (c) Anna Schumaker. */ #include extern "C" { #include #include } #include #include static database track_db; static const std::string __track_key(struct library *library, const std::string &path) { std :: string res; if (library) { gchar *g_res = g_strdup_printf("%u/%s", library->index(), path.c_str()); res = g_res; g_free(g_res); } return res; } track :: track() : tr_album(NULL), tr_artist(NULL), tr_genre(NULL), tr_library(NULL), tr_count(0), tr_length(0), tr_track(0) {} track :: track(const std::string &key) { const TagLib_AudioProperties *audio; struct library *library; unsigned int lib_id; TagLib_File *file; TagLib_Tag *tag; std::string full; char *path, *lower; sscanf(key.c_str(), "%u/%m[^\n]", &lib_id, &path); library = library_get(lib_id); full = library_file(library, path); file = taglib_file_new(full.c_str()); if (!file || !taglib_file_is_valid(file)) { printf("WARNING: Could not read tags for: %s\n", full.c_str()); goto out; } tag = taglib_file_tag(file); audio = taglib_file_audioproperties(file); tr_album = album_find(taglib_tag_album(tag), taglib_tag_year(tag)); tr_artist = artist_find(taglib_tag_artist(tag)); tr_genre = genre_find(taglib_tag_genre(tag)); tr_library = library; tr_library->li_size++; date_set(&tr_date, 0, 0, 0); tr_count = 0; tr_length = taglib_audioproperties_length(audio); tr_track = taglib_tag_track(tag); tr_path = path; tr_title = taglib_tag_title(tag); lower = string_lowercase(tr_title.c_str()); tr_lower = lower; date_set(&tr_date, 0, 0, 0); filter :: add(tr_title, index()); filter :: add(tr_artist->ar_name, index()); filter :: add(tr_album->al_name, index()); taglib_tag_free_strings(); taglib_file_free(file); g_free(lower); out: g_free(path); } track :: ~track() { if (tr_library) tr_library->li_size--; } const std::string track :: primary_key() const { return __track_key(tr_library, tr_path); } void track :: read(file &file) { unsigned int library_id, artist_id, album_id, genre_id; gchar *path, *name, *lower; file_readf(&file, "%u %u %u %u %u", &library_id, &artist_id, &album_id, &genre_id, &tr_track); date_read(&file, &tr_date); file_readf(&file, "%u %u", &tr_count, &tr_length); name = file_readl(&file); path = file_readl(&file); lower = string_lowercase(name); tr_title = name; tr_path = path; tr_lower = lower; g_free(name); g_free(path); g_free(lower); tr_library = library_get(library_id); tr_artist = artist_get(artist_id); tr_album = album_get(album_id); tr_genre = genre_get(genre_id); filter :: add(tr_title, index()); filter :: add(tr_artist->ar_name, index()); filter :: add(tr_album->al_name, index()); tr_library->li_size++; } void track :: write(file &file) { file_writef(&file, "%u %u %u %u %u ", tr_library->index(), tr_artist->index(), tr_album->index(), tr_genre->index(), tr_track); date_write(&file, &tr_date); file_writef(&file, " %u %u %s\n%s\n", tr_count, tr_length, tr_title.c_str(), tr_path.c_str()); } void track_db_init() { db_init(&track_db, "track.db", false); db_load(&track_db); } void track_db_deinit() { db_deinit(&track_db); } void track_db_commit() { db_save(&track_db); } const database *track_db_get() { return &track_db; } struct track *track_add(struct library *library, const std::string &filepath) { std::string path = filepath.substr(library->primary_key().size() + 1); std::string key = __track_key(library, path); if (db_get(&track_db, key.c_str())) return NULL; return db_insert(&track_db, new struct track(key)); } void track_remove(struct track *track) { db_remove(&track_db, track); } void track_remove_all(struct library *library) { struct track *it, *next; db_for_each(it, next, &track_db) { if (it->tr_library == library) db_remove(&track_db, it); } track_db_commit(); } struct track *track_get(const unsigned int index) { return db_at(&track_db, index); } int track_compare(struct track *lhs, struct track *rhs) { return string_compare(lhs->tr_lower.c_str(), rhs->tr_lower.c_str()); } const std::string track_path(struct track *track) { if (track->tr_library) return library_file(track->tr_library, track->tr_path); return ""; } void track_played(struct track *track) { track->tr_count++; date_today(&track->tr_date); track_db_commit(); } const std::string track_last_play(struct track *track) { std::string res = "Never"; char *buf; if (track->tr_count > 0) { buf = date_string(&track->tr_date); res = buf; g_free(buf); } return res; }