diff --git a/db/collectionDB.cpp b/db/collectionDB.cpp index 117aee4..9d9fbd4 100644 --- a/db/collectionDB.cpp +++ b/db/collectionDB.cpp @@ -1,1112 +1,1122 @@ /* Babe - tiny music player Copyright (C) 2017 Camilo Higuita This program 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. This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "collectionDB.h" #include #include #include #include "../utils/babeconsole.h" using namespace BAE; CollectionDB::CollectionDB(QObject *parent) : QObject(parent) { QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this]() { this->m_db.close(); this->instance->deleteLater(); this->instance = nullptr; }); this->name = QUuid::createUuid().toString(); if(!BAE::fileExists(BAE::CollectionDBPath + BAE::DBName)) { QDir collectionDBPath_dir(BAE::CollectionDBPath); if (!collectionDBPath_dir.exists()) collectionDBPath_dir.mkpath("."); this->openDB(this->name); qDebug()<<"Collection doesn't exists, trying to create it" << BAE::CollectionDBPath + BAE::DBName; this->prepareCollectionDB(); }else this->openDB(this->name); } CollectionDB::~CollectionDB() { qDebug()<< "DELETING COLLECTIONDB SINGLETON"; } CollectionDB *CollectionDB::instance = nullptr; CollectionDB *CollectionDB::getInstance() { if(!instance) { instance = new CollectionDB(); qDebug() << "getInstance(): First DBActions instance\n"; return instance; } else { qDebug()<< "getInstance(): previous DBActions instance\n"; return instance; } } void CollectionDB::deleteInstance() { delete this; } void CollectionDB::prepareCollectionDB() { QSqlQuery query(this->m_db); QFile file(":/db/script.sql"); qDebug()<< file.exists(); if (!file.exists()) { QString log = QStringLiteral("Fatal error on build database. The file '"); log.append(file.fileName() + QStringLiteral("' for database and tables creation query cannot be not found!")); qDebug()<getQuery(queryStr); if (!query.exec()) { qDebug()<m_db); query.prepare(sqlQueryString); int k = 0; foreach (const QVariant &value, values) query.bindValue(k++, value); return query.exec(); } bool CollectionDB::update(const QString &tableName, const FMH::MODEL &updateData, const QVariantMap &where) { if (tableName.isEmpty()) { qDebug()<getQuery(sqlQueryString); qDebug()<getQuery(queryStr); return query.exec(); } +bool CollectionDB::remove(const QString &table, const QString &column, const QVariantMap &where) +{ + return false;} + bool CollectionDB::execQuery(QSqlQuery &query) const { if(query.exec()) return true; qDebug()<<"ERROR ON EXEC QUERY"; qDebug()<getQuery(queryTxt); return query.exec(); } void CollectionDB::openDB(const QString &name) { if(!QSqlDatabase::contains(name)) { this->m_db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), name); this->m_db.setDatabaseName(BAE::CollectionDBPath + BAE::DBName); } if (!this->m_db.isOpen()) { if(!this->m_db.open()) qDebug()<<"ERROR OPENING DB"<m_db.lastError().text()<execQuery("PRAGMA journal_mode=WAL"); } } } bool CollectionDB::addTrack(const FMH::MODEL &track) { auto url = track[FMH::MODEL_KEY::URL]; auto title = track[FMH::MODEL_KEY::TITLE]; auto artist = track[FMH::MODEL_KEY::ARTIST]; auto album = track[FMH::MODEL_KEY::ALBUM]; auto genre = track[FMH::MODEL_KEY::GENRE]; auto year = track[FMH::MODEL_KEY::RELEASEDATE]; auto sourceUrl = track[FMH::MODEL_KEY::SOURCE]; auto duration = track[FMH::MODEL_KEY::DURATION]; auto fav = track[FMH::MODEL_KEY::FAV]; auto trackNumber = track[FMH::MODEL_KEY::TRACK]; auto artwork = track[FMH::MODEL_KEY::ARTWORK].isEmpty() ? "" : track[FMH::MODEL_KEY::ARTWORK]; auto artistTrack = track; artistTrack[FMH::MODEL_KEY::ARTWORK] = ""; BAE::artworkCache(artistTrack, FMH::MODEL_KEY::ARTIST); auto artistArtwork = artistTrack[FMH::MODEL_KEY::ARTWORK]; /* first needs to insert the source, album and artist*/ QVariantMap sourceMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::URL], sourceUrl}, {FMH::MODEL_NAME[FMH::MODEL_KEY::SOURCETYPE], sourceType(url)}}; insert(TABLEMAP[BAE::TABLE::SOURCES], sourceMap); QVariantMap artistMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTWORK], artistArtwork}, {FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI], ""}}; insert(TABLEMAP[TABLE::ARTISTS],artistMap); QVariantMap albumMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], album}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTWORK], artwork}, {FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI],""}}; insert(TABLEMAP[TABLE::ALBUMS],albumMap); QVariantMap trackMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::URL], url}, {FMH::MODEL_NAME[FMH::MODEL_KEY::SOURCE], sourceUrl}, {FMH::MODEL_NAME[FMH::MODEL_KEY::TRACK], trackNumber}, {FMH::MODEL_NAME[FMH::MODEL_KEY::TITLE], title}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], album}, {FMH::MODEL_NAME[FMH::MODEL_KEY::DURATION], duration}, {FMH::MODEL_NAME[FMH::MODEL_KEY::COUNT], 0}, {FMH::MODEL_NAME[FMH::MODEL_KEY::FAV], fav}, {FMH::MODEL_NAME[FMH::MODEL_KEY::RATE], 0}, {FMH::MODEL_NAME[FMH::MODEL_KEY::RELEASEDATE], year}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ADDDATE], QDateTime::currentDateTime()}, {FMH::MODEL_NAME[FMH::MODEL_KEY::LYRICS],""}, {FMH::MODEL_NAME[FMH::MODEL_KEY::GENRE], genre}, {FMH::MODEL_NAME[FMH::MODEL_KEY::COLOR], ""}, {FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI], ""}, {FMH::MODEL_NAME[FMH::MODEL_KEY::COMMENT], ""}}; return this->insert(BAE::TABLEMAP[BAE::TABLE::TRACKS], trackMap); } bool CollectionDB::updateTrack(const FMH::MODEL &track) { if(this->check_existance(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], track[FMH::MODEL_KEY::URL])) { QVariantMap artistMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], track[FMH::MODEL_KEY::ARTIST]}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTWORK], ""}, {FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI],""}}; insert(TABLEMAP[TABLE::ARTISTS],artistMap); 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]}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTWORK], ""}, {FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI],""}}; insert(TABLEMAP[TABLE::ALBUMS],albumMap); QVariantMap condition {{FMH::MODEL_NAME[FMH::MODEL_KEY::URL], track[FMH::MODEL_KEY::URL]}}; if(this->update(TABLEMAP[TABLE::TRACKS], track, condition)) if(cleanAlbums()) cleanArtists(); return true; } return false; } bool CollectionDB::rateTrack(const QString &path, const int &value) { if(update(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::RATE], value, FMH::MODEL_NAME[FMH::MODEL_KEY::URL], path)) return true; return false; } bool CollectionDB::colorTagTrack(const QString &path, const QString &value) { if(update(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::COLOR], value, FMH::MODEL_NAME[FMH::MODEL_KEY::URL], path)) return true; return false; } bool CollectionDB::lyricsTrack(const FMH::MODEL &track, const QString &value) { 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])) return true; return false; } bool CollectionDB::tagsTrack(const FMH::MODEL &track, const QString &value, const QString &context) { auto url = track[FMH::MODEL_KEY::URL]; qDebug()<<"INSERTIN TRACK TAG"<getDBData(queryTxt); if(result.isEmpty()) return false; auto oldAlbum = result.first(); 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::ARTWORK], oldAlbum[FMH::MODEL_KEY::ARTWORK]}, {FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI], oldAlbum[FMH::MODEL_KEY::WIKI]}}; if (!insert(TABLEMAP[TABLE::ALBUMS],albumMap)) return false; // update albums SET album = "newalbumname" WHERE album = "albumname" NAD artist = "aretist name"; queryTxt = QString("UPDATE %1 SET %2 = %3 AND %4 = %5 WHERE %2 = %6 AND %4 = %5").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]); auto query = this->getQuery(queryTxt); if(!execQuery(query)) return false; 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); query.prepare(queryTxt); if(!execQuery(query)) return false; return true; } bool CollectionDB::playedTrack(const QString &url, const int &increment) { auto queryTxt = QString("UPDATE %1 SET %2 = %2 + %3 WHERE %4 = \"%5\"").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::COUNT], QString::number(increment), FMH::MODEL_NAME[FMH::MODEL_KEY::URL], url); auto query = this->getQuery(queryTxt); if(query.exec()) return true; return false; } bool CollectionDB::wikiTrack(const FMH::MODEL &track, const QString &value) { auto url = track[FMH::MODEL_KEY::URL]; if(update(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI], value, FMH::MODEL_NAME[FMH::MODEL_KEY::URL], url)) return true; return false; } bool CollectionDB::wikiArtist(const FMH::MODEL &track, const QString &value) { auto artist = track[FMH::MODEL_KEY::ARTIST]; if(update(TABLEMAP[TABLE::ARTISTS], FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI], value, FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist)) return true; return false; } bool CollectionDB::tagsArtist(const FMH::MODEL &track, const QString &value, const QString &context) { auto artist = track[FMH::MODEL_KEY::ARTIST]; QVariantMap tagMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::TAG], value}, {FMH::MODEL_NAME[FMH::MODEL_KEY::CONTEXT], context}}; QVariantMap artistTagMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::TAG], value}, {FMH::MODEL_NAME[FMH::MODEL_KEY::CONTEXT], context}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist}}; insert(TABLEMAP[TABLE::TAGS],tagMap); insert(TABLEMAP[TABLE::ARTISTS_TAGS],artistTagMap); return true; } bool CollectionDB::wikiAlbum(const FMH::MODEL &track, QString value) { auto artist = track[FMH::MODEL_KEY::ARTIST]; auto album = track[FMH::MODEL_KEY::ALBUM]; auto queryStr = QString("UPDATE %1 SET %2 = \"%3\" WHERE %4 = \"%5\" AND %6 = \"%7\"").arg( TABLEMAP[TABLE::ALBUMS], FMH::MODEL_NAME[FMH::MODEL_KEY::WIKI], value.replace("\"","\"\""), FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], album,FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist); qDebug()<getQuery(queryStr); return query.exec(); } bool CollectionDB::tagsAlbum(const FMH::MODEL &track, const QString &value, const QString &context) { auto artist = track[FMH::MODEL_KEY::ARTIST]; auto album = track[FMH::MODEL_KEY::ALBUM]; QVariantMap tagMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::TAG],value},{FMH::MODEL_NAME[FMH::MODEL_KEY::CONTEXT],context}}; QVariantMap albumsTagMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::TAG],value}, {FMH::MODEL_NAME[FMH::MODEL_KEY::CONTEXT],context}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST],artist}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM],album}}; insert(TABLEMAP[TABLE::TAGS],tagMap); insert(TABLEMAP[TABLE::ALBUMS_TAGS],albumsTagMap); return true; } bool CollectionDB::addPlaylist(const QString &title) { if(!title.isEmpty()) { QVariantMap playlist {{FMH::MODEL_NAME[FMH::MODEL_KEY::PLAYLIST], title}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ADDDATE], QDateTime::currentDateTime()}}; if(insert(TABLEMAP[TABLE::PLAYLISTS],playlist)) return true; } return false; } bool CollectionDB::trackPlaylist(const QString &url, const QString &playlist) { QVariantMap map {{FMH::MODEL_NAME[FMH::MODEL_KEY::PLAYLIST],playlist}, {FMH::MODEL_NAME[FMH::MODEL_KEY::URL],url}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ADDDATE],QDate::currentDate()}}; if(insert(TABLEMAP[TABLE::TRACKS_PLAYLISTS],map)) return true; return false; } bool CollectionDB::addFolder(const QString &url) { QVariantMap map {{FMH::MODEL_NAME[FMH::MODEL_KEY::URL],url}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ADDDATE],QDateTime::currentDateTime()}}; if(insert(TABLEMAP[TABLE::FOLDERS],map)) return true; return false; } FMH::MODEL_LIST CollectionDB::getDBData(const QStringList &urls) { FMH::MODEL_LIST mapList; for(auto url : urls) { 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); mapList << this->getDBData(queryTxt); } return mapList; } -FMH::MODEL_LIST CollectionDB::getDBData(const QString &queryTxt) +FMH::MODEL_LIST CollectionDB::getDBData(const QString &queryTxt, std::function modifier) { FMH::MODEL_LIST mapList; auto query = this->getQuery(queryTxt); if(query.exec()) { while(query.next()) { FMH::MODEL data; for(auto key : FMH::MODEL_NAME.keys()) if(query.record().indexOf(FMH::MODEL_NAME[key]) > -1) data.insert(key, query.value(FMH::MODEL_NAME[key]).toString()); - + if(modifier) + modifier(data); mapList << data; } }else qDebug()<< query.lastError()<< query.lastQuery(); return mapList; } QVariantList CollectionDB::getDBDataQML(const QString &queryTxt) { QVariantList mapList; auto query = this->getQuery(queryTxt); if(query.exec()) { while(query.next()) { QVariantMap data; for(auto key : FMH::MODEL_NAME.keys()) if(query.record().indexOf(FMH::MODEL_NAME[key])>-1) data[FMH::MODEL_NAME[key]] = query.value(FMH::MODEL_NAME[key]).toString(); mapList<< data; } }else qDebug()<< (query.lastError().text()+" "+query.lastQuery()); return mapList; } QStringList CollectionDB::dataToList(const FMH::MODEL_LIST &list, const FMH::MODEL_KEY &key) { if(list.isEmpty()) return QStringList(); QStringList response; for(auto track : list) response << track[key]; return response; } FMH::MODEL_LIST CollectionDB::getAlbumTracks(const QString &album, const QString &artist, const FMH::MODEL_KEY &orderBy, const BAE::W &order) { auto queryTxt = QString("SELECT * FROM %1 WHERE %2 = \"%3\" AND %4 = \"%5\" ORDER by %6 %7").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]); return this->getDBData(queryTxt); } FMH::MODEL_LIST CollectionDB::getArtistTracks(const QString &artist, const FMH::MODEL_KEY &orderBy, const BAE::W &order) { auto queryTxt = 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]); return this->getDBData(queryTxt); } QStringList CollectionDB::getArtistAlbums(const QString &artist) { QStringList albums; 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]); auto query = this->getDBData(queryTxt); for(auto track : query) albums << track[FMH::MODEL_KEY::ALBUM]; return albums; } FMH::MODEL_LIST CollectionDB::getBabedTracks(const FMH::MODEL_KEY &orderBy, const BAE::W &order) { auto queryTxt = QString("SELECT * FROM %1 WHERE %2 = 1 ORDER by %3 %4").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::FAV], FMH::MODEL_NAME[orderBy], SLANG[order]); return this->getDBData(queryTxt); } FMH::MODEL_LIST CollectionDB::getSearchedTracks(const FMH::MODEL_KEY &where, const QString &search) { QString queryTxt; if(where == FMH::MODEL_KEY::COUNT || where == FMH::MODEL_KEY::RATE || where == FMH::MODEL_KEY::FAV) queryTxt = QString("SELECT t.*, al.artwork 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); else if(where == FMH::MODEL_KEY::WIKI) queryTxt = QString("SELECT DISTINCT t.*, al.artwork 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").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); else if(where == FMH::MODEL_KEY::PLAYLIST) queryTxt = QString("SELECT t.* FROM %1 t INNER JOIN %2 tp ON t.%3 = tp.%3 WHERE tp.%4 = \"%5\"").arg(TABLEMAP[TABLE::TRACKS], TABLEMAP[TABLE::TRACKS_PLAYLISTS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], FMH::MODEL_NAME[where], search); else if(where == FMH::MODEL_KEY::TAG) queryTxt = QString("SELECT t.* FROM %1 t INNER JOIN %2 tt ON t.%3 = tt.%3 WHERE tt.%4 = \"%5\" COLLATE NOCASE " "UNION " "SELECT t.* FROM %1 t INNER JOIN %6 at ON t.%7 = at.%7 AND t.%8 = at.%8 WHERE at.%4 = \"%5\" COLLATE NOCASE " "UNION " "SELECT t.* FROM %1 t INNER JOIN %9 art ON t.%8 = art.%8 WHERE art.%4 LIKE \"%%5%\" COLLATE NOCASE " "UNION " "SELECT DISTINCT t.* FROM %1 t INNER JOIN %9 at ON t.%8 = at.%4 WHERE at.%8 LIKE \"%%5%\" COLLATE NOCASE").arg( TABLEMAP[TABLE::TRACKS], TABLEMAP[TABLE::TRACKS_TAGS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], FMH::MODEL_NAME[where], search, TABLEMAP[TABLE::ALBUMS_TAGS], FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], TABLEMAP[TABLE::ARTISTS_TAGS]); // else if(where == FMH::MODEL_KEY::SQL) // queryTxt = search; else queryTxt = QString("SELECT t.*, al.artwork 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").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[where], search); return this->getDBData(queryTxt); } FMH::MODEL_LIST CollectionDB::getPlaylistTracks(const QString &playlist, const FMH::MODEL_KEY &orderBy, const BAE::W &order) { auto queryTxt= QString("SELECT t.* FROM %1 t INNER JOIN %2 tp ON t.%3 = tp.%3 WHERE tp.%4 = '%5' ORDER BY tp.%6 %7").arg(TABLEMAP[TABLE::TRACKS], TABLEMAP[TABLE::TRACKS_PLAYLISTS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], FMH::MODEL_NAME[FMH::MODEL_KEY::PLAYLIST], playlist, FMH::MODEL_NAME[orderBy], SLANG[order]); return this->getDBData(queryTxt); } FMH::MODEL_LIST CollectionDB::getFavTracks(const int &stars, const int &limit, const FMH::MODEL_KEY &orderBy, const BAE::W &order) { auto queryTxt= QString("SELECT * FROM %1 WHERE %2 >= %3 ORDER BY %4 %5 LIMIT %6" ).arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::RATE], QString::number(stars), FMH::MODEL_NAME[orderBy],SLANG[order],QString::number(limit)); return this->getDBData(queryTxt); } FMH::MODEL_LIST CollectionDB::getRecentTracks(const int &limit, const FMH::MODEL_KEY &orderBy, const BAE::W &order) { 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)); return this->getDBData(queryTxt); } FMH::MODEL_LIST CollectionDB::getOnlineTracks(const FMH::MODEL_KEY &orderBy, const BAE::W &order) { auto queryTxt= QString("SELECT * FROM %1 WHERE %2 LIKE \"%3%\" ORDER BY %4 %5" ).arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], YoutubeCachePath, FMH::MODEL_NAME[orderBy], SLANG[order]); return this->getDBData(queryTxt); } QStringList CollectionDB::getSourcesFolders() { auto data = this->getDBData("select * from folders order by strftime(\"%s\", addDate) desc"); if(data.isEmpty()) return QStringList(); return this->dataToList(data, FMH::MODEL_KEY::URL); } FMH::MODEL_LIST CollectionDB::getMostPlayedTracks(const int &greaterThan, const int &limit, const FMH::MODEL_KEY &orderBy, const BAE::W &order) { auto queryTxt = 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)); return this->getDBData(queryTxt); } QString CollectionDB::trackColorTag(const QString &path) { QString color; auto query = this->getDBData(QString("SELECT %1 FROM %2 WHERE %3 = \"%4\"").arg(FMH::MODEL_NAME[FMH::MODEL_KEY::COLOR], TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL],path)); for(auto track : query) color = track[FMH::MODEL_KEY::COLOR]; return color; } QStringList CollectionDB::getTrackTags(const QString &path) { Q_UNUSED(path); return {}; } int CollectionDB::getTrackStars(const QString &path) { int stars = 0; 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)); for(auto track : query) stars = track[FMH::MODEL_KEY::RATE].toInt(); return stars; } //QStringList CollectionDB::getArtistTags(const QString &artist) //{ // QStringList tags; // auto queryStr = QString("SELECT at.%1 FROM %2 at " // "INNER JOIN %3 ta ON ta.%1 = at.%1 " // "WHERE ta.%4 = '%5' " // "AND at.%6 = \"%7\"").arg(FMH::MODEL_NAME[KEY::TAG], // TABLEMAP[TABLE::ARTISTS_TAGS], // TABLEMAP[TABLE::TAGS], // FMH::MODEL_NAME[KEY::CONTEXT], // PULPO::CONTEXT_MAP[PULPO::CONTEXT::ARTIST_SIMILAR], // FMH::MODEL_NAME[KEY::ARTIST],artist); // auto query = this->getDBData(queryStr); // for(auto track : query) // tags << track[KEY::TAG]; // return tags; //} //QStringList CollectionDB::getAlbumTags(const QString &album, const QString &artist) //{ // QStringList tags; // auto queryStr = QString("SELECT at.%1 FROM %2 at " // "INNER JOIN %3 ta ON ta.%1 = at.%1 " // "WHERE ta.%4 = '%5' AND at.%6 = \"%7\" AND at.%8 = \"%9\"").arg(FMH::MODEL_NAME[KEY::TAG], // TABLEMAP[TABLE::ALBUMS_TAGS], // TABLEMAP[TABLE::TAGS], // FMH::MODEL_NAME[KEY::CONTEXT], // PULPO::CONTEXT_MAP[PULPO::CONTEXT::TAG], // FMH::MODEL_NAME[KEY::ALBUM],album, // FMH::MODEL_NAME[KEY::ARTIST],artist); // auto query = this->getDBData(queryStr); // for(auto track : query) // tags << track[KEY::TAG]; // return tags; //} QStringList CollectionDB::getPlaylistsList() { QStringList playlists; auto queryTxt = QString("SELECT %1, %2 FROM %3 ORDER BY %2 DESC").arg(FMH::MODEL_NAME[FMH::MODEL_KEY::PLAYLIST], FMH::MODEL_NAME[FMH::MODEL_KEY::ADDDATE], TABLEMAP[TABLE::PLAYLISTS]); for(auto data : this->getDBData(queryTxt)) playlists << data[FMH::MODEL_KEY::PLAYLIST]; return playlists; } FMH::MODEL_LIST CollectionDB::getPlaylists() { auto queryTxt = QString("SELECT %1, %2 FROM %3 ORDER BY %2 DESC").arg(FMH::MODEL_NAME[FMH::MODEL_KEY::PLAYLIST], FMH::MODEL_NAME[FMH::MODEL_KEY::ADDDATE], TABLEMAP[TABLE::PLAYLISTS]); return this->getDBData(queryTxt); } bool CollectionDB::removeTrack(const QString &path) { auto queryTxt = QString("DELETE FROM %1 WHERE %2 = \"%3\"").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL],path); auto query = this->getQuery(queryTxt); if(query.exec()) { if(cleanAlbums()) cleanArtists(); return true; } return false; } QSqlQuery CollectionDB::getQuery(const QString &queryTxt) { return QSqlQuery(queryTxt, this->m_db); } bool CollectionDB::removeSource(const QString &url) { const auto path = url.endsWith("/") ? url.chopped(1) : url; auto queryTxt = QString("DELETE FROM %1 WHERE %2 LIKE \"%3%\"").arg(TABLEMAP[TABLE::TRACKS_PLAYLISTS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], path); qDebug() << queryTxt; auto query = this->getQuery(queryTxt); if(query.exec()) { queryTxt = QString("DELETE FROM %1 WHERE %2 LIKE \"%3%\"").arg(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::SOURCE], path); query.prepare(queryTxt); if(query.exec()) { queryTxt = QString("DELETE FROM %1 WHERE %2 LIKE \"%3%\"").arg(TABLEMAP[TABLE::SOURCES], FMH::MODEL_NAME[FMH::MODEL_KEY::URL],path); query.prepare(queryTxt); if(query.exec()) { this->removeFolder(path); if(cleanAlbums()) cleanArtists(); return true; } } } return false; } sourceTypes CollectionDB::sourceType(const QString &url) { /*for now*/ Q_UNUSED(url); return sourceTypes::LOCAL; } /*******************OLD STUFF********************/ void CollectionDB::insertArtwork(const FMH::MODEL &track) { auto artist = track[FMH::MODEL_KEY::ARTIST]; auto album =track[FMH::MODEL_KEY::ALBUM]; auto path = track[FMH::MODEL_KEY::ARTWORK]; switch(BAE::albumType(track)) { case TABLE::ALBUMS : { auto queryStr = QString("UPDATE %1 SET %2 = \"%3\" WHERE %4 = \"%5\" AND %6 = \"%7\"").arg(TABLEMAP[TABLE::ALBUMS], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTWORK], path.isEmpty() ? SLANG[W::NONE] : path, FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], album, FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist); auto query = this->getQuery(queryStr); if(!query.exec())qDebug()<<"COULDNT Artwork[cover] inerted into DB"<getQuery(queryStr); if(!query.exec())qDebug()<<"COULDNT Artwork[head] inerted into DB"<getQuery(queryTxt); return query.exec(); } bool CollectionDB::removePlaylist(const QString &playlist) { QString queryTxt; queryTxt = QString("DELETE FROM %1 WHERE %2 = \"%3\"").arg(TABLEMAP[TABLE::TRACKS_PLAYLISTS], FMH::MODEL_NAME[FMH::MODEL_KEY::PLAYLIST],playlist); auto query = this->getQuery(queryTxt); if(!query.exec()) return false; queryTxt = QString("DELETE FROM %1 WHERE %2 = \"%3\"").arg(TABLEMAP[TABLE::PLAYLISTS], FMH::MODEL_NAME[FMH::MODEL_KEY::PLAYLIST],playlist); query.prepare(queryTxt); return query.exec(); } void CollectionDB::removeMissingTracks() { auto tracks = this->getDBData("select url from tracks"); for(auto track : tracks) if(!BAE::fileExists(track[FMH::MODEL_KEY::URL])) this->removeTrack(track[FMH::MODEL_KEY::URL]); } +bool CollectionDB::removeArtwork(const QString &table, const QVariantMap &item) +{ + return this->update(table, {{FMH::MODEL_KEY::ARTWORK, ""}}, item); +} + bool CollectionDB::removeArtist(const QString &artist) { - auto queryTxt = QString("DELETE FROM %1 WHERE %2 = \"%3\" ").arg(TABLEMAP[TABLE::ARTISTS], + const auto queryTxt = QString("DELETE FROM %1 WHERE %2 = \"%3\" ").arg(TABLEMAP[TABLE::ARTISTS], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST],artist); auto query = this->getQuery(queryTxt); return query.exec(); } bool CollectionDB::cleanArtists() { // delete from artists where artist in (select artist from artists except select distinct artist from tracks); - auto queryTxt=QString("DELETE FROM %1 WHERE %2 IN (SELECT %2 FROM %1 EXCEPT SELECT DISTINCT %2 FROM %3)").arg( + 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] ); qDebug()<getQuery(queryTxt); emit this->artistsCleaned(query.numRowsAffected()); return query.exec(); } bool CollectionDB::removeFolder(const QString &url) { - auto queryTxt=QString("DELETE FROM %1 WHERE %2 LIKE \"%3%\"").arg( + const auto queryTxt=QString("DELETE FROM %1 WHERE %2 LIKE \"%3%\"").arg( TABLEMAP[TABLE::FOLDERS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], url); qDebug()<getQuery(queryTxt); return query.exec(); } bool CollectionDB::favTrack(const QString &path, const bool &value) { if(this->update(TABLEMAP[TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::FAV], value ? 1 : 0, FMH::MODEL_NAME[FMH::MODEL_KEY::URL], path)) return true; return false; } bool CollectionDB::removeAlbum(const QString &album, const QString &artist) { 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); auto query = this->getQuery(queryTxt); return query.exec(); } bool CollectionDB::cleanAlbums() { // delete from albums where (album, artist) in (select a.album, a.artist from albums a except select distinct album, artist from tracks); auto queryTxt=QString("DELETE FROM %1 WHERE (%2, %3) IN (SELECT %2, %3 FROM %1 EXCEPT SELECT DISTINCT %2, %3 FROM %4)").arg( TABLEMAP[TABLE::ALBUMS], FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], TABLEMAP[TABLE::TRACKS] ); qDebug()<getQuery(queryTxt); emit albumsCleaned(query.numRowsAffected()); return query.exec(); } diff --git a/db/collectionDB.h b/db/collectionDB.h index 91a763b..a961242 100644 --- a/db/collectionDB.h +++ b/db/collectionDB.h @@ -1,130 +1,131 @@ #ifndef COLLECTIONDB_H #define COLLECTIONDB_H #include #include #include #include #include #include #include #include #include #include #include #include - +#include #include "../utils/bae.h" enum sourceTypes { LOCAL, ONLINE, DEVICE }; class CollectionDB : public QObject { Q_OBJECT public: static CollectionDB *getInstance(); void deleteInstance(); bool insert(const QString &tableName, const QVariantMap &insertData); bool update(const QString &tableName, const FMH::MODEL &updateData, const QVariantMap &where); bool update(const QString &table, const QString &column, const QVariant &newValue, const QVariant &op, const QString &id); - bool remove(); + bool remove(const QString &table, const QString &column, const QVariantMap &where); bool execQuery(QSqlQuery &query) const; bool execQuery(const QString &queryTxt); /*basic public actions*/ void prepareCollectionDB(); bool check_existance(const QString &tableName, const QString &searchId, const QString &search); /* usefull actions */ void insertArtwork(const FMH::MODEL &track); bool addTrack(const FMH::MODEL &track); bool updateTrack(const FMH::MODEL &track); Q_INVOKABLE bool rateTrack(const QString &path, const int &value); Q_INVOKABLE bool colorTagTrack(const QString &path, const QString &value); Q_INVOKABLE QString trackColorTag(const QString &path); bool lyricsTrack(const FMH::MODEL &track, const QString &value); Q_INVOKABLE bool playedTrack(const QString &url, const int &increment = 1); bool wikiTrack(const FMH::MODEL &track, const QString &value); bool tagsTrack(const FMH::MODEL &track, const QString &value, const QString &context); bool albumTrack(const FMH::MODEL &track, const QString &value); bool trackTrack(const FMH::MODEL &track, const QString &value); bool wikiArtist(const FMH::MODEL &track, const QString &value); bool tagsArtist(const FMH::MODEL &track, const QString &value, const QString &context = ""); bool wikiAlbum(const FMH::MODEL &track, QString value); bool tagsAlbum(const FMH::MODEL &track, const QString &value, const QString &context = ""); Q_INVOKABLE bool addPlaylist(const QString &title); bool trackPlaylist(const QString &url, const QString &playlist); bool addFolder(const QString &url); bool removeFolder(const QString &url); bool favTrack(const QString &path, const bool &value); FMH::MODEL_LIST getDBData(const QStringList &urls); - FMH::MODEL_LIST getDBData(const QString &queryTxt); + FMH::MODEL_LIST getDBData(const QString &queryTxt, std::function modifier = nullptr); QVariantList getDBDataQML(const QString &queryTxt); static QStringList dataToList(const FMH::MODEL_LIST &list, const FMH::MODEL_KEY &key); FMH::MODEL_LIST getAlbumTracks(const QString &album, const QString &artist, const FMH::MODEL_KEY &orderBy = FMH::MODEL_KEY::TRACK, const BAE::W &order = BAE::W::ASC); FMH::MODEL_LIST getArtistTracks(const QString &artist, const FMH::MODEL_KEY &orderBy = FMH::MODEL_KEY::ALBUM, const BAE::W &order = BAE::W::ASC); FMH::MODEL_LIST getBabedTracks(const FMH::MODEL_KEY &orderBy = FMH::MODEL_KEY::COUNT, const BAE::W &order = BAE::W::DESC); FMH::MODEL_LIST getSearchedTracks(const FMH::MODEL_KEY &where, const QString &search); FMH::MODEL_LIST getPlaylistTracks(const QString &playlist, const FMH::MODEL_KEY &orderBy = FMH::MODEL_KEY::ADDDATE, const BAE::W &order = BAE::W::DESC); FMH::MODEL_LIST getMostPlayedTracks(const int &greaterThan = 1, const int &limit = 50, const FMH::MODEL_KEY &orderBy = FMH::MODEL_KEY::COUNT, const BAE::W &order = BAE::W::DESC); FMH::MODEL_LIST getFavTracks(const int &stars = 1, const int &limit = 50, const FMH::MODEL_KEY &orderBy = FMH::MODEL_KEY::RATE, const BAE::W &order = BAE::W::DESC); FMH::MODEL_LIST getRecentTracks(const int &limit = 50, const FMH::MODEL_KEY &orderBy = FMH::MODEL_KEY::ADDDATE, const BAE::W &order = BAE::W::DESC); FMH::MODEL_LIST getOnlineTracks(const FMH::MODEL_KEY &orderBy = FMH::MODEL_KEY::ADDDATE, const BAE::W &order = BAE::W::DESC); Q_INVOKABLE QStringList getSourcesFolders(); QStringList getTrackTags(const QString &path); Q_INVOKABLE int getTrackStars(const QString &path); // QStringList getArtistTags(const QString &artist); // QStringList getAlbumTags(const QString &album, const QString &artist); QStringList getArtistAlbums(const QString &artist); FMH::MODEL_LIST getPlaylists(); QStringList getPlaylistsList(); Q_INVOKABLE bool removePlaylistTrack(const QString &url, const QString &playlist); Q_INVOKABLE bool removePlaylist(const QString &playlist); Q_INVOKABLE void removeMissingTracks(); + bool removeArtwork(const QString &table, const QVariantMap &item); bool removeArtist(const QString &artist); bool cleanArtists(); bool removeAlbum(const QString &album, const QString &artist); bool cleanAlbums(); Q_INVOKABLE bool removeSource(const QString &url); Q_INVOKABLE bool removeTrack(const QString &path); QSqlQuery getQuery(const QString &queryTxt); /*useful tools*/ sourceTypes sourceType(const QString &url); void openDB(const QString &name); private: static CollectionDB* instance; QString name; QSqlDatabase m_db; explicit CollectionDB( QObject *parent = nullptr); ~CollectionDB(); public slots: signals: void trackInserted(); void artworkInserted(const FMH::MODEL &albumMap); void DBactionFinished(); void albumsCleaned(const int &amount); void artistsCleaned(const int &amount); }; #endif // COLLECTION_H diff --git a/models/albums/albumsmodel.cpp b/models/albums/albumsmodel.cpp index 53842bb..5224833 100644 --- a/models/albums/albumsmodel.cpp +++ b/models/albums/albumsmodel.cpp @@ -1,274 +1,271 @@ #include "albumsmodel.h" #include "db/collectionDB.h" #include "utils/brain.h" #include AlbumsModel::AlbumsModel(QObject *parent) : BaseList(parent) { this->db = CollectionDB::getInstance(); connect(this, &AlbumsModel::queryChanged, this, &AlbumsModel::setList); } -AlbumsModel::~AlbumsModel() -{ - -} +AlbumsModel::~AlbumsModel() {} FMH::MODEL_LIST AlbumsModel::items() const { return this->list; } void AlbumsModel::setQuery(const QUERY &query) { if(this->query == query) return; this->query = query; - qDebug()<< "setting query"<< this->query; - emit this->queryChanged(); } AlbumsModel::QUERY AlbumsModel::getQuery() const { return this->query; } void AlbumsModel::setSortBy(const SORTBY &sort) { if(this->sort == sort) return; this->sort = sort; - this->preListChanged(); + emit this->preListChanged(); this->sortList(); - this->postListChanged(); + emit this->postListChanged(); emit this->sortByChanged(); } AlbumsModel::SORTBY AlbumsModel::getSortBy() const { return this->sort; } void AlbumsModel::sortList() { const auto key = static_cast(this->sort); qDebug()<< "SORTING LIST BY"<< this->sort; - qSort(this->list.begin(), this->list.end(), [key](const FMH::MODEL &e1, const FMH::MODEL &e2) -> bool + std::sort(this->list.begin(), this->list.end(), [key](const FMH::MODEL &e1, const FMH::MODEL &e2) -> bool { - auto role = key; - + const auto role = key; switch(role) { case FMH::MODEL_KEY::RELEASEDATE: { if(e1[role].toDouble() > e2[role].toDouble()) return true; break; } case FMH::MODEL_KEY::ADDDATE: { - auto currentTime = QDateTime::currentDateTime(); + const auto date1 = QDateTime::fromString(e1[role], Qt::TextDate); + const auto date2 = QDateTime::fromString(e2[role], Qt::TextDate); - auto date1 = QDateTime::fromString(e1[role], Qt::TextDate); - auto date2 = QDateTime::fromString(e2[role], Qt::TextDate); - - if(date1.secsTo(currentTime) < date2.secsTo(currentTime)) + if(date1.secsTo(QDateTime::currentDateTime()) < date2.secsTo(QDateTime::currentDateTime())) return true; - break; } case FMH::MODEL_KEY::ARTIST: case FMH::MODEL_KEY::ALBUM: { const auto str1 = QString(e1[role]).toLower(); const auto str2 = QString(e2[role]).toLower(); if(str1 < str2) return true; break; } default: if(e1[role] < e2[role]) return true; } return false; }); } + + void AlbumsModel::setList() { emit this->preListChanged(); QString m_Query; if(this->query == AlbumsModel::QUERY::ALBUMS) m_Query = "select * from albums order by album asc"; else if(this->query == AlbumsModel::QUERY::ARTISTS) m_Query = "select * from artists order by artist asc"; - this->list = this->db->getDBData(m_Query); - - - qDebug()<< "my LIST" ; + this->list = this->db->getDBData(m_Query, [=](FMH::MODEL &item) + { + if(!FMH::fileExists(item[FMH::MODEL_KEY::ARTWORK])) + { + this->db->removeArtwork(FMH::MODEL_NAME[static_cast(this->query)], FM::toMap(item)); + item[FMH::MODEL_KEY::ARTWORK] = ""; + } + }); this->sortList(); emit this->postListChanged(); } void AlbumsModel::fetchInformation() { qDebug() << "RNUNGING BRAIN EFFORRTS"; QFutureWatcher *watcher = new QFutureWatcher; - QObject::connect(watcher, &QFutureWatcher::finished, [=]() { watcher->deleteLater(); }); auto func = [=]() { QList requests; int index = -1; for(auto &album : this->list) { index++; if(!album[FMH::MODEL_KEY::ARTWORK].isEmpty()) continue; if(BAE::artworkCache(album, FMH::MODEL_KEY::ALBUM)) { + qDebug()<< "cache artwork done" << album; db->insertArtwork(album); - this->updateArtwork(index, album[FMH::MODEL_KEY::ARTWORK]); + emit this->updateModel(index, {FMH::MODEL_KEY::ARTWORK}); continue; } PULPO::REQUEST request; request.track = album; request.ontology = this->query == AlbumsModel::QUERY::ALBUMS ? PULPO::ONTOLOGY::ALBUM : PULPO::ONTOLOGY::ARTIST; request.services = {PULPO::SERVICES::LastFm, PULPO::SERVICES::Spotify, PULPO::SERVICES::MusicBrainz}; request.info = {PULPO::INFO::ARTWORK}; request.callback = [=](PULPO::REQUEST request, PULPO::RESPONSES responses) { qDebug() << "DONE WITH " << request.track ; for(const auto &res : responses) { if(res.context == PULPO::CONTEXT::IMAGE && !res.value.toString().isEmpty()) { qDebug()<<"SAVING ARTWORK FOR: " << request.track[FMH::MODEL_KEY::ALBUM]; auto downloader = new FMH::Downloader; QObject::connect(downloader, &FMH::Downloader::fileSaved, [=](QString path) { qDebug()<< "Saving artwork file to" << path; FMH::MODEL newTrack = request.track; newTrack[FMH::MODEL_KEY::ARTWORK] = path; db->insertArtwork(newTrack); this->updateArtwork(index, path); downloader->deleteLater(); }); QStringList filePathList = res.value.toString().split('/'); const auto format = "." + filePathList.at(filePathList.count() - 1).split(".").last(); QString name = !request.track[FMH::MODEL_KEY::ALBUM].isEmpty() ? request.track[FMH::MODEL_KEY::ARTIST] + "_" + request.track[FMH::MODEL_KEY::ALBUM] : request.track[FMH::MODEL_KEY::ARTIST]; name.replace("/", "-"); name.replace("&", "-"); downloader->setFile(res.value.toString(), BAE::CachePath + name + format); } } }; requests << request; } Pulpo pulpo; QEventLoop loop; QObject::connect(&pulpo, &Pulpo::finished, &loop, &QEventLoop::quit); bool stop = false; QObject::connect(this, &AlbumsModel::destroyed, [&]() { qDebug()<< stop << &stop; stop = true; qDebug()<< stop << &stop; }); for(const auto &req : requests) { if(stop) { loop.quit(); return; } pulpo.request(req); loop.exec(); } }; QFuture t1 = QtConcurrent::run(func); watcher->setFuture(t1); } void AlbumsModel::updateArtwork(const int index, const QString &artwork) { if(index >= this->list.size() || index < 0) return; this->list[index][FMH::MODEL_KEY::ARTWORK] = artwork; emit this->updateModel(index, {FMH::MODEL_KEY::ARTWORK}); } QVariantMap AlbumsModel::get(const int &index) const { if(index >= this->list.size() || index < 0) return QVariantMap(); return FM::toMap(this->list.at(index)); } void AlbumsModel::append(const QVariantMap &item) { if(item.isEmpty()) return; emit this->preItemAppended(); FMH::MODEL model; for(auto key : item.keys()) model.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); this->list << model; emit this->postItemAppended(); } void AlbumsModel::append(const QVariantMap &item, const int &at) { if(item.isEmpty()) return; if(at > this->list.size() || at < 0) return; qDebug()<< "trying to append at" << at << item["title"]; emit this->preItemAppendedAt(at); FMH::MODEL model; for(auto key : item.keys()) model.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); this->list.insert(at, model); emit this->postItemAppended(); } void AlbumsModel::refresh() { this->setList(); } diff --git a/models/albums/albumsmodel.h b/models/albums/albumsmodel.h index 710a81e..04d1ee0 100644 --- a/models/albums/albumsmodel.h +++ b/models/albums/albumsmodel.h @@ -1,66 +1,67 @@ #ifndef ALBUMSMODEL_H #define ALBUMSMODEL_H #include #include "models/baselist.h" class CollectionDB; class AlbumsModel : public BaseList { Q_OBJECT Q_PROPERTY(AlbumsModel::QUERY query READ getQuery WRITE setQuery NOTIFY queryChanged()) Q_PROPERTY(AlbumsModel::SORTBY sortBy READ getSortBy WRITE setSortBy NOTIFY sortByChanged) public: enum SORTBY : uint_fast8_t { ADDDATE = FMH::MODEL_KEY::ADDDATE, RELEASEDATE = FMH::MODEL_KEY::RELEASEDATE, ARTIST = FMH::MODEL_KEY::ARTIST, ALBUM = FMH::MODEL_KEY::ALBUM }; Q_ENUM(SORTBY) enum QUERY : uint_fast8_t { - ARTISTS, ALBUMS + ARTISTS = FMH::MODEL_KEY::ARTIST, + ALBUMS = FMH::MODEL_KEY::ALBUM }; Q_ENUM(QUERY) explicit AlbumsModel(QObject *parent = nullptr); ~AlbumsModel(); FMH::MODEL_LIST items() const override; void setQuery(const AlbumsModel::QUERY &query); AlbumsModel::QUERY getQuery() const; void setSortBy(const AlbumsModel::SORTBY &sort); AlbumsModel::SORTBY getSortBy() const; private: CollectionDB *db; FMH::MODEL_LIST list; void sortList(); void setList(); AlbumsModel::QUERY query; AlbumsModel::SORTBY sort = AlbumsModel::SORTBY::ADDDATE; void updateArtwork(const int index, const QString &artwork); signals: void queryChanged(); void sortByChanged(); public slots: QVariantMap get(const int &index) const override; void append(const QVariantMap &item); void append(const QVariantMap &item, const int &at); void refresh(); void fetchInformation(); }; #endif // ALBUMSMODEL_H diff --git a/vvave.cpp b/vvave.cpp index 4a09371..026ebef 100644 --- a/vvave.cpp +++ b/vvave.cpp @@ -1,168 +1,165 @@ #include "vvave.h" #include "db/collectionDB.h" #include "settings/fileloader.h" #include "utils/brain.h" #if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID)) #include "kde/notify.h" #endif #include #include #ifdef STATIC_MAUIKIT #include "fm.h" #else #include #endif /* * Sets upthe app default config paths * BrainDeamon to get collection information * YoutubeFetcher ? * * */ vvave::vvave(QObject *parent) : QObject(parent) { this->db = CollectionDB::getInstance(); for(const auto &path : {BAE::CachePath, BAE::YoutubeCachePath}) { QDir dirPath(path); if (!dirPath.exists()) dirPath.mkpath("."); } #if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID)) if(!FMH::fileExists(BAE::NotifyDir+"/vvave.notifyrc")) QFile::copy(":/assets/vvave.notifyrc", BAE::NotifyDir+"/vvave.notifyrc"); this->notify = new Notify(this); connect(this->notify, &Notify::babeSong, [this]() { // emit this->babeIt(); }); connect(this->notify, &Notify::skipSong, [this]() { // emit this->skipTrack(); }); #endif } vvave::~vvave() {} void vvave::checkCollection(const QStringList &paths, std::function cb) { QFutureWatcher *watcher = new QFutureWatcher; connect(watcher, &QFutureWatcher::finished, [=]() { const uint newTracks = watcher->future().result(); if(cb) cb(newTracks); watcher->deleteLater(); }); const auto func = [=]() -> uint { auto newPaths = paths; for(auto path : newPaths) if(path.startsWith("file://")) path.replace("file://", ""); return FLoader::getTracks(newPaths); }; QFuture t1 = QtConcurrent::run(func); watcher->setFuture(t1); } //// PUBLIC SLOTS QVariantList vvave::sourceFolders() { const auto sources = this->db->getDBData("select * from sources"); QVariantList res; for(const auto &item : sources) res << FMH::getDirInfo(item[FMH::MODEL_KEY::URL]); return res; } bool vvave::removeSource(const QString &source) { if(!this->getSourceFolders().contains(source)) return false; return this->db->removeSource(source); } QString vvave::moodColor(const int &index) { if(index < BAE::MoodColors.size() && index > -1) return BAE::MoodColors.at(index); else return ""; } void vvave::scanDir(const QStringList &paths) { - this->checkCollection(paths, [=](uint size) - { - emit this->refreshTables(size); - }); + this->checkCollection(paths, [=](uint size) {emit this->refreshTables(size);}); } QStringList vvave::getSourceFolders() { return this->db->getSourcesFolders(); } void vvave::openUrls(const QStringList &urls) { if(urls.isEmpty()) return; QVariantList data; TagInfo info; for(QString url : urls) if(db->check_existance(BAE::TABLEMAP[BAE::TABLE::TRACKS], FMH::MODEL_NAME[FMH::MODEL_KEY::URL], url)) { data << FM::toMap(this->db->getDBData(QStringList() << url).first()); } else { if(info.feed(url)) { auto album = BAE::fixString(info.getAlbum()); auto track= info.getTrack(); auto title = BAE::fixString(info.getTitle()); /* to fix*/ auto artist = BAE::fixString(info.getArtist()); auto genre = info.getGenre(); auto sourceUrl = QFileInfo(url).dir().path(); auto duration = info.getDuration(); auto year = info.getYear(); data << QVariantMap({ {FMH::MODEL_NAME[FMH::MODEL_KEY::URL], url}, {FMH::MODEL_NAME[FMH::MODEL_KEY::TRACK], QString::number(track)}, {FMH::MODEL_NAME[FMH::MODEL_KEY::TITLE], title}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ARTIST], artist}, {FMH::MODEL_NAME[FMH::MODEL_KEY::ALBUM], album}, {FMH::MODEL_NAME[FMH::MODEL_KEY::DURATION],QString::number(duration)}, {FMH::MODEL_NAME[FMH::MODEL_KEY::GENRE], genre}, {FMH::MODEL_NAME[FMH::MODEL_KEY::SOURCE], sourceUrl}, {FMH::MODEL_NAME[FMH::MODEL_KEY::FAV],"0"}, {FMH::MODEL_NAME[FMH::MODEL_KEY::RELEASEDATE], QString::number(year)} }); } } qDebug()<<"opening urls " << urls << data; emit this->openFiles(data); }