ocarina/core/library.cpp

246 lines
4.7 KiB
C++

/**
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/library.h>
#include <core/print.h>
#include <glib.h>
#include <taglib/tag.h>
#include <taglib/fileref.h>
class LibraryQueue : public Queue {
private:
File f;
public:
LibraryQueue() : Queue(Q_ENABLED | Q_REPEAT), f("library.q", 0)
{
Queue :: sort(SORT_ARTIST, true);
Queue :: sort(SORT_YEAR, false);
Queue :: sort(SORT_TRACK, false);
}
void save()
{
std::vector<struct sort_info>::iterator it;
f.open(OPEN_WRITE);
f << _flags << " " << _sort_order.size();
for (it = _sort_order.begin(); it != _sort_order.end(); it++)
f << " " << it->field << " " << it->ascending;
f << std::endl;
f.close();
}
void load()
{
unsigned int field;
bool ascending;
unsigned int n;
if (!f.open(OPEN_READ))
return;
f >> _flags >> n;
for (unsigned int i = 0; i < n; i++) {
f >> field >> ascending;
Queue :: sort((sort_t)field, (i == 0) ? true : false);
if (ascending == false)
Queue :: sort((sort_t)field, false);
}
}
void set_flag(queue_flags f) { Queue :: set_flag(f); save(); }
void unset_flag(queue_flags f) { Queue :: unset_flag(f); save(); }
void sort(sort_t field, bool ascending)
{
Queue :: sort(field, ascending);
save();
};
};
static LibraryQueue library_q;
struct scan_info {
Library *library;
std :: string path;
};
static void scan_path(struct scan_info &);
/*
* Scanning functions are here
*/
static void tag_track(Library *library, const std::string &filepath)
{
Track *track;
TagLib :: Tag *tag;
TagLib :: AudioProperties *audio;
TagLib :: FileRef ref(filepath.c_str(), true, TagLib::AudioProperties::Fast);
if (ref.isNull()) {
print("WARNING: Could not read tags for file %s\n", filepath.c_str());
return;
}
tag = ref.tag();
audio = ref.audioProperties();
track = tags :: add_track(
tags :: get_album(tag->album().stripWhiteSpace().to8Bit(true), tag->year()),
tags :: get_artist(tag->artist().stripWhiteSpace().to8Bit(true)),
tags :: get_genre(tag->genre().stripWhiteSpace().to8Bit(true)),
library, filepath,
tag->title().stripWhiteSpace().to8Bit(true),
audio->length(), tag->track()
);
if (track)
library_q.add(track);
}
static void process_path(Library *library, const std :: string &dir,
const std :: string &name)
{
struct scan_info scan = {
.library = library,
.path = dir + "/" + name,
};
if (g_file_test(scan.path.c_str(), G_FILE_TEST_IS_DIR) == true)
idle :: schedule (scan_path, scan);
else
tag_track(library, scan.path);
}
static void scan_path(struct scan_info &scan)
{
GDir *dir;
const char *name;
dir = g_dir_open(scan.path.c_str(), 0, NULL);
if (dir == NULL)
return;
name = g_dir_read_name(dir);
while (name != NULL) {
process_path(scan.library, scan.path, name);
name = g_dir_read_name(dir);
}
tags :: commit_track_db();
}
static void validate_library(Library *&library)
{
Track *track;
for (unsigned int i = 0; i < tags :: track_size(); i++) {
track = tags :: get_track(i);
if (!track || (track->library() != library))
continue;
if (g_file_test(track->path().c_str(), G_FILE_TEST_EXISTS) == false) {
library_q.del(track);
tags :: remove_track(track);
}
}
}
/*
* External API begins here
*/
void library :: init()
{
Track *track;
library_q.load();
for (unsigned int i = 0; i < tags :: track_size(); i++) {
track = tags :: get_track(i);
if (track && (track->library()->enabled()))
library_q.add(track);
}
}
Library *library :: add(const std::string &dir)
{
Library *library = NULL;
if (g_file_test(dir.c_str(), G_FILE_TEST_IS_DIR) == false)
return library;
library = tags :: get_library(dir);
if (library)
update(library);
return library;
}
void library :: remove(Library *library)
{
if (library) {
set_enabled(library, false);
tags :: remove_library_tracks(library);
tags :: remove_library(library);
}
}
void library :: update(Library *library)
{
struct scan_info scan = {
.library = library,
};
if (library) {
scan.path = library->primary_key();
idle :: schedule(validate_library, library);
idle :: schedule(scan_path, scan);
}
}
void library :: update_all()
{
Library *library;
for (unsigned int i = 0; i < tags :: library_size(); i++) {
library = tags :: get_library(i);
if (library)
update(library);
}
}
void library :: set_enabled(Library *library, bool enabled)
{
Track *track;
if (!library || (library->enabled() == enabled))
return;
library->set_enabled(enabled);
for (unsigned int i = 0; i < tags :: track_size(); i++) {
track = tags :: get_track(i);
if (track && (track->library() == library)) {
if (enabled)
library_q.add(track);
else
library_q.del(track);
}
}
}
Queue *library :: get_queue()
{
return &library_q;
}