2010-03-24 00:11:46 +01:00
|
|
|
/* This file is part of Clementine.
|
|
|
|
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2009-12-24 20:16:07 +01:00
|
|
|
#ifndef LIBRARYBACKEND_H
|
|
|
|
#define LIBRARYBACKEND_H
|
|
|
|
|
|
|
|
#include <QObject>
|
|
|
|
#include <QSqlError>
|
|
|
|
#include <QSqlDatabase>
|
|
|
|
#include <QMutex>
|
2010-02-27 21:12:22 +01:00
|
|
|
#include <QSet>
|
2009-12-24 20:16:07 +01:00
|
|
|
|
|
|
|
#include "directory.h"
|
|
|
|
#include "song.h"
|
2010-02-28 19:04:50 +01:00
|
|
|
#include "libraryquery.h"
|
2010-04-14 23:03:00 +02:00
|
|
|
#include "playlistitem.h"
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2010-03-21 14:29:06 +01:00
|
|
|
#include <sqlite3.h>
|
|
|
|
|
2010-03-22 17:03:24 +01:00
|
|
|
#include "gtest/gtest_prod.h"
|
|
|
|
|
2010-03-23 18:26:54 +01:00
|
|
|
class LibraryBackendInterface : public QObject {
|
2009-12-24 20:16:07 +01:00
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
2010-03-23 18:26:54 +01:00
|
|
|
LibraryBackendInterface(QObject* parent = 0);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2010-02-28 23:07:59 +01:00
|
|
|
struct Album {
|
2010-03-23 22:52:42 +01:00
|
|
|
Album() {}
|
|
|
|
Album(const QString& _artist, const QString& _album_name,
|
|
|
|
const QString& _art_automatic, const QString& _art_manual)
|
|
|
|
: artist(_artist), album_name(_album_name),
|
|
|
|
art_automatic(_art_automatic), art_manual(_art_manual) {}
|
|
|
|
|
2010-02-28 20:25:52 +01:00
|
|
|
QString artist;
|
2010-02-28 19:04:50 +01:00
|
|
|
QString album_name;
|
2010-02-28 23:07:59 +01:00
|
|
|
|
2010-02-28 19:04:50 +01:00
|
|
|
QString art_automatic;
|
|
|
|
QString art_manual;
|
|
|
|
};
|
2010-02-28 23:07:59 +01:00
|
|
|
typedef QList<Album> AlbumList;
|
2010-02-28 19:04:50 +01:00
|
|
|
|
2010-04-14 23:03:00 +02:00
|
|
|
struct Playlist {
|
|
|
|
int id;
|
|
|
|
QString name;
|
|
|
|
};
|
|
|
|
typedef QList<Playlist> PlaylistList;
|
|
|
|
|
2010-03-25 15:33:09 +01:00
|
|
|
virtual void Stop() {};
|
|
|
|
|
2010-03-23 18:26:54 +01:00
|
|
|
// Get a list of directories in the library. Emits DirectoriesDiscovered.
|
|
|
|
virtual void LoadDirectoriesAsync() = 0;
|
|
|
|
|
|
|
|
// Counts the songs in the library. Emits TotalSongCountUpdated
|
|
|
|
virtual void UpdateTotalSongCountAsync() = 0;
|
|
|
|
|
2010-04-14 23:03:00 +02:00
|
|
|
// Functions for getting songs
|
2010-03-23 18:26:54 +01:00
|
|
|
virtual SongList FindSongsInDirectory(int id) = 0;
|
2010-04-04 16:59:55 +02:00
|
|
|
virtual SubdirectoryList SubdirsInDirectory(int id) = 0;
|
2010-03-23 18:26:54 +01:00
|
|
|
|
|
|
|
virtual QStringList GetAllArtists(const QueryOptions& opt = QueryOptions()) = 0;
|
|
|
|
virtual SongList GetSongs(const QString& artist, const QString& album, const QueryOptions& opt = QueryOptions()) = 0;
|
|
|
|
|
|
|
|
virtual bool HasCompilations(const QueryOptions& opt = QueryOptions()) = 0;
|
|
|
|
virtual SongList GetCompilationSongs(const QString& album, const QueryOptions& opt = QueryOptions()) = 0;
|
|
|
|
|
|
|
|
virtual AlbumList GetAllAlbums(const QueryOptions& opt = QueryOptions()) = 0;
|
|
|
|
virtual AlbumList GetAlbumsByArtist(const QString& artist, const QueryOptions& opt = QueryOptions()) = 0;
|
|
|
|
virtual AlbumList GetCompilationAlbums(const QueryOptions& opt = QueryOptions()) = 0;
|
|
|
|
|
|
|
|
virtual void UpdateManualAlbumArtAsync(const QString& artist, const QString& album, const QString& art) = 0;
|
|
|
|
virtual Album GetAlbumArt(const QString& artist, const QString& album) = 0;
|
|
|
|
|
|
|
|
virtual Song GetSongById(int id) = 0;
|
|
|
|
|
2010-04-14 23:03:00 +02:00
|
|
|
virtual bool ExecQuery(LibraryQuery* q) = 0;
|
|
|
|
|
|
|
|
// Add or remove directories to the library
|
2010-03-23 18:26:54 +01:00
|
|
|
virtual void AddDirectory(const QString& path) = 0;
|
|
|
|
virtual void RemoveDirectory(const Directory& dir) = 0;
|
|
|
|
|
2010-04-14 23:03:00 +02:00
|
|
|
// Update compilation flags on songs
|
2010-03-23 18:26:54 +01:00
|
|
|
virtual void UpdateCompilationsAsync() = 0;
|
|
|
|
|
2010-04-14 23:03:00 +02:00
|
|
|
// Functions for getting playlists
|
|
|
|
virtual PlaylistList GetAllPlaylists() = 0;
|
|
|
|
virtual PlaylistItemList GetPlaylistItems(int playlist) = 0;
|
2010-04-15 00:05:41 +02:00
|
|
|
virtual void SavePlaylistAsync(int playlist, const PlaylistItemList& items) = 0;
|
2010-03-31 02:30:57 +02:00
|
|
|
|
2010-03-23 18:26:54 +01:00
|
|
|
public slots:
|
|
|
|
virtual void LoadDirectories() = 0;
|
|
|
|
virtual void UpdateTotalSongCount() = 0;
|
|
|
|
virtual void AddOrUpdateSongs(const SongList& songs) = 0;
|
|
|
|
virtual void UpdateMTimesOnly(const SongList& songs) = 0;
|
|
|
|
virtual void DeleteSongs(const SongList& songs) = 0;
|
2010-04-04 16:59:55 +02:00
|
|
|
virtual void AddOrUpdateSubdirs(const SubdirectoryList& subdirs) = 0;
|
2010-03-23 18:26:54 +01:00
|
|
|
virtual void UpdateCompilations() = 0;
|
|
|
|
virtual void UpdateManualAlbumArt(const QString& artist, const QString& album, const QString& art) = 0;
|
|
|
|
virtual void ForceCompilation(const QString& artist, const QString& album, bool on) = 0;
|
2010-04-15 00:05:41 +02:00
|
|
|
virtual void SavePlaylist(int playlist, const PlaylistItemList& items) = 0;
|
2010-03-23 18:26:54 +01:00
|
|
|
|
|
|
|
signals:
|
|
|
|
void Error(const QString& message);
|
|
|
|
|
2010-04-01 18:59:32 +02:00
|
|
|
void DirectoryDiscovered(const Directory& dir, const SubdirectoryList& subdirs);
|
|
|
|
void DirectoryDeleted(const Directory& dir);
|
2010-03-23 18:26:54 +01:00
|
|
|
|
|
|
|
void SongsDiscovered(const SongList& songs);
|
|
|
|
void SongsDeleted(const SongList& songs);
|
|
|
|
|
|
|
|
void TotalSongCountUpdated(int total);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class LibraryBackend : public LibraryBackendInterface {
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
LibraryBackend(QObject* parent = 0, const QString& database_name = QString());
|
|
|
|
|
2010-03-08 19:07:18 +01:00
|
|
|
static const int kSchemaVersion;
|
|
|
|
|
2009-12-24 20:16:07 +01:00
|
|
|
// This actually refers to the location of the sqlite database
|
2010-03-03 00:37:12 +01:00
|
|
|
static QString DefaultDatabaseDirectory();
|
2009-12-24 20:16:07 +01:00
|
|
|
|
|
|
|
// Get a list of directories in the library. Emits DirectoriesDiscovered.
|
|
|
|
void LoadDirectoriesAsync();
|
|
|
|
|
|
|
|
// Counts the songs in the library. Emits TotalSongCountUpdated
|
|
|
|
void UpdateTotalSongCountAsync();
|
|
|
|
|
|
|
|
SongList FindSongsInDirectory(int id);
|
2010-04-04 16:59:55 +02:00
|
|
|
SubdirectoryList SubdirsInDirectory(int id);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2010-02-28 19:04:50 +01:00
|
|
|
QStringList GetAllArtists(const QueryOptions& opt = QueryOptions());
|
|
|
|
SongList GetSongs(const QString& artist, const QString& album, const QueryOptions& opt = QueryOptions());
|
|
|
|
|
|
|
|
bool HasCompilations(const QueryOptions& opt = QueryOptions());
|
|
|
|
SongList GetCompilationSongs(const QString& album, const QueryOptions& opt = QueryOptions());
|
2009-12-24 20:16:07 +01:00
|
|
|
|
2010-02-28 23:07:59 +01:00
|
|
|
AlbumList GetAllAlbums(const QueryOptions& opt = QueryOptions());
|
|
|
|
AlbumList GetAlbumsByArtist(const QString& artist, const QueryOptions& opt = QueryOptions());
|
|
|
|
AlbumList GetCompilationAlbums(const QueryOptions& opt = QueryOptions());
|
|
|
|
|
2010-02-28 20:25:52 +01:00
|
|
|
void UpdateManualAlbumArtAsync(const QString& artist, const QString& album, const QString& art);
|
2010-02-28 23:07:59 +01:00
|
|
|
Album GetAlbumArt(const QString& artist, const QString& album);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
|
|
|
Song GetSongById(int id);
|
|
|
|
|
|
|
|
void AddDirectory(const QString& path);
|
|
|
|
void RemoveDirectory(const Directory& dir);
|
|
|
|
|
2010-02-27 21:12:22 +01:00
|
|
|
void UpdateCompilationsAsync();
|
|
|
|
|
2010-03-31 02:30:57 +02:00
|
|
|
bool ExecQuery(LibraryQuery* q);
|
|
|
|
|
2010-04-14 23:03:00 +02:00
|
|
|
PlaylistList GetAllPlaylists();
|
|
|
|
PlaylistItemList GetPlaylistItems(int playlist);
|
2010-04-15 00:05:41 +02:00
|
|
|
void SavePlaylistAsync(int playlist, const PlaylistItemList& items);
|
2010-04-14 23:03:00 +02:00
|
|
|
|
2009-12-24 20:16:07 +01:00
|
|
|
public slots:
|
|
|
|
void LoadDirectories();
|
|
|
|
void UpdateTotalSongCount();
|
|
|
|
void AddOrUpdateSongs(const SongList& songs);
|
|
|
|
void UpdateMTimesOnly(const SongList& songs);
|
|
|
|
void DeleteSongs(const SongList& songs);
|
2010-04-04 16:59:55 +02:00
|
|
|
void AddOrUpdateSubdirs(const SubdirectoryList& subdirs);
|
2010-02-27 21:12:22 +01:00
|
|
|
void UpdateCompilations();
|
2010-03-03 19:38:20 +01:00
|
|
|
void UpdateManualAlbumArt(const QString& artist, const QString& album, const QString& art);
|
2010-03-21 00:59:39 +01:00
|
|
|
void ForceCompilation(const QString& artist, const QString& album, bool on);
|
2010-04-15 00:05:41 +02:00
|
|
|
void SavePlaylist(int playlist, const PlaylistItemList& items);
|
2009-12-24 20:16:07 +01:00
|
|
|
|
|
|
|
private:
|
2010-02-27 21:12:22 +01:00
|
|
|
struct CompilationInfo {
|
|
|
|
CompilationInfo() : has_samplers(false), has_not_samplers(false) {}
|
|
|
|
|
|
|
|
QSet<QString> artists;
|
|
|
|
QSet<QString> directories;
|
|
|
|
|
|
|
|
bool has_samplers;
|
|
|
|
bool has_not_samplers;
|
|
|
|
};
|
|
|
|
|
2009-12-24 20:16:07 +01:00
|
|
|
QSqlDatabase Connect();
|
2010-02-27 21:12:22 +01:00
|
|
|
void UpdateDatabaseSchema(int version, QSqlDatabase& db);
|
2009-12-24 20:16:07 +01:00
|
|
|
bool CheckErrors(const QSqlError& error);
|
|
|
|
|
2010-02-27 21:12:22 +01:00
|
|
|
void UpdateCompilations(QSqlQuery& find_songs, QSqlQuery& update,
|
2010-03-21 23:14:07 +01:00
|
|
|
SongList& deleted_songs, SongList& added_songs,
|
2010-02-27 21:12:22 +01:00
|
|
|
const QString& album, int sampler);
|
2010-02-28 23:07:59 +01:00
|
|
|
AlbumList GetAlbums(const QString& artist, bool compilation = false,
|
|
|
|
const QueryOptions& opt = QueryOptions());
|
2010-04-01 18:59:32 +02:00
|
|
|
SubdirectoryList SubdirsInDirectory(int id, QSqlDatabase& db);
|
2010-02-27 21:12:22 +01:00
|
|
|
|
2009-12-24 20:16:07 +01:00
|
|
|
private:
|
|
|
|
static const char* kDatabaseName;
|
2010-02-27 21:12:22 +01:00
|
|
|
|
2009-12-24 20:16:07 +01:00
|
|
|
QString directory_;
|
|
|
|
QMutex connect_mutex_;
|
2010-03-01 23:00:15 +01:00
|
|
|
|
2010-03-03 00:37:12 +01:00
|
|
|
// Used by tests
|
|
|
|
QString injected_database_name_;
|
2010-03-21 14:29:06 +01:00
|
|
|
|
|
|
|
|
2010-03-25 14:58:24 +01:00
|
|
|
uint query_hash_;
|
|
|
|
QStringList query_cache_;
|
|
|
|
|
2010-03-22 17:03:24 +01:00
|
|
|
FRIEND_TEST(LibraryBackendTest, LikeWorksWithAllAscii);
|
|
|
|
FRIEND_TEST(LibraryBackendTest, LikeWorksWithUnicode);
|
|
|
|
FRIEND_TEST(LibraryBackendTest, LikeAsciiCaseInsensitive);
|
|
|
|
FRIEND_TEST(LibraryBackendTest, LikeUnicodeCaseInsensitive);
|
2010-03-25 14:58:24 +01:00
|
|
|
FRIEND_TEST(LibraryBackendTest, LikePerformance);
|
|
|
|
FRIEND_TEST(LibraryBackendTest, LikeCacheInvalidated);
|
|
|
|
FRIEND_TEST(LibraryBackendTest, LikeQuerySplit);
|
2010-03-22 17:03:24 +01:00
|
|
|
|
2010-03-21 14:29:06 +01:00
|
|
|
// Do static initialisation like loading sqlite functions.
|
2010-03-24 17:02:06 +01:00
|
|
|
static void StaticInit();
|
2010-03-21 14:29:06 +01:00
|
|
|
// Custom LIKE() function for sqlite.
|
2010-03-25 14:58:24 +01:00
|
|
|
bool Like(const char* needle, const char* haystack);
|
2010-03-21 14:29:06 +01:00
|
|
|
static void SqliteLike(sqlite3_context* context, int argc, sqlite3_value** argv);
|
2010-03-22 19:35:31 +01:00
|
|
|
typedef int (*Sqlite3CreateFunc) (
|
2010-03-21 14:29:06 +01:00
|
|
|
sqlite3*, const char*, int, int, void*,
|
|
|
|
void (*) (sqlite3_context*, int, sqlite3_value**),
|
|
|
|
void (*) (sqlite3_context*, int, sqlite3_value**),
|
|
|
|
void (*) (sqlite3_context*));
|
|
|
|
|
|
|
|
// Sqlite3 functions. These will be loaded from the sqlite3 plugin.
|
|
|
|
static Sqlite3CreateFunc _sqlite3_create_function;
|
|
|
|
static int (*_sqlite3_value_type) (sqlite3_value*);
|
2010-03-21 17:11:26 +01:00
|
|
|
static sqlite_int64 (*_sqlite3_value_int64) (sqlite3_value*);
|
2010-03-22 19:35:31 +01:00
|
|
|
static const uchar* (*_sqlite3_value_text) (sqlite3_value*);
|
2010-03-22 19:46:41 +01:00
|
|
|
static void (*_sqlite3_result_int64) (sqlite3_context*, sqlite_int64);
|
2010-03-25 14:58:24 +01:00
|
|
|
static void* (*_sqlite3_user_data) (sqlite3_context*);
|
2010-03-24 17:02:06 +01:00
|
|
|
|
|
|
|
static bool sStaticInitDone;
|
|
|
|
static bool sLoadedSqliteSymbols;
|
2009-12-24 20:16:07 +01:00
|
|
|
};
|
|
|
|
|
2010-04-04 18:28:34 +02:00
|
|
|
class MemoryLibraryBackend : public LibraryBackend {
|
|
|
|
public:
|
|
|
|
MemoryLibraryBackend(QObject* parent = 0)
|
|
|
|
: LibraryBackend(parent, ":memory:") {}
|
|
|
|
};
|
|
|
|
|
2009-12-24 20:16:07 +01:00
|
|
|
#endif // LIBRARYBACKEND_H
|