ocarina/core/tags.cpp

217 lines
4.5 KiB
C++

/**
* @file
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/tags.h>
#include <core/tags/tags.h>
#include <core/filter.h>
#include <core/print.h>
#include <taglib/tag.h>
#include <taglib/fileref.h>
Database<Track> track_db("track.db", false);
/**
*
* Track tag
*
*/
Track :: Track(const std::string &f, Library *library)
: _album(NULL), _artist(NULL), _genre(NULL), _library(library),
_count(0), _path(f.substr(library->primary_key().size() + 1))
{
library->inc_size();
}
void Track :: read(File &f)
{
unsigned int library_id, artist_id, album_id, genre_id;
f >> library_id >> artist_id >> album_id >> genre_id;
f >> _track >> _date.year >> _date.month >> _date.day;
f >> _count >> _length;
GenericTag :: read(f);
_path = f.getline();
_library = tags :: get_library(library_id);
_artist = tags :: get_artist(artist_id);
_album = tags :: get_album(album_id);
_genre = tags :: get_genre(genre_id);
filter :: add(name(), index());
filter :: add(_artist->name(), index());
filter :: add(_album->name(), index());
_library->inc_size();
}
void Track :: write(File &f)
{
f << _library->index() << " " << _artist->index() << " ";
f << _album->index() << " " << _genre->index() << " " << _track << " ";
f << _date.year << " " << _date.month << " " << _date.day << " ";
f << _count << " " << _length << " ";
GenericTag :: write(f);
f << std::endl << _path << std::endl;
}
static inline const std::string format_tag(const TagLib::String &str)
{
return str.stripWhiteSpace().to8Bit(true);
}
template <class T>
static T *find_or_insert(const T &tag, Database<T> &db)
{
T *ret = db.find(tag.primary_key());
if (!ret)
ret = db.insert(tag);
return ret;
}
bool Track :: tag()
{
TagLib :: Tag *tag;
TagLib :: AudioProperties *audio;
TagLib :: FileRef ref(path().c_str(), true, TagLib::AudioProperties::Fast);
_library->inc_size();
if (ref.isNull()) {
print("WARNING: Could not read tags for file %s\n", path().c_str());
return false;
}
tag = ref.tag();
audio = ref.audioProperties();
_artist = tags :: get_artist(format_tag(tag->artist()));
_album = tags :: get_album(format_tag(tag->album()), tag->year());
_genre = tags :: get_genre(format_tag(tag->genre()));
_track = tag->track();
_length = audio->length();
//_title = format_tag(tag->title());
//title_lower = filter :: add(title, index());
filter :: add(_artist->name(), index());
filter :: add(_album->name(), index());
return true;
}
/*
* Returns:
* 0: lhs == rhs
* < 0: lhs < rhs, or rhs is empty
* > 0: lhs > rhs, or lhs is empty
*/
static inline int compare_string(const std::string &a, const std::string &b)
{
if (a.size() == 0)
return 1;
else if (b.size() == 0)
return -1;
return a.compare(b);
}
static inline int compare_uint(unsigned int a, unsigned int b)
{
if (a == b)
return 0;
if (a < b)
return -1;
return 1;
}
int Track :: less_than(Track *rhs, sort_t field)
{
int ret;
switch (field) {
case SORT_ARTIST:
return _artist->compare(rhs->artist());
case SORT_ALBUM:
return _album->compare(rhs->album());
case SORT_COUNT:
return compare_uint(_count, rhs->_count);
case SORT_GENRE:
return _genre->compare(rhs->genre());
case SORT_LENGTH:
return compare_uint(_length, rhs->_length);
case SORT_PLAYED:
ret = compare_uint(_date.year, rhs->_date.year);
if (ret == 0) {
ret = compare_uint(_date.month, rhs->_date.month);
if (ret == 0)
ret = compare_uint(_date.day, rhs->_date.day);
}
return ret;
case SORT_TITLE:
return compare(rhs);
case SORT_TRACK:
return compare_uint(_track, rhs->_track);
case SORT_YEAR:
return compare_uint(_album->year(), rhs->album()->year());
}
return 0;
}
/**
*
* Tagdb functions
*
*/
void tagdb :: init()
{
tags :: init();
track_db.load();
}
void tagdb :: commit()
{
track_db.save();
}
Track *tagdb :: add_track(const std::string &filepath, Library *library)
{
Track *track = track_db.insert(Track(filepath, library));
if (track && !track->tag()) {
remove_track(track->index());
track = NULL;
}
return track;
}
void tagdb :: remove_track(unsigned int track_id)
{
track_db.remove(track_id);
}
void tagdb :: remove_library(unsigned int library_id)
{
Database<Track>::iterator it;
for (it = track_db.begin(); it != track_db.end(); it = track_db.next(it)) {
if ((*it)->library()->index() == library_id)
track_db.remove((*it)->index());
}
tagdb :: commit();
tags :: remove_library(tags :: get_library(library_id));
}
Track *tagdb :: lookup(unsigned int track_id)
{
return track_db.at(track_id);
}
Database<Track> &tagdb :: get_track_db()
{
return track_db;
}