From ad761011d64493d12a0a2e7628936b944de3cbf2 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 11 Jan 2021 16:58:25 +0300 Subject: [PATCH] Added ability to fetch song cover from external resource. --- Telegram/CMakeLists.txt | 2 + Telegram/SourceFiles/data/data_document.cpp | 8 + .../storage/storage_cloud_song_cover.cpp | 151 ++++++++++++++++++ .../storage/storage_cloud_song_cover.h | 16 ++ 4 files changed, 177 insertions(+) create mode 100644 Telegram/SourceFiles/storage/storage_cloud_song_cover.cpp create mode 100644 Telegram/SourceFiles/storage/storage_cloud_song_cover.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 4ebda77fea..9d8dcff78d 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -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 diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index dc14957915..a615e17f02 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.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()); diff --git a/Telegram/SourceFiles/storage/storage_cloud_song_cover.cpp b/Telegram/SourceFiles/storage/storage_cloud_song_cover.cpp new file mode 100644 index 0000000000..b5168e4d28 --- /dev/null +++ b/Telegram/SourceFiles/storage/storage_cloud_song_cover.cpp @@ -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 +#include +#include +#include + +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 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 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 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 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::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 diff --git a/Telegram/SourceFiles/storage/storage_cloud_song_cover.h b/Telegram/SourceFiles/storage/storage_cloud_song_cover.h new file mode 100644 index 0000000000..8b649f9eaa --- /dev/null +++ b/Telegram/SourceFiles/storage/storage_cloud_song_cover.h @@ -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 document); + +} // namespace Storage::CloudSongCover