1 #include <QtDebug>
2 #include <QStandardPaths>
3 #include <QSettings>
4 #include <QFile>
5 #include <QFileInfo>
6 #include <QSqlError>
7 
8 #include "library/queryutil.h"
9 #include "library/banshee/bansheedbconnection.h"
10 #include "util/performancetimer.h"
11 
BansheeDbConnection()12 BansheeDbConnection::BansheeDbConnection() {
13 }
14 
~BansheeDbConnection()15 BansheeDbConnection::~BansheeDbConnection() {
16     qDebug() << "Close Banshee database";
17     m_database.close();
18 }
19 
open(const QString & databaseFile)20 bool BansheeDbConnection::open(const QString& databaseFile) {
21     m_database = QSqlDatabase::addDatabase("QSQLITE", "BANSHE_DB_CONNECTION");
22     m_database.setHostName("localhost");
23     m_database.setDatabaseName(databaseFile);
24     m_database.setConnectOptions("SQLITE_OPEN_READONLY");
25 
26     //Open the database connection in this thread.
27     if (!m_database.open()) {
28         m_database.setConnectOptions(); // clear options
29         qWarning() << "Failed to open Banshee database." << m_database.lastError();
30         return false;
31     } else {
32         // TODO(DSC): Verify schema
33         // Banshee Schema file:
34         // https://git.gnome.org/browse/banshee/tree/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
35         // "Grouping" was introduced in schema 19 2008-08-19
36         // Tested from 39 to 45
37         qDebug() << "Successful opened Banshee database";
38         return true;
39     }
40 }
41 
getSchemaVersion()42 int BansheeDbConnection::getSchemaVersion() {
43     QSqlQuery query(m_database);
44     query.prepare("SELECT Value FROM CoreConfiguration WHERE Key = \"DatabaseVersion\"");
45 
46     if (query.exec()) {
47         if (query.next()) {
48             return query.value(0).toInt();
49         }
50     } else {
51         LOG_FAILED_QUERY(query);
52     }
53     return -1;
54 }
55 
getPlaylists()56 QList<BansheeDbConnection::Playlist> BansheeDbConnection::getPlaylists() {
57 
58     QList<BansheeDbConnection::Playlist> list;
59     BansheeDbConnection::Playlist playlist;
60 
61     QSqlQuery query(m_database);
62     query.prepare("SELECT PlaylistID, Name FROM CorePlaylists ORDER By Name");
63 
64     if (query.exec()) {
65         while (query.next()) {
66             playlist.playlistId = query.value(0).toString();
67             playlist.name = query.value(1).toString();
68             list.append(playlist);
69         }
70     } else {
71         LOG_FAILED_QUERY(query);
72     }
73     return list;
74 }
75 
getPlaylistEntries(int playlistId)76 QList<BansheeDbConnection::PlaylistEntry> BansheeDbConnection::getPlaylistEntries(int playlistId) {
77 
78     PerformanceTimer time;
79     time.start();
80 
81     QList<BansheeDbConnection::PlaylistEntry> list;
82     BansheeDbConnection::PlaylistEntry entry;
83 
84     QSqlQuery query(m_database);
85     query.setForwardOnly(true); // Saves about 50% time
86 
87     QString queryString;
88 
89     if (playlistId == 0) {
90         // Create Master Playlist
91         queryString = QString(
92             "SELECT "
93             "CoreTracks.TrackID, "        // 0
94             "CoreTracks.TrackID, "        // 1
95             "CoreTracks.Title, "          // 2
96             "CoreTracks.Uri, "            // 3
97             "CoreTracks.Duration, "       // 4
98             "CoreTracks.ArtistID, "       // 5
99             "CoreArtists.Name, "          // 6
100             "CoreTracks.Year, "           // 7
101             "CoreTracks.AlbumID, "        // 8
102             "CoreAlbums.Title, "          // 9
103             "CoreTracks.Rating, "         // 10
104             "CoreTracks.Genre, "          // 11
105             "CoreTracks.TrackNumber, "    // 12
106             "CoreTracks.DateAddedStamp, " // 13
107             "CoreTracks.BPM, "            // 14
108             "CoreTracks.BitRate, "        // 15
109             "CoreTracks.Comment, "        // 16
110             "CoreTracks.PlayCount, "      // 17
111             "CoreTracks.Composer, "       // 18
112             "CoreTracks.Grouping, "       // 19
113             "CoreAlbums.ArtistID, "       // 20
114             "AlbumArtists.Name "          // 21
115             "FROM CoreTracks "
116             "INNER JOIN CoreArtists ON CoreArtists.ArtistID = CoreTracks.ArtistID "
117             "INNER JOIN CoreArtists AlbumArtists ON AlbumArtists.ArtistID = CoreAlbums.ArtistID "
118             "INNER JOIN CoreAlbums ON CoreAlbums.AlbumID = CoreTracks.AlbumID ");
119      } else {
120         // SELECT playlist from CorePlaylistEntries
121         queryString = QString(
122             "SELECT "
123             "CorePlaylistEntries.TrackID, "   // 0
124             "CorePlaylistEntries.ViewOrder, " // 1
125             "CoreTracks.Title, "              // 2
126             "CoreTracks.Uri, "                // 3
127             "CoreTracks.Duration, "           // 4
128             "CoreTracks.ArtistID, "           // 5
129             "CoreArtists.Name, "              // 6
130             "CoreTracks.Year, "               // 7
131             "CoreTracks.AlbumID, "            // 8
132             "CoreAlbums.Title, "              // 9
133             "CoreTracks.Rating, "             // 10
134             "CoreTracks.Genre, "              // 11
135             "CoreTracks.TrackNumber, "        // 12
136             "CoreTracks.DateAddedStamp, "     // 13
137             "CoreTracks.BPM, "                // 14
138             "CoreTracks.BitRate, "            // 15
139             "CoreTracks.Comment, "            // 16
140             "CoreTracks.PlayCount, "          // 17
141             "CoreTracks.Composer, "           // 18
142             "CoreTracks.Grouping, "           // 19
143             "CoreAlbums.ArtistID, "           // 20
144             "AlbumArtists.Name "              // 21
145             "FROM CorePlaylistEntries "
146             "INNER JOIN CoreTracks ON CoreTracks.TrackID = CorePlaylistEntries.TrackID "
147             "INNER JOIN CoreArtists ON CoreArtists.ArtistID = CoreTracks.ArtistID "
148             "INNER JOIN CoreArtists AlbumArtists ON AlbumArtists.ArtistID = CoreAlbums.ArtistID "
149             "INNER JOIN CoreAlbums ON CoreAlbums.AlbumID = CoreTracks.AlbumID "
150             "WHERE CorePlaylistEntries.PlaylistID = %1")
151                 .arg(playlistId);
152     }
153 
154     query.prepare(queryString);
155 
156     if (query.exec()) {
157         while (query.next()) {
158             entry.trackId = query.value(0).toInt();
159             entry.viewOrder = query.value(1).toInt();
160             m_trackMap[entry.trackId].title = query.value(2).toString();
161             m_trackMap[entry.trackId].uri = QUrl::fromEncoded(query.value(3).toByteArray(), QUrl::StrictMode);
162             m_trackMap[entry.trackId].duration = query.value(4).toInt();
163 
164             int artistId = query.value(5).toInt();
165             m_artistMap[artistId].name = query.value(6).toString();
166             m_trackMap[entry.trackId].year = query.value(7).toInt();
167             int albumId = query.value(8).toInt();
168             m_albumMap[albumId].title = query.value(9).toString();
169             int albumArtistId = query.value(20).toInt();
170             m_artistMap[albumArtistId].name = query.value(21).toString();
171             m_trackMap[entry.trackId].rating = query.value(10).toInt();
172             m_trackMap[entry.trackId].genre = query.value(11).toString();
173             m_trackMap[entry.trackId].grouping = query.value(19).toString();
174             m_trackMap[entry.trackId].tracknumber = query.value(12).toInt();
175             m_trackMap[entry.trackId].dateadded = query.value(13).toInt();
176             m_trackMap[entry.trackId].bpm = query.value(14).toInt();
177             m_trackMap[entry.trackId].bitrate = query.value(15).toInt();
178             m_trackMap[entry.trackId].comment = query.value(16).toString();
179             m_trackMap[entry.trackId].playcount = query.value(17).toInt();
180             m_trackMap[entry.trackId].composer = query.value(18).toString();
181 
182             entry.pTrack = &m_trackMap[entry.trackId];
183             entry.pArtist = &m_artistMap[artistId];
184             entry.pAlbum = &m_albumMap[albumId];
185             entry.pAlbumArtist = &m_artistMap[albumArtistId];
186             list.append(entry);
187         }
188     } else {
189         LOG_FAILED_QUERY(query);
190     }
191 
192     qDebug() << "BansheeDbConnection::getPlaylistEntries(), took"
193              << time.elapsed().debugMillisWithUnit();
194 
195     return list;
196 }
197 
198 // static
getDatabaseFile()199 QString BansheeDbConnection::getDatabaseFile() {
200 
201     QString dbfile;
202 
203     // Banshee Application Data Path
204     // on Windows - "%APPDATA%\banshee-1" ("<Drive>:\Documents and Settings\<login>\<Application Data>\banshee-1")
205     // on Unix and Mac OS X - "$HOME/.config/banshee-1"
206 
207     QSettings ini(QSettings::IniFormat, QSettings::UserScope,
208             "banshee-1","banshee");
209     dbfile = QFileInfo(ini.fileName()).absolutePath();
210     dbfile += "/banshee.db";
211     if (QFile::exists(dbfile)) {
212         return dbfile;
213     }
214 
215     // Legacy Banshee Application Data Path
216     QSettings ini2(QSettings::IniFormat, QSettings::UserScope,
217             "banshee","banshee");
218     dbfile = QFileInfo(ini2.fileName()).absolutePath();
219     dbfile += "/banshee.db";
220     if (QFile::exists(dbfile)) {
221         return dbfile;
222     }
223 
224     // Legacy Banshee Application Data Path
225     dbfile = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
226     dbfile += "/.gnome2/banshee/banshee.db";
227     if (QFile::exists(dbfile)) {
228         return dbfile;
229     }
230 
231     return QString();
232 }
233