Merge tag 'v5.11.1' into dev

This commit is contained in:
AlexeyZavar
2025-02-14 00:23:48 +03:00
188 changed files with 4147 additions and 1082 deletions
+89 -4
View File
@@ -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;
}