/* * Cantata * * Copyright (c) 2011-2022 Craig Drummond * * ---- * * 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 2 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; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "onlinedbservice.h" #include "gui/covers.h" #include "models/roles.h" #include "network/networkaccessmanager.h" #include "qtiocompressor/qtiocompressor.h" #include "db/onlinedb.h" #include OnlineXmlParser::OnlineXmlParser() { thread=new Thread(metaObject()->className()); moveToThread(thread); thread->start(); connect(this, SIGNAL(startParsing(NetworkJob*)), this, SLOT(doParsing(NetworkJob*))); } OnlineXmlParser::~OnlineXmlParser() { } void OnlineXmlParser::start(NetworkJob *job) { emit startParsing(job); } void OnlineXmlParser::doParsing(NetworkJob *job) { QtIOCompressor comp(job->actualJob()); comp.setStreamFormat(QtIOCompressor::GzipFormat); if (comp.open(QIODevice::ReadOnly)) { QXmlStreamReader reader; reader.setDevice(&comp); emit startUpdate(); int artistCount=parse(reader); if (artistCount>0) { emit endUpdate(); emit stats(artistCount); } else { emit error(tr("Failed to parse")); emit abortUpdate(); } } else { emit error(tr("Failed to parse")); } emit complete(); } OnlineDbService::OnlineDbService(LibraryDb *d, QObject *p) : SqlLibraryModel(d, p, T_Genre) , lastPc(-1) , job(nullptr) { connect(Covers::self(), SIGNAL(cover(Song,QImage,QString)), this, SLOT(cover(Song,QImage,QString))); } QVariant OnlineDbService::data(const QModelIndex &index, int role) const { if (!index.isValid()) { switch (role) { case Cantata::Role_TitleText: return title(); case Cantata::Role_SubText: if (!status.isEmpty()) { return status; } if (!stats.isEmpty()) { return stats; } return descr(); case Qt::DecorationRole: return icon(); } } return SqlLibraryModel::data(index, role); } bool OnlineDbService::previouslyDownloaded() const { // Create DB, if it does not already exist static_cast(db)->create(); return 0!=db->getCurrentVersion(); } void OnlineDbService::open() { if (0==rowCount(QModelIndex())) { // Create DB, if it does not already exist static_cast(db)->create(); libraryUpdated(); updateStats(); } } void OnlineDbService::download(bool redownload) { if (job) { return; } if (redownload || !previouslyDownloaded()) { job=NetworkAccessManager::self()->get(QUrl(listingUrl())); connect(job, SIGNAL(downloadPercent(int)), this, SLOT(downloadPercent(int))); connect(job, SIGNAL(finished()), this, SLOT(downloadFinished())); lastPc=-1; downloadPercent(0); } } void OnlineDbService::abort() { if (job) { job->cancelAndDelete(); job=nullptr; } db->abortUpdate(); } void OnlineDbService::cover(const Song &song, const QImage &img, const QString &file) { if (file.isEmpty() || img.isNull() || !song.isFromOnlineService() || song.onlineService()!=name()) { return; } const Item *genre=root ? root->getChild(song.genres[0]) : nullptr; if (genre) { const Item *artist=static_cast(genre)->getChild(song.albumArtistOrComposer()); if (artist) { const Item *album=static_cast(artist)->getChild(song.albumId()); if (album) { QModelIndex idx=index(album->getRow(), 0, index(artist->getRow(), 0, index(genre->getRow(), 0, QModelIndex()))); emit dataChanged(idx, idx); } } } } void OnlineDbService::updateStatus(const QString &msg) { status=msg; emit dataChanged(QModelIndex(), QModelIndex()); } void OnlineDbService::downloadPercent(int pc) { if (lastPc!=pc) { lastPc=pc; updateStatus(tr("Downloading...%1%").arg(pc)); } } void OnlineDbService::downloadFinished() { NetworkJob *reply=qobject_cast(sender()); if (!reply) { return; } if (reply!=job) { reply->deleteLater(); return; } if (reply->ok()) { // Ensure DB is created static_cast(db)->create(); updateStatus(tr("Parsing music list....")); OnlineXmlParser *parser=createParser(); db->clear(); connect(parser, SIGNAL(startUpdate()), static_cast(db), SLOT(startUpdate())); connect(parser, SIGNAL(endUpdate()), static_cast(db), SLOT(endUpdate())); connect(parser, SIGNAL(abortUpdate()), static_cast(db), SLOT(abortUpdate())); connect(parser, SIGNAL(stats(int)), static_cast(db), SLOT(insertStats(int))); connect(parser, SIGNAL(coverUrl(QString,QString,QString)), static_cast(db), SLOT(storeCoverUrl(QString,QString,QString))); connect(parser, SIGNAL(songs(QList*)), static_cast(db), SLOT(insertSongs(QList*))); connect(parser, SIGNAL(complete()), job, SLOT(deleteLater())); connect(parser, SIGNAL(complete()), this, SLOT(updateStats())); connect(parser, SIGNAL(error(QString)), this, SIGNAL(error(QString))); connect(parser, SIGNAL(complete()), parser, SLOT(deleteLater())); parser->start(reply); } else { reply->deleteLater(); updateStatus(QString()); emit error(tr("Failed to download")); } job=nullptr; } void OnlineDbService::updateStats() { int numArtists=static_cast(db)->getStats(); if (numArtists>0) { stats=tr("%n Artist(s)", "", numArtists); } else { stats=QString(); } updateStatus(QString()); } #include "moc_onlinedbservice.cpp"