ocarina/core/tags/track.cpp

220 lines
4.6 KiB
C++

/**
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/filter.h>
extern "C" {
#include <core/string.h>
#include <taglib/tag_c.h>
}
#include <core/tags/track.h>
#include <glib.h>
static database<struct track> 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<struct track> *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;
}