FUCKING REFACTOR
This commit is contained in:
371
lib/api/api_service_media.dart
Normal file
371
lib/api/api_service_media.dart
Normal file
@@ -0,0 +1,371 @@
|
||||
part of 'api_service.dart';
|
||||
|
||||
extension ApiServiceMedia on ApiService {
|
||||
void updateProfileText(
|
||||
String firstName,
|
||||
String lastName,
|
||||
String description,
|
||||
) {
|
||||
final payload = {
|
||||
"firstName": firstName,
|
||||
"lastName": lastName,
|
||||
"description": description,
|
||||
};
|
||||
_sendMessage(16, payload);
|
||||
}
|
||||
|
||||
Future<void> updateProfilePhoto(String firstName, String lastName) async {
|
||||
try {
|
||||
final picker = ImagePicker();
|
||||
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
|
||||
if (image == null) return;
|
||||
|
||||
print("Запрашиваем URL для загрузки фото...");
|
||||
final int seq = _sendMessage(80, {"count": 1});
|
||||
final response = await messages.firstWhere((msg) => msg['seq'] == seq);
|
||||
final String uploadUrl = response['payload']['url'];
|
||||
print("URL получен: $uploadUrl");
|
||||
|
||||
print("Загружаем фото на сервер...");
|
||||
var request = http.MultipartRequest('POST', Uri.parse(uploadUrl));
|
||||
request.files.add(await http.MultipartFile.fromPath('file', image.path));
|
||||
var streamedResponse = await request.send();
|
||||
var httpResponse = await http.Response.fromStream(streamedResponse);
|
||||
|
||||
if (httpResponse.statusCode != 200) {
|
||||
throw Exception("Ошибка загрузки фото: ${httpResponse.body}");
|
||||
}
|
||||
|
||||
final uploadResult = jsonDecode(httpResponse.body);
|
||||
final String photoToken = uploadResult['photos'].values.first['token'];
|
||||
print("Фото загружено, получен токен: $photoToken");
|
||||
|
||||
print("Привязываем фото к профилю...");
|
||||
final payload = {
|
||||
"firstName": firstName,
|
||||
"lastName": lastName,
|
||||
"photoToken": photoToken,
|
||||
"avatarType": "USER_AVATAR",
|
||||
};
|
||||
_sendMessage(16, payload);
|
||||
print("Запрос на смену аватара отправлен.");
|
||||
} catch (e) {
|
||||
print("!!! Ошибка в процессе смены аватара: $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> sendPhotoMessage(
|
||||
int chatId, {
|
||||
String? localPath,
|
||||
String? caption,
|
||||
int? cidOverride,
|
||||
int? senderId,
|
||||
}) async {
|
||||
try {
|
||||
XFile? image;
|
||||
if (localPath != null) {
|
||||
image = XFile(localPath);
|
||||
} else {
|
||||
final picker = ImagePicker();
|
||||
image = await picker.pickImage(source: ImageSource.gallery);
|
||||
if (image == null) return;
|
||||
}
|
||||
|
||||
await waitUntilOnline();
|
||||
|
||||
final int seq80 = _sendMessage(80, {"count": 1});
|
||||
final resp80 = await messages.firstWhere((m) => m['seq'] == seq80);
|
||||
final String uploadUrl = resp80['payload']['url'];
|
||||
|
||||
var request = http.MultipartRequest('POST', Uri.parse(uploadUrl));
|
||||
request.files.add(await http.MultipartFile.fromPath('file', image.path));
|
||||
var streamed = await request.send();
|
||||
var httpResp = await http.Response.fromStream(streamed);
|
||||
if (httpResp.statusCode != 200) {
|
||||
throw Exception(
|
||||
'Ошибка загрузки фото: ${httpResp.statusCode} ${httpResp.body}',
|
||||
);
|
||||
}
|
||||
final uploadJson = jsonDecode(httpResp.body) as Map<String, dynamic>;
|
||||
final Map photos = uploadJson['photos'] as Map;
|
||||
if (photos.isEmpty) throw Exception('Не получен токен фото');
|
||||
final String photoToken = (photos.values.first as Map)['token'];
|
||||
|
||||
final int cid = cidOverride ?? DateTime.now().millisecondsSinceEpoch;
|
||||
final payload = {
|
||||
"chatId": chatId,
|
||||
"message": {
|
||||
"text": caption?.trim() ?? "",
|
||||
"cid": cid,
|
||||
"elements": [],
|
||||
"attaches": [
|
||||
{"_type": "PHOTO", "photoToken": photoToken},
|
||||
],
|
||||
},
|
||||
"notify": true,
|
||||
};
|
||||
|
||||
clearChatsCache();
|
||||
|
||||
if (localPath != null) {
|
||||
_emitLocal({
|
||||
'ver': 11,
|
||||
'cmd': 1,
|
||||
'seq': -1,
|
||||
'opcode': 128,
|
||||
'payload': {
|
||||
'chatId': chatId,
|
||||
'message': {
|
||||
'id': 'local_$cid',
|
||||
'sender': senderId ?? 0,
|
||||
'time': DateTime.now().millisecondsSinceEpoch,
|
||||
'text': caption?.trim() ?? '',
|
||||
'type': 'USER',
|
||||
'cid': cid,
|
||||
'attaches': [
|
||||
{'_type': 'PHOTO', 'url': 'file://$localPath'},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
_sendMessage(64, payload);
|
||||
} catch (e) {
|
||||
print('Ошибка отправки фото-сообщения: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> sendPhotoMessages(
|
||||
int chatId, {
|
||||
required List<String> localPaths,
|
||||
String? caption,
|
||||
int? senderId,
|
||||
}) async {
|
||||
if (localPaths.isEmpty) return;
|
||||
try {
|
||||
await waitUntilOnline();
|
||||
|
||||
final int cid = DateTime.now().millisecondsSinceEpoch;
|
||||
_emitLocal({
|
||||
'ver': 11,
|
||||
'cmd': 1,
|
||||
'seq': -1,
|
||||
'opcode': 128,
|
||||
'payload': {
|
||||
'chatId': chatId,
|
||||
'message': {
|
||||
'id': 'local_$cid',
|
||||
'sender': senderId ?? 0,
|
||||
'time': DateTime.now().millisecondsSinceEpoch,
|
||||
'text': caption?.trim() ?? '',
|
||||
'type': 'USER',
|
||||
'cid': cid,
|
||||
'attaches': [
|
||||
for (final p in localPaths)
|
||||
{'_type': 'PHOTO', 'url': 'file://$p'},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
final List<Map<String, String>> photoTokens = [];
|
||||
for (final path in localPaths) {
|
||||
final int seq80 = _sendMessage(80, {"count": 1});
|
||||
final resp80 = await messages.firstWhere((m) => m['seq'] == seq80);
|
||||
final String uploadUrl = resp80['payload']['url'];
|
||||
|
||||
var request = http.MultipartRequest('POST', Uri.parse(uploadUrl));
|
||||
request.files.add(await http.MultipartFile.fromPath('file', path));
|
||||
var streamed = await request.send();
|
||||
var httpResp = await http.Response.fromStream(streamed);
|
||||
if (httpResp.statusCode != 200) {
|
||||
throw Exception(
|
||||
'Ошибка загрузки фото: ${httpResp.statusCode} ${httpResp.body}',
|
||||
);
|
||||
}
|
||||
final uploadJson = jsonDecode(httpResp.body) as Map<String, dynamic>;
|
||||
final Map photos = uploadJson['photos'] as Map;
|
||||
if (photos.isEmpty) throw Exception('Не получен токен фото');
|
||||
final String photoToken = (photos.values.first as Map)['token'];
|
||||
photoTokens.add({"token": photoToken});
|
||||
}
|
||||
|
||||
final payload = {
|
||||
"chatId": chatId,
|
||||
"message": {
|
||||
"text": caption?.trim() ?? "",
|
||||
"cid": cid,
|
||||
"elements": [],
|
||||
"attaches": [
|
||||
for (final t in photoTokens)
|
||||
{"_type": "PHOTO", "photoToken": t["token"]},
|
||||
],
|
||||
},
|
||||
"notify": true,
|
||||
};
|
||||
|
||||
clearChatsCache();
|
||||
_sendMessage(64, payload);
|
||||
} catch (e) {
|
||||
print('Ошибка отправки фото-сообщений: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> sendFileMessage(
|
||||
int chatId, {
|
||||
String? caption,
|
||||
int? senderId,
|
||||
}) async {
|
||||
try {
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.any,
|
||||
);
|
||||
|
||||
if (result == null || result.files.single.path == null) {
|
||||
print("Выбор файла отменен");
|
||||
return;
|
||||
}
|
||||
|
||||
final String filePath = result.files.single.path!;
|
||||
final String fileName = result.files.single.name;
|
||||
final int fileSize = result.files.single.size;
|
||||
|
||||
await waitUntilOnline();
|
||||
|
||||
final int seq87 = _sendMessage(87, {"count": 1});
|
||||
final resp87 = await messages.firstWhere((m) => m['seq'] == seq87);
|
||||
|
||||
if (resp87['payload'] == null ||
|
||||
resp87['payload']['info'] == null ||
|
||||
(resp87['payload']['info'] as List).isEmpty) {
|
||||
throw Exception('Неверный ответ на Opcode 87: отсутствует "info"');
|
||||
}
|
||||
|
||||
final uploadInfo = (resp87['payload']['info'] as List).first;
|
||||
final String uploadUrl = uploadInfo['url'];
|
||||
final int fileId = uploadInfo['fileId'];
|
||||
|
||||
print('Получен fileId: $fileId и URL: $uploadUrl');
|
||||
|
||||
var request = http.MultipartRequest('POST', Uri.parse(uploadUrl));
|
||||
request.files.add(await http.MultipartFile.fromPath('file', filePath));
|
||||
var streamed = await request.send();
|
||||
var httpResp = await http.Response.fromStream(streamed);
|
||||
if (httpResp.statusCode != 200) {
|
||||
throw Exception(
|
||||
'Ошибка загрузки файла: ${httpResp.statusCode} ${httpResp.body}',
|
||||
);
|
||||
}
|
||||
|
||||
print('Файл успешно загружен на сервер.');
|
||||
|
||||
final int cid = DateTime.now().millisecondsSinceEpoch;
|
||||
final payload = {
|
||||
"chatId": chatId,
|
||||
"message": {
|
||||
"text": caption?.trim() ?? "",
|
||||
"cid": cid,
|
||||
"elements": [],
|
||||
"attaches": [
|
||||
{"_type": "FILE", "fileId": fileId},
|
||||
],
|
||||
},
|
||||
"notify": true,
|
||||
};
|
||||
|
||||
clearChatsCache();
|
||||
|
||||
_emitLocal({
|
||||
'ver': 11,
|
||||
'cmd': 1,
|
||||
'seq': -1,
|
||||
'opcode': 128,
|
||||
'payload': {
|
||||
'chatId': chatId,
|
||||
'message': {
|
||||
'id': 'local_$cid',
|
||||
'sender': senderId ?? 0,
|
||||
'time': DateTime.now().millisecondsSinceEpoch,
|
||||
'text': caption?.trim() ?? '',
|
||||
'type': 'USER',
|
||||
'cid': cid,
|
||||
'attaches': [
|
||||
{
|
||||
'_type': 'FILE',
|
||||
'name': fileName,
|
||||
'size': fileSize,
|
||||
'url': 'file://$filePath',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
_sendMessage(64, payload);
|
||||
print('Сообщение о файле (Opcode 64) отправлено.');
|
||||
} catch (e) {
|
||||
print('Ошибка отправки файла: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getVideoUrl(int videoId, int chatId, String messageId) async {
|
||||
await waitUntilOnline();
|
||||
|
||||
final payload = {
|
||||
"videoId": videoId,
|
||||
"chatId": chatId,
|
||||
"messageId": messageId,
|
||||
};
|
||||
|
||||
final int seq = _sendMessage(83, payload);
|
||||
print('Запрашиваем URL для videoId: $videoId (seq: $seq)');
|
||||
|
||||
try {
|
||||
final response = await messages
|
||||
.firstWhere((msg) => msg['seq'] == seq && msg['opcode'] == 83)
|
||||
.timeout(const Duration(seconds: 15));
|
||||
|
||||
if (response['cmd'] == 3) {
|
||||
throw Exception(
|
||||
'Ошибка получения URL видео: ${response['payload']?['message']}',
|
||||
);
|
||||
}
|
||||
|
||||
final videoPayload = response['payload'] as Map<String, dynamic>?;
|
||||
if (videoPayload == null) {
|
||||
throw Exception('Получен пустой payload для видео');
|
||||
}
|
||||
|
||||
String? videoUrl =
|
||||
videoPayload['MP4_720'] as String? ??
|
||||
videoPayload['MP4_480'] as String? ??
|
||||
videoPayload['MP4_1080'] as String? ??
|
||||
videoPayload['MP4_360'] as String?;
|
||||
|
||||
if (videoUrl == null) {
|
||||
final mp4Key = videoPayload.keys.firstWhere(
|
||||
(k) => k.startsWith('MP4_'),
|
||||
orElse: () => '',
|
||||
);
|
||||
if (mp4Key.isNotEmpty) {
|
||||
videoUrl = videoPayload[mp4Key] as String?;
|
||||
}
|
||||
}
|
||||
|
||||
if (videoUrl != null) {
|
||||
print('URL для videoId: $videoId успешно получен.');
|
||||
return videoUrl;
|
||||
} else {
|
||||
throw Exception('Не найден ни один MP4 URL в ответе');
|
||||
}
|
||||
} on TimeoutException {
|
||||
print('Таймаут ожидания URL для videoId: $videoId');
|
||||
throw Exception('Сервер не ответил на запрос видео вовремя');
|
||||
} catch (e) {
|
||||
print('Ошибка в getVideoUrl: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user