QString CPlayer::replace_tokens(QString str, bool hidePlayingState) { QString status_text = ""; switch(GetState()) { case PLAYER_STOPPED: if(GetPlayer()=="") status_text = ""; else status_text = "Stopped"; break; case PLAYER_PAUSED: status_text = "Paused"; break; case PLAYER_PLAYING: status_text = (hidePlayingState? "" : "Playing"); break; } replace_token(str,"title" ,GetTitle()); replace_token(str,"artist" ,GetArtist()); replace_token(str,"album" ,GetAlbum()); replace_token(str,"duration" ,GetDuration(),GetDuration()); replace_token(str,"played" ,GetPosition(),GetDuration()); replace_token(str,"remaining",GetDuration() - GetPosition(),GetDuration()); replace_token(str,"status" ,status_text); replace_token(str,"player" ,GetPlayer()); replace_token(str,"file" ,GetFilePath()); replace_token(str,"shuffle" ,(GetShuffle() ? "Shuffle" : "")); replace_token(str,"repeat" ,(GetRepeat() ? "Repeat" : "")); replace_token(str,"rating" ,QString::number(GetRating())); replace_token(str,"lyrics" ,GetLyrics()); return str; }
void SubsonicLibraryScanner::OnGetAlbumFinished(QNetworkReply* reply) { reply->deleteLater(); pending_requests_.remove(reply); QXmlStreamReader reader(reply); reader.readNextStartElement(); Q_ASSERT(reader.name() == "subsonic-response"); if (reader.attributes().value("status") != "ok") { // TODO: error handling return; } // Read album information reader.readNextStartElement(); Q_ASSERT(reader.name() == "album"); QString album_artist = reader.attributes().value("artist").toString(); // Read song information while (reader.readNextStartElement()) { Q_ASSERT(reader.name() == "song"); Song song; QString id = reader.attributes().value("id").toString(); song.set_title(reader.attributes().value("title").toString()); song.set_album(reader.attributes().value("album").toString()); song.set_track(reader.attributes().value("track").toString().toInt()); song.set_disc(reader.attributes().value("discNumber").toString().toInt()); song.set_artist(reader.attributes().value("artist").toString()); song.set_albumartist(album_artist); song.set_bitrate(reader.attributes().value("bitRate").toString().toInt()); song.set_year(reader.attributes().value("year").toString().toInt()); song.set_genre(reader.attributes().value("genre").toString()); qint64 length = reader.attributes().value("duration").toString().toInt(); length *= kNsecPerSec; song.set_length_nanosec(length); QUrl url = QUrl(QString("subsonic://%1").arg(id)); song.set_url(url); song.set_filesize(reader.attributes().value("size").toString().toInt()); // We need to set these to satisfy the database constraints song.set_directory_id(0); song.set_mtime(0); song.set_ctime(0); songs_ << song; reader.skipCurrentElement(); } // Start the next request if albums remain if (!album_queue_.empty()) { GetAlbum(album_queue_.dequeue()); } // If this was the last response, we're done! if (album_queue_.empty() && pending_requests_.empty()) { scanning_ = false; emit ScanFinished(); } }
void AlbumArtManagerDialog::request () { Model_->clear (); const auto& artist = GetArtist (); const auto& album = GetAlbum (); if (artist.isEmpty () || album.isEmpty ()) return; AAMgr_->CheckAlbumArt (artist, album, true); RequestScheduled_ = false; }
void AlbumArtManagerDialog::on_BrowseButton__released () { const auto& filename = QFileDialog::getOpenFileName (this, tr ("Choose album art"), QDir::homePath (), tr ("Images (*.png *.jpg *.jpeg);;All files (*.*)")); if (filename.isEmpty ()) return; QImage image (filename); if (image.isNull ()) return; handleImages ({ GetArtist (), GetAlbum () }, { image }); }
void SubsonicLibraryScanner::OnGetAlbumListFinished(QNetworkReply* reply, int offset) { reply->deleteLater(); QXmlStreamReader reader(reply); reader.readNextStartElement(); Q_ASSERT(reader.name() == "subsonic-response"); if (reader.attributes().value("status") != "ok") { reader.readNextStartElement(); int error = reader.attributes().value("code").toString().toInt(); // Compatibility with Ampache : // When there is no data, Ampache returns NotFound // whereas Subsonic returns empty albumList2 tag switch (error) { case SubsonicService::ApiError_NotFound: break; default: return; } } int albums_added = 0; reader.readNextStartElement(); Q_ASSERT(reader.name() == "albumList2"); while (reader.readNextStartElement()) { Q_ASSERT(reader.name() == "album"); album_queue_ << reader.attributes().value("id").toString(); albums_added++; reader.skipCurrentElement(); } if (albums_added > 0) { // Non-empty reply means potentially more albums to fetch GetAlbumList(offset + kAlbumChunkSize); } else if (album_queue_.size() == 0) { // Empty reply and no albums means an empty Subsonic server scanning_ = false; } else { // Empty reply but we have some albums, time to start fetching songs // Start up the maximum number of concurrent requests, finished requests get // replaced with new ones for (int i = 0; i < kConcurrentRequests && !album_queue_.empty(); ++i) { GetAlbum(album_queue_.dequeue()); } } }
void AlbumArtManagerDialog::handleImages (const Media::AlbumInfo& info, const QList<QImage>& images) { qDebug () << Q_FUNC_INFO << images.size (); if (info.Album_ != GetAlbum () || info.Artist_ != GetArtist ()) return; auto watcher = new QFutureWatcher<ScaleResult> (); connect (watcher, SIGNAL (finished ()), this, SLOT (handleResized ())); auto worker = [info] (const QImage& image) -> ScaleResult { const auto& scaled = image.scaled (200, 200, Qt::KeepAspectRatio, Qt::SmoothTransformation); return { scaled, image, info }; }; watcher->setFuture (QtConcurrent::mapped (images, std::function<ScaleResult (QImage)> (worker))); }
void AlbumArtManagerDialog::handleResized () { auto watcher = dynamic_cast<QFutureWatcher<ScaleResult>*> (sender ()); watcher->deleteLater (); for (const auto& result : watcher->future ()) { if (result.Info_.Album_ != GetAlbum () || result.Info_.Artist_ != GetArtist ()) continue; auto item = new QStandardItem (); item->setIcon (QIcon (QPixmap::fromImage (result.Image_))); item->setText (QString::fromUtf8 ("%1×%2") .arg (result.SourceImage_.width ()) .arg (result.SourceImage_.height ())); item->setEditable (false); Model_->appendRow (item); FullImages_ << result.SourceImage_; } }
void SubsonicLibraryScanner::OnGetAlbumListFinished( QNetworkReply* reply, int offset) { reply->deleteLater(); QXmlStreamReader reader(reply); reader.readNextStartElement(); Q_ASSERT(reader.name() == "subsonic-response"); if (reader.attributes().value("status") != "ok") { // TODO: error handling return; } int albums_added = 0; reader.readNextStartElement(); Q_ASSERT(reader.name() == "albumList2"); while (reader.readNextStartElement()) { Q_ASSERT(reader.name() == "album"); album_queue_ << reader.attributes().value("id").toString(); albums_added++; reader.skipCurrentElement(); } if (albums_added > 0) { // Non-empty reply means potentially more albums to fetch GetAlbumList(offset + kAlbumChunkSize); } else if (album_queue_.size() == 0) { // Empty reply and no albums means an empty Subsonic server scanning_ = false; } else { // Empty reply but we have some albums, time to start fetching songs // Start up the maximum number of concurrent requests, finished requests get replaced with new ones for (int i = 0; i < kConcurrentRequests && !album_queue_.empty(); ++i) { GetAlbum(album_queue_.dequeue()); } } }
PlaylistItemList SubsonicDynamicPlaylist::GenerateMore(int count) { SubsonicService* service = InternetModel::Service<SubsonicService>(); const int task_id = service->app_->task_manager()->StartTask(tr("Fetching Playlist Items")); BOOST_SCOPE_EXIT((service)(task_id)) { // stop task when we're done service->app_->task_manager()->SetTaskFinished(task_id); } BOOST_SCOPE_EXIT_END QUrl url = service->BuildRequestUrl("GetAlbumList"); QNetworkAccessManager network; if (count > kMaxCount) count = kMaxCount; url.addQueryItem("type", GetTypeString()); url.addQueryItem("size", QString::number(count)); url.addQueryItem("offset", QString::number(offset_)); PlaylistItemList items; QNetworkReply* reply = Send(network, url, service->usesslv3_); WaitForSignal(reply, SIGNAL(finished())); reply->deleteLater(); if (reply->error() != QNetworkReply::NoError) { qLog(Warning) << "HTTP error returned from Subsonic:" << reply->errorString() << ", url:" << url.toString(); return items; // empty } QXmlStreamReader reader(reply); reader.readNextStartElement(); if (reader.name() != "subsonic-response") { qLog(Warning) << "Not a subsonic-response, aboring playlist fetch"; return items; } if (reader.attributes().value("status") != "ok") { reader.readNextStartElement(); int error = reader.attributes().value("code").toString().toInt(); qLog(Warning) << "An error occured fetching data. Code: " << error << " Message: " << reader.attributes().value("message").toString(); } reader.readNextStartElement(); if (reader.name() != "albumList") { qLog(Warning) << "albumList tag expected. Aboring playlist fetch"; return items; } while (reader.readNextStartElement()) { if (reader.name() != "album") { qLog(Warning) << "album tag expected. Aboring playlist fetch"; return items; } qLog(Debug) << "Getting album: " << reader.attributes().value("album").toString(); GetAlbum(service, items, reader.attributes().value("id").toString(), network, service->usesslv3_); reader.skipCurrentElement(); } offset_ += count; return items; }