212 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| 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 "api/api_ringtones.h"
 | |
| 
 | |
| #include "api/api_toggling_media.h"
 | |
| #include "apiwrap.h"
 | |
| #include "base/random.h"
 | |
| #include "base/unixtime.h"
 | |
| #include "data/data_document.h"
 | |
| #include "data/data_document_media.h"
 | |
| #include "data/data_file_origin.h"
 | |
| #include "data/data_session.h"
 | |
| #include "data/notify/data_notify_settings.h"
 | |
| #include "main/main_account.h"
 | |
| #include "main/main_app_config.h"
 | |
| #include "main/main_session.h"
 | |
| #include "storage/file_upload.h"
 | |
| #include "storage/localimageloader.h"
 | |
| 
 | |
| namespace Api {
 | |
| namespace {
 | |
| 
 | |
| SendMediaReady PrepareRingtoneDocument(
 | |
| 		MTP::DcId dcId,
 | |
| 		const QString &filename,
 | |
| 		const QString &filemime,
 | |
| 		const QByteArray &content) {
 | |
| 	auto attributes = QVector<MTPDocumentAttribute>(
 | |
| 		1,
 | |
| 		MTP_documentAttributeFilename(MTP_string(filename)));
 | |
| 	const auto id = base::RandomValue<DocumentId>();
 | |
| 	const auto document = MTP_document(
 | |
| 		MTP_flags(0),
 | |
| 		MTP_long(id),
 | |
| 		MTP_long(0),
 | |
| 		MTP_bytes(),
 | |
| 		MTP_int(base::unixtime::now()),
 | |
| 		MTP_string(filemime),
 | |
| 		MTP_long(content.size()),
 | |
| 		MTP_vector<MTPPhotoSize>(),
 | |
| 		MTPVector<MTPVideoSize>(),
 | |
| 		MTP_int(dcId),
 | |
| 		MTP_vector<MTPDocumentAttribute>(std::move(attributes)));
 | |
| 
 | |
| 	return SendMediaReady(
 | |
| 		SendMediaType::File,
 | |
| 		QString(), // filepath
 | |
| 		filename,
 | |
| 		content.size(),
 | |
| 		content,
 | |
| 		id,
 | |
| 		0,
 | |
| 		QString(),
 | |
| 		PeerId(),
 | |
| 		MTP_photoEmpty(MTP_long(0)),
 | |
| 		PreparedPhotoThumbs(),
 | |
| 		document,
 | |
| 		QByteArray(),
 | |
| 		0);
 | |
| }
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| Ringtones::Ringtones(not_null<ApiWrap*> api)
 | |
| : _session(&api->session())
 | |
| , _api(&api->instance()) {
 | |
| 	crl::on_main(_session, [=] {
 | |
| 		// You can't use _session->lifetime() in the constructor,
 | |
| 		// only queued, because it is not constructed yet.
 | |
| 		_session->uploader().documentReady(
 | |
| 		) | rpl::start_with_next([=](const Storage::UploadedMedia &data) {
 | |
| 			ready(data.fullId, data.info.file);
 | |
| 		}, _session->lifetime());
 | |
| 	});
 | |
| }
 | |
| 
 | |
| void Ringtones::upload(
 | |
| 		const QString &filename,
 | |
| 		const QString &filemime,
 | |
| 		const QByteArray &content) {
 | |
| 	const auto ready = PrepareRingtoneDocument(
 | |
| 		_api.instance().mainDcId(),
 | |
| 		filename,
 | |
| 		filemime,
 | |
| 		content);
 | |
| 
 | |
| 	const auto uploadedData = UploadedData{ filename, filemime, content };
 | |
| 	const auto fakeId = FullMsgId(
 | |
| 		_session->userPeerId(),
 | |
| 		_session->data().nextLocalMessageId());
 | |
| 	const auto already = ranges::find_if(
 | |
| 		_uploads,
 | |
| 		[&](const auto &d) {
 | |
| 			return uploadedData.filemime == d.second.filemime
 | |
| 				&& uploadedData.filename == d.second.filename;
 | |
| 		});
 | |
| 	if (already != end(_uploads)) {
 | |
| 		_session->uploader().cancel(already->first);
 | |
| 		_uploads.erase(already);
 | |
| 	}
 | |
| 	_uploads.emplace(fakeId, uploadedData);
 | |
| 	_session->uploader().uploadMedia(fakeId, ready);
 | |
| }
 | |
| 
 | |
| void Ringtones::ready(const FullMsgId &msgId, const MTPInputFile &file) {
 | |
| 	const auto maybeUploadedData = _uploads.take(msgId);
 | |
| 	if (!maybeUploadedData) {
 | |
| 		return;
 | |
| 	}
 | |
| 	const auto uploadedData = *maybeUploadedData;
 | |
| 	_api.request(MTPaccount_UploadRingtone(
 | |
| 		file,
 | |
| 		MTP_string(uploadedData.filename),
 | |
| 		MTP_string(uploadedData.filemime)
 | |
| 	)).done([=, content = uploadedData.content](const MTPDocument &result) {
 | |
| 		const auto document = _session->data().processDocument(result);
 | |
| 		_list.documents.insert(_list.documents.begin(), document->id);
 | |
| 		const auto media = document->createMediaView();
 | |
| 		media->setBytes(content);
 | |
| 		document->owner().notifySettings().cacheSound(document);
 | |
| 		_uploadDones.fire_copy(document->id);
 | |
| 	}).fail([=](const MTP::Error &error) {
 | |
| 		_uploadFails.fire_copy(error.type());
 | |
| 	}).send();
 | |
| }
 | |
| 
 | |
| void Ringtones::requestList() {
 | |
| 	if (_list.requestId) {
 | |
| 		return;
 | |
| 	}
 | |
| 	_list.requestId = _api.request(
 | |
| 		MTPaccount_GetSavedRingtones(MTP_long(_list.hash))
 | |
| 	).done([=](const MTPaccount_SavedRingtones &result) {
 | |
| 		_list.requestId = 0;
 | |
| 		result.match([&](const MTPDaccount_savedRingtones &data) {
 | |
| 			_list.hash = data.vhash().v;
 | |
| 			_list.documents.clear();
 | |
| 			_list.documents.reserve(data.vringtones().v.size());
 | |
| 			for (const auto &d : data.vringtones().v) {
 | |
| 				const auto document = _session->data().processDocument(d);
 | |
| 				document->forceToCache(true);
 | |
| 				_list.documents.emplace_back(document->id);
 | |
| 			}
 | |
| 			_list.updates.fire({});
 | |
| 		}, [&](const MTPDaccount_savedRingtonesNotModified &) {
 | |
| 		});
 | |
| 	}).fail([=] {
 | |
| 		_list.requestId = 0;
 | |
| 	}).send();
 | |
| }
 | |
| 
 | |
| const Ringtones::Ids &Ringtones::list() const {
 | |
| 	return _list.documents;
 | |
| }
 | |
| 
 | |
| rpl::producer<> Ringtones::listUpdates() const {
 | |
| 	return _list.updates.events();
 | |
| }
 | |
| 
 | |
| rpl::producer<QString> Ringtones::uploadFails() const {
 | |
| 	return _uploadFails.events();
 | |
| }
 | |
| 
 | |
| rpl::producer<DocumentId> Ringtones::uploadDones() const {
 | |
| 	return _uploadDones.events();
 | |
| }
 | |
| 
 | |
| void Ringtones::applyUpdate() {
 | |
| 	_list.hash = 0;
 | |
| 	_list.documents.clear();
 | |
| 	requestList();
 | |
| }
 | |
| 
 | |
| void Ringtones::remove(DocumentId id) {
 | |
| 	if (const auto document = _session->data().document(id)) {
 | |
| 		ToggleSavedRingtone(
 | |
| 			document,
 | |
| 			Data::FileOriginRingtones(),
 | |
| 			crl::guard(&document->session(), [=] {
 | |
| 				const auto it = ranges::find(_list.documents, id);
 | |
| 				if (it != end(_list.documents)) {
 | |
| 					_list.documents.erase(it);
 | |
| 				}
 | |
| 			}),
 | |
| 			false);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int64 Ringtones::maxSize() const {
 | |
| 	return _session->account().appConfig().get<int>(
 | |
| 		"ringtone_size_max",
 | |
| 		100 * 1024);
 | |
| }
 | |
| 
 | |
| int Ringtones::maxSavedCount() const {
 | |
| 	return _session->account().appConfig().get<int>(
 | |
| 		"ringtone_saved_count_max",
 | |
| 		100);
 | |
| }
 | |
| 
 | |
| int Ringtones::maxDuration() const {
 | |
| 	return _session->account().appConfig().get<int>(
 | |
| 		"ringtone_duration_max",
 | |
| 		5);
 | |
| }
 | |
| 
 | |
| } // namespace Api
 | 
