File indexing completed on 2024-05-19 04:48:25

0001 /*
0002    Babe - tiny music player
0003    Copyright (C) 2017  Camilo Higuita
0004    This program is free software; you can redistribute it and/or modify
0005    it under the terms of the GNU General Public License as published by
0006    the Free Software Foundation; either version 3 of the License, or
0007    (at your option) any later version.
0008    This program is distributed in the hope that it will be useful,
0009    but WITHOUT ANY WARRANTY; without even the implied warranty of
0010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0011    GNU General Public License for more details.
0012    You should have received a copy of the GNU General Public License
0013    along with this program; if not, write to the Free Software Foundation,
0014    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
0015 
0016    */
0017 
0018 #include "collectionDB.h"
0019 
0020 #include <QString>
0021 #include <QStringList>
0022 #include <QUuid>
0023 #include <QDateTime>
0024 
0025 #include <MauiKit3/Core/fmh.h>
0026 #include <MauiKit3/FileBrowsing/fmstatic.h>
0027 
0028 using namespace BAE;
0029 
0030 CollectionDB::CollectionDB(QObject *parent)
0031     : QObject(parent)
0032 {
0033     this->name = QUuid::createUuid().toString();
0034 
0035     if (!FMH::fileExists(QUrl::fromUserInput(BAE::CollectionDBPath + BAE::DBName))) {
0036         QDir collectionDBPath_dir(BAE::CollectionDBPath);
0037         if (!collectionDBPath_dir.exists())
0038             collectionDBPath_dir.mkpath(".");
0039 
0040         this->openDB(this->name);
0041         qDebug() << "Collection doesn't exists, trying to create it" << BAE::CollectionDBPath + BAE::DBName;
0042         this->prepareCollectionDB();
0043 
0044     } else
0045         this->openDB(this->name);
0046 }
0047 
0048 void CollectionDB::prepareCollectionDB()
0049 {
0050     QSqlQuery query(this->m_db);
0051 
0052     QFile file(":/db/script.sql");
0053     qDebug() << file.exists();
0054 
0055     if (!file.exists()) {
0056         QString log = QStringLiteral("Fatal error on build database. The file '");
0057         log.append(file.fileName() + QStringLiteral("' for database and tables creation query cannot be not found!"));
0058         qDebug() << log;
0059         return;
0060     }
0061 
0062     if (!file.open(QIODevice::ReadOnly)) {
0063         qDebug() << QStringLiteral("Fatal error on try to create database! The file with sql queries for database creation cannot be opened!");
0064         return;
0065     }
0066 
0067     bool hasText;
0068     QString line;
0069     QByteArray readLine;
0070     QString cleanedLine;
0071     QStringList strings;
0072 
0073     while (!file.atEnd()) {
0074         hasText = false;
0075         line = "";
0076         readLine = "";
0077         cleanedLine = "";
0078         strings.clear();
0079         while (!hasText) {
0080             readLine = file.readLine();
0081             cleanedLine = readLine.trimmed();
0082             strings = cleanedLine.split("--");
0083             cleanedLine = strings.at(0);
0084             if (!cleanedLine.startsWith("--") && !cleanedLine.startsWith("DROP") && !cleanedLine.isEmpty())
0085                 line += cleanedLine;
0086             if (cleanedLine.endsWith(";"))
0087                 break;
0088             if (cleanedLine.startsWith("COMMIT"))
0089                 hasText = true;
0090         }
0091         if (!line.isEmpty()) {
0092             if (!query.exec(line)) {
0093                 qDebug() << "exec failed" << query.lastQuery() << query.lastError();
0094             }
0095 
0096         } else
0097             qDebug() << "exec wrong" << query.lastError();
0098     }
0099     file.close();
0100 }
0101 
0102 bool CollectionDB::check_existance(const QString &tableName, const QString &searchId, const QString &search)
0103 {
0104     auto queryStr = QString("SELECT %1 FROM %2 WHERE %3 = \"%4\"").arg(searchId, tableName, searchId, search);
0105     auto query = this->getQuery(queryStr);
0106 
0107     if (!query.exec()) {
0108         qDebug() << query.lastError().text();
0109         return false;
0110     }
0111 
0112     if (query.first())
0113         return true;
0114 
0115     return false;
0116 }
0117 
0118 bool CollectionDB::insert(const QString &tableName, const QVariantMap &insertData)
0119 {
0120     if (tableName.isEmpty()) {
0121         qDebug() << QStringLiteral("Fatal error on insert! The table name is empty!");
0122         return false;
0123 
0124     } else if (insertData.isEmpty()) {
0125         qDebug() << QStringLiteral("Fatal error on insert! The insertData is empty!");
0126         return false;
0127     }
0128 
0129     QStringList strValues;
0130     QStringList fields = insertData.keys();
0131     QVariantList values = insertData.values();
0132     int totalFields = fields.size();
0133     for (int i = 0; i < totalFields; ++i)
0134         strValues.append("?");
0135 
0136     QString sqlQueryString = "INSERT INTO " + tableName + " (" + QString(fields.join(",")) + ") VALUES(" + QString(strValues.join(",")) + ")";
0137     QSqlQuery query(this->m_db);
0138     query.prepare(sqlQueryString);
0139 
0140     int k = 0;
0141     foreach (const QVariant &value, values)
0142         query.bindValue(k++, value);
0143 
0144     return query.exec();
0145 }
0146 
0147 bool CollectionDB::update(const QString &tableName, const FMH::MODEL &updateData, const QVariantMap &where)
0148 {
0149     if (tableName.isEmpty()) {
0150         qDebug() << QStringLiteral("Fatal error on insert! The table name is empty!");
0151         return false;
0152     } else if (updateData.isEmpty()) {
0153         qDebug() << QStringLiteral("Fatal error on insert! The insertData is empty!");
0154         return false;
0155     }
0156 
0157     QStringList set;
0158     const auto updateKeys = updateData.keys();
0159     for (const auto &key : updateKeys)
0160     {
0161         set.append(QString("%1 = \"%2\"").arg(FMH::MODEL_NAME[key], updateData[key]));
0162     }
0163 
0164     QStringList condition;
0165     const auto whereKeys = where.keys();
0166     for (const auto &key : whereKeys)
0167     {
0168         condition.append(QString("%1 = \"%2\"").arg(key, where[key].toString()));
0169     }
0170 
0171     const QString sqlQueryString = "UPDATE " + tableName + " SET " + QString(set.join(",")) + " WHERE " + QString(condition.join(" AND "));
0172 
0173     auto query = this->getQuery(sqlQueryString);
0174 
0175     qDebug() << sqlQueryString;
0176     return this->execQuery(query);
0177 }
0178 
0179 bool CollectionDB::update(const QString &table, const QString &column, const QVariant &newValue, const QVariant &op, const QString &id)
0180 {
0181     const auto queryStr = QString("UPDATE %1 SET %2 = \"%3\" WHERE %4 = \"%5\"").arg(table, column, newValue.toString().replace("\"", "\"\""), op.toString(), id);
0182     auto query = this->getQuery(queryStr);
0183     return query.exec();
0184 }
0185 
0186 bool CollectionDB::remove(const QString &table, const QString &column, const QVariantMap &where)
0187 {
0188     Q_UNUSED(table)
0189     Q_UNUSED(column)
0190     Q_UNUSED(where)
0191 
0192     return false;
0193 }
0194 
0195 bool CollectionDB::execQuery(QSqlQuery &query) const
0196 {
0197     if (query.exec())
0198         return true;
0199     qDebug() << "ERROR ON EXEC QUERY";
0200     qDebug() << query.lastError() << query.lastQuery();
0201     return false;
0202 }
0203 
0204 bool CollectionDB::execQuery(const QString &queryTxt)
0205 {
0206     auto query = this->getQuery(queryTxt);
0207     return this->execQuery(query);
0208 }
0209 
0210 void CollectionDB::openDB(const QString &name)
0211 {
0212     if (!QSqlDatabase::contains(name)) {
0213         this->m_db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), name);
0214         this->m_db.setDatabaseName(BAE::CollectionDBPath + BAE::DBName);
0215     }
0216 
0217     if (!this->m_db.isOpen()) {
0218         if (!this->m_db.open())
0219             qDebug() << "ERROR OPENING DB" << this->m_db.lastError().text() << m_db.connectionName();
0220         else {
0221             qDebug() << "Setting pragma WAL";
0222             this->execQuery("PRAGMA journal_mode=WAL");
0223         }
0224     }
0225 }
0226 
0227 bool CollectionDB::addTrack(const FMH::MODEL &track)
0228 {
0229     if (track.isEmpty())
0230         return false;
0231 
0232     const auto url = track[FMH::MODEL_KEY::URL];
0233     if (check_existance(TABLEMAP[BAE::TABLE::TRACKS], BAE::KEYMAP[BAE::KEY::URL], url)) {
0234         return false;
0235     }
0236 
0237     const auto title = track[FMH::MODEL_KEY::TITLE];
0238     const auto artist = track[FMH::MODEL_KEY::ARTIST];
0239     const auto album = track[FMH::MODEL_KEY::ALBUM];
0240     const auto genre = track[FMH::MODEL_KEY::GENRE];
0241     const auto year = track[FMH::MODEL_KEY::RELEASEDATE];
0242     const auto sourceUrl = track[FMH::MODEL_KEY::SOURCE];
0243     const auto duration = track[FMH::MODEL_KEY::DURATION];
0244     const auto trackNumber = track[FMH::MODEL_KEY::TRACK];
0245     const auto comment = track[FMH::MODEL_KEY::COMMENT];
0246 
0247     /* first needs to insert the source, album and artist*/
0248     const QVariantMap sourceMap{{FMH::MODEL_NAME[FMH::MODEL_KEY::URL], sourceUrl}, {FMH::MODEL_NAME[FMH::MODEL_KEY::SOURCETYPE], sourceType(url)}};
0249 
0250     if (insert(TABLEMAP[BAE::TABLE::SOURCES], sourceMap))
0251         Q_EMIT sourceInserted(sourceMap);
0252 
0253     const QVariantMap artistMap{{FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist}, {FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI], ""}};
0254 
0255     if (insert(TABLEMAP[TABLE::ARTISTS], artistMap))
0256         Q_EMIT artistInserted(artistMap);
0257 
0258     const QVariantMap albumMap{{FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], album}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist}, {FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI], ""}};
0259 
0260     if (insert(TABLEMAP[TABLE::ALBUMS], albumMap))
0261         Q_EMIT albumInserted(albumMap);
0262 
0263     const QVariantMap trackMap{{FMH::MODEL_NAME[FMH::MODEL_KEY::URL], url},
0264                                {FMH::MODEL_NAME[FMH::MODEL_KEY::SOURCE], sourceUrl},
0265                                {FMH::MODEL_NAME[FMH::MODEL_KEY::TRACK], trackNumber},
0266                                {FMH::MODEL_NAME[FMH::MODEL_KEY::TITLE], title},
0267                                {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist},
0268                                {FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], album},
0269                                {FMH::MODEL_NAME[FMH::MODEL_KEY::DURATION], duration},
0270                                {FMH::MODEL_NAME[FMH::MODEL_KEY::COUNT], 0},
0271                                {FMH::MODEL_NAME[FMH::MODEL_KEY::RATE], 0},
0272                                {FMH::MODEL_NAME[FMH::MODEL_KEY::RELEASEDATE], year},
0273                                {FMH::MODEL_NAME[FMH::MODEL_KEY::ADDDATE], QDateTime::currentDateTime()},
0274                                {FMH::MODEL_NAME[FMH::MODEL_KEY::LYRICS], ""},
0275                                {FMH::MODEL_NAME[FMH::MODEL_KEY::GENRE], genre},
0276                                {FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI], ""},
0277                                {FMH::MODEL_NAME[FMH::MODEL_KEY::COMMENT], comment}};
0278 
0279     if (this->insert(BAE::TABLEMAP[BAE::TABLE::TRACKS], trackMap)) {
0280         qDebug() << "TrackInserted!!!!!!" << trackMap;
0281         Q_EMIT trackInserted(trackMap);
0282         return true;
0283     }
0284 
0285     return false;
0286 }
0287 
0288 bool CollectionDB::updateTrack(const FMH::MODEL &track)
0289 {
0290     if (this->check_existance(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], track[FMH::MODEL_KEY::URL])) {
0291         QVariantMap artistMap{{FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], track[FMH::MODEL_KEY::ARTIST]}};
0292 
0293         insert(TABLEMAP[TABLE::ARTISTS], artistMap);
0294 
0295         QVariantMap albumMap{{FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], track[FMH::MODEL_KEY::ALBUM]}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], track[FMH::MODEL_KEY::ARTIST]}};
0296 
0297         insert(TABLEMAP[TABLE::ALBUMS], albumMap);
0298 
0299         QVariantMap condition{{FMH::MODEL_NAME[FMH::MODEL_KEY::URL], track[FMH::MODEL_KEY::URL]}};
0300 
0301         if (this->update(TABLEMAP[TABLE::TRACKS], track, condition))
0302         {
0303             if (cleanAlbums())
0304             {
0305                 cleanArtists();
0306             }
0307         }
0308 
0309         return true;
0310     }
0311 
0312     return false;
0313 }
0314 
0315 bool CollectionDB::rateTrack(const QString &path, const int &value)
0316 {
0317     if (update(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::RATE], value, FMH::MODEL_NAME[FMH::MODEL_KEY::URL], path))
0318         return true;
0319     return false;
0320 }
0321 
0322 bool CollectionDB::lyricsTrack(const FMH::MODEL &track, const QString &value)
0323 {
0324     if (update(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::LYRICS], value, FMH::MODEL_NAME[FMH::MODEL_KEY::URL], track[FMH::MODEL_KEY::URL]))
0325     {
0326         return true;
0327     }
0328     return false;
0329 }
0330 
0331 bool CollectionDB::albumTrack(const FMH::MODEL &track, const QString &value)
0332 {
0333     auto album = track[FMH::MODEL_KEY::ALBUM];
0334     auto artist = track[FMH::MODEL_KEY::ARTIST];
0335     //    auto url = track[FMH::MODEL_KEY::URL];
0336 
0337     auto queryTxt = QString("SELECT * %1 WHERE %2 = %3 AND %4 = %5").arg(TABLEMAP[TABLE::ALBUMS], FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], album, FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist);
0338 
0339     auto result = this->getDBData(queryTxt);
0340     if (result.isEmpty())
0341         return false;
0342 
0343     auto oldAlbum = result.first();
0344     QVariantMap albumMap{{FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], value}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], oldAlbum[FMH::MODEL_KEY::ARTIST]}, {FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI], oldAlbum[FMH::MODEL_KEY::WIKI]}};
0345 
0346     if (!insert(TABLEMAP[TABLE::ALBUMS], albumMap))
0347         return false;
0348 
0349     // update albums SET album = "newalbumname" WHERE album = "albumname" NAD artist = "aretist name";
0350     queryTxt = QString("UPDATE %1 SET %2 = %3 AND %4 = %5 WHERE %2 = %6 AND %4 = %5")
0351             .arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], value, FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], oldAlbum[FMH::MODEL_KEY::ARTIST], oldAlbum[FMH::MODEL_KEY::ALBUM]);
0352     auto query = this->getQuery(queryTxt);
0353 
0354     if (!execQuery(query))
0355         return false;
0356 
0357     queryTxt = QString("DELETE FROM %1 WHERE %2 = %3 AND %4 = %5").arg(TABLEMAP[TABLE::ALBUMS], FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], oldAlbum[FMH::MODEL_KEY::ALBUM], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist);
0358     query.prepare(queryTxt);
0359 
0360     if (!execQuery(query))
0361         return false;
0362 
0363     return true;
0364 }
0365 
0366 bool CollectionDB::playedTrack(const QString &url)
0367 {    
0368     auto query = getQuery();
0369     query.prepare("UPDATE TRACKS SET count = count + 1 WHERE url = :url");
0370     query.bindValue(":url", url);
0371 
0372     if (query.exec())
0373     {
0374 //        query.clar();
0375         auto query2 = getQuery();
0376 
0377         query2.prepare("UPDATE TRACKS SET lastsync = :date WHERE url = :url");
0378         query2.bindValue(":date", QDateTime::currentDateTime());
0379         query2.bindValue(":url", url);
0380 
0381         query2.exec();
0382         return true;
0383     }
0384 
0385     return false;
0386 }
0387 
0388 FMH::MODEL_LIST CollectionDB::getDBData(const QStringList &urls)
0389 {
0390     FMH::MODEL_LIST mapList;
0391 
0392     for (const auto &url : urls) {
0393         const auto queryTxt = QString("SELECT * FROM %1 t INNER JOIN albums a on a.album = t.album and a.artist = t.artist WHERE t.%2 = \"%3\"").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], url);
0394 
0395         mapList << this->getDBData(queryTxt);
0396     }
0397 
0398     return mapList;
0399 }
0400 
0401 FMH::MODEL_LIST CollectionDB::getDBData(const QString &queryTxt, std::function<bool(FMH::MODEL &item)> modifier)
0402 {
0403     FMH::MODEL_LIST mapList;
0404 
0405     auto query = this->getQuery(queryTxt);
0406 
0407     if (query.exec()) {
0408         const auto keys = FMH::MODEL_NAME.keys();
0409 
0410         while (query.next()) {
0411             FMH::MODEL data;
0412             for (const auto &key : keys)
0413             {
0414                 if (query.record().indexOf(FMH::MODEL_NAME[key]) > -1)
0415                 {
0416                     data.insert(key, query.value(FMH::MODEL_NAME[key]).toString());
0417                 }
0418             }
0419 
0420             if (modifier) {
0421                 if (!modifier(data))
0422                 {
0423                     continue;
0424                 }
0425             }
0426 
0427             mapList << data;
0428         }
0429 
0430     } else
0431         qDebug() << query.lastError() << query.lastQuery();
0432 
0433     return mapList;
0434 }
0435 
0436 FMH::MODEL_LIST CollectionDB::getAlbumTracks(const QString &album, const QString &artist, const FMH::MODEL_KEY &orderBy, const BAE::W &order)
0437 {
0438     const auto queryTxt = QString("SELECT * FROM %1 WHERE %2 = \"%3\" AND %4 = \"%5\" ORDER by %6 %7")
0439             .arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist, FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], album, FMH::MODEL_NAME[orderBy], SLANG[order]);
0440 
0441     return this->getDBData(queryTxt);
0442 }
0443 
0444 FMH::MODEL_LIST CollectionDB::getArtistTracks(const QString &artist, const FMH::MODEL_KEY &orderBy, const BAE::W &order)
0445 {
0446     const auto queryTxt =
0447             QString("SELECT * FROM %1 WHERE %2 = \"%3\" ORDER by %4 %5, %6 %5").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist, FMH::MODEL_NAME[orderBy], SLANG[order], FMH::MODEL_NAME[FMH::MODEL_KEY::TRACK]);
0448 
0449     return this->getDBData(queryTxt);
0450 }
0451 
0452 QStringList CollectionDB::getArtistAlbums(const QString &artist)
0453 {
0454     QStringList albums;
0455 
0456     const auto queryTxt = QString("SELECT %4 FROM %1 WHERE %2 = \"%3\" ORDER BY %4 ASC").arg(TABLEMAP[TABLE::ALBUMS], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist, FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM]);
0457     auto query = this->getDBData(queryTxt);
0458 
0459     for (const auto &track : query)
0460         albums << track[FMH::MODEL_KEY::ALBUM];
0461 
0462     return albums;
0463 }
0464 
0465 FMH::MODEL_LIST CollectionDB::getSearchedTracks(const FMH::MODEL_KEY &where, const QString &search)
0466 {
0467     QString queryTxt;
0468 
0469     if (where == FMH::MODEL_KEY::COUNT || where == FMH::MODEL_KEY::RATE)
0470         queryTxt = QString("SELECT t.* FROM %1 t inner join albums al on al.album = t.album and t.artist = al.artist WHERE %2 = \"%3\"").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[where], search);
0471     else if (where == FMH::MODEL_KEY::WIKI)
0472 
0473         queryTxt = QString("SELECT DISTINCT t.* FROM %1 t INNER JOIN %2 al ON t.%3 = al.%3 INNER JOIN %4 ar ON t.%5 = ar.%5 WHERE al.%6 LIKE \"%%7%\" OR ar.%6 LIKE \"%%7%\" COLLATE NOCASE")
0474                 .arg(TABLEMAP[TABLE::TRACKS], TABLEMAP[TABLE::ALBUMS], FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], TABLEMAP[TABLE::ARTISTS], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], FMH::MODEL_NAME[where], search);
0475     else
0476         queryTxt = QString("SELECT t.* FROM %1 t inner join albums al on al.album = t.album and t.artist = al.artist WHERE t.%2 LIKE \"%%3%\" ORDER BY strftime(\"%s\", t.addDate) desc LIMIT 1000")
0477                 .arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[where], search);
0478 
0479     return this->getDBData(queryTxt);
0480 }
0481 
0482 FMH::MODEL_LIST CollectionDB::getRecentTracks(const int &limit, const FMH::MODEL_KEY &orderBy, const BAE::W &order)
0483 {
0484     const auto queryTxt = QString("SELECT * FROM %1 ORDER BY strftime(\"%s\",%2) %3 LIMIT %4").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[orderBy], SLANG[order], QString::number(limit));
0485 
0486     return this->getDBData(queryTxt);
0487 }
0488 
0489 FMH::MODEL_LIST CollectionDB::getMostPlayedTracks(const int &greaterThan, const int &limit, const FMH::MODEL_KEY &orderBy, const BAE::W &order)
0490 {
0491     auto queryTxt =
0492             QString("SELECT * FROM %1 WHERE %2 > %3 ORDER BY %4 %5 LIMIT %6").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::COUNT], QString::number(greaterThan), FMH::MODEL_NAME[orderBy], SLANG[order], QString::number(limit));
0493 
0494     return this->getDBData(queryTxt);
0495 }
0496 
0497 int CollectionDB::getTrackStars(const QString &path)
0498 {
0499     int stars = 0;
0500     auto query = this->getDBData(QString("SELECT %1 FROM %2 WHERE %3 = \"%4\"").arg(FMH::MODEL_NAME[FMH::MODEL_KEY::RATE], TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], path));
0501 
0502     for (auto track : query)
0503         stars = track[FMH::MODEL_KEY::RATE].toInt();
0504 
0505     return stars;
0506 }
0507 
0508 bool CollectionDB::removeTrack(const QString &path)
0509 {
0510     auto queryTxt = QString("DELETE FROM %1 WHERE %2 =  \"%3\"").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], path);
0511     auto query = this->getQuery(queryTxt);
0512     if (query.exec()) {
0513         if (cleanAlbums())
0514             cleanArtists();
0515         return true;
0516     }
0517     return false;
0518 }
0519 
0520 QSqlQuery CollectionDB::getQuery(const QString &queryTxt) const
0521 {
0522     return QSqlQuery(queryTxt, this->m_db);
0523 }
0524 
0525 QSqlQuery CollectionDB::getQuery() const
0526 {
0527     QSqlQuery query(this->m_db);
0528     return query;
0529 }
0530 
0531 bool CollectionDB::removeSource(const QString &url)
0532 {
0533     const auto path = url.endsWith("/") ? url.chopped(1) : url;
0534 
0535     auto queryTxt = QString("DELETE FROM %1 WHERE %2 LIKE \"%3%\"").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::SOURCE], path);
0536 
0537     auto query = this->getQuery(queryTxt);
0538     query.prepare(queryTxt);
0539 
0540     if (query.exec()) {
0541         queryTxt = QString("DELETE FROM %1 WHERE %2 LIKE \"%3%\"").arg(TABLEMAP[TABLE::SOURCES], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], path);
0542         query.prepare(queryTxt);
0543         if (query.exec()) {
0544             if (cleanAlbums())
0545                 cleanArtists();
0546             return true;
0547         }
0548     }
0549 
0550     return false;
0551 }
0552 
0553 sourceTypes CollectionDB::sourceType(const QString &url)
0554 {
0555     /*for now*/
0556     Q_UNUSED(url);
0557     return sourceTypes::LOCAL;
0558 }
0559 
0560 /*******************OLD STUFF********************/
0561 
0562 void CollectionDB::removeMissingTracks()
0563 {
0564     auto tracks = this->getDBData("select url from tracks");
0565 
0566     for (auto track : tracks)
0567         if (!FMH::fileExists(track[FMH::MODEL_KEY::URL]))
0568             this->removeTrack(track[FMH::MODEL_KEY::URL]);
0569 }
0570 
0571 bool CollectionDB::removeArtist(const QString &artist)
0572 {
0573     const auto queryTxt = QString("DELETE FROM %1 WHERE %2 = \"%3\" ").arg(TABLEMAP[TABLE::ARTISTS], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist);
0574     auto query = this->getQuery(queryTxt);
0575 
0576     return query.exec();
0577 }
0578 
0579 bool CollectionDB::cleanArtists()
0580 {
0581     //    delete from artists where artist in (select artist from artists except select distinct artist from tracks);
0582     const auto queryTxt = QString("DELETE FROM %1 WHERE %2 IN (SELECT %2 FROM %1 EXCEPT SELECT DISTINCT %2 FROM %3)").arg(TABLEMAP[TABLE::ARTISTS], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], TABLEMAP[TABLE::TRACKS]);
0583     qDebug() << queryTxt;
0584 
0585     auto query = this->getQuery(queryTxt);
0586     Q_EMIT this->artistsCleaned(query.numRowsAffected());
0587     return query.exec();
0588 }
0589 
0590 bool CollectionDB::removeAlbum(const QString &album, const QString &artist)
0591 {
0592     const auto queryTxt = QString("DELETE FROM %1 WHERE %2 = \"%3\" AND %4 = \"%5\"").arg(TABLEMAP[TABLE::ALBUMS], FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], album, FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist);
0593 
0594     auto query = this->getQuery(queryTxt);
0595     return query.exec();
0596 }
0597 
0598 bool CollectionDB::cleanAlbums()
0599 {
0600     //    delete from albums where (album, artist) in (select a.album, a.artist from albums a except select distinct album, artist from tracks);
0601     const auto queryTxt = QString("DELETE FROM %1 WHERE (%2, %3) IN (SELECT %2, %3 FROM %1 EXCEPT SELECT DISTINCT %2, %3  FROM %4)")
0602             .arg(TABLEMAP[TABLE::ALBUMS], FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], TABLEMAP[TABLE::TRACKS]);
0603     qDebug() << queryTxt;
0604     auto query = this->getQuery(queryTxt);
0605     Q_EMIT albumsCleaned(query.numRowsAffected());
0606     return query.exec();
0607 }