Switch over to the new tagdb implementation
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
This commit is contained in:
parent
2a3d4ca2e0
commit
a14f6145a5
|
@ -96,19 +96,19 @@ void on_collection_toggled(const Glib::ustring &path)
|
||||||
row[collection_cols.c_col_enabled]);
|
row[collection_cols.c_col_enabled]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_library_add(unsigned int id, library :: Library *path)
|
static void on_library_add(unsigned int id, Library *library)
|
||||||
{
|
{
|
||||||
Gtk::TreeModel::Row row;
|
Gtk::TreeModel::Row row;
|
||||||
Glib::RefPtr<Gtk::ListStore> list = get_collection_list();
|
Glib::RefPtr<Gtk::ListStore> list = get_collection_list();
|
||||||
|
|
||||||
row = *(list->append());
|
row = *(list->append());
|
||||||
row[collection_cols.c_col_id] = id;
|
row[collection_cols.c_col_id] = id;
|
||||||
row[collection_cols.c_col_enabled] = path->enabled;
|
row[collection_cols.c_col_enabled] = library->enabled;
|
||||||
row[collection_cols.c_col_size] = path->size;
|
row[collection_cols.c_col_size] = library->count;
|
||||||
row[collection_cols.c_col_path] = path->root_path;
|
row[collection_cols.c_col_path] = library->root_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_library_update(unsigned int id, library :: Library *path)
|
static void on_library_update(unsigned int id, Library *library)
|
||||||
{
|
{
|
||||||
Gtk::TreeModel::Row row;
|
Gtk::TreeModel::Row row;
|
||||||
Glib::RefPtr<Gtk::ListStore> list = get_collection_list();
|
Glib::RefPtr<Gtk::ListStore> list = get_collection_list();
|
||||||
|
@ -118,7 +118,7 @@ static void on_library_update(unsigned int id, library :: Library *path)
|
||||||
it != children.end(); it++) {
|
it != children.end(); it++) {
|
||||||
row = *it;
|
row = *it;
|
||||||
if (row[collection_cols.c_col_id] == id)
|
if (row[collection_cols.c_col_id] == id)
|
||||||
row[collection_cols.c_col_size] = path->size;
|
row[collection_cols.c_col_size] = library->count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
gui/gui.cpp
14
gui/gui.cpp
|
@ -64,7 +64,7 @@ static void set_label_text(Gtk::Label *label, const std::string &size,
|
||||||
Glib::Markup::escape_text(text) + "</span>");
|
Glib::Markup::escape_text(text) + "</span>");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_track_loaded(library :: Song &song)
|
static void on_track_loaded(Track *track)
|
||||||
{
|
{
|
||||||
Gtk::ToggleButton *ban = get_widget<Gtk::ToggleButton>("o_ban");
|
Gtk::ToggleButton *ban = get_widget<Gtk::ToggleButton>("o_ban");
|
||||||
Gtk::ToggleButton *fav = get_widget<Gtk::ToggleButton>("o_favorite");
|
Gtk::ToggleButton *fav = get_widget<Gtk::ToggleButton>("o_favorite");
|
||||||
|
@ -73,16 +73,16 @@ static void on_track_loaded(library :: Song &song)
|
||||||
Gtk::Label *album = get_widget<Gtk::Label>("o_album");
|
Gtk::Label *album = get_widget<Gtk::Label>("o_album");
|
||||||
Gtk::Label *duration = get_widget<Gtk::Label>("o_total_time");
|
Gtk::Label *duration = get_widget<Gtk::Label>("o_total_time");
|
||||||
|
|
||||||
set_label_text(title, "xx-large", song.track->title);
|
set_label_text(title, "xx-large", track->title);
|
||||||
set_label_text(artist, "x-large", "By: " + song.artist->name);
|
set_label_text(artist, "x-large", "By: " + track->artist->name);
|
||||||
set_label_text(album, "x-large", "From: " + song.album->name);
|
set_label_text(album, "x-large", "From: " + track->album->name);
|
||||||
duration->set_text(song.track->length_str);
|
duration->set_text(track->length_str);
|
||||||
|
|
||||||
std::set<unsigned int> ids = playlist :: get_tracks("Banned");
|
std::set<unsigned int> ids = playlist :: get_tracks("Banned");
|
||||||
bool banned = ids.find(song.track_id) != ids.end();
|
bool banned = ids.find(track->id) != ids.end();
|
||||||
|
|
||||||
ids = playlist :: get_tracks("Favorites");
|
ids = playlist :: get_tracks("Favorites");
|
||||||
bool favorite = ids.find(song.track_id) != ids.end();
|
bool favorite = ids.find(track->id) != ids.end();
|
||||||
|
|
||||||
ban_connection.block();
|
ban_connection.block();
|
||||||
fav_connection.block();
|
fav_connection.block();
|
||||||
|
|
|
@ -110,7 +110,7 @@ GType PlayqueueModel::get_column_type_vfunc(int index) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayqueueModel::get_value_uint(struct library::Song &song, int column,
|
void PlayqueueModel::get_value_uint(Track *track, int column,
|
||||||
Glib::ValueBase &value) const
|
Glib::ValueBase &value) const
|
||||||
{
|
{
|
||||||
Glib::Value<unsigned int> specific;
|
Glib::Value<unsigned int> specific;
|
||||||
|
@ -118,20 +118,20 @@ void PlayqueueModel::get_value_uint(struct library::Song &song, int column,
|
||||||
|
|
||||||
switch (column) {
|
switch (column) {
|
||||||
case 0:
|
case 0:
|
||||||
specific.set(song.track->track);
|
specific.set(track->track);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
specific.set(song.album->year);
|
specific.set(track->album->year);
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
specific.set(song.track->play_count);
|
specific.set(track->play_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
value.init(Glib::Value<unsigned int>::value_type());
|
value.init(Glib::Value<unsigned int>::value_type());
|
||||||
value = specific;
|
value = specific;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayqueueModel::get_value_str(struct library::Song &song, int column,
|
void PlayqueueModel::get_value_str(Track *track, int column,
|
||||||
Glib::ValueBase &value) const
|
Glib::ValueBase &value) const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -140,32 +140,32 @@ void PlayqueueModel::get_value_str(struct library::Song &song, int column,
|
||||||
|
|
||||||
switch (column) {
|
switch (column) {
|
||||||
case 1:
|
case 1:
|
||||||
specific.set(song.track->title);
|
specific.set(track->title);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
specific.set(song.track->length_str);
|
specific.set(track->length_str);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
specific.set(song.artist->name);
|
specific.set(track->artist->name);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
specific.set(song.album->name);
|
specific.set(track->album->name);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
specific.set(song.genre->name);
|
specific.set(track->genre->name);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
if (song.track->play_count == 0)
|
if (track->play_count == 0)
|
||||||
specific.set("Never");
|
specific.set("Never");
|
||||||
else {
|
else {
|
||||||
ss << song.track->last_month << " / ";
|
ss << track->last_month << " / ";
|
||||||
ss << song.track->last_day << " / ";
|
ss << track->last_day << " / ";
|
||||||
ss << song.track->last_year;
|
ss << track->last_year;
|
||||||
specific.set(ss.str());
|
specific.set(ss.str());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
specific.set(Glib::Markup::escape_text(song.track->full_path));
|
specific.set(Glib::Markup::escape_text(track->path()));
|
||||||
}
|
}
|
||||||
|
|
||||||
value.init(Glib::Value<std::string>::value_type());
|
value.init(Glib::Value<std::string>::value_type());
|
||||||
|
@ -177,7 +177,7 @@ void PlayqueueModel::get_value_vfunc(const Gtk::TreeIter &iter, int column,
|
||||||
Glib::ValueBase &value) const
|
Glib::ValueBase &value) const
|
||||||
{
|
{
|
||||||
unsigned int row;
|
unsigned int row;
|
||||||
struct library::Song song;
|
Track *track;
|
||||||
|
|
||||||
if (!check_iter_validity(iter))
|
if (!check_iter_validity(iter))
|
||||||
return;
|
return;
|
||||||
|
@ -186,16 +186,16 @@ void PlayqueueModel::get_value_vfunc(const Gtk::TreeIter &iter, int column,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
row = GPOINTER_TO_UINT(iter.gobj()->user_data);
|
row = GPOINTER_TO_UINT(iter.gobj()->user_data);
|
||||||
library :: lookup((*queue)[row], &song);
|
track = tagdb :: lookup((*queue)[row]);
|
||||||
|
|
||||||
switch (column) {
|
switch (column) {
|
||||||
case 0:
|
case 0:
|
||||||
case 5:
|
case 5:
|
||||||
case 7:
|
case 7:
|
||||||
get_value_uint(song, column, value);
|
get_value_uint(track, column, value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
get_value_str(song, column, value);
|
get_value_str(track, column, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ struct Callbacks {
|
||||||
/* Audio callbacks */
|
/* Audio callbacks */
|
||||||
void (*on_play)();
|
void (*on_play)();
|
||||||
void (*on_pause)();
|
void (*on_pause)();
|
||||||
void (*on_track_loaded)(library :: Song &);
|
void (*on_track_loaded)(Track *);
|
||||||
void (*on_pause_count_changed)(bool, unsigned int);
|
void (*on_pause_count_changed)(bool, unsigned int);
|
||||||
|
|
||||||
/* Deck callbacks */
|
/* Deck callbacks */
|
||||||
|
@ -20,8 +20,8 @@ struct Callbacks {
|
||||||
void (*on_pq_removed)(Playqueue *);
|
void (*on_pq_removed)(Playqueue *);
|
||||||
|
|
||||||
/* Library callbacks */
|
/* Library callbacks */
|
||||||
void (*on_library_add)(unsigned int, library :: Library *);
|
void (*on_library_add)(unsigned int, Library *);
|
||||||
void (*on_library_update)(unsigned int, library :: Library *);
|
void (*on_library_update)(unsigned int, Library *);
|
||||||
void (*on_library_track_add)(unsigned int);
|
void (*on_library_track_add)(unsigned int);
|
||||||
void (*on_library_track_del)(unsigned int);
|
void (*on_library_track_del)(unsigned int);
|
||||||
void (*on_library_track_updated)(unsigned int);
|
void (*on_library_track_updated)(unsigned int);
|
||||||
|
|
|
@ -4,14 +4,9 @@
|
||||||
#ifndef OCARINA_LIBRARY_H
|
#ifndef OCARINA_LIBRARY_H
|
||||||
#define OCARINA_LIBRARY_H
|
#define OCARINA_LIBRARY_H
|
||||||
|
|
||||||
#include <database.h>
|
#include <tags.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <taglib/tag.h>
|
|
||||||
#include <taglib/fileref.h>
|
|
||||||
|
|
||||||
struct ImportData;
|
|
||||||
|
|
||||||
namespace library
|
namespace library
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -24,100 +19,12 @@ namespace library
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class AGInfo : public DatabaseEntry {
|
|
||||||
public:
|
|
||||||
DB_Type db_type;
|
|
||||||
std :: string name;
|
|
||||||
std :: string key_lower;
|
|
||||||
|
|
||||||
AGInfo();
|
|
||||||
AGInfo(DB_Type, TagLib :: Tag *);
|
|
||||||
AGInfo(DB_Type, const std::string &);
|
|
||||||
const std::string primary_key() const;
|
|
||||||
void read(File &);
|
|
||||||
void write(File &);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Album : public DatabaseEntry {
|
|
||||||
public:
|
|
||||||
std :: string name;
|
|
||||||
std :: string name_lower;
|
|
||||||
unsigned int year;
|
|
||||||
|
|
||||||
Album();
|
|
||||||
Album(TagLib :: Tag *, unsigned int);
|
|
||||||
Album(const std::string &, unsigned int, unsigned int);
|
|
||||||
const std::string primary_key() const;
|
|
||||||
void read(File &);
|
|
||||||
void write(File &);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Library : public DatabaseEntry {
|
|
||||||
public:
|
|
||||||
std::string root_path;
|
|
||||||
unsigned int size;
|
|
||||||
bool enabled;
|
|
||||||
|
|
||||||
Library();
|
|
||||||
Library(const std::string &, bool);
|
|
||||||
const std::string primary_key() const;
|
|
||||||
void read(File &);
|
|
||||||
void write(File &);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Track : public DatabaseEntry {
|
|
||||||
public:
|
|
||||||
unsigned int library_id;
|
|
||||||
unsigned int artist_id;
|
|
||||||
unsigned int album_id;
|
|
||||||
unsigned int genre_id;
|
|
||||||
|
|
||||||
unsigned int track;
|
|
||||||
unsigned int last_year;
|
|
||||||
unsigned int last_month;
|
|
||||||
unsigned int last_day;
|
|
||||||
unsigned int play_count;
|
|
||||||
unsigned int length;
|
|
||||||
|
|
||||||
std :: string title;
|
|
||||||
std :: string title_lower;
|
|
||||||
std :: string length_str;
|
|
||||||
std :: string filepath;
|
|
||||||
std :: string full_path;
|
|
||||||
|
|
||||||
Track();
|
|
||||||
Track(TagLib :: Tag *, TagLib :: AudioProperties *,
|
|
||||||
unsigned int, unsigned int, unsigned int,
|
|
||||||
unsigned int, const std :: string &);
|
|
||||||
Track(ImportData *, unsigned int, unsigned int,
|
|
||||||
unsigned int, unsigned int);
|
|
||||||
const std::string primary_key() const;
|
|
||||||
void read(File &);
|
|
||||||
void write(File &);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Song {
|
|
||||||
unsigned int track_id;
|
|
||||||
library :: Album *album;
|
|
||||||
library :: AGInfo *artist;
|
|
||||||
library :: AGInfo *genre;
|
|
||||||
library :: Library *library;
|
|
||||||
library :: Track *track;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void add_path(const std::string &);
|
void add_path(const std::string &);
|
||||||
void del_path(unsigned int);
|
void del_path(unsigned int);
|
||||||
void update_path(unsigned int);
|
void update_path(unsigned int);
|
||||||
void update_all();
|
void update_all();
|
||||||
void set_enabled(unsigned int, bool);
|
void set_enabled(unsigned int, bool);
|
||||||
void lookup(unsigned int, library :: Song *);
|
|
||||||
Library *lookup_path(unsigned int);
|
|
||||||
void import();
|
void import();
|
||||||
void track_played(unsigned int);
|
void track_played(unsigned int);
|
||||||
#ifdef CONFIG_TEST
|
#ifdef CONFIG_TEST
|
||||||
|
|
|
@ -21,8 +21,8 @@ Gtk::Window *ocarina_init(int *, char ***);
|
||||||
class PlayqueueModel : public Gtk::TreeModel, public Glib::Object {
|
class PlayqueueModel : public Gtk::TreeModel, public Glib::Object {
|
||||||
private:
|
private:
|
||||||
void increment_stamp();
|
void increment_stamp();
|
||||||
void get_value_uint(struct library::Song &, int, Glib::ValueBase &) const;
|
void get_value_uint(Track *, int, Glib::ValueBase &) const;
|
||||||
void get_value_str(struct library::Song &, int, Glib::ValueBase &) const;
|
void get_value_str(Track *, int, Glib::ValueBase &) const;
|
||||||
bool check_iter_validity(const Gtk::TreeIter &) const;
|
bool check_iter_validity(const Gtk::TreeIter &) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -17,18 +17,6 @@ enum playqueue_flags {
|
||||||
PQ_DISABLE_CHANGED_SIZE = (1 << 31),
|
PQ_DISABLE_CHANGED_SIZE = (1 << 31),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sort_t {
|
|
||||||
SORT_ARTIST,
|
|
||||||
SORT_ALBUM,
|
|
||||||
SORT_COUNT,
|
|
||||||
SORT_GENRE,
|
|
||||||
SORT_LENGTH,
|
|
||||||
SORT_PLAYED,
|
|
||||||
SORT_TITLE,
|
|
||||||
SORT_TRACK,
|
|
||||||
SORT_YEAR,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sort_info {
|
struct sort_info {
|
||||||
sort_t field;
|
sort_t field;
|
||||||
bool ascending;
|
bool ascending;
|
||||||
|
@ -42,7 +30,7 @@ private:
|
||||||
unsigned int cur;
|
unsigned int cur;
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
|
|
||||||
unsigned int find_sorted_id(library :: Song &);
|
unsigned int find_sorted_id(Track *);
|
||||||
void _add_sort(sort_t, bool);
|
void _add_sort(sort_t, bool);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -121,6 +121,7 @@ namespace tagdb
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void commit();
|
void commit();
|
||||||
|
void commit_library();
|
||||||
|
|
||||||
Track *add_track(const std::string &, Library *);
|
Track *add_track(const std::string &, Library *);
|
||||||
Track *import_track(const std::string &, Library *, const ImportData &);
|
Track *import_track(const std::string &, Library *, const ImportData &);
|
||||||
|
@ -128,6 +129,7 @@ namespace tagdb
|
||||||
void remove_track(unsigned int);
|
void remove_track(unsigned int);
|
||||||
void remove_library(unsigned int);
|
void remove_library(unsigned int);
|
||||||
Track *lookup(unsigned int);
|
Track *lookup(unsigned int);
|
||||||
|
Library *lookup_library(unsigned int);
|
||||||
Database<Track> &get_track_db();
|
Database<Track> &get_track_db();
|
||||||
Database<Library> &get_library_db();
|
Database<Library> &get_library_db();
|
||||||
|
|
||||||
|
|
|
@ -26,11 +26,10 @@ static void parse_error(GstMessage *error)
|
||||||
{
|
{
|
||||||
GError *err;
|
GError *err;
|
||||||
gchar *debug;
|
gchar *debug;
|
||||||
library :: Song song;
|
Track *track = tagdb :: lookup(cur_trackid);
|
||||||
|
|
||||||
library :: lookup(cur_trackid, &song);
|
|
||||||
gst_message_parse_error(error, &err, &debug);
|
gst_message_parse_error(error, &err, &debug);
|
||||||
g_print("Error playing file: %s\n", song.track->primary_key().c_str());
|
g_print("Error playing file: %s\n", track->path().c_str());
|
||||||
g_print("Error: %s\n", err->message);
|
g_print("Error: %s\n", err->message);
|
||||||
g_error_free(err);
|
g_error_free(err);
|
||||||
g_free(debug);
|
g_free(debug);
|
||||||
|
@ -91,11 +90,11 @@ static void save_state()
|
||||||
f_cur_track.close();
|
f_cur_track.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool load_song(library :: Song &song)
|
static bool load_song(Track *track)
|
||||||
{
|
{
|
||||||
GstState state;
|
GstState state;
|
||||||
gchar *uri;
|
gchar *uri;
|
||||||
std::string filepath = song.library->root_path + "/" + song.track->filepath;
|
std::string filepath = track->path();
|
||||||
|
|
||||||
if (o_should_pause == true) {
|
if (o_should_pause == true) {
|
||||||
state = GST_STATE_PAUSED;
|
state = GST_STATE_PAUSED;
|
||||||
|
@ -110,7 +109,7 @@ static bool load_song(library :: Song &song)
|
||||||
g_object_set(G_OBJECT(ocarina_player), "uri", uri, NULL);
|
g_object_set(G_OBJECT(ocarina_player), "uri", uri, NULL);
|
||||||
g_free(uri);
|
g_free(uri);
|
||||||
|
|
||||||
get_callbacks()->on_track_loaded(song);
|
get_callbacks()->on_track_loaded(track);
|
||||||
return change_state(state);
|
return change_state(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,13 +190,13 @@ void audio :: seek_to(long pos)
|
||||||
|
|
||||||
void audio :: next()
|
void audio :: next()
|
||||||
{
|
{
|
||||||
library :: Song song;
|
Track *track;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
|
|
||||||
track_loaded = false;
|
track_loaded = false;
|
||||||
id = deck :: next();
|
id = deck :: next();
|
||||||
library :: lookup(id, &song);
|
track = tagdb :: lookup(id);
|
||||||
load_song(song);
|
load_song(track);
|
||||||
track_loaded = true;
|
track_loaded = true;
|
||||||
|
|
||||||
cur_trackid = id;
|
cur_trackid = id;
|
||||||
|
@ -209,33 +208,33 @@ void audio :: next()
|
||||||
|
|
||||||
void audio :: previous()
|
void audio :: previous()
|
||||||
{
|
{
|
||||||
library :: Song song;
|
Track *track;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
|
|
||||||
id = o_recently_played.next();
|
id = o_recently_played.next();
|
||||||
if (id == cur_trackid)
|
if (id == cur_trackid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
library :: lookup(id, &song);
|
track = tagdb :: lookup(id);
|
||||||
load_song(song);
|
load_song(track);
|
||||||
cur_trackid = id;
|
cur_trackid = id;
|
||||||
save_state();
|
save_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio :: load_trackid(unsigned int track_id)
|
void audio :: load_trackid(unsigned int track_id)
|
||||||
{
|
{
|
||||||
library :: Song song;
|
Track *track;
|
||||||
|
|
||||||
if ((track_id == cur_trackid) && (track_loaded == true))
|
if ((track_id == cur_trackid) && (track_loaded == true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
track_loaded = false;
|
track_loaded = false;
|
||||||
try {
|
try {
|
||||||
library :: lookup(track_id, &song);
|
track = tagdb :: lookup(track_id);
|
||||||
} catch (int err) {
|
} catch (int err) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
load_song(song);
|
load_song(track);
|
||||||
track_loaded = true;
|
track_loaded = true;
|
||||||
|
|
||||||
cur_trackid = track_id;
|
cur_trackid = track_id;
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
static void no_op() {}
|
static void no_op() {}
|
||||||
static void no_op(unsigned int) {}
|
static void no_op(unsigned int) {}
|
||||||
static void no_op(bool, unsigned int) {}
|
static void no_op(bool, unsigned int) {}
|
||||||
static void no_op(unsigned int id, library :: Library *path) {}
|
static void no_op(unsigned int id, Library *path) {}
|
||||||
static void no_op(Playqueue *, unsigned int) {}
|
static void no_op(Playqueue *, unsigned int) {}
|
||||||
static void no_op(Playqueue *) {}
|
static void no_op(Playqueue *) {}
|
||||||
static void no_op(library :: Song &) {}
|
static void no_op(Track *) {}
|
||||||
|
|
||||||
|
|
||||||
static struct Callbacks callbacks = {
|
static struct Callbacks callbacks = {
|
||||||
|
|
504
lib/library.cpp
504
lib/library.cpp
|
@ -11,319 +11,40 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
static Database<library :: Album> album_db("album.db", false);
|
|
||||||
static Database<library :: AGInfo> artist_db("artist.db", false);
|
|
||||||
static Database<library :: AGInfo> genre_db("genre.db", false);
|
|
||||||
static Database<library :: Track> track_db("track.db", false);
|
|
||||||
static Database<library :: Library> library_db("library.db", false);
|
|
||||||
|
|
||||||
struct ImportData {
|
|
||||||
std::string filepath;
|
|
||||||
std::string title;
|
|
||||||
unsigned int track;
|
|
||||||
unsigned int last_day;
|
|
||||||
unsigned int last_month;
|
|
||||||
unsigned int last_year;
|
|
||||||
unsigned int length;
|
|
||||||
unsigned int count;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* library :: Artist: Artist tag information
|
|
||||||
*/
|
|
||||||
|
|
||||||
library :: AGInfo :: AGInfo()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
library :: AGInfo :: AGInfo(DB_Type type, TagLib :: Tag *tag)
|
|
||||||
: db_type(type)
|
|
||||||
{
|
|
||||||
if (db_type == DB_ARTIST)
|
|
||||||
name = tag->artist().stripWhiteSpace().to8Bit(true);
|
|
||||||
else if (db_type == DB_GENRE)
|
|
||||||
name = tag->genre().stripWhiteSpace().to8Bit(true);
|
|
||||||
else
|
|
||||||
throw -E_INVAL;
|
|
||||||
|
|
||||||
key_lower = filter :: lowercase(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
library :: AGInfo :: AGInfo(DB_Type type, const std::string &str)
|
|
||||||
: db_type(type)
|
|
||||||
{
|
|
||||||
if ((db_type == DB_ARTIST) || (db_type == DB_GENRE)) {
|
|
||||||
name = str;
|
|
||||||
key_lower = filter :: lowercase(name);
|
|
||||||
} else
|
|
||||||
throw -E_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string library :: AGInfo :: primary_key() const
|
|
||||||
{
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void library :: AGInfo :: read(File &f)
|
|
||||||
{
|
|
||||||
name = f.getline();
|
|
||||||
key_lower = filter :: lowercase(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void library :: AGInfo :: write(File &f)
|
|
||||||
{
|
|
||||||
f << name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* library :: Album: Album tag information
|
|
||||||
*/
|
|
||||||
|
|
||||||
library :: Album :: Album()
|
|
||||||
: name(""), year(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
library :: Album :: Album(TagLib :: Tag *tag, unsigned int artist)
|
|
||||||
: name(tag->album().stripWhiteSpace().to8Bit(true)),
|
|
||||||
year(tag->year())
|
|
||||||
{
|
|
||||||
name_lower = filter :: lowercase(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
library :: Album :: Album(const std::string &str, unsigned int yr, unsigned int artist)
|
|
||||||
: name(str), year(yr)
|
|
||||||
{
|
|
||||||
name_lower = filter :: lowercase(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string library :: Album :: primary_key() const
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << name << "." << year;
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void library :: Album :: read(File &f)
|
|
||||||
{
|
|
||||||
f >> year;
|
|
||||||
name = f.getline();
|
|
||||||
name_lower = filter :: lowercase(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void library :: Album :: write(File &f)
|
|
||||||
{
|
|
||||||
f << year << " " << name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* library :: Library: Basic information about each directory in the library
|
|
||||||
*/
|
|
||||||
|
|
||||||
library :: Library :: Library()
|
|
||||||
: root_path(""), size(0), enabled(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
library :: Library :: Library(const std::string &path, bool is_enabled)
|
|
||||||
: root_path(path), size(0), enabled(is_enabled)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string library :: Library :: primary_key() const
|
|
||||||
{
|
|
||||||
return root_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
void library :: Library :: read(File &f)
|
|
||||||
{
|
|
||||||
f >> enabled;
|
|
||||||
root_path = f.getline();
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void library :: Library :: write(File &f)
|
|
||||||
{
|
|
||||||
f << enabled << " " << root_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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()),
|
|
||||||
title(tag->title().stripWhiteSpace().to8Bit(true))
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
unsigned int minutes, seconds;
|
|
||||||
|
|
||||||
full_path = path;
|
|
||||||
filepath = path.substr(library_db.at(library_id)->root_path.size() + 1);
|
|
||||||
title_lower = filter :: lowercase(title);
|
|
||||||
|
|
||||||
minutes = length / 60;
|
|
||||||
seconds = length % 60;
|
|
||||||
ss << minutes << ":";
|
|
||||||
if (seconds < 10)
|
|
||||||
ss << "0";
|
|
||||||
ss << seconds;
|
|
||||||
length_str = ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
library :: Track :: Track(struct ImportData *data, unsigned int lib,
|
|
||||||
unsigned int artist, unsigned int album,
|
|
||||||
unsigned int genre)
|
|
||||||
: library_id(lib), artist_id(artist), album_id(album), genre_id(genre),
|
|
||||||
track(data->track), last_year(data->last_year), last_month(data->last_month),
|
|
||||||
last_day(data->last_day), play_count(data->count), length(data->length),
|
|
||||||
title(data->title)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
unsigned int minutes, seconds;
|
|
||||||
|
|
||||||
full_path = data->filepath;
|
|
||||||
filepath = full_path.substr(library_db.at(library_id)->root_path.size() + 1);
|
|
||||||
title_lower = filter :: lowercase(title);
|
|
||||||
|
|
||||||
minutes = length / 60;
|
|
||||||
seconds = length % 60;
|
|
||||||
ss << minutes << ":";
|
|
||||||
if (seconds < 10)
|
|
||||||
ss << "0";
|
|
||||||
ss << seconds;
|
|
||||||
length_str = ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string library :: Track :: primary_key() const
|
|
||||||
{
|
|
||||||
return full_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
void library :: Track :: read(File &f)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
unsigned int minutes, seconds;
|
|
||||||
|
|
||||||
f >> library_id >> artist_id >> album_id >> genre_id;
|
|
||||||
f >> track >> last_year >> last_month >> last_day;
|
|
||||||
f >> play_count >> length;
|
|
||||||
title = f.getline();
|
|
||||||
filepath = f.getline();
|
|
||||||
|
|
||||||
title_lower = filter :: lowercase(title);
|
|
||||||
full_path = library_db.at(library_id)->root_path + "/" + filepath;
|
|
||||||
library_db.at(library_id)->size++;
|
|
||||||
|
|
||||||
minutes = length / 60;
|
|
||||||
seconds = length % 60;
|
|
||||||
ss << minutes << ":";
|
|
||||||
if (seconds < 10)
|
|
||||||
ss << "0";
|
|
||||||
ss << seconds;
|
|
||||||
length_str = ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 << " "; // << std :: endl;
|
|
||||||
f << title << std :: endl;
|
|
||||||
f << filepath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal library functions
|
* Internal library functions
|
||||||
*/
|
*/
|
||||||
struct scan_info {
|
struct scan_info {
|
||||||
unsigned int lib_id;
|
Library *library;
|
||||||
std :: string path;
|
std :: string path;
|
||||||
};
|
};
|
||||||
static void do_scan_path(struct scan_info &);
|
static void do_scan_path(struct scan_info &);
|
||||||
|
|
||||||
static void read_tags(unsigned int lib_id, const std :: string &path)
|
static void read_tags(const std::string &path, Library *library)
|
||||||
{
|
{
|
||||||
TagLib :: Tag *tag;
|
Track *track = tagdb :: add_track(path, library);
|
||||||
TagLib :: AudioProperties *audio;
|
get_callbacks()->on_library_track_add(track->id);
|
||||||
TagLib :: FileRef ref(path.c_str(), true, TagLib :: AudioProperties :: Fast);
|
|
||||||
unsigned int artist_id, album_id, genre_id, track_id;
|
|
||||||
|
|
||||||
if (ref.isNull()) {
|
|
||||||
print("ERROR: Could not read tags for file %s\n", path.c_str());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tag = ref.tag();
|
static void process_path(Library *library, const std :: string &dir,
|
||||||
|
|
||||||
audio = ref.audioProperties();
|
|
||||||
|
|
||||||
artist_id = artist_db.insert(library :: AGInfo(library :: DB_ARTIST, tag))->id;
|
|
||||||
album_id = album_db.insert(library :: Album(tag, artist_id))->id;
|
|
||||||
genre_id = genre_db.insert(library :: AGInfo(library :: DB_GENRE, tag))->id;
|
|
||||||
track_id = track_db.insert(library :: Track(tag, audio, lib_id,
|
|
||||||
artist_id, album_id, genre_id, path))->id;
|
|
||||||
|
|
||||||
library_db.at(lib_id)->size++;
|
|
||||||
|
|
||||||
filter::add(artist_db.at(artist_id)->name, track_id);
|
|
||||||
filter::add(album_db.at(album_id)->name, track_id);
|
|
||||||
filter::add(track_db.at(track_id)->title, track_id);
|
|
||||||
get_callbacks()->on_library_track_add(track_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool process_path(unsigned int lib_id, const std :: string &dir,
|
|
||||||
const std :: string &name)
|
const std :: string &name)
|
||||||
{
|
{
|
||||||
struct scan_info scan;
|
struct scan_info scan;
|
||||||
bool changed = false;
|
|
||||||
std :: string path = dir + "/" + name;
|
std :: string path = dir + "/" + name;
|
||||||
|
|
||||||
if (g_file_test(path.c_str(), G_FILE_TEST_IS_DIR) == true) {
|
if (g_file_test(path.c_str(), G_FILE_TEST_IS_DIR) == true) {
|
||||||
scan.lib_id = lib_id;
|
scan.library = library;
|
||||||
scan.path = path;
|
scan.path = path;
|
||||||
idle :: schedule (do_scan_path, scan);
|
idle :: schedule (do_scan_path, scan);
|
||||||
} else {
|
} else
|
||||||
if (track_db.find(path) == NULL) {
|
read_tags(path, library);
|
||||||
read_tags(lib_id, path);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void save_all_dbs()
|
|
||||||
{
|
|
||||||
artist_db.save();
|
|
||||||
album_db.save();
|
|
||||||
genre_db.save();
|
|
||||||
track_db.save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_scan_path(struct scan_info &scan)
|
static void do_scan_path(struct scan_info &scan)
|
||||||
{
|
{
|
||||||
GDir *dir;
|
GDir *dir;
|
||||||
const char *name;
|
const char *name;
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
dir = g_dir_open(scan.path.c_str(), 0, NULL);
|
dir = g_dir_open(scan.path.c_str(), 0, NULL);
|
||||||
if (dir == NULL)
|
if (dir == NULL)
|
||||||
|
@ -331,86 +52,65 @@ static void do_scan_path(struct scan_info &scan)
|
||||||
|
|
||||||
name = g_dir_read_name(dir);
|
name = g_dir_read_name(dir);
|
||||||
while (name != NULL) {
|
while (name != NULL) {
|
||||||
if (process_path(scan.lib_id, scan.path, name))
|
process_path(scan.library, scan.path, name);
|
||||||
changed = true;
|
|
||||||
name = g_dir_read_name(dir);
|
name = g_dir_read_name(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed == true) {
|
tagdb :: commit();
|
||||||
save_all_dbs();
|
get_callbacks()->on_library_update(scan.library->id, scan.library);
|
||||||
get_callbacks()->on_library_update(scan.lib_id,
|
|
||||||
&(*library_db.at(scan.lib_id)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_validate_library(unsigned int &lib_id)
|
static void do_validate_library(unsigned int &lib_id)
|
||||||
{
|
{
|
||||||
std :: string path;
|
std :: string path;
|
||||||
bool changed = false;
|
Database<Track> *db = &tagdb :: get_track_db();
|
||||||
|
Database<Track>::iterator it;
|
||||||
|
|
||||||
if (track_db.size() == 0)
|
for (it = db->begin(); it != db->end(); it = db->next(it)) {
|
||||||
return;
|
Track *track = *it;
|
||||||
|
if (track->library->id != lib_id)
|
||||||
Database<library :: Track>::iterator it;
|
|
||||||
for (it = track_db.begin(); it != track_db.end(); it = track_db.next(it)) {
|
|
||||||
if ((*it)->library_id != lib_id)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
path = (*it)->primary_key();
|
if (g_file_test(track->path().c_str(), G_FILE_TEST_EXISTS) == false) {
|
||||||
if (g_file_test(path.c_str(), G_FILE_TEST_EXISTS) == false) {
|
dprint("Removing file: %s\n", track->path().c_str());
|
||||||
dprint("Removing file: %s\n", path.c_str());
|
tagdb :: remove_track(track->id);
|
||||||
track_db.remove(it - track_db.begin());
|
|
||||||
library_db.at(lib_id)->size--;
|
|
||||||
changed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed == true) {
|
get_callbacks()->on_library_update(lib_id, tagdb :: lookup_library(lib_id));
|
||||||
get_callbacks()->on_library_update(lib_id, &(*library_db.at(lib_id)));
|
|
||||||
save_all_dbs();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_update_library(unsigned int lib_id)
|
static void do_update_library(unsigned int lib_id)
|
||||||
{
|
{
|
||||||
struct scan_info scan = { lib_id, library_db.at(lib_id)->root_path };
|
Library *library = tagdb :: lookup_library(lib_id);
|
||||||
|
struct scan_info scan = { library, library->root_path };
|
||||||
idle :: schedule(do_validate_library, lib_id);
|
idle :: schedule(do_validate_library, lib_id);
|
||||||
idle :: schedule(do_scan_path, scan);
|
idle :: schedule(do_scan_path, scan);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_import_track(File &f, unsigned int lib_id)
|
static void do_import_track(File &f, Library *library)
|
||||||
{
|
{
|
||||||
struct ImportData data;
|
struct ImportData data;
|
||||||
std::string artist, album, genre;
|
unsigned int year, banned, tmp;
|
||||||
unsigned int artist_id, album_id, genre_id, track_id, year, banned, tmp;
|
|
||||||
|
|
||||||
data.filepath = f.getline();
|
std::string filepath = f.getline();
|
||||||
data.title = f.getline();
|
std::string title = f.getline();
|
||||||
|
std::string artist = f.getline();
|
||||||
|
std::string album = f.getline();
|
||||||
|
std::string comment = f.getline();
|
||||||
|
std::string genre = f.getline();
|
||||||
|
std::string lenstr = f.getline();
|
||||||
|
|
||||||
artist = f.getline();
|
f >> tmp /* id */ >> year >> tmp >> data.play_count;
|
||||||
album = f.getline();
|
f >> data.last_day >> data.last_month >> data.last_year >> tmp;
|
||||||
f.getline(); /* comment */
|
|
||||||
genre = f.getline();
|
|
||||||
f.getline(); /* lenstr */
|
|
||||||
f >> tmp /* id */ >> year >> data.track >> data.count;
|
|
||||||
f >> data.last_day >> data.last_month >> data.last_year >> data.length;
|
|
||||||
f >> tmp >> tmp >>tmp >> banned; /* bitrate, sample, channels, banned */
|
f >> tmp >> tmp >>tmp >> banned; /* bitrate, sample, channels, banned */
|
||||||
f.getline(); /* get rest of line */
|
f.getline(); /* get rest of line */
|
||||||
|
|
||||||
artist_id = artist_db.insert(library :: AGInfo(library :: DB_ARTIST, artist))->id;
|
Track *track = tagdb :: import_track(filepath, library, data);
|
||||||
album_id = album_db.insert(library :: Album(album, year, artist_id))->id;
|
get_callbacks()->on_library_track_add(track->id);
|
||||||
genre_id = genre_db.insert(library :: AGInfo(library :: DB_GENRE, genre))->id;
|
|
||||||
track_id = track_db.insert(library :: Track(&data, lib_id, artist_id,
|
|
||||||
album_id, genre_id))->id;
|
|
||||||
library_db.at(lib_id)->size++;
|
|
||||||
|
|
||||||
filter::add(artist_db.at(artist_id)->name, track_id);
|
|
||||||
filter::add(album_db.at(album_id)->name, track_id);
|
|
||||||
filter::add(track_db.at(track_id)->title, track_id);
|
|
||||||
get_callbacks()->on_library_track_add(track_id);
|
|
||||||
|
|
||||||
if (banned == true)
|
if (banned == true)
|
||||||
get_callbacks()->on_library_import_ban(track_id);
|
get_callbacks()->on_library_import_ban(track->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_import_library(std::string &s)
|
static void do_import_library(std::string &s)
|
||||||
|
@ -431,21 +131,19 @@ static void do_import_library(std::string &s)
|
||||||
path = f.getline();
|
path = f.getline();
|
||||||
f >> id >> enabled >> next_id >> size;
|
f >> id >> enabled >> next_id >> size;
|
||||||
|
|
||||||
/* Assign this path a new id */
|
Library *library = tagdb :: add_library(path);
|
||||||
if (library_db.find(path) != NULL) {
|
if (library == NULL) {
|
||||||
print("Library already contains path: %s, skipping\n", path.c_str());
|
print("Library already contains path: %s, skipping\n", path.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
print("Adding path: %s\n", path.c_str());
|
print("Adding path: %s\n", path.c_str());
|
||||||
id = library_db.insert(library :: Library(path, enabled))->id;
|
get_callbacks()->on_library_add(library->id, library);
|
||||||
get_callbacks()->on_library_add(id, &(*library_db.at(id)));
|
|
||||||
library_db.save();
|
|
||||||
|
|
||||||
f.getline(); /* Get rest of line */
|
f.getline(); /* Get rest of line */
|
||||||
for (unsigned int i = 0; i < size; i++)
|
for (unsigned int i = 0; i < size; i++)
|
||||||
do_import_track(f, id);
|
do_import_track(f, library);
|
||||||
save_all_dbs();
|
tagdb :: commit();
|
||||||
get_callbacks()->on_library_update(id, &(*library_db.at(id)));
|
get_callbacks()->on_library_update(library->id, library);
|
||||||
|
|
||||||
library :: update_path(id);
|
library :: update_path(id);
|
||||||
}
|
}
|
||||||
|
@ -458,120 +156,86 @@ static void do_import_library(std::string &s)
|
||||||
|
|
||||||
void library :: init()
|
void library :: init()
|
||||||
{
|
{
|
||||||
album_db.load();
|
tagdb :: init();
|
||||||
artist_db.load();
|
|
||||||
genre_db.load();
|
|
||||||
library_db.load();
|
|
||||||
track_db.load();
|
|
||||||
|
|
||||||
|
Database<Track> *db = &tagdb :: get_track_db();
|
||||||
Database<Track>::iterator it;
|
Database<Track>::iterator it;
|
||||||
for (it = track_db.begin(); it != track_db.end(); it = track_db.next(it)) {
|
|
||||||
filter::add(artist_db.at((*it)->artist_id)->name, (*it)->id);
|
|
||||||
filter::add(album_db.at((*it)->album_id)->name, (*it)->id);
|
|
||||||
filter::add((*it)->title, (*it)->id);
|
|
||||||
|
|
||||||
if (library_db.at((*it)->library_id)->enabled)
|
for (it = db->begin(); it != db->end(); it = db->next(it)) {
|
||||||
|
if ((*it)->library->enabled)
|
||||||
get_callbacks()->on_library_track_add((*it)->id);
|
get_callbacks()->on_library_track_add((*it)->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Database<Library> *ldb = &tagdb :: get_library_db();
|
||||||
Database<Library>::iterator l_it;
|
Database<Library>::iterator l_it;
|
||||||
for (l_it = library_db.begin(); l_it != library_db.end(); l_it = library_db.next(l_it))
|
|
||||||
get_callbacks()->on_library_add((*l_it)->id, &(*library_db.at((*l_it)->id)));
|
for (l_it = ldb->begin(); l_it != ldb->end(); l_it = ldb->next(l_it))
|
||||||
|
get_callbacks()->on_library_add((*l_it)->id, *l_it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void library :: add_path(const std::string &dir)
|
void library :: add_path(const std::string &dir)
|
||||||
{
|
{
|
||||||
unsigned int id;
|
|
||||||
if (g_file_test(dir.c_str(), G_FILE_TEST_IS_DIR) == false)
|
if (g_file_test(dir.c_str(), G_FILE_TEST_IS_DIR) == false)
|
||||||
throw -E_INVAL;
|
throw -E_INVAL;
|
||||||
if (library_db.find(dir) != NULL)
|
|
||||||
|
Library *library = tagdb :: add_library(dir);
|
||||||
|
if (!library)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
id = library_db.insert(library :: Library(dir, true))->id;
|
get_callbacks()->on_library_add(library->id, library);
|
||||||
library_db.save();
|
update_path(library->id);
|
||||||
|
|
||||||
get_callbacks()->on_library_add(id, &(*library_db.at(id)));
|
|
||||||
update_path(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void library :: del_path(unsigned int id)
|
void library :: del_path(unsigned int id)
|
||||||
{
|
{
|
||||||
|
Database<Track> *db = &tagdb :: get_track_db();
|
||||||
Database<Track>::iterator it;
|
Database<Track>::iterator it;
|
||||||
|
|
||||||
for (it = track_db.begin(); it != track_db.end(); it = track_db.next(it)) {
|
for (it = db->begin(); it != db->end(); it = db->next(it)) {
|
||||||
if ((*it)->library_id == id) {
|
if ((*it)->library->id == id)
|
||||||
get_callbacks()->on_library_track_del((*it)->id);
|
get_callbacks()->on_library_track_del((*it)->id);
|
||||||
track_db.remove((*it)->id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
library_db.remove(id);
|
tagdb :: remove_library(id);
|
||||||
|
tagdb :: commit();
|
||||||
track_db.save();
|
|
||||||
library_db.save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void library :: update_path(unsigned int id)
|
void library :: update_path(unsigned int id)
|
||||||
{
|
{
|
||||||
if (id > library_db.size())
|
Library *library = tagdb :: lookup_library(id);
|
||||||
return;
|
if (library)
|
||||||
if (library_db.at(id) == NULL)
|
do_update_library(library->id);
|
||||||
return;
|
|
||||||
do_update_library(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void library :: update_all()
|
void library :: update_all()
|
||||||
{
|
{
|
||||||
|
Database<Library> *db = &tagdb :: get_library_db();
|
||||||
Database<Library>::iterator it;
|
Database<Library>::iterator it;
|
||||||
|
|
||||||
for (it = library_db.begin(); it != library_db.end(); it = library_db.next(it))
|
for (it = db->begin(); it != db->end(); it = db->next(it))
|
||||||
update_path(it - library_db.begin());
|
update_path((*it)->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void library :: set_enabled(unsigned int id, bool enabled)
|
void library :: set_enabled(unsigned int id, bool enabled)
|
||||||
{
|
{
|
||||||
unsigned int t;
|
Library *library = tagdb :: lookup_library(id);
|
||||||
|
|
||||||
|
library->enabled = enabled;
|
||||||
|
tagdb :: commit_library();
|
||||||
|
|
||||||
|
Database<Track> *db = &(tagdb :: get_track_db());
|
||||||
Database<Track>::iterator it;
|
Database<Track>::iterator it;
|
||||||
|
|
||||||
library_db.at(id)->enabled = enabled;
|
for (it = db->begin(); it != db->end(); it = db->next(it)) {
|
||||||
library_db.save();
|
if ((*it)->library->id == id) {
|
||||||
|
|
||||||
for (it = track_db.begin(); it != track_db.end(); it = track_db.next(it)) {
|
|
||||||
if ((*it)->library_id == id) {
|
|
||||||
t = it - track_db.begin();
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
get_callbacks()->on_library_track_add(t);
|
get_callbacks()->on_library_track_add((*it)->id);
|
||||||
else
|
else
|
||||||
get_callbacks()->on_library_track_del(t);
|
get_callbacks()->on_library_track_del((*it)->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void library :: lookup(unsigned int id, library :: Song *song)
|
|
||||||
{
|
|
||||||
if (id >= track_db.actual_size())
|
|
||||||
throw -E_EXIST;
|
|
||||||
|
|
||||||
song->track = &(*track_db.at(id));
|
|
||||||
if (song->track == NULL)
|
|
||||||
throw -E_EXIST;
|
|
||||||
|
|
||||||
song->track_id = id;
|
|
||||||
song->artist = &(*artist_db.at(song->track->artist_id));
|
|
||||||
song->album = &(*album_db.at(song->track->album_id));
|
|
||||||
song->genre = &(*genre_db.at(song->track->genre_id));
|
|
||||||
song->library = &(*library_db.at(song->track->library_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
library :: Library *library :: lookup_path(unsigned int id)
|
|
||||||
{
|
|
||||||
if (id >= library_db.actual_size())
|
|
||||||
throw -E_EXIST;
|
|
||||||
if (library_db.at(id) == NULL)
|
|
||||||
throw -E_EXIST;
|
|
||||||
return &(*library_db.at(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
void library :: import()
|
void library :: import()
|
||||||
{
|
{
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
|
@ -597,14 +261,18 @@ void library :: track_played(unsigned int id)
|
||||||
{
|
{
|
||||||
time_t the_time = time(NULL);
|
time_t the_time = time(NULL);
|
||||||
struct tm *now = localtime(&the_time);
|
struct tm *now = localtime(&the_time);
|
||||||
|
Track *track = tagdb :: lookup(id);
|
||||||
|
|
||||||
track_db.at(id)->play_count++;
|
if (!track)
|
||||||
track_db.at(id)->last_day = now->tm_mday;
|
return;
|
||||||
track_db.at(id)->last_month = now->tm_mon + 1;
|
|
||||||
track_db.at(id)->last_year = now->tm_year + 1900;
|
|
||||||
|
|
||||||
track_db.save();
|
track->play_count++;
|
||||||
get_callbacks()->on_library_track_updated(id);
|
track->last_day = now->tm_mday;
|
||||||
|
track->last_month = now->tm_mon + 1;
|
||||||
|
track->last_year = now->tm_year + 1900;
|
||||||
|
|
||||||
|
tagdb :: commit();
|
||||||
|
get_callbacks()->on_library_track_updated(track->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_TEST
|
#ifdef CONFIG_TEST
|
||||||
|
|
|
@ -97,72 +97,21 @@ std::string Playqueue :: get_length_str()
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns:
|
|
||||||
* 0: lhs == rhs
|
|
||||||
* < 0: lhs < rhs
|
|
||||||
* > 0: lhs > rhs
|
|
||||||
*/
|
|
||||||
static inline int compare_uint(unsigned int a, unsigned int b)
|
|
||||||
{
|
|
||||||
if (a == b)
|
|
||||||
return 0;
|
|
||||||
if (a < b)
|
|
||||||
return -1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* std::string.compare() returns
|
* std::string.compare() returns
|
||||||
* 0: Strings are equal
|
* 0: Strings are equal
|
||||||
* < 0: a < b
|
* < 0: a < b
|
||||||
* > 0: a > b
|
* > 0: a > b
|
||||||
*/
|
*/
|
||||||
static inline int track_compare(library :: Song &lhs, library :: Song &rhs,
|
static inline int track_compare(Track *lhs, Track *rhs, sort_t field)
|
||||||
sort_t field)
|
|
||||||
{
|
{
|
||||||
switch (field) {
|
int ret = lhs->less_than(rhs, field);
|
||||||
case SORT_ARTIST:
|
if (field == SORT_YEAR && ret == 0)
|
||||||
return compare_string(lhs.artist->key_lower, rhs.artist->key_lower);
|
ret = lhs->less_than(rhs, SORT_ALBUM);
|
||||||
case SORT_ALBUM:
|
|
||||||
return compare_string(lhs.album->name_lower, rhs.album->name_lower);
|
|
||||||
case SORT_COUNT:
|
|
||||||
return compare_uint(lhs.track->play_count, rhs.track->play_count);
|
|
||||||
case SORT_GENRE:
|
|
||||||
return compare_string(lhs.genre->key_lower, rhs.genre->key_lower);
|
|
||||||
case SORT_LENGTH:
|
|
||||||
return compare_uint(lhs.track->length, rhs.track->length);
|
|
||||||
case SORT_PLAYED:
|
|
||||||
return compare_uint(lhs.track->play_count, rhs.track->play_count);
|
|
||||||
case SORT_TITLE:
|
|
||||||
return compare_string(lhs.track->title_lower, rhs.track->title_lower);
|
|
||||||
case SORT_TRACK:
|
|
||||||
return compare_uint(lhs.track->track, rhs.track->track);
|
|
||||||
default: //case SORT_YEAR
|
|
||||||
int ret = compare_uint(lhs.album->year, rhs.album->year);
|
|
||||||
if (ret != 0)
|
|
||||||
return ret;
|
return ret;
|
||||||
return compare_string(lhs.album->name_lower, rhs.album->name_lower);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool track_less_than(library :: Song &lhs, library :: Song &rhs,
|
static bool track_less_than(Track *lhs, Track *rhs, std::list<sort_info> &order)
|
||||||
std::list<sort_info> &order)
|
|
||||||
{
|
{
|
||||||
std::list<sort_info>::iterator it;
|
std::list<sort_info>::iterator it;
|
||||||
int res;
|
int res;
|
||||||
|
@ -178,9 +127,9 @@ static bool track_less_than(library :: Song &lhs, library :: Song &rhs,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Playqueue :: find_sorted_id(library :: Song &rhs)
|
unsigned int Playqueue :: find_sorted_id(Track *rhs)
|
||||||
{
|
{
|
||||||
library :: Song lhs;
|
Track *lhs;
|
||||||
unsigned int begin = 0, end = (tracks.size() - 1), mid;
|
unsigned int begin = 0, end = (tracks.size() - 1), mid;
|
||||||
|
|
||||||
if (tracks.size() == 0)
|
if (tracks.size() == 0)
|
||||||
|
@ -188,7 +137,7 @@ unsigned int Playqueue :: find_sorted_id(library :: Song &rhs)
|
||||||
|
|
||||||
while (end > begin) {
|
while (end > begin) {
|
||||||
mid = begin + ((end - begin) / 2);
|
mid = begin + ((end - begin) / 2);
|
||||||
library :: lookup(tracks[mid], &lhs);
|
lhs = tagdb :: lookup(tracks[mid]);
|
||||||
if (track_less_than(lhs, rhs, sort_order))
|
if (track_less_than(lhs, rhs, sort_order))
|
||||||
begin = mid + 1;
|
begin = mid + 1;
|
||||||
else {
|
else {
|
||||||
|
@ -199,7 +148,7 @@ unsigned int Playqueue :: find_sorted_id(library :: Song &rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
library :: lookup(tracks[begin], &lhs);
|
lhs = tagdb :: lookup(tracks[begin]);
|
||||||
if (track_less_than(lhs, rhs, sort_order))
|
if (track_less_than(lhs, rhs, sort_order))
|
||||||
return begin + 1;
|
return begin + 1;
|
||||||
return begin;
|
return begin;
|
||||||
|
@ -208,14 +157,13 @@ unsigned int Playqueue :: find_sorted_id(library :: Song &rhs)
|
||||||
unsigned int Playqueue :: add(unsigned int track_id)
|
unsigned int Playqueue :: add(unsigned int track_id)
|
||||||
{
|
{
|
||||||
unsigned int id = tracks.size();
|
unsigned int id = tracks.size();
|
||||||
library :: Song song;
|
Track *track = tagdb :: lookup(track_id);
|
||||||
library :: lookup(track_id, &song);
|
|
||||||
|
|
||||||
if (sort_order.size() > 0)
|
if (sort_order.size() > 0)
|
||||||
id = find_sorted_id(song);
|
id = find_sorted_id(track);
|
||||||
|
|
||||||
tracks.insert(tracks.begin() + id, track_id);
|
tracks.insert(tracks.begin() + id, track_id);
|
||||||
length += song.track->length;
|
length += track->length;
|
||||||
get_callbacks()->on_queue_track_add(this, id);
|
get_callbacks()->on_queue_track_add(this, id);
|
||||||
if (!(flags & PQ_DISABLE_CHANGED_SIZE))
|
if (!(flags & PQ_DISABLE_CHANGED_SIZE))
|
||||||
get_callbacks()->on_queue_changed();
|
get_callbacks()->on_queue_changed();
|
||||||
|
@ -224,11 +172,11 @@ unsigned int Playqueue :: add(unsigned int track_id)
|
||||||
|
|
||||||
unsigned int Playqueue :: add_front(unsigned int track_id)
|
unsigned int Playqueue :: add_front(unsigned int track_id)
|
||||||
{
|
{
|
||||||
library :: Song song;
|
Track *track;
|
||||||
tracks.insert(tracks.begin(), track_id);
|
tracks.insert(tracks.begin(), track_id);
|
||||||
|
|
||||||
library :: lookup(track_id, &song);
|
track = tagdb :: lookup(track_id);
|
||||||
length += song.track->length;
|
length += track->length;
|
||||||
get_callbacks()->on_queue_track_add(this, 0);
|
get_callbacks()->on_queue_track_add(this, 0);
|
||||||
if (!(flags & PQ_DISABLE_CHANGED_SIZE))
|
if (!(flags & PQ_DISABLE_CHANGED_SIZE))
|
||||||
get_callbacks()->on_queue_changed();
|
get_callbacks()->on_queue_changed();
|
||||||
|
@ -237,12 +185,12 @@ unsigned int Playqueue :: add_front(unsigned int track_id)
|
||||||
|
|
||||||
void Playqueue :: del(unsigned int plist_id)
|
void Playqueue :: del(unsigned int plist_id)
|
||||||
{
|
{
|
||||||
library :: Song song;
|
Track *track;
|
||||||
unsigned int track_id = tracks[plist_id];
|
unsigned int track_id = tracks[plist_id];
|
||||||
|
|
||||||
tracks.erase(tracks.begin() + plist_id);
|
tracks.erase(tracks.begin() + plist_id);
|
||||||
library :: lookup(track_id, &song);
|
track = tagdb :: lookup(track_id);
|
||||||
length -= song.track->length;
|
length -= track->length;
|
||||||
get_callbacks()->on_queue_track_del(this, plist_id);
|
get_callbacks()->on_queue_track_del(this, plist_id);
|
||||||
if (!(flags & PQ_DISABLE_CHANGED_SIZE))
|
if (!(flags & PQ_DISABLE_CHANGED_SIZE))
|
||||||
get_callbacks()->on_queue_changed();
|
get_callbacks()->on_queue_changed();
|
||||||
|
@ -281,9 +229,8 @@ public:
|
||||||
SortTracks(std::list<sort_info> f) : fields(f) {}
|
SortTracks(std::list<sort_info> f) : fields(f) {}
|
||||||
bool operator()(unsigned int a, unsigned int b)
|
bool operator()(unsigned int a, unsigned int b)
|
||||||
{
|
{
|
||||||
library::Song lhs, rhs;
|
Track *lhs = tagdb :: lookup(a);
|
||||||
library :: lookup(a, &lhs);
|
Track *rhs = tagdb :: lookup(b);
|
||||||
library :: lookup(b, &rhs);
|
|
||||||
return track_less_than(lhs, rhs, fields);
|
return track_less_than(lhs, rhs, fields);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
10
lib/tags.cpp
10
lib/tags.cpp
|
@ -324,6 +324,11 @@ void tagdb :: commit()
|
||||||
track_db.save();
|
track_db.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tagdb :: commit_library()
|
||||||
|
{
|
||||||
|
library_db.save();
|
||||||
|
}
|
||||||
|
|
||||||
Track *tagdb :: add_track(const std::string &filepath, Library *library)
|
Track *tagdb :: add_track(const std::string &filepath, Library *library)
|
||||||
{
|
{
|
||||||
unsigned int size = track_db.size();
|
unsigned int size = track_db.size();
|
||||||
|
@ -376,6 +381,11 @@ Track *tagdb :: lookup(unsigned int track_id)
|
||||||
return track_db.at(track_id);
|
return track_db.at(track_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Library *tagdb :: lookup_library(unsigned int library_id)
|
||||||
|
{
|
||||||
|
return library_db.at(library_id);
|
||||||
|
}
|
||||||
|
|
||||||
Database<Track> &tagdb :: get_track_db()
|
Database<Track> &tagdb :: get_track_db()
|
||||||
{
|
{
|
||||||
return track_db;
|
return track_db;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user