/* Echo Media Player
* Copyright (C) 2008 Shane O'Connell
*
* [ The original file includes a copyright header in this location describing
* the file as being released under the terms of the GNU General Public
* License. It has been removed in order to display the file as part of the
* archive. ]
*/
#include "Library.h"
#include "Database.h"
#include <mpegfile.h>
#include <tag.h>
#include <cassert>
#include <iostream>
using namespace std;
Library::Library(long long library_id, const Glib::ustring& name, const Glib::ustring& icon)
: db(*Database::m_instance), m_library_id(library_id), m_name(name), m_icon(icon)
{
assert(Database::m_instance);
SQLstmt stmt;
db.prepare(stmt, Glib::ustring::compose(
"SELECT COUNT(*) FROM LibraryTracks "
"WHERE LibraryID = %1", m_library_id));
bool is_row = stmt.step();
assert(is_row);
m_tracks.reserve(stmt.get_column_int(0));
db.prepare(stmt, Glib::ustring::compose(
"SELECT Artists.ArtistID, Albums.AlbumID, TrackName, TrackNumber, TrackRating, TrackURI"
" FROM LibraryTracks, Tracks, Artists, Albums"
" WHERE LibraryTracks.TrackID = Tracks.TrackID"
" AND Tracks.AlbumID = Albums.AlbumID"
" AND Albums.ArtistID = Artists.ArtistID"
" AND LibraryTracks.LibraryID = %1"
" ORDER BY ArtistName, AlbumReleaseDate, AlbumName, TrackNumber",
m_library_id));
while (stmt.step()) {
StringRef album = db.get_album_from_id(stmt.get_column_int(1));
StringRef artist = db.get_artist_from_id(stmt.get_column_int(0));
m_tracks.push_back(TrackRef(new Track(
stmt.get_column_text(5), // URI
stmt.get_column_text(2), // Name
artist, album,
stmt.get_column_int(3) // Track number
)));
}
}
TrackRef Library::get_track(int index) const
{
assert(index >= 0);
assert(index < (int)m_tracks.size());
return m_tracks[index];
}
void Library::refresh()
{
SQLstmt stmt;
db.prepare(stmt, Glib::ustring::compose(
"SELECT LibraryURI FROM Libraries "
"WHERE LibraryID = %1", m_library_id));
bool is_row = stmt.step();
assert(is_row);
std::string base_uri = stmt.get_column_text(0);
refresh_from_uri(base_uri);
// TODO signal stuff has been updated
}
void Library::refresh_from_uri(const std::string& uri)
{
while (Glib::MainContext::get_default()->pending())
Glib::MainContext::get_default()->iteration(false);
try
{
Glib::RefPtr<Gio::File> file = Gio::File::create_for_uri(uri);
Glib::RefPtr<Gio::FileInfo> file_info = file->query_info(
"standard::type,standard::fast-content-type");
if (file_info->get_file_type() == Gio::FILE_TYPE_DIRECTORY)
{
signal_refesh_pulse().emit(file->get_parse_name());
Glib::RefPtr<Gio::FileEnumerator> children = file->enumerate_children(
"standard::name,standard::display-name");
Glib::RefPtr<Gio::FileInfo> child;
while (child = children->next_file()) {
if (child->get_display_name().size() >= 1
&& child->get_display_name().at(0) != '.') {
// TODO add some kind of protection against infinitely recursive directories
refresh_from_uri(file->get_child(child->get_name())->get_uri());
}
}
}
else
{
string content_type = file_info->get_attribute_string("standard::fast-content-type");
if (file->is_native() && content_type == "audio/mpeg") // MP3
{
// TODO trim whitespace at either side of the mp3 title/artist/album etc.
TagLib::MPEG::File file_tags(file->get_path().c_str());
TrackRef track = TrackRef(new Track(
uri,
file_tags.tag()->title().to8Bit(true),
file_tags.tag()->artist().to8Bit(true),
file_tags.tag()->album().to8Bit(true),
file_tags.tag()->track()));
// TODO make sure tags are okay before accepting
// if they aren't okay use the filename as the title
update_refreshed_track(track);
}
}
}
catch (Gio::Error e)
{
// TODO show error message to user when this happens
}
}
void Library::update_refreshed_track(TrackRef track)
{
long long artist_id = db.get_artist_id(track->get_artist());
long long album_id = db.get_album_id(artist_id, track->get_album());
long long track_id = db.get_track_id(track->get_uri());
// TODO can we just insert a track into Tracks without checking if it's there first
// by using the UNIQUE contraint on TrackURI with a REPLACE conflict clause?
// The only problem is if that changes the TrackID or just uses the one the original had
if (track_id == -1) {
/* db.run("CREATE TABLE IF NOT EXISTS Tracks ("
" TrackID INTEGER PRIMARY KEY,"
" AlbumID INTEGER,"
" TrackName TEXT,"
" TrackNumber INTEGER,"
" TrackRating INTEGER,"
" TrackURI TEXT"
")"); */
SQLstmt stmt;
db.prepare(stmt, "INSERT INTO Tracks (AlbumID, TrackName, TrackNumber, TrackURI) "
"VALUES(?, ?, ?, ?)");
stmt.bind(1, album_id);
stmt.bind(2, track->get_title());
stmt.bind(3, track->get_track_number());
stmt.bind(4, track->get_uri());
stmt.step();
track_id = db.last_rowid();
}
else {
SQLstmt stmt;
db.prepare(stmt, "UPDATE Tracks SET "
"AlbumID = ?, TrackName = ?, TrackNumber = ? WHERE TrackID = ?");
stmt.bind(1, album_id);
stmt.bind(2, track->get_title());
stmt.bind(3, track->get_track_number());
stmt.bind(4, track_id);
stmt.step();
}
/* db.run("CREATE TABLE IF NOT EXISTS LibraryTracks ("
" LibraryID INTEGER,"
" TrackID INTEGER,"
" UNIQUE(LibraryID, TrackID) REPLACE"
")");*/
//long long track_id = db.last_rowid();
SQLstmt stmt;
db.prepare(stmt, "INSERT INTO LibraryTracks (LibraryID, TrackID) VALUES(?, ?)");
stmt.bind(1, m_library_id);
stmt.bind(2, track_id);
stmt.step();
}