mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Merge tag 'v5.11.1' into dev
This commit is contained in:
@@ -335,6 +335,11 @@ void Uploader::upload(
|
||||
if (file->type == SendMediaType::ThemeFile) {
|
||||
document->checkWallPaperProperties();
|
||||
}
|
||||
if (file->videoCover) {
|
||||
session().data().processPhoto(
|
||||
file->videoCover->photo,
|
||||
file->videoCover->photoThumbs);
|
||||
}
|
||||
}
|
||||
_queue.push_back({ itemId, file });
|
||||
if (!_nextTimer.isActive()) {
|
||||
@@ -348,9 +353,26 @@ void Uploader::failed(FullMsgId itemId) {
|
||||
const auto entry = std::move(*i);
|
||||
_queue.erase(i);
|
||||
notifyFailed(entry);
|
||||
} else if (const auto coverId = _videoIdToCoverId.take(itemId)) {
|
||||
if (const auto video = _videoWaitingCover.take(*coverId)) {
|
||||
const auto document = session().data().document(video->id);
|
||||
if (document->uploading()) {
|
||||
document->status = FileUploadFailed;
|
||||
}
|
||||
_documentFailed.fire_copy(video->fullId);
|
||||
}
|
||||
failed(*coverId);
|
||||
} else if (const auto video = _videoWaitingCover.take(itemId)) {
|
||||
_videoIdToCoverId.remove(video->fullId);
|
||||
const auto document = session().data().document(video->id);
|
||||
if (document->uploading()) {
|
||||
document->status = FileUploadFailed;
|
||||
}
|
||||
_documentFailed.fire_copy(video->fullId);
|
||||
}
|
||||
cancelRequests(itemId);
|
||||
maybeFinishFront();
|
||||
|
||||
crl::on_main(this, [=] {
|
||||
maybeSend();
|
||||
});
|
||||
@@ -854,7 +876,8 @@ void Uploader::finishFront() {
|
||||
MTP_int(entry.parts->size()),
|
||||
MTP_string(photoFilename),
|
||||
MTP_bytes(md5));
|
||||
_photoReady.fire({
|
||||
auto ready = UploadedMedia{
|
||||
.id = entry.file->id,
|
||||
.fullId = entry.itemId,
|
||||
.info = {
|
||||
.file = file,
|
||||
@@ -862,7 +885,13 @@ void Uploader::finishFront() {
|
||||
},
|
||||
.options = options,
|
||||
.edit = edit,
|
||||
});
|
||||
};
|
||||
const auto i = _videoWaitingCover.find(entry.itemId);
|
||||
if (i != end(_videoWaitingCover)) {
|
||||
uploadCoverAsPhoto(i->second.fullId, std::move(ready));
|
||||
} else {
|
||||
_photoReady.fire(std::move(ready));
|
||||
}
|
||||
} else if (entry.file->type == SendMediaType::File
|
||||
|| entry.file->type == SendMediaType::ThemeFile
|
||||
|| entry.file->type == SendMediaType::Audio
|
||||
@@ -892,7 +921,8 @@ void Uploader::finishFront() {
|
||||
MTP_string(thumbFilename),
|
||||
MTP_bytes(thumbMd5));
|
||||
}();
|
||||
_documentReady.fire({
|
||||
auto ready = UploadedMedia{
|
||||
.id = entry.file->id,
|
||||
.fullId = entry.itemId,
|
||||
.info = {
|
||||
.file = file,
|
||||
@@ -901,7 +931,12 @@ void Uploader::finishFront() {
|
||||
},
|
||||
.options = options,
|
||||
.edit = edit,
|
||||
});
|
||||
};
|
||||
if (entry.file->videoCover) {
|
||||
uploadVideoCover(std::move(ready), entry.file->videoCover);
|
||||
} else {
|
||||
_documentReady.fire(std::move(ready));
|
||||
}
|
||||
} else if (entry.file->type == SendMediaType::Secure) {
|
||||
_secureReady.fire({
|
||||
entry.itemId,
|
||||
@@ -916,4 +951,54 @@ void Uploader::partFailed(const MTP::Error &error, mtpRequestId requestId) {
|
||||
failed(request.itemId);
|
||||
}
|
||||
|
||||
void Uploader::uploadVideoCover(
|
||||
UploadedMedia &&video,
|
||||
std::shared_ptr<FilePrepareResult> videoCover) {
|
||||
const auto coverId = FullMsgId(
|
||||
videoCover->to.peer,
|
||||
session().data().nextLocalMessageId());
|
||||
_videoIdToCoverId.emplace(video.fullId, coverId);
|
||||
_videoWaitingCover.emplace(coverId, std::move(video));
|
||||
|
||||
upload(coverId, videoCover);
|
||||
}
|
||||
|
||||
void Uploader::uploadCoverAsPhoto(
|
||||
FullMsgId videoId,
|
||||
UploadedMedia &&cover) {
|
||||
const auto coverId = cover.fullId;
|
||||
_api->request(MTPmessages_UploadMedia(
|
||||
MTP_flags(0),
|
||||
MTPstring(), // business_connection_id
|
||||
session().data().peer(videoId.peer)->input,
|
||||
MTP_inputMediaUploadedPhoto(
|
||||
MTP_flags(0),
|
||||
cover.info.file,
|
||||
MTP_vector<MTPInputDocument>(0),
|
||||
MTP_int(0))
|
||||
)).done([=](const MTPMessageMedia &result) {
|
||||
result.match([&](const MTPDmessageMediaPhoto &data) {
|
||||
const auto photo = data.vphoto();
|
||||
if (!photo || photo->type() != mtpc_photo) {
|
||||
failed(coverId);
|
||||
return;
|
||||
}
|
||||
const auto &fields = photo->c_photo();
|
||||
if (const auto coverId = _videoIdToCoverId.take(videoId)) {
|
||||
if (auto video = _videoWaitingCover.take(*coverId)) {
|
||||
video->info.videoCover = MTP_inputPhoto(
|
||||
fields.vid(),
|
||||
fields.vaccess_hash(),
|
||||
fields.vfile_reference());
|
||||
_documentReady.fire(std::move(*video));
|
||||
}
|
||||
}
|
||||
}, [&](const auto &) {
|
||||
failed(coverId);
|
||||
});
|
||||
}).fail([=] {
|
||||
failed(coverId);
|
||||
}).send();
|
||||
}
|
||||
|
||||
} // namespace Storage
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace Storage {
|
||||
constexpr auto kUseBigFilesFrom = 30 * 1024 * 1024;
|
||||
|
||||
struct UploadedMedia {
|
||||
uint64 id = 0;
|
||||
FullMsgId fullId;
|
||||
Api::RemoteFileInfo info;
|
||||
Api::SendOptions options;
|
||||
@@ -134,6 +135,11 @@ private:
|
||||
void partFailed(const MTP::Error &error, mtpRequestId requestId);
|
||||
Request finishRequest(mtpRequestId requestId);
|
||||
|
||||
void uploadVideoCover(
|
||||
UploadedMedia &&video,
|
||||
std::shared_ptr<FilePrepareResult> videoCover);
|
||||
void uploadCoverAsPhoto(FullMsgId videoId, UploadedMedia &&cover);
|
||||
|
||||
void processPhotoProgress(FullMsgId itemId);
|
||||
void processPhotoFailed(FullMsgId itemId);
|
||||
void processDocumentProgress(FullMsgId itemId);
|
||||
@@ -163,6 +169,9 @@ private:
|
||||
crl::time _latestDcIndexRemoved = 0;
|
||||
std::vector<Request> _pendingFromRemovedDcIndices;
|
||||
|
||||
base::flat_map<FullMsgId, FullMsgId> _videoIdToCoverId;
|
||||
base::flat_map<FullMsgId, UploadedMedia> _videoWaitingCover;
|
||||
|
||||
FullMsgId _pausedId;
|
||||
base::Timer _nextTimer, _stopSessionsTimer;
|
||||
|
||||
|
||||
@@ -469,6 +469,7 @@ FileLoadTask::FileLoadTask(
|
||||
const QString &filepath,
|
||||
const QByteArray &content,
|
||||
std::unique_ptr<Ui::PreparedFileInformation> information,
|
||||
std::unique_ptr<FileLoadTask> videoCover,
|
||||
SendMediaType type,
|
||||
const FileLoadTo &to,
|
||||
const TextWithTags &caption,
|
||||
@@ -482,6 +483,7 @@ FileLoadTask::FileLoadTask(
|
||||
, _album(std::move(album))
|
||||
, _filepath(filepath)
|
||||
, _content(content)
|
||||
, _videoCover(std::move(videoCover))
|
||||
, _information(std::move(information))
|
||||
, _type(type)
|
||||
, _caption(caption)
|
||||
@@ -689,6 +691,15 @@ void FileLoadTask::process(Args &&args) {
|
||||
.spoiler = _spoiler,
|
||||
.album = _album,
|
||||
});
|
||||
if (const auto cover = _videoCover.get()) {
|
||||
cover->process();
|
||||
if (const auto &result = cover->peekResult()) {
|
||||
if (result->type == SendMediaType::Photo
|
||||
&& !result->fileparts.empty()) {
|
||||
_result->videoCover = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString filename, filemime;
|
||||
qint64 filesize = 0;
|
||||
@@ -1074,8 +1085,8 @@ void FileLoadTask::finish() {
|
||||
}
|
||||
}
|
||||
|
||||
FilePrepareResult *FileLoadTask::peekResult() const {
|
||||
return _result.get();
|
||||
const std::shared_ptr<FilePrepareResult> &FileLoadTask::peekResult() const {
|
||||
return _result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Ui::PreparedFileInformation> FileLoadTask::readMediaInformation(
|
||||
|
||||
@@ -196,6 +196,8 @@ struct FilePrepareResult {
|
||||
|
||||
std::vector<MTPInputDocument> attachedStickers;
|
||||
|
||||
std::shared_ptr<FilePrepareResult> videoCover;
|
||||
|
||||
void setFileData(const QByteArray &filedata);
|
||||
void setThumbData(const QByteArray &thumbdata);
|
||||
|
||||
@@ -222,6 +224,7 @@ public:
|
||||
const QString &filepath,
|
||||
const QByteArray &content,
|
||||
std::unique_ptr<Ui::PreparedFileInformation> information,
|
||||
std::unique_ptr<FileLoadTask> videoCover,
|
||||
SendMediaType type,
|
||||
const FileLoadTo &to,
|
||||
const TextWithTags &caption,
|
||||
@@ -252,7 +255,8 @@ public:
|
||||
}
|
||||
void finish() override;
|
||||
|
||||
FilePrepareResult *peekResult() const;
|
||||
[[nodiscard]] auto peekResult() const
|
||||
-> const std::shared_ptr<FilePrepareResult> &;
|
||||
|
||||
private:
|
||||
static bool CheckForSong(
|
||||
@@ -281,6 +285,7 @@ private:
|
||||
const std::shared_ptr<SendingAlbum> _album;
|
||||
QString _filepath;
|
||||
QByteArray _content;
|
||||
std::unique_ptr<FileLoadTask> _videoCover;
|
||||
std::unique_ptr<Ui::PreparedFileInformation> _information;
|
||||
crl::time _duration = 0;
|
||||
VoiceWaveform _waveform;
|
||||
|
||||
@@ -47,6 +47,7 @@ using Database = Cache::Database;
|
||||
|
||||
constexpr auto kDelayedWriteTimeout = crl::time(1000);
|
||||
constexpr auto kWriteSearchSuggestionsDelay = 5 * crl::time(1000);
|
||||
constexpr auto kMaxSavedPlaybackPositions = 256;
|
||||
|
||||
constexpr auto kStickersVersionTag = quint32(-1);
|
||||
constexpr auto kStickersSerializeVersion = 4;
|
||||
@@ -96,6 +97,7 @@ enum { // Local Storage Keys
|
||||
lskWebviewTokens = 0x19, // data: QByteArray bots, QByteArray other
|
||||
lskRoundPlaceholder = 0x1a, // no data
|
||||
lskInlineBotsDownloads = 0x1b, // no data
|
||||
lskMediaLastPlaybackPositions = 0x1c, // no data
|
||||
};
|
||||
|
||||
auto EmptyMessageDraftSources()
|
||||
@@ -228,6 +230,7 @@ base::flat_set<QString> Account::collectGoodNames() const {
|
||||
_searchSuggestionsKey,
|
||||
_roundPlaceholderKey,
|
||||
_inlineBotsDownloadsKey,
|
||||
_mediaLastPlaybackPositionsKey,
|
||||
};
|
||||
auto result = base::flat_set<QString>{
|
||||
"map0",
|
||||
@@ -316,6 +319,7 @@ Account::ReadMapResult Account::readMapWith(
|
||||
quint64 searchSuggestionsKey = 0;
|
||||
quint64 roundPlaceholderKey = 0;
|
||||
quint64 inlineBotsDownloadsKey = 0;
|
||||
quint64 mediaLastPlaybackPositionsKey = 0;
|
||||
QByteArray webviewStorageTokenBots, webviewStorageTokenOther;
|
||||
while (!map.stream.atEnd()) {
|
||||
quint32 keyType;
|
||||
@@ -431,6 +435,9 @@ Account::ReadMapResult Account::readMapWith(
|
||||
case lskInlineBotsDownloads: {
|
||||
map.stream >> inlineBotsDownloadsKey;
|
||||
} break;
|
||||
case lskMediaLastPlaybackPositions: {
|
||||
map.stream >> mediaLastPlaybackPositionsKey;
|
||||
} break;
|
||||
case lskWebviewTokens: {
|
||||
map.stream
|
||||
>> webviewStorageTokenBots
|
||||
@@ -474,6 +481,7 @@ Account::ReadMapResult Account::readMapWith(
|
||||
_searchSuggestionsKey = searchSuggestionsKey;
|
||||
_roundPlaceholderKey = roundPlaceholderKey;
|
||||
_inlineBotsDownloadsKey = inlineBotsDownloadsKey;
|
||||
_mediaLastPlaybackPositionsKey = mediaLastPlaybackPositionsKey;
|
||||
_oldMapVersion = mapData.version;
|
||||
_webviewStorageIdBots.token = webviewStorageTokenBots;
|
||||
_webviewStorageIdOther.token = webviewStorageTokenOther;
|
||||
@@ -590,6 +598,7 @@ void Account::writeMap() {
|
||||
}
|
||||
if (_roundPlaceholderKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_inlineBotsDownloadsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_mediaLastPlaybackPositionsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
|
||||
EncryptedDescriptor mapData(mapSize);
|
||||
if (!self.isEmpty()) {
|
||||
@@ -668,6 +677,10 @@ void Account::writeMap() {
|
||||
mapData.stream << quint32(lskInlineBotsDownloads);
|
||||
mapData.stream << quint64(_inlineBotsDownloadsKey);
|
||||
}
|
||||
if (_mediaLastPlaybackPositionsKey) {
|
||||
mapData.stream << quint32(lskMediaLastPlaybackPositions);
|
||||
mapData.stream << quint64(_mediaLastPlaybackPositionsKey);
|
||||
}
|
||||
map.writeEncrypted(mapData, _localKey);
|
||||
|
||||
_mapChanged = false;
|
||||
@@ -699,6 +712,7 @@ void Account::reset() {
|
||||
_searchSuggestionsKey = 0;
|
||||
_roundPlaceholderKey = 0;
|
||||
_inlineBotsDownloadsKey = 0;
|
||||
_mediaLastPlaybackPositionsKey = 0;
|
||||
_oldMapVersion = 0;
|
||||
_fileLocations.clear();
|
||||
_fileLocationPairs.clear();
|
||||
@@ -709,6 +723,7 @@ void Account::reset() {
|
||||
_cacheTotalTimeLimit = Database::Settings().totalTimeLimit;
|
||||
_cacheBigFileTotalSizeLimit = Database::Settings().totalSizeLimit;
|
||||
_cacheBigFileTotalTimeLimit = Database::Settings().totalTimeLimit;
|
||||
_mediaLastPlaybackPosition.clear();
|
||||
|
||||
const auto wvbots = _webviewStorageIdBots.path;
|
||||
const auto wvother = _webviewStorageIdOther.path;
|
||||
@@ -2943,6 +2958,96 @@ Export::Settings Account::readExportSettings() {
|
||||
: Export::Settings();
|
||||
}
|
||||
|
||||
void Account::setMediaLastPlaybackPosition(DocumentId id, crl::time time) {
|
||||
auto &map = _mediaLastPlaybackPosition;
|
||||
const auto i = ranges::find(
|
||||
map,
|
||||
id,
|
||||
&std::pair<DocumentId, crl::time>::first);
|
||||
if (i != map.end()) {
|
||||
if (time > 0) {
|
||||
if (i->second == time) {
|
||||
return;
|
||||
}
|
||||
i->second = time;
|
||||
std::rotate(i, i + 1, map.end());
|
||||
} else {
|
||||
map.erase(i);
|
||||
}
|
||||
} else if (time > 0) {
|
||||
if (map.size() >= kMaxSavedPlaybackPositions) {
|
||||
map.erase(map.begin());
|
||||
}
|
||||
map.emplace_back(id, time);
|
||||
}
|
||||
writeMediaLastPlaybackPositions();
|
||||
}
|
||||
|
||||
crl::time Account::mediaLastPlaybackPosition(DocumentId id) const {
|
||||
const_cast<Account*>(this)->readMediaLastPlaybackPositions();
|
||||
const auto i = ranges::find(
|
||||
_mediaLastPlaybackPosition,
|
||||
id,
|
||||
&std::pair<DocumentId, crl::time>::first);
|
||||
return (i != _mediaLastPlaybackPosition.end()) ? i->second : 0;
|
||||
}
|
||||
|
||||
void Account::writeMediaLastPlaybackPositions() {
|
||||
if (_mediaLastPlaybackPosition.empty()) {
|
||||
if (_mediaLastPlaybackPositionsKey) {
|
||||
ClearKey(_mediaLastPlaybackPositionsKey, _basePath);
|
||||
_mediaLastPlaybackPositionsKey = 0;
|
||||
writeMapDelayed();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!_mediaLastPlaybackPositionsKey) {
|
||||
_mediaLastPlaybackPositionsKey = GenerateKey(_basePath);
|
||||
writeMapQueued();
|
||||
}
|
||||
quint32 size = sizeof(quint32)
|
||||
+ _mediaLastPlaybackPosition.size() * sizeof(quint64) * 2;
|
||||
EncryptedDescriptor data(size);
|
||||
data.stream << quint32(_mediaLastPlaybackPosition.size());
|
||||
for (const auto &[id, time] : _mediaLastPlaybackPosition) {
|
||||
data.stream << quint64(id) << qint64(time);
|
||||
}
|
||||
|
||||
FileWriteDescriptor file(_mediaLastPlaybackPositionsKey, _basePath);
|
||||
file.writeEncrypted(data, _localKey);
|
||||
}
|
||||
|
||||
void Account::readMediaLastPlaybackPositions() {
|
||||
if (_mediaLastPlaybackPositionsRead) {
|
||||
return;
|
||||
}
|
||||
_mediaLastPlaybackPositionsRead = true;
|
||||
if (!_mediaLastPlaybackPositionsKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileReadDescriptor file;
|
||||
if (!ReadEncryptedFile(
|
||||
file,
|
||||
_mediaLastPlaybackPositionsKey,
|
||||
_basePath,
|
||||
_localKey)) {
|
||||
ClearKey(_mediaLastPlaybackPositionsKey, _basePath);
|
||||
_mediaLastPlaybackPositionsKey = 0;
|
||||
writeMapDelayed();
|
||||
return;
|
||||
}
|
||||
|
||||
quint32 size = 0;
|
||||
file.stream >> size;
|
||||
for (auto i = 0; i < size; ++i) {
|
||||
quint64 id = 0;
|
||||
qint64 time = 0;
|
||||
file.stream >> id >> time;
|
||||
_mediaLastPlaybackPosition.emplace_back(DocumentId(id), time);
|
||||
}
|
||||
}
|
||||
|
||||
void Account::writeSearchSuggestionsDelayed() {
|
||||
Expects(_owner->sessionExists());
|
||||
|
||||
|
||||
@@ -150,6 +150,9 @@ public:
|
||||
void writeExportSettings(const Export::Settings &settings);
|
||||
[[nodiscard]] Export::Settings readExportSettings();
|
||||
|
||||
void setMediaLastPlaybackPosition(DocumentId id, crl::time time);
|
||||
[[nodiscard]] crl::time mediaLastPlaybackPosition(DocumentId id) const;
|
||||
|
||||
void writeSearchSuggestionsDelayed();
|
||||
void writeSearchSuggestionsIfNeeded();
|
||||
void writeSearchSuggestions();
|
||||
@@ -261,6 +264,9 @@ private:
|
||||
void readTrustedBots();
|
||||
void writeTrustedBots();
|
||||
|
||||
void readMediaLastPlaybackPositions();
|
||||
void writeMediaLastPlaybackPositions();
|
||||
|
||||
std::optional<RecentHashtagPack> saveRecentHashtags(
|
||||
Fn<RecentHashtagPack()> getPack,
|
||||
const QString &text);
|
||||
@@ -311,6 +317,7 @@ private:
|
||||
FileKey _searchSuggestionsKey = 0;
|
||||
FileKey _roundPlaceholderKey = 0;
|
||||
FileKey _inlineBotsDownloadsKey = 0;
|
||||
FileKey _mediaLastPlaybackPositionsKey = 0;
|
||||
|
||||
qint64 _cacheTotalSizeLimit = 0;
|
||||
qint64 _cacheBigFileTotalSizeLimit = 0;
|
||||
@@ -323,6 +330,9 @@ private:
|
||||
bool _recentHashtagsAndBotsWereRead = false;
|
||||
bool _searchSuggestionsRead = false;
|
||||
bool _inlineBotsDownloadsRead = false;
|
||||
bool _mediaLastPlaybackPositionsRead = false;
|
||||
|
||||
std::vector<std::pair<DocumentId, crl::time>> _mediaLastPlaybackPosition;
|
||||
|
||||
Webview::StorageId _webviewStorageIdBots;
|
||||
Webview::StorageId _webviewStorageIdOther;
|
||||
|
||||
@@ -362,10 +362,22 @@ void UpdateImageDetails(
|
||||
|
||||
bool ApplyModifications(PreparedList &list) {
|
||||
auto applied = false;
|
||||
for (auto &file : list.files) {
|
||||
const auto apply = [&](PreparedFile &file, QSize strictSize = {}) {
|
||||
const auto image = std::get_if<Image>(&file.information->media);
|
||||
const auto guard = gsl::finally([&] {
|
||||
if (!image || strictSize.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
applied = true;
|
||||
file.path = QString();
|
||||
file.content = QByteArray();
|
||||
image->data = image->data.scaled(
|
||||
strictSize,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
});
|
||||
if (!image || !image->modifications) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
applied = true;
|
||||
file.path = QString();
|
||||
@@ -373,6 +385,16 @@ bool ApplyModifications(PreparedList &list) {
|
||||
image->data = Editor::ImageModified(
|
||||
std::move(image->data),
|
||||
image->modifications);
|
||||
};
|
||||
for (auto &file : list.files) {
|
||||
apply(file);
|
||||
if (const auto cover = file.videoCover.get()) {
|
||||
const auto video = file.information
|
||||
? std::get_if<Ui::PreparedFileInformation::Video>(
|
||||
&file.information->media)
|
||||
: nullptr;
|
||||
apply(*cover, video ? video->thumbnail.size() : QSize());
|
||||
}
|
||||
}
|
||||
return applied;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user