Export file thumbs, use in video messages.

This commit is contained in:
John Preston 2018-07-07 23:58:54 +03:00
parent cb8ff398a5
commit cef50e5f52
7 changed files with 143 additions and 81 deletions

View file

@ -119,45 +119,45 @@ pre {
}
.color_red,
.userpic1,
.media_call .thumb,
.media_file .thumb,
.media_live_location .thumb {
.media_call .fill,
.media_file .fill,
.media_live_location .fill {
background-color: #ff5555;
}
.color_green,
.userpic2,
.media_call.success .thumb {
.media_call.success .fill {
background-color: #64bf47;
}
.color_yellow,
.userpic3,
.media_venue .thumb {
.media_venue .fill {
background-color: #ffab00;
}
.color_blue,
.userpic4,
.media_audio_file .thumb,
.media_voice_message .thumb {
.media_audio_file .fill,
.media_voice_message .fill {
background-color: #4f9cd9;
}
.color_purple,
.userpic5,
.media_game .thumb {
.media_game .fill {
background-color: #9884e8;
}
.color_pink,
.userpic6,
.media_invoice .thumb {
.media_invoice .fill {
background-color: #e671a5;
}
.color_sea,
.userpic7,
.media_location .thumb {
.media_location .fill {
background-color: #47bcd1;
}
.color_orange,
.userpic8,
.media_contact .thumb {
.media_contact .fill {
background-color: #ff8c44;
}
.personal_info {
@ -289,10 +289,13 @@ a.block_link:hover {
margin: 0 -10px;
padding: 5px 10px;
}
.default .media .fill,
.default .media .thumb {
width: 48px;
height: 48px;
border-radius: 50%;
}
.default .media .fill {
background-repeat: no-repeat;
background-position: 12px 12px;
background-size: 24px 24px;
@ -399,30 +402,30 @@ a.block_link:hover {
.page_header a.content {
background-image: url(../images/back@2x.png);
}
.media_call .thumb {
.media_call .fill {
background-image: url(../images/media_call@2x.png)
}
.media_contact .thumb {
.media_contact .fill {
background-image: url(../images/media_contact@2x.png)
}
.media_file .thumb {
.media_file .fill {
background-image: url(../images/media_file@2x.png)
}
.media_game .thumb {
.media_game .fill {
background-image: url(../images/media_game@2x.png)
}
.media_live_location .thumb,
.media_location .thumb,
.media_venue .thumb {
.media_live_location .fill,
.media_location .fill,
.media_venue .fill {
background-image: url(../images/media_location@2x.png)
}
.media_audio_file .thumb {
.media_audio_file .fill {
background-image: url(../images/media_music@2x.png)
}
.media_invoice .thumb {
.media_invoice .fill {
background-image: url(../images/media_shop@2x.png)
}
.media_voice_message .thumb {
.media_voice_message .fill {
background-image: url(../images/media_voice@2x.png)
}
}

View file

@ -389,17 +389,36 @@ Document ParseDocument(
data.match([&](const MTPDdocument &data) {
result.id = data.vid.v;
result.date = data.vdate.v;
result.mime = ParseString(data.vmime_type);
ParseAttributes(result, data.vattributes);
result.file.size = data.vsize.v;
result.file.location.dcId = data.vdc_id.v;
result.file.location.data = MTP_inputDocumentFileLocation(
data.vid,
data.vaccess_hash,
data.vversion);
result.mime = ParseString(data.vmime_type);
ParseAttributes(result, data.vattributes);
result.file.suggestedPath = suggestedFolder
const auto path = result.file.suggestedPath = suggestedFolder
+ DocumentFolder(result) + '/'
+ CleanDocumentName(ComputeDocumentName(context, result));
result.thumb = data.vthumb.match([](const MTPDphotoSizeEmpty &) {
return Image();
}, [&](const auto &data) {
auto result = Image();
result.width = data.vw.v;
result.height = data.vh.v;
result.file.location = ParseLocation(data.vlocation);
if constexpr (MTPDphotoCachedSize::Is<decltype(data)>()) {
result.file.content = data.vbytes.v;
result.file.size = result.file.content.size();
} else {
result.file.content = QByteArray();
result.file.size = data.vsize.v;
}
result.file.suggestedPath = path + "_thumb.jpg";
return result;
});
}, [&](const MTPDdocumentEmpty &data) {
result.id = data.vid.v;
});
@ -735,6 +754,24 @@ const File &Media::file() const {
});
}
Image &Media::thumb() {
return content.match([](Document &data) -> Image& {
return data.thumb;
}, [](auto&) -> Image& {
static Image result;
return result;
});
}
const Image &Media::thumb() const {
return content.match([](const Document &data) -> const Image& {
return data.thumb;
}, [](const auto &) -> const Image& {
static const Image result;
return result;
});
}
Media ParseMedia(
ParseMediaContext &context,
const MTPMessageMedia &data,
@ -936,6 +973,14 @@ const File &Message::file() const {
return media.file();
}
Image &Message::thumb() {
return media.thumb();
}
const Image &Message::thumb() const {
return media.thumb();
}
Message ParseMessage(
ParseMediaContext &context,
const MTPMessage &data,

View file

@ -114,6 +114,7 @@ struct Document {
TimeId date = 0;
File file;
Image thumb;
Utf8String name;
Utf8String mime;
@ -292,6 +293,8 @@ struct Media {
File &file();
const File &file() const;
Image &thumb();
const Image &thumb() const;
};
struct ParseMediaContext {
@ -478,6 +481,8 @@ struct Message {
File &file();
const File &file() const;
Image &thumb();
const Image &thumb() const;
};
Message ParseMessage(

View file

@ -139,7 +139,7 @@ struct ApiWrap::UserpicsProcess {
base::optional<Data::UserpicsSlice> slice;
uint64 maxId = 0;
bool lastSlice = false;
int fileIndex = -1;
int fileIndex = 0;
};
struct ApiWrap::OtherDataProcess {
@ -210,7 +210,7 @@ struct ApiWrap::ChatProcess {
Data::ParseMediaContext context;
base::optional<Data::MessagesSlice> slice;
bool lastSlice = false;
int fileIndex = -1;
int fileIndex = 0;
};
@ -727,7 +727,7 @@ void ApiWrap::loadUserpicsFiles(Data::UserpicsSlice &&slice) {
_userpicsProcess->lastSlice = true;
}
_userpicsProcess->slice = std::move(slice);
_userpicsProcess->fileIndex = -1;
_userpicsProcess->fileIndex = 0;
loadNextUserpic();
}
@ -735,14 +735,11 @@ void ApiWrap::loadNextUserpic() {
Expects(_userpicsProcess != nullptr);
Expects(_userpicsProcess->slice.has_value());
auto &list = _userpicsProcess->slice->list;
while (true) {
const auto index = ++_userpicsProcess->fileIndex;
if (index >= list.size()) {
break;
}
for (auto &list = _userpicsProcess->slice->list
; _userpicsProcess->fileIndex < list.size()
; ++_userpicsProcess->fileIndex) {
const auto ready = processFileLoad(
list[index].image.file,
list[_userpicsProcess->fileIndex].image.file,
[=](FileProgress value) { return loadUserpicProgress(value); },
[=](const QString &path) { loadUserpicDone(path); });
if (!ready) {
@ -1213,7 +1210,7 @@ void ApiWrap::loadMessagesFiles(Data::MessagesSlice &&slice) {
_chatProcess->lastSlice = true;
}
_chatProcess->slice = std::move(slice);
_chatProcess->fileIndex = -1;
_chatProcess->fileIndex = 0;
loadNextMessageFile();
}
@ -1222,23 +1219,31 @@ void ApiWrap::loadNextMessageFile() {
Expects(_chatProcess != nullptr);
Expects(_chatProcess->slice.has_value());
auto &list = _chatProcess->slice->list;
while (true) {
const auto index = ++_chatProcess->fileIndex;
if (index >= list.size()) {
break;
}
for (auto &list = _chatProcess->slice->list
; _chatProcess->fileIndex < list.size()
; ++_chatProcess->fileIndex) {
const auto fileProgress = [=](FileProgress value) {
return loadMessageFileProgress(value);
};
const auto ready = processFileLoad(
list[index].file(),
list[_chatProcess->fileIndex].file(),
fileProgress,
[=](const QString &path) { loadMessageFileDone(path); },
&list[index]);
&list[_chatProcess->fileIndex]);
if (!ready) {
return;
}
const auto thumbProgress = [=](FileProgress value) {
return loadMessageThumbProgress(value);
};
const auto thumbReady = processFileLoad(
list[_chatProcess->fileIndex].thumb().file,
thumbProgress,
[=](const QString &path) { loadMessageThumbDone(path); },
&list[_chatProcess->fileIndex]);
if (!thumbReady) {
return;
}
}
finishMessagesSlice();
}
@ -1296,6 +1301,25 @@ void ApiWrap::loadMessageFileDone(const QString &relativePath) {
loadNextMessageFile();
}
bool ApiWrap::loadMessageThumbProgress(FileProgress progress) {
return loadMessageFileProgress(progress);
}
void ApiWrap::loadMessageThumbDone(const QString &relativePath) {
Expects(_chatProcess != nullptr);
Expects(_chatProcess->slice.has_value());
Expects((_chatProcess->fileIndex >= 0)
&& (_chatProcess->fileIndex < _chatProcess->slice->list.size()));
const auto index = _chatProcess->fileIndex;
auto &file = _chatProcess->slice->list[index].thumb().file;
file.relativePath = relativePath;
if (relativePath.isEmpty()) {
file.skipReason = Data::File::SkipReason::Unavailable;
}
loadNextMessageFile();
}
void ApiWrap::finishMessages() {
Expects(_chatProcess != nullptr);
Expects(!_chatProcess->slice.has_value());
@ -1311,7 +1335,8 @@ bool ApiWrap::processFileLoad(
Data::Message *message) {
using SkipReason = Data::File::SkipReason;
if (!file.relativePath.isEmpty()) {
if (!file.relativePath.isEmpty()
|| file.skipReason != SkipReason::None) {
return true;
} else if (!file.location && file.content.isEmpty()) {
file.skipReason = SkipReason::Unavailable;

View file

@ -150,6 +150,8 @@ private:
void loadNextMessageFile();
bool loadMessageFileProgress(FileProgress value);
void loadMessageFileDone(const QString &relativePath);
bool loadMessageThumbProgress(FileProgress value);
void loadMessageThumbDone(const QString &relativePath);
void finishMessagesSlice();
void finishMessages();

View file

@ -262,10 +262,6 @@ Data::Utf8String FormatUsername(const Data::Utf8String &username) {
return username.isEmpty() ? username : ('@' + username);
}
QByteArray FormatFilePath(const Data::File &file) {
return file.relativePath.toUtf8();
}
bool DisplayDate(TimeId date, TimeId previousDate) {
if (!previousDate) {
return true;
@ -353,6 +349,7 @@ struct MediaData {
QByteArray description;
QByteArray status;
QByteArray classes;
QString thumb;
QString link;
};
@ -884,33 +881,6 @@ auto HtmlWriter::Wrap::pushMessage(
"of Telegram Desktop. Please update the application.") };
}
using SkipReason = Data::File::SkipReason;
const auto formatPath = [&](
const Data::File &file,
const QByteArray &label,
const QByteArray &name = QByteArray()) {
Expects(!file.relativePath.isEmpty()
|| file.skipReason != SkipReason::None);
const auto pre = name.isEmpty()
? QByteArray()
: SerializeString(name + ' ');
switch (file.skipReason) {
case SkipReason::Unavailable:
return pre + "(" + label + " unavailable, "
"please try again later)";
case SkipReason::FileSize:
return pre + "(" + label + " exceeds maximum size. "
"Change data exporting settings to download.)";
case SkipReason::FileType:
return pre + "(" + label + " not included. "
"Change data exporting settings to download.)";
case SkipReason::None: return SerializeLink(
FormatFilePath(file),
relativePath(file.relativePath));
}
Unexpected("Skip reason while writing file path.");
};
const auto wrapReplyToLink = [&](const QByteArray &text) {
return "<a href=\"#message"
+ NumberToString(message.replyToMsgId)
@ -1184,8 +1154,16 @@ QByteArray HtmlWriter::Wrap::pushMedia(
}
}));
}
result.append(pushDiv("thumb pull_left"));
result.append(popTag());
if (data.thumb.isEmpty()) {
result.append(pushDiv("fill pull_left"));
result.append(popTag());
} else {
result.append(pushTag("img", {
{ "class", "thumb pull_left" },
{ "src", relativePath(data.thumb).toUtf8() },
{ "empty", "" }
}));
}
result.append(pushDiv("body"));
if (!data.title.isEmpty()) {
result.append(pushDiv("title bold"));
@ -1248,10 +1226,10 @@ MediaData HtmlWriter::Wrap::prepareMediaData(
+ "x"
+ NumberToString(photo.image.height);
result.classes = "media_file"; // #TODO export
result.link = FormatFilePath(photo.image.file);
result.link = photo.image.file.relativePath;
}, [&](const Document &data) {
// #TODO export: sticker + thumb (video, video message) + self destruct (ttl)
result.link = FormatFilePath(data.file);
result.link = data.file.relativePath;
if (data.isSticker) {
result.title = "Sticker";
result.status = data.stickerEmoji;
@ -1259,7 +1237,8 @@ MediaData HtmlWriter::Wrap::prepareMediaData(
} else if (data.isVideoMessage) {
result.title = "Video message";
result.status = FormatDuration(data.duration);
result.classes = "media_file"; // #TODO export
result.thumb = data.thumb.file.relativePath;
result.classes = "media_file";
} else if (data.isVoiceMessage) {
result.title = "Voice message";
result.status = FormatDuration(data.duration);
@ -1292,7 +1271,7 @@ MediaData HtmlWriter::Wrap::prepareMediaData(
result.status = FormatPhoneNumber(data.info.phoneNumber);
if (!data.vcard.content.isEmpty()) {
result.status += " - vCard";
result.link = FormatFilePath(data.vcard);
result.link = data.vcard.relativePath;
}
}, [&](const GeoPoint &data) {
if (message.media.ttl) {

View file

@ -486,6 +486,9 @@ QByteArray SerializeMessage(
pushTTL();
}, [&](const Document &data) {
pushPath(data.file, "file");
if (data.thumb.width > 0) {
pushPath(data.thumb.file, "thumbnail");
}
const auto pushType = [&](const QByteArray &value) {
push("media_type", value);
};