Added ability to fetch song cover from external resource.
This commit is contained in:
parent
3fadf2ee54
commit
ad761011d6
|
@ -961,6 +961,8 @@ PRIVATE
|
|||
storage/storage_account.h
|
||||
storage/storage_cloud_blob.cpp
|
||||
storage/storage_cloud_blob.h
|
||||
storage/storage_cloud_song_cover.cpp
|
||||
storage/storage_cloud_song_cover.h
|
||||
storage/storage_domain.cpp
|
||||
storage/storage_domain.h
|
||||
storage/storage_facade.cpp
|
||||
|
|
|
@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/media/history_view_gif.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "storage/cache/storage_cache_database.h"
|
||||
#include "storage/storage_cloud_song_cover.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
|
@ -540,6 +541,13 @@ void DocumentData::setattributes(
|
|||
songData->duration = data.vduration().v;
|
||||
songData->title = qs(data.vtitle().value_or_empty());
|
||||
songData->performer = qs(data.vperformer().value_or_empty());
|
||||
|
||||
if (!hasThumbnail()
|
||||
&& !songData->title.isEmpty()
|
||||
&& !songData->performer.isEmpty()) {
|
||||
|
||||
Storage::CloudSongCover::LoadThumbnailFromExternal(this);
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDdocumentAttributeFilename &data) {
|
||||
_filename = qs(data.vfile_name());
|
||||
|
|
151
Telegram/SourceFiles/storage/storage_cloud_song_cover.cpp
Normal file
151
Telegram/SourceFiles/storage/storage_cloud_song_cover.cpp
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "storage/storage_cloud_song_cover.h"
|
||||
|
||||
#include "data/data_cloud_file.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "storage/file_download.h"
|
||||
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QJsonValue>
|
||||
|
||||
namespace Storage::CloudSongCover {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxResponseSize = 1024 * 1024;
|
||||
constexpr auto kDefaultCoverSize = 100;
|
||||
|
||||
struct Responce {
|
||||
const QString artworkUrl;
|
||||
const int size;
|
||||
};
|
||||
|
||||
auto Location(const QString &url) {
|
||||
return DownloadLocation{ PlainUrlLocation{ url } };
|
||||
}
|
||||
|
||||
auto JsonUrl(not_null<SongData*> song) {
|
||||
return QString("https://itunes.apple.com/search?term=" \
|
||||
"%1 %2&entity=song&limit=4").arg(song->performer).arg(song->title);
|
||||
}
|
||||
|
||||
// Dummy JSON responce.
|
||||
// {
|
||||
// "resultCount": 2,
|
||||
// "results": [
|
||||
// {
|
||||
// "artworkUrl100": ""
|
||||
// },
|
||||
// {
|
||||
// "artworkUrl100": ""
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
|
||||
std::optional<Responce> ParseResponce(const QByteArray &response) {
|
||||
if (response.size() >= kMaxResponseSize) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
|
||||
const auto document = QJsonDocument::fromJson(response, &error);
|
||||
|
||||
const auto log = [](const QString &message) {
|
||||
DEBUG_LOG(("Parse Artwork JSON Error: %1.").arg(message));
|
||||
};
|
||||
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
log(error.errorString());
|
||||
return std::nullopt;
|
||||
} else if (!document.isObject()) {
|
||||
log("not an object received in JSON");
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto results = document.object().value("results");
|
||||
if (!results.isArray()) {
|
||||
log("'results' field not found");
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto resultsArray = results.toArray();
|
||||
if (resultsArray.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto artworkUrl = resultsArray.first().toObject()
|
||||
.value("artworkUrl100").toString();
|
||||
if (artworkUrl.isEmpty()) {
|
||||
log("'artworkUrl100' field is empty");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return Responce{ artworkUrl, kDefaultCoverSize };
|
||||
}
|
||||
|
||||
void LoadAndApplyThumbnail(
|
||||
not_null<DocumentData*> document,
|
||||
const Responce &responce) {
|
||||
const auto size = responce.size;
|
||||
const auto imageWithLocation = ImageWithLocation{
|
||||
.location = ImageLocation(Location(responce.artworkUrl), size, size)
|
||||
};
|
||||
|
||||
document->updateThumbnails(
|
||||
QByteArray(),
|
||||
imageWithLocation,
|
||||
ImageWithLocation{ .location = ImageLocation() });
|
||||
|
||||
document->loadThumbnail(Data::FileOrigin());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LoadThumbnailFromExternal(not_null<DocumentData*> document) {
|
||||
const auto songData = document->song();
|
||||
if (!songData
|
||||
|| songData->performer.isEmpty()
|
||||
|| songData->title.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &size = kDefaultCoverSize;
|
||||
const auto jsonLocation = ImageWithLocation{
|
||||
.location = ImageLocation(Location(JsonUrl(songData)), size, size)
|
||||
};
|
||||
|
||||
const auto jsonCloudFile = std::make_shared<Data::CloudFile>();
|
||||
Data::UpdateCloudFile(
|
||||
*jsonCloudFile,
|
||||
jsonLocation,
|
||||
document->owner().cache(),
|
||||
0, // Cache tag.
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
auto done = [=](const QByteArray &result) {
|
||||
if (!jsonCloudFile) {
|
||||
return;
|
||||
}
|
||||
if (const auto responce = ParseResponce(result)) {
|
||||
LoadAndApplyThumbnail(document, *responce);
|
||||
}
|
||||
};
|
||||
Data::LoadCloudFile(
|
||||
&document->session(),
|
||||
*jsonCloudFile,
|
||||
Data::FileOrigin(),
|
||||
LoadFromCloudOrLocal,
|
||||
true,
|
||||
0,
|
||||
[] { return true; },
|
||||
std::move(done));
|
||||
}
|
||||
|
||||
} // namespace Storage::CloudSongCover
|
16
Telegram/SourceFiles/storage/storage_cloud_song_cover.h
Normal file
16
Telegram/SourceFiles/storage/storage_cloud_song_cover.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class DocumentData;
|
||||
|
||||
namespace Storage::CloudSongCover {
|
||||
|
||||
void LoadThumbnailFromExternal(not_null<DocumentData*> document);
|
||||
|
||||
} // namespace Storage::CloudSongCover
|
Loading…
Reference in New Issue
Block a user