diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index b46a9e68f..11c8b4e0a 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -1660,8 +1660,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 "lng_export_option_info_about" = "Your chosen screen name, username, phone number and profile pictures.";
 "lng_export_option_contacts" = "Contacts list";
 "lng_export_option_contacts_about" = "If you allow access, contacts are continuously synced with Telegram. You can adjust this in Settings > Privacy & Security on mobile devices.";
-"lng_export_option_sessions" = "Sessions list";
+"lng_export_option_sessions" = "Active sessions";
 "lng_export_option_sessions_about" = "We store this to display your connected devices in Settings > Privacy & Security > Active Sessions. Terminating a session removes this data from Telegram servers.";
+"lng_export_header_other" = "Other";
+"lng_export_option_other" = "Miscellaneous data";
+"lng_export_option_other_about" = "Other types of data not mentioned above. (beta)";
 "lng_export_header_chats" = "Chat export settings";
 "lng_export_option_personal_chats" = "Personal chats";
 "lng_export_option_bot_chats" = "Bot chats";
@@ -1705,7 +1708,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 "lng_export_total_size" = "Total size: {size}.";
 "lng_export_folder" = "Choose export folder";
 "lng_export_invalid" = "Sorry, you have started a new data export, so this data export is now cancelled.";
-"lng_export_delay" = "Sorry, for security reasons, you will be able to begin downloading your data in 24 hours. We have notified all your devices about the export request to make sure it's authorized and give you time to react if it's not.\n\nPlease come back on {date} and repeat the request using the same device.";
+"lng_export_delay" = "Sorry, for security reasons, you will be able to begin downloading your data in {hours}. We have notified all your devices about the export request to make sure it's authorized and give you time to react if it's not.\n\nPlease come back on {date} and repeat the request using the same device.";
+"lng_export_delay_less_than_hour" = "less than an hour";
+"lng_export_delay_hours#one" = "{count} hour";
+"lng_export_delay_hours#other" = "{count} hours";
 "lng_export_suggest_title" = "Data export ready";
 "lng_export_suggest_text" = "You can now download the data you requested. Start exporting data?";
 "lng_export_suggest_cancel" = "Not now";
diff --git a/Telegram/Resources/scheme.tl b/Telegram/Resources/scheme.tl
index 48e6a2e77..7b022aaa4 100644
--- a/Telegram/Resources/scheme.tl
+++ b/Telegram/Resources/scheme.tl
@@ -192,6 +192,7 @@ inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLo
 inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
 inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation;
 inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
+inputTakeoutFileLocation#29be5899 = InputFileLocation;
 
 inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;
 
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index 0f96a9643..ad57e3962 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -71,6 +71,10 @@ Session::Session(not_null<AuthSession*> session)
 }
 
 void Session::startExport() {
+	if (_exportPanel) {
+		_exportPanel->activatePanel();
+		return;
+	}
 	_export = std::make_unique<Export::ControllerWrap>();
 	_exportPanel = std::make_unique<Export::View::PanelController>(
 		_export.get());
diff --git a/Telegram/SourceFiles/export/export_api_wrap.cpp b/Telegram/SourceFiles/export/export_api_wrap.cpp
index c7e5c404a..7f5316b54 100644
--- a/Telegram/SourceFiles/export/export_api_wrap.cpp
+++ b/Telegram/SourceFiles/export/export_api_wrap.cpp
@@ -62,6 +62,8 @@ LocationKey ComputeLocationKey(const Data::FileLocation &value) {
 	}, [&](const MTPDinputEncryptedFileLocation &data) {
 		result.type |= (4ULL << 24);
 		result.id = data.vid.v;
+	}, [&](const MTPDinputTakeoutFileLocation &data) {
+		result.type |= (5ULL << 24);
 	});
 	return result;
 }
@@ -140,6 +142,11 @@ struct ApiWrap::UserpicsProcess {
 	int fileIndex = -1;
 };
 
+struct ApiWrap::OtherDataProcess {
+	Data::File file;
+	FnMut<void(Data::File&&)> done;
+};
+
 struct ApiWrap::FileProcess {
 	FileProcess(const QString &path, Output::Stats *stats);
 
@@ -259,7 +266,8 @@ auto ApiWrap::splitRequest(int index, Request &&request) {
 }
 
 auto ApiWrap::fileRequest(const Data::FileLocation &location, int offset) {
-	Expects(location.dcId != 0);
+	Expects(location.dcId != 0
+		|| location.data.type() == mtpc_inputTakeoutFileLocation);
 	Expects(_takeoutId.has_value());
 
 	return std::move(_mtp.request(MTPInvokeWithTakeout<MTPupload_GetFile>(
@@ -269,7 +277,14 @@ auto ApiWrap::fileRequest(const Data::FileLocation &location, int offset) {
 			MTP_int(offset),
 			MTP_int(kFileChunkSize))
 	)).fail([=](RPCError &&result) {
-		error(std::move(result));
+		if (result.type() == qstr("TAKEOUT_FILE_EMPTY")
+			&& _otherDataProcess != nullptr) {
+			filePartDone(0, MTP_upload_file(MTP_storage_filePartial(),
+				MTP_int(0),
+				MTP_bytes(QByteArray())));
+		} else {
+			error(std::move(result));
+		}
 	}).toDC(MTP::ShiftDcId(location.dcId, MTP::kExportMediaDcShift)));
 }
 
@@ -376,6 +391,8 @@ void ApiWrap::requestSplitRanges() {
 void ApiWrap::requestDialogsCount() {
 	Expects(_startProcess != nullptr);
 
+	validateSplits();
+
 	splitRequest(_startProcess->splitIndex, MTPmessages_GetDialogs(
 		MTP_flags(0),
 		MTP_int(0), // offset_date
@@ -467,7 +484,7 @@ void ApiWrap::requestDialogsList(
 void ApiWrap::validateSplits() {
 	if (_splits.empty()) {
 		_splits.push_back(MTP_messageRange(
-			MTP_int(0),
+			MTP_int(1),
 			MTP_int(std::numeric_limits<int>::max())));
 	}
 }
@@ -524,6 +541,29 @@ void ApiWrap::requestPersonalInfo(FnMut<void(Data::PersonalInfo&&)> done) {
 	}).send();
 }
 
+void ApiWrap::requestOtherData(
+		const QString &suggestedPath,
+		FnMut<void(Data::File&&)> done) {
+	Expects(_otherDataProcess == nullptr);
+
+	_otherDataProcess = std::make_unique<OtherDataProcess>();
+	_otherDataProcess->done = std::move(done);
+	_otherDataProcess->file.location.data = MTP_inputTakeoutFileLocation();
+	_otherDataProcess->file.suggestedPath = suggestedPath;
+	loadFile(
+		_otherDataProcess->file,
+		[](FileProgress progress) { return true; },
+		[=](const QString &result) { otherDataDone(result); });
+}
+
+void ApiWrap::otherDataDone(const QString &relativePath) {
+	Expects(_otherDataProcess != nullptr);
+
+	_otherDataProcess->file.relativePath = relativePath;
+	const auto process = base::take(_otherDataProcess);
+	process->done(std::move(process->file));
+}
+
 void ApiWrap::requestUserpics(
 		FnMut<bool(Data::UserpicsInfo&&)> start,
 		Fn<bool(DownloadProgress)> progress,
@@ -1185,7 +1225,8 @@ void ApiWrap::loadFile(
 		Fn<bool(FileProgress)> progress,
 		FnMut<void(QString)> done) {
 	Expects(_fileProcess == nullptr);
-	Expects(file.location.dcId != 0);
+	Expects(file.location.dcId != 0
+		|| file.location.data.type() == mtpc_inputTakeoutFileLocation);
 
 	_fileProcess = prepareFileProcess(file);
 	_fileProcess->progress = std::move(progress);
@@ -1265,6 +1306,11 @@ void ApiWrap::filePartDone(int offset, const MTPupload_File &result) {
 			error("Empty bytes received in file part.");
 			return;
 		}
+		const auto result = _fileProcess->file.writeBlock({});
+		if (!result) {
+			ioError(result);
+			return;
+		}
 	} else {
 		using Request = FileProcess::Request;
 		auto &requests = _fileProcess->requests;
diff --git a/Telegram/SourceFiles/export/export_api_wrap.h b/Telegram/SourceFiles/export/export_api_wrap.h
index 32f5c0833..7e5a59c6e 100644
--- a/Telegram/SourceFiles/export/export_api_wrap.h
+++ b/Telegram/SourceFiles/export/export_api_wrap.h
@@ -58,6 +58,10 @@ public:
 
 	void requestPersonalInfo(FnMut<void(Data::PersonalInfo&&)> done);
 
+	void requestOtherData(
+		const QString &suggestedPath,
+		FnMut<void(Data::File&&)> done);
+
 	struct DownloadProgress {
 		QString path;
 		int itemIndex = 0;
@@ -91,6 +95,7 @@ private:
 	struct StartProcess;
 	struct ContactsProcess;
 	struct UserpicsProcess;
+	struct OtherDataProcess;
 	struct FileProcess;
 	struct FileProgress;
 	struct ChatsProcess;
@@ -116,6 +121,8 @@ private:
 	void finishUserpicsSlice();
 	void finishUserpics();
 
+	void otherDataDone(const QString &relativePath);
+
 	void validateSplits();
 
 	void requestDialogsSlice();
@@ -186,6 +193,7 @@ private:
 	std::unique_ptr<LoadedFileCache> _fileCache;
 	std::unique_ptr<ContactsProcess> _contactsProcess;
 	std::unique_ptr<UserpicsProcess> _userpicsProcess;
+	std::unique_ptr<OtherDataProcess> _otherDataProcess;
 	std::unique_ptr<FileProcess> _fileProcess;
 	std::unique_ptr<LeftChannelsProcess> _leftChannelsProcess;
 	std::unique_ptr<DialogsProcess> _dialogsProcess;
diff --git a/Telegram/SourceFiles/export/export_controller.cpp b/Telegram/SourceFiles/export/export_controller.cpp
index 7cb980877..985ed971b 100644
--- a/Telegram/SourceFiles/export/export_controller.cpp
+++ b/Telegram/SourceFiles/export/export_controller.cpp
@@ -57,6 +57,7 @@ private:
 	void exportUserpics();
 	void exportContacts();
 	void exportSessions();
+	void exportOtherData();
 	void exportDialogs();
 	void exportNextDialog();
 	void exportLeftChannels();
@@ -73,6 +74,7 @@ private:
 	ProcessingState stateUserpics(const DownloadProgress &progress) const;
 	ProcessingState stateContacts() const;
 	ProcessingState stateSessions() const;
+	ProcessingState stateOtherData() const;
 	ProcessingState stateLeftChannels(
 		const DownloadProgress &progress) const;
 	ProcessingState stateDialogs(const DownloadProgress &progress) const;
@@ -250,6 +252,9 @@ void Controller::fillExportSteps() {
 	if (_settings.types & Type::Sessions) {
 		_steps.push_back(Step::Sessions);
 	}
+	if (_settings.types & Type::OtherData) {
+		_steps.push_back(Step::OtherData);
+	}
 	if (_settings.types & Type::AnyChatsMask) {
 		_steps.push_back(Step::Dialogs);
 	}
@@ -286,6 +291,9 @@ void Controller::fillSubstepsInSteps(const ApiWrap::StartInfo &info) {
 	if (_settings.types & Settings::Type::Sessions) {
 		push(Step::Sessions, 1);
 	}
+	if (_settings.types & Settings::Type::OtherData) {
+		push(Step::OtherData, 1);
+	}
 	if (_settings.types & Settings::Type::GroupsChannelsMask) {
 		push(Step::LeftChannels, info.leftChannelsCount);
 	}
@@ -321,6 +329,7 @@ void Controller::exportNext() {
 	case Step::Userpics: return exportUserpics();
 	case Step::Contacts: return exportContacts();
 	case Step::Sessions: return exportSessions();
+	case Step::OtherData: return exportOtherData();
 	case Step::LeftChannels: return exportLeftChannels();
 	case Step::Dialogs: return exportDialogs();
 	}
@@ -329,7 +338,6 @@ void Controller::exportNext() {
 
 void Controller::initialize() {
 	setState(stateInitializing());
-
 	_api.startExport(_settings, &_stats, [=](ApiWrap::StartInfo info) {
 		if (ioCatchError(_writer->start(_settings, &_stats))) {
 			return;
@@ -340,6 +348,7 @@ void Controller::initialize() {
 }
 
 void Controller::collectLeftChannels() {
+	setState(stateLeftChannelsList(0));
 	_api.requestLeftChannelsList([=](int count) {
 		setState(stateLeftChannelsList(count));
 		return true;
@@ -350,6 +359,7 @@ void Controller::collectLeftChannels() {
 }
 
 void Controller::collectDialogsList() {
+	setState(stateDialogsList(0));
 	_api.requestDialogsList([=](int count) {
 		setState(stateDialogsList(count));
 		return true;
@@ -360,6 +370,7 @@ void Controller::collectDialogsList() {
 }
 
 void Controller::exportPersonalInfo() {
+	setState(statePersonalInfo());
 	_api.requestPersonalInfo([=](Data::PersonalInfo &&result) {
 		if (ioCatchError(_writer->writePersonal(result))) {
 			return;
@@ -395,6 +406,7 @@ void Controller::exportUserpics() {
 }
 
 void Controller::exportContacts() {
+	setState(stateContacts());
 	_api.requestContacts([=](Data::ContactsList &&result) {
 		if (ioCatchError(_writer->writeContactsList(result))) {
 			return;
@@ -404,6 +416,7 @@ void Controller::exportContacts() {
 }
 
 void Controller::exportSessions() {
+	setState(stateSessions());
 	_api.requestSessions([=](Data::SessionsList &&result) {
 		if (ioCatchError(_writer->writeSessionsList(result))) {
 			return;
@@ -412,6 +425,17 @@ void Controller::exportSessions() {
 	});
 }
 
+void Controller::exportOtherData() {
+	setState(stateOtherData());
+	const auto relativePath = "lists/other_data.json";
+	_api.requestOtherData(relativePath, [=](Data::File &&result) {
+		if (ioCatchError(_writer->writeOtherData(result))) {
+			return;
+		}
+		exportNext();
+	});
+}
+
 void Controller::exportDialogs() {
 	if (ioCatchError(_writer->writeDialogsStart(_dialogsInfo))) {
 		return;
@@ -573,6 +597,10 @@ ProcessingState Controller::stateSessions() const {
 	return prepareState(Step::Sessions);
 }
 
+ProcessingState Controller::stateOtherData() const {
+	return prepareState(Step::OtherData);
+}
+
 ProcessingState Controller::stateLeftChannels(
 		const DownloadProgress & progress) const {
 	const auto step = Step::LeftChannels;
diff --git a/Telegram/SourceFiles/export/export_controller.h b/Telegram/SourceFiles/export/export_controller.h
index 9d38f1882..ac1928438 100644
--- a/Telegram/SourceFiles/export/export_controller.h
+++ b/Telegram/SourceFiles/export/export_controller.h
@@ -33,6 +33,7 @@ struct ProcessingState {
 		Userpics,
 		Contacts,
 		Sessions,
+		OtherData,
 		LeftChannels,
 		Dialogs,
 	};
diff --git a/Telegram/SourceFiles/export/export_settings.cpp b/Telegram/SourceFiles/export/export_settings.cpp
index 082f90bcd..d44e17fcb 100644
--- a/Telegram/SourceFiles/export/export_settings.cpp
+++ b/Telegram/SourceFiles/export/export_settings.cpp
@@ -37,7 +37,7 @@ bool Settings::validate() const {
 		return false;
 	} else if ((fullChats & MustNotBeFull) != 0) {
 		return false;
-	} else if (format != Format::Text && format != Format::Json) {
+	} else if (format != Format::Html && format != Format::Json) {
 		return false;
 	} else if (!media.validate()) {
 		return false;
diff --git a/Telegram/SourceFiles/export/export_settings.h b/Telegram/SourceFiles/export/export_settings.h
index 129d43f73..123c2c624 100644
--- a/Telegram/SourceFiles/export/export_settings.h
+++ b/Telegram/SourceFiles/export/export_settings.h
@@ -50,12 +50,13 @@ struct Settings {
 		Userpics            = 0x002,
 		Contacts            = 0x004,
 		Sessions            = 0x008,
-		PersonalChats       = 0x010,
-		BotChats            = 0x020,
-		PrivateGroups       = 0x040,
-		PublicGroups        = 0x080,
-		PrivateChannels     = 0x100,
-		PublicChannels      = 0x200,
+		OtherData           = 0x010,
+		PersonalChats       = 0x020,
+		BotChats            = 0x040,
+		PrivateGroups       = 0x080,
+		PublicGroups        = 0x100,
+		PrivateChannels     = 0x200,
+		PublicChannels      = 0x400,
 
 		GroupsMask          = PrivateGroups | PublicGroups,
 		ChannelsMask        = PrivateChannels | PublicChannels,
@@ -63,7 +64,7 @@ struct Settings {
 		NonChannelChatsMask = PersonalChats | BotChats | PrivateGroups,
 		AnyChatsMask        = PersonalChats | BotChats | GroupsChannelsMask,
 		NonChatsMask        = PersonalInfo | Userpics | Contacts | Sessions,
-		AllMask             = NonChatsMask | AnyChatsMask,
+		AllMask             = NonChatsMask | OtherData | AnyChatsMask,
 	};
 	using Types = base::flags<Type>;
 	friend inline constexpr auto is_flag_type(Type) { return true; };
diff --git a/Telegram/SourceFiles/export/output/export_output_abstract.h b/Telegram/SourceFiles/export/output/export_output_abstract.h
index b0a485ca9..e28ae4e7a 100644
--- a/Telegram/SourceFiles/export/output/export_output_abstract.h
+++ b/Telegram/SourceFiles/export/output/export_output_abstract.h
@@ -19,6 +19,7 @@ struct SessionsList;
 struct DialogsInfo;
 struct DialogInfo;
 struct MessagesSlice;
+struct File;
 } // namespace Data
 
 struct Settings;
@@ -60,6 +61,9 @@ public:
 	[[nodiscard]] virtual Result writeSessionsList(
 		const Data::SessionsList &data) = 0;
 
+	[[nodiscard]] virtual Result writeOtherData(
+		const Data::File &data) = 0;
+
 	[[nodiscard]] virtual Result writeDialogsStart(
 		const Data::DialogsInfo &data) = 0;
 	[[nodiscard]] virtual Result writeDialogStart(
diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp
index da1c404a6..9bfda6cd3 100644
--- a/Telegram/SourceFiles/export/output/export_output_html.cpp
+++ b/Telegram/SourceFiles/export/output/export_output_html.cpp
@@ -637,7 +637,7 @@ QByteArray HtmlWriter::Wrap::end() const {
 }
 
 HtmlWriter::Wrap::~Wrap() {
-	Expects(_file.empty() || _closed);
+	(void)close();
 }
 
 HtmlWriter::HtmlWriter() = default;
@@ -1019,6 +1019,17 @@ Result HtmlWriter::writeWebSessions(const Data::SessionsList &data) {
 	return _summary->writeBlock(header);
 }
 
+Result HtmlWriter::writeOtherData(const Data::File &data) {
+	Expects(_summary != nullptr);
+
+	const auto header = SerializeLink(
+		"Other data",
+		_summary->relativePath(data))
+		+ kLineBreak
+		+ kLineBreak;
+	return _summary->writeBlock(header);
+}
+
 Result HtmlWriter::writeDialogsStart(const Data::DialogsInfo &data) {
 	return writeChatsStart(
 		data,
@@ -1123,7 +1134,9 @@ Result HtmlWriter::writeChatSlice(const Data::MessagesSlice &data) {
 			data.peers,
 			_settings.internalLinksDomain));
 	}
-	const auto full = kLineBreak + JoinList(kLineBreak, list);
+	const auto full = _chat->empty()
+		? JoinList(kLineBreak, list)
+		: kLineBreak + JoinList(kLineBreak, list);
 	return _chat->writeBlock(full);
 }
 
@@ -1172,7 +1185,7 @@ Result HtmlWriter::writeChatEnd() {
 		}
 		Unexpected("Dialog type in TypeString.");
 	};
-	return _chats->writeBlock(SerializeKeyValue({
+	return _chats->writeBlock(kLineBreak + SerializeKeyValue({
 		{ "Name", SerializeString(NameString(_dialog, _dialog.type)) },
 		{ "Type", SerializeString(TypeString(_dialog.type)) },
 		{
@@ -1190,7 +1203,7 @@ Result HtmlWriter::writeChatEnd() {
 						(_dialog.relativePath + "messages.html")))
 				: QByteArray())
 		}
-	}) + kLineBreak);
+	}));
 }
 
 Result HtmlWriter::writeChatsEnd() {
diff --git a/Telegram/SourceFiles/export/output/export_output_html.h b/Telegram/SourceFiles/export/output/export_output_html.h
index fad9725b2..6a1fd8e2f 100644
--- a/Telegram/SourceFiles/export/output/export_output_html.h
+++ b/Telegram/SourceFiles/export/output/export_output_html.h
@@ -35,6 +35,8 @@ public:
 
 	Result writeSessionsList(const Data::SessionsList &data) override;
 
+	Result writeOtherData(const Data::File &data) override;
+
 	Result writeDialogsStart(const Data::DialogsInfo &data) override;
 	Result writeDialogStart(const Data::DialogInfo &data) override;
 	Result writeDialogSlice(const Data::MessagesSlice &data) override;
diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp
index 5627b9083..9300b3009 100644
--- a/Telegram/SourceFiles/export/output/export_output_json.cpp
+++ b/Telegram/SourceFiles/export/output/export_output_json.cpp
@@ -13,6 +13,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "core/utils.h"
 
 #include <QtCore/QDateTime>
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonValue>
 
 namespace Export {
 namespace Output {
@@ -793,6 +797,77 @@ Result JsonWriter::writeSessionsList(const Data::SessionsList &data) {
 	return Result::Success();
 }
 
+Result JsonWriter::writeOtherData(const Data::File &data) {
+	Expects(_output != nullptr);
+	Expects(data.skipReason == Data::File::SkipReason::None);
+	Expects(!data.relativePath.isEmpty());
+
+	QFile f(pathWithRelativePath(data.relativePath));
+	if (!f.open(QIODevice::ReadOnly)) {
+		return Result(Result::Type::FatalError, f.fileName());
+	}
+	const auto content = f.readAll();
+	if (content.isEmpty()) {
+		return Result::Success();
+	}
+	auto error = QJsonParseError{ 0, QJsonParseError::NoError };
+	const auto document = QJsonDocument::fromJson(content, &error);
+	if (error.error != QJsonParseError::NoError) {
+		return Result(Result::Type::FatalError, f.fileName());
+	}
+	auto block = prepareObjectItemStart("other_data");
+	Fn<void(const QJsonObject &data)> pushObject;
+	Fn<void(const QJsonArray &data)> pushArray;
+	Fn<void(const QJsonValue &data)> pushValue;
+	pushObject = [&](const QJsonObject &data) {
+		block.append(pushNesting(Context::kObject));
+		for (auto i = data.begin(); i != data.end(); ++i) {
+			if ((*i).type() != QJsonValue::Undefined) {
+				block.append(prepareObjectItemStart(i.key().toUtf8()));
+				pushValue(*i);
+			}
+		}
+		block.append(popNesting());
+	};
+	pushArray = [&](const QJsonArray &data) {
+		block.append(pushNesting(Context::kArray));
+		for (auto i = data.begin(); i != data.end(); ++i) {
+			if ((*i).type() != QJsonValue::Undefined) {
+				block.append(prepareArrayItemStart());
+				pushValue(*i);
+			}
+		}
+		block.append(popNesting());
+	};
+	pushValue = [&](const QJsonValue &data) {
+		switch (data.type()) {
+		case QJsonValue::Null:
+			block.append("null");
+			return;
+		case QJsonValue::Bool:
+			block.append(data.toBool() ? "true" : "false");
+			return;
+		case QJsonValue::Double:
+			block.append(Data::NumberToString(data.toDouble()));
+			return;
+		case QJsonValue::String:
+			block.append(SerializeString(data.toString().toUtf8()));
+			return;
+		case QJsonValue::Array:
+			return pushArray(data.toArray());
+		case QJsonValue::Object:
+			return pushObject(data.toObject());
+		}
+		Unexpected("Type of json valuein JsonWriter::writeOtherData.");
+	};
+	if (document.isObject()) {
+		pushObject(document.object());
+	} else {
+		pushArray(document.array());
+	}
+	return _output->writeBlock(block);
+}
+
 Result JsonWriter::writeSessions(const Data::SessionsList &data) {
 	Expects(_output != nullptr);
 
diff --git a/Telegram/SourceFiles/export/output/export_output_json.h b/Telegram/SourceFiles/export/output/export_output_json.h
index 49d535510..fb59c50ea 100644
--- a/Telegram/SourceFiles/export/output/export_output_json.h
+++ b/Telegram/SourceFiles/export/output/export_output_json.h
@@ -45,6 +45,8 @@ public:
 
 	Result writeSessionsList(const Data::SessionsList &data) override;
 
+	Result writeOtherData(const Data::File &data) override;
+
 	Result writeDialogsStart(const Data::DialogsInfo &data) override;
 	Result writeDialogStart(const Data::DialogInfo &data) override;
 	Result writeDialogSlice(const Data::MessagesSlice &data) override;
diff --git a/Telegram/SourceFiles/export/output/export_output_text.cpp b/Telegram/SourceFiles/export/output/export_output_text.cpp
index b3f32c926..4c578c4cf 100644
--- a/Telegram/SourceFiles/export/output/export_output_text.cpp
+++ b/Telegram/SourceFiles/export/output/export_output_text.cpp
@@ -762,6 +762,15 @@ Result TextWriter::writeWebSessions(const Data::SessionsList &data) {
 	return _summary->writeBlock(header);
 }
 
+Result TextWriter::writeOtherData(const Data::File &data) {
+	Expects(_summary != nullptr);
+
+	const auto header = "Other data - " + data.relativePath.toUtf8()
+		+ kLineBreak
+		+ kLineBreak;
+	return _summary->writeBlock(header);
+}
+
 Result TextWriter::writeDialogsStart(const Data::DialogsInfo &data) {
 	return writeChatsStart(
 		data,
@@ -864,7 +873,9 @@ Result TextWriter::writeChatSlice(const Data::MessagesSlice &data) {
 			data.peers,
 			_settings.internalLinksDomain));
 	}
-	const auto full = kLineBreak + JoinList(kLineBreak, list);
+	const auto full = _chat->empty()
+		? JoinList(kLineBreak, list)
+		: kLineBreak + JoinList(kLineBreak, list);
 	return _chat->writeBlock(full);
 }
 
@@ -911,7 +922,7 @@ Result TextWriter::writeChatEnd() {
 		}
 		Unexpected("Dialog type in TypeString.");
 	};
-	return _chats->writeBlock(SerializeKeyValue({
+	return _chats->writeBlock(kLineBreak + SerializeKeyValue({
 		{ "Name", NameString(_dialog, _dialog.type) },
 		{ "Type", TypeString(_dialog.type) },
 		{
@@ -926,7 +937,7 @@ Result TextWriter::writeChatEnd() {
 				? (_dialog.relativePath + "messages.txt").toUtf8()
 				: QByteArray())
 		}
-	}) + kLineBreak);
+	}));
 }
 
 Result TextWriter::writeChatsEnd() {
diff --git a/Telegram/SourceFiles/export/output/export_output_text.h b/Telegram/SourceFiles/export/output/export_output_text.h
index 2c7265394..3d966236d 100644
--- a/Telegram/SourceFiles/export/output/export_output_text.h
+++ b/Telegram/SourceFiles/export/output/export_output_text.h
@@ -33,6 +33,8 @@ public:
 
 	Result writeSessionsList(const Data::SessionsList &data) override;
 
+	Result writeOtherData(const Data::File &data) override;
+
 	Result writeDialogsStart(const Data::DialogsInfo &data) override;
 	Result writeDialogStart(const Data::DialogInfo &data) override;
 	Result writeDialogSlice(const Data::MessagesSlice &data) override;
diff --git a/Telegram/SourceFiles/export/view/export_view_content.cpp b/Telegram/SourceFiles/export/view/export_view_content.cpp
index 60fcda275..f358a2d13 100644
--- a/Telegram/SourceFiles/export/view/export_view_content.cpp
+++ b/Telegram/SourceFiles/export/view/export_view_content.cpp
@@ -80,6 +80,9 @@ Content ContentFromState(const ProcessingState &state) {
 	case Step::Sessions:
 		pushMain(lang(lng_export_option_sessions));
 		break;
+	case Step::OtherData:
+		pushMain(lang(lng_export_option_other));
+		break;
 	case Step::LeftChannels:
 	case Step::Dialogs:
 		pushMain(lang(lng_export_state_chats));
diff --git a/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp b/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp
index f2f86deb2..ed5e9fb75 100644
--- a/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp
+++ b/Telegram/SourceFiles/export/view/export_view_panel_controller.cpp
@@ -91,8 +91,10 @@ void SuggestStart() {
 
 void ClearSuggestStart() {
 	auto settings = Local::ReadExportSettings();
-	settings.availableAt = 0;
-	Local::WriteExportSettings(settings);
+	if (settings.availableAt) {
+		settings.availableAt = 0;
+		Local::WriteExportSettings(settings);
+	}
 }
 
 PanelController::PanelController(not_null<ControllerWrap*> process)
@@ -160,7 +162,18 @@ void PanelController::showError(const ApiErrorState &error) {
 			qstr("TAKEOUT_INIT_DELAY_").size()).toInt(), 1);
 		const auto now = QDateTime::currentDateTime();
 		const auto when = now.addSecs(seconds);
-		showError(lng_export_delay(lt_date, langDateTimeFull(when)));
+		const auto hours = seconds / 3600;
+		const auto hoursText = [&] {
+			if (hours <= 0) {
+				return lang(lng_export_delay_less_than_hour);
+			}
+			return lng_export_delay_hours(lt_count, hours);
+		}();
+		showError(lng_export_delay(
+			lt_hours,
+			hoursText,
+			lt_date,
+			langDateTimeFull(when)));
 
 		_settings->availableAt = unixtime() + seconds;
 		_saveSettingsTimer.callOnce(kSaveSettingsTimeout);
@@ -217,6 +230,9 @@ void PanelController::showError(const QString &text) {
 }
 
 void PanelController::showProgress() {
+	_settings->availableAt = 0;
+	ClearSuggestStart();
+
 	_panel->setTitle(Lang::Viewer(lng_export_progress_title));
 
 	auto progress = base::make_unique_q<ProgressWidget>(
diff --git a/Telegram/SourceFiles/export/view/export_view_settings.cpp b/Telegram/SourceFiles/export/view/export_view_settings.cpp
index b873f4c13..b9ee8f204 100644
--- a/Telegram/SourceFiles/export/view/export_view_settings.cpp
+++ b/Telegram/SourceFiles/export/view/export_view_settings.cpp
@@ -134,6 +134,13 @@ void SettingsWidget::setupOptions(not_null<Ui::VerticalLayout*> container) {
 		Type::PublicChannels);
 
 	setupMediaOptions(container);
+
+	addHeader(container, lng_export_header_other);
+	addOptionWithAbout(
+		container,
+		lng_export_option_other,
+		Type::OtherData,
+		lng_export_option_other_about);
 }
 
 void SettingsWidget::setupMediaOptions(
@@ -320,12 +327,12 @@ not_null<Ui::Checkbox*> SettingsWidget::addOption(
 	return checkbox;
 }
 
-void SettingsWidget::addOptionWithAbout(
+not_null<Ui::Checkbox*> SettingsWidget::addOptionWithAbout(
 		not_null<Ui::VerticalLayout*> container,
 		LangKey key,
 		Types types,
 		LangKey about) {
-	addOption(container, key, types);
+	const auto result = addOption(container, key, types);
 	const auto label = container->add(
 		object_ptr<Ui::FlatLabel>(
 			container,
@@ -333,6 +340,7 @@ void SettingsWidget::addOptionWithAbout(
 			Ui::FlatLabel::InitType::Simple,
 			st::exportAboutOptionLabel),
 		st::exportAboutOptionPadding);
+	return result;
 }
 
 void SettingsWidget::addChatOption(
diff --git a/Telegram/SourceFiles/export/view/export_view_settings.h b/Telegram/SourceFiles/export/view/export_view_settings.h
index 34c804afa..13cbc061c 100644
--- a/Telegram/SourceFiles/export/view/export_view_settings.h
+++ b/Telegram/SourceFiles/export/view/export_view_settings.h
@@ -51,12 +51,12 @@ private:
 		not_null<Ui::VerticalLayout*> container,
 		LangKey key,
 		Types types);
-	void addOptionWithAbout(
+	not_null<Ui::Checkbox*> addOptionWithAbout(
 		not_null<Ui::VerticalLayout*> container,
 		LangKey key,
 		Types types,
 		LangKey about);
-	void addChatOption(
+ 	void addChatOption(
 		not_null<Ui::VerticalLayout*> container,
 		LangKey key,
 		Types types);