2013-10-27 17:25:26 -04:00
|
|
|
/*
|
|
|
|
* Copyright 2013 (c) Anna Schumaker.
|
|
|
|
*/
|
|
|
|
#include <library.h>
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
2013-12-10 17:38:42 -05:00
|
|
|
static Database<library :: Artist, const std::string> artist_db("artist.db");
|
|
|
|
static Database<library :: Album, std::pair<const std::string, unsigned int> > album_db("album.db");
|
|
|
|
static Database<library :: Genre, const std::string> genre_db("genre.db");
|
|
|
|
static Database<library :: Library, const std::string> library_db("library.db");
|
|
|
|
static Database<library :: Track, const std::string> track_db("track.db");
|
2013-10-27 17:25:26 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-10 16:09:31 -05:00
|
|
|
/*
|
|
|
|
* library :: Artist: Artist tag information
|
|
|
|
*/
|
2013-11-10 16:45:52 -05:00
|
|
|
|
2013-11-10 16:09:31 -05:00
|
|
|
library :: Artist :: Artist()
|
|
|
|
: name("")
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-11-10 16:57:28 -05:00
|
|
|
library :: Artist :: Artist(TagLib :: Tag *tag)
|
2013-12-08 20:52:14 -05:00
|
|
|
: name(tag->artist().stripWhiteSpace().to8Bit(true))
|
2013-11-10 16:09:31 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-12-08 20:52:14 -05:00
|
|
|
const std::string &library :: Artist :: primary_key()
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2013-11-10 16:09:31 -05:00
|
|
|
void library :: Artist :: read(File &f)
|
|
|
|
{
|
|
|
|
name = f.getline();
|
|
|
|
}
|
|
|
|
|
|
|
|
void library :: Artist :: write(File &f)
|
|
|
|
{
|
|
|
|
f << name;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
|
|
void library :: Artist :: print()
|
|
|
|
{
|
|
|
|
:: print("Artist: %s", name.c_str());
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_DEBUG */
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-10 16:45:52 -05:00
|
|
|
/*
|
|
|
|
* library :: Album: Album tag information
|
|
|
|
*/
|
|
|
|
|
|
|
|
library :: Album :: Album()
|
|
|
|
: name(""), year(0), artist_id(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-11-10 16:57:28 -05:00
|
|
|
library :: Album :: Album(TagLib :: Tag *tag, unsigned int artist)
|
2013-12-08 20:52:14 -05:00
|
|
|
: name(tag->album().stripWhiteSpace().to8Bit(true)),
|
|
|
|
year(tag->year()), artist_id(artist)
|
2013-11-10 16:45:52 -05:00
|
|
|
{
|
2013-12-10 17:38:42 -05:00
|
|
|
key = make_pair(name, artist_id);
|
2013-11-10 16:45:52 -05:00
|
|
|
}
|
|
|
|
|
2013-12-10 17:38:42 -05:00
|
|
|
std :: pair<std::string, unsigned int> &library :: Album :: primary_key()
|
2013-12-08 20:52:14 -05:00
|
|
|
{
|
2013-12-10 17:38:42 -05:00
|
|
|
return key;
|
2013-12-08 20:52:14 -05:00
|
|
|
}
|
|
|
|
|
2013-11-10 16:45:52 -05:00
|
|
|
void library :: Album :: read(File &f)
|
|
|
|
{
|
|
|
|
f >> artist_id >> year;
|
|
|
|
name = f.getline();
|
|
|
|
}
|
|
|
|
|
|
|
|
void library :: Album :: write(File &f)
|
|
|
|
{
|
|
|
|
f << artist_id << " " << year << " " << name;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
|
|
void library :: Album :: print()
|
|
|
|
{
|
|
|
|
:: print("Album: %s (%u) by %s", name.c_str(), year, artist_db[artist_id].name.c_str());
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_DEBUG */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* library :: Genre: Genre tag information
|
|
|
|
*/
|
|
|
|
|
|
|
|
library :: Genre :: Genre()
|
|
|
|
: name("")
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-11-10 16:57:28 -05:00
|
|
|
library :: Genre :: Genre(TagLib :: Tag *tag)
|
|
|
|
: name(tag->genre().to8Bit(true))
|
2013-11-10 16:45:52 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-12-08 20:52:14 -05:00
|
|
|
const std::string &library :: Genre :: primary_key()
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2013-11-10 16:45:52 -05:00
|
|
|
void library :: Genre :: read(File &f)
|
|
|
|
{
|
|
|
|
name = f.getline();
|
|
|
|
}
|
|
|
|
|
|
|
|
void library :: Genre :: write(File &f)
|
|
|
|
{
|
|
|
|
f << name;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
|
|
void library :: Genre :: print()
|
|
|
|
{
|
|
|
|
:: print("Genre: %s", name.c_str());
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_DEBUG */
|
|
|
|
|
|
|
|
|
2013-11-10 16:09:31 -05:00
|
|
|
|
2013-10-27 17:25:26 -04:00
|
|
|
/*
|
|
|
|
* library :: Library: Basic information about each directory in the library
|
|
|
|
*/
|
|
|
|
|
2013-11-03 16:03:01 -05:00
|
|
|
library :: Library :: Library()
|
|
|
|
: root_path(""), enabled(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-10-27 17:25:26 -04:00
|
|
|
library :: Library :: Library(const std::string &path, bool is_enabled)
|
|
|
|
: root_path(path), enabled(is_enabled)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-12-08 20:52:14 -05:00
|
|
|
const std::string &library :: Library :: primary_key()
|
|
|
|
{
|
|
|
|
return root_path;
|
|
|
|
}
|
|
|
|
|
2013-10-27 17:25:26 -04:00
|
|
|
void library :: Library :: read(File &f)
|
|
|
|
{
|
2013-11-03 16:03:01 -05:00
|
|
|
f >> enabled;
|
|
|
|
root_path = f.getline();
|
2013-10-27 17:25:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void library :: Library :: write(File &f)
|
|
|
|
{
|
2013-11-03 16:03:01 -05:00
|
|
|
f << enabled << " " << root_path;
|
2013-10-27 17:25:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
|
|
void library :: Library :: print()
|
|
|
|
{
|
|
|
|
:: print("%s", root_path.c_str());
|
|
|
|
if (enabled == true)
|
|
|
|
:: print(" (enabled)");
|
|
|
|
else
|
|
|
|
:: print(" (disabled)");
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_DEBUG */
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-10 17:37:35 -05:00
|
|
|
/*
|
|
|
|
* library :: Track: Track tag information
|
|
|
|
*/
|
|
|
|
|
|
|
|
library :: Track :: Track()
|
|
|
|
: library_id(0), artist_id(0), album_id(0), genre_id(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
library :: Track :: Track(TagLib :: Tag *tag, TagLib :: AudioProperties *audio,
|
|
|
|
unsigned int lib, unsigned int artist, unsigned int album,
|
|
|
|
unsigned int genre, const std :: string &path)
|
|
|
|
: library_id(lib), artist_id(artist), album_id(album), genre_id(genre),
|
|
|
|
track(tag->track()), last_year(0), last_month(0), last_day(0),
|
|
|
|
play_count(0), length(audio->length()), banned(false),
|
|
|
|
title(tag->title().to8Bit(true))
|
|
|
|
{
|
|
|
|
filepath = path.substr(library_db[library_id].root_path.size() + 1);
|
|
|
|
}
|
|
|
|
|
2013-12-08 20:52:14 -05:00
|
|
|
const std::string &library :: Track :: primary_key()
|
|
|
|
{
|
|
|
|
return filepath;
|
|
|
|
}
|
|
|
|
|
2013-11-10 17:37:35 -05:00
|
|
|
void library :: Track :: read(File &f)
|
|
|
|
{
|
|
|
|
f >> library_id >> artist_id >> album_id >> genre_id;
|
|
|
|
f >> track >> last_year >> last_month >> last_day;
|
|
|
|
f >> play_count >> length >> banned;
|
|
|
|
title = f.getline();
|
|
|
|
filepath = f.getline();
|
|
|
|
}
|
|
|
|
|
|
|
|
void library :: Track :: write(File &f)
|
|
|
|
{
|
|
|
|
f << library_id << " " << artist_id << " " << album_id << " " << genre_id;
|
|
|
|
f << " " << track << " " << last_year << " " << last_month << " " << last_day;
|
|
|
|
f << " " << play_count << " " << length << " " << banned << std :: endl;
|
|
|
|
f << title << std :: endl;
|
|
|
|
f << filepath;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
|
|
void library :: Track :: print()
|
|
|
|
{
|
|
|
|
:: print("%u. %s by %s from %s (%u)\n", track, title.c_str(),
|
|
|
|
artist_db[artist_id].name.c_str(),
|
|
|
|
album_db[album_id].name.c_str(), album_db[album_id].year);
|
|
|
|
:: print(" Genre: %s, Length: %u (seconds)\n",
|
|
|
|
genre_db[genre_id].name.c_str(), length);
|
|
|
|
:: print(" Play count: %u, last played %u/%u/%u\n", play_count,
|
|
|
|
last_day, last_month, last_year);
|
|
|
|
:: print(" %s", filepath.c_str());
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_DEBUG */
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-10 16:09:31 -05:00
|
|
|
/*
|
|
|
|
* Internal library functions
|
|
|
|
*/
|
|
|
|
static void do_update(unsigned int, const std :: string &);
|
|
|
|
|
|
|
|
static void read_tags(unsigned int lib_id, const std :: string &path)
|
|
|
|
{
|
|
|
|
TagLib :: Tag *tag;
|
2013-12-10 17:38:42 -05:00
|
|
|
TagLib :: AudioProperties *audio;
|
2013-11-10 17:37:35 -05:00
|
|
|
TagLib :: FileRef ref(path.c_str(), true, TagLib :: AudioProperties :: Fast);
|
2013-12-10 17:38:42 -05:00
|
|
|
unsigned int artist_id, album_id, genre_id;
|
2013-11-10 16:09:31 -05:00
|
|
|
|
|
|
|
if (ref.isNull()) {
|
|
|
|
print("ERROR: Could not read tags for file %s", path.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tag = ref.tag();
|
2013-11-10 17:37:35 -05:00
|
|
|
|
2013-12-10 17:38:42 -05:00
|
|
|
audio = ref.audioProperties();
|
2013-12-08 20:52:14 -05:00
|
|
|
|
|
|
|
artist_id = artist_db.insert(library :: Artist(tag));
|
2013-12-10 17:38:42 -05:00
|
|
|
album_id = album_db.insert(library :: Album(tag, artist_id));
|
|
|
|
genre_id = genre_db.insert(library :: Genre(tag));
|
|
|
|
track_db.insert(library :: Track(tag, audio, lib_id, artist_id,
|
|
|
|
album_id, genre_id, path));
|
2013-11-10 16:09:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void process_path(unsigned int lib_id, const std :: string &dir,
|
|
|
|
const std :: string &name)
|
|
|
|
{
|
|
|
|
std :: string path = dir + "/" + name;
|
|
|
|
|
|
|
|
if (g_file_test(path.c_str(), G_FILE_TEST_IS_DIR) == true)
|
|
|
|
do_update(lib_id, path);
|
|
|
|
else
|
|
|
|
read_tags(lib_id, path);
|
|
|
|
}
|
|
|
|
|
2013-11-10 17:37:35 -05:00
|
|
|
static void save_all_dbs()
|
|
|
|
{
|
|
|
|
artist_db.save();
|
|
|
|
album_db.save();
|
|
|
|
genre_db.save();
|
|
|
|
track_db.save();
|
|
|
|
}
|
|
|
|
|
2013-11-10 16:09:31 -05:00
|
|
|
static void do_update(unsigned int lib_id, const std :: string &path)
|
|
|
|
{
|
|
|
|
GDir *dir;
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
dir = g_dir_open(path.c_str(), 0, NULL);
|
|
|
|
if (dir == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
name = g_dir_read_name(dir);
|
|
|
|
while (name != NULL) {
|
|
|
|
process_path(lib_id, path, name);
|
2013-11-10 17:37:35 -05:00
|
|
|
save_all_dbs();
|
2013-11-10 16:09:31 -05:00
|
|
|
name = g_dir_read_name(dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-10-27 17:25:26 -04:00
|
|
|
/*
|
|
|
|
* API used by the GUI begins here
|
|
|
|
*/
|
|
|
|
|
2013-11-03 16:03:01 -05:00
|
|
|
void library :: init()
|
|
|
|
{
|
|
|
|
library_db.load();
|
|
|
|
}
|
|
|
|
|
2013-10-27 17:25:26 -04:00
|
|
|
bool library :: add_path(const std::string &dir)
|
|
|
|
{
|
2013-11-10 16:09:31 -05:00
|
|
|
unsigned int id;
|
2013-10-27 17:25:26 -04:00
|
|
|
if (g_file_test(dir.c_str(), G_FILE_TEST_IS_DIR) == false)
|
|
|
|
return false;
|
|
|
|
|
2013-11-10 16:09:31 -05:00
|
|
|
id = library_db.insert(library :: Library(dir, true));
|
2013-11-03 16:03:01 -05:00
|
|
|
library_db.save();
|
2013-11-10 16:09:31 -05:00
|
|
|
update_path(id);
|
2013-10-27 17:25:26 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void library :: del_path(unsigned int id)
|
|
|
|
{
|
|
|
|
library_db.remove(id);
|
2013-11-03 16:03:01 -05:00
|
|
|
library_db.save();
|
2013-10-27 17:25:26 -04:00
|
|
|
}
|
|
|
|
|
2013-11-10 16:09:31 -05:00
|
|
|
void library :: update_path(unsigned int id)
|
|
|
|
{
|
|
|
|
if (id > library_db.size())
|
|
|
|
return;
|
|
|
|
if (library_db[id].valid == false)
|
|
|
|
return;
|
|
|
|
do_update(id, library_db[id].root_path);
|
|
|
|
}
|
|
|
|
|
2013-11-17 14:41:22 -05:00
|
|
|
bool library :: lookup(unsigned int id, library :: Song *song)
|
|
|
|
{
|
|
|
|
if (id >= track_db.num_rows())
|
|
|
|
return false;
|
|
|
|
song->track = &track_db[id];
|
|
|
|
song->artist = &artist_db[song->track->artist_id];
|
|
|
|
song->album = &album_db[song->track->album_id];
|
|
|
|
song->genre = &genre_db[song->track->genre_id];
|
|
|
|
song->library = &library_db[song->track->library_id];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-10-27 17:25:26 -04:00
|
|
|
#ifdef CONFIG_DEBUG
|
|
|
|
void library :: print_db(DB_Type type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
2013-11-10 16:45:52 -05:00
|
|
|
case DB_ALBUM:
|
|
|
|
album_db.print();
|
|
|
|
break;
|
2013-11-10 16:09:31 -05:00
|
|
|
case DB_ARTIST:
|
|
|
|
artist_db.print();
|
|
|
|
break;
|
2013-11-10 16:45:52 -05:00
|
|
|
case DB_GENRE:
|
|
|
|
genre_db.print();
|
|
|
|
break;
|
2013-10-27 17:25:26 -04:00
|
|
|
case DB_LIBRARY:
|
|
|
|
library_db.print();
|
|
|
|
break;
|
2013-11-10 17:37:35 -05:00
|
|
|
case DB_TRACK:
|
|
|
|
track_db.print();
|
2013-10-27 17:25:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void library :: reset()
|
|
|
|
{
|
2013-11-10 16:45:52 -05:00
|
|
|
album_db.clear();
|
2013-11-10 16:09:31 -05:00
|
|
|
artist_db.clear();
|
2013-11-10 16:45:52 -05:00
|
|
|
genre_db.clear();
|
2013-10-27 17:25:26 -04:00
|
|
|
library_db.clear();
|
2013-11-10 17:37:35 -05:00
|
|
|
track_db.clear();
|
2013-10-27 17:25:26 -04:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_DEBUG */
|