mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-04-19 02:12:54 +00:00
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
138 lines
4.5 KiB
Dart
138 lines
4.5 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
import 'package:drift/drift.dart' show Value;
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
|
import 'package:pro_video_editor/pro_video_editor.dart';
|
|
import 'package:twonly/globals.dart';
|
|
import 'package:twonly/src/channels/video_compression.channel.dart';
|
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
|
import 'package:twonly/src/database/twonly.db.dart';
|
|
import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
|
|
import 'package:twonly/src/utils/log.dart';
|
|
|
|
Future<void> compressImage(
|
|
File sourceFile,
|
|
File destinationFile,
|
|
) async {
|
|
final stopwatch = Stopwatch()..start();
|
|
|
|
try {
|
|
var compressedBytes = await FlutterImageCompress.compressWithFile(
|
|
sourceFile.path,
|
|
format: CompressFormat.webp,
|
|
quality: 90,
|
|
);
|
|
|
|
if (compressedBytes == null) {
|
|
throw Exception(
|
|
'Could not compress media file: Sending original file.',
|
|
);
|
|
}
|
|
|
|
Log.info('Compressed images size in bytes: ${compressedBytes.length}');
|
|
|
|
if (compressedBytes.length >= 1 * 1000 * 1000) {
|
|
// if the media file is over 1MB compress it with 60%
|
|
final tmpCompressedBytes = await FlutterImageCompress.compressWithFile(
|
|
sourceFile.path,
|
|
format: CompressFormat.webp,
|
|
quality: 60,
|
|
);
|
|
if (tmpCompressedBytes != null) {
|
|
Log.error(
|
|
'Could not compress media file with 60%: $sourceFile. Sending original 90% compressed file.',
|
|
);
|
|
compressedBytes = tmpCompressedBytes;
|
|
}
|
|
}
|
|
|
|
await destinationFile.writeAsBytes(compressedBytes);
|
|
} catch (e) {
|
|
Log.warn('$e');
|
|
sourceFile.copySync(destinationFile.path);
|
|
}
|
|
|
|
stopwatch.stop();
|
|
|
|
Log.info(
|
|
'Compression of the image took: ${stopwatch.elapsedMilliseconds} milliseconds.',
|
|
);
|
|
}
|
|
|
|
Future<void> compressAndOverlayVideo(MediaFileService media) async {
|
|
if (media.tempPath.existsSync()) {
|
|
media.tempPath.deleteSync();
|
|
}
|
|
if (media.ffmpegOutputPath.existsSync()) {
|
|
media.ffmpegOutputPath.deleteSync();
|
|
}
|
|
|
|
final stopwatch = Stopwatch()..start();
|
|
|
|
try {
|
|
final task = VideoRenderData(
|
|
video: EditorVideo.file(media.originalPath),
|
|
imageBytes: media.overlayImagePath.readAsBytesSync(),
|
|
enableAudio: !media.removeAudio,
|
|
);
|
|
|
|
await ProVideoEditor.instance
|
|
.renderVideoToFile(media.ffmpegOutputPath.path, task);
|
|
|
|
if (Platform.isIOS ||
|
|
media.ffmpegOutputPath.statSync().size >= 10_000_000 ||
|
|
!kReleaseMode) {
|
|
String? compressedPath;
|
|
try {
|
|
compressedPath = await VideoCompressionChannel.compressVideo(
|
|
inputPath: media.ffmpegOutputPath.path,
|
|
outputPath: media.tempPath.path,
|
|
onProgress: (progress) async {
|
|
await twonlyDB.mediaFilesDao.updateMedia(
|
|
media.mediaFile.mediaId,
|
|
MediaFilesCompanion(
|
|
preProgressingProcess: Value((progress * 100).toInt()),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
} catch (e) {
|
|
Log.error('during video compression: $e');
|
|
}
|
|
|
|
if (compressedPath == null) {
|
|
Log.error('Could not compress video using original video.');
|
|
// as a fall back use the non compressed version
|
|
media.ffmpegOutputPath.copySync(media.tempPath.path);
|
|
}
|
|
} else {
|
|
// In case the video is smaller than 10MB do not compress it...
|
|
media.ffmpegOutputPath.copySync(media.tempPath.path);
|
|
}
|
|
|
|
stopwatch.stop();
|
|
|
|
final sizeFrom = (media.ffmpegOutputPath.statSync().size / 1024 / 1024)
|
|
.toStringAsFixed(2);
|
|
final sizeTo =
|
|
(media.tempPath.statSync().size / 1024 / 1024).toStringAsFixed(2);
|
|
|
|
Log.info(
|
|
'It took ${stopwatch.elapsedMilliseconds}ms to compress the video. Reduced from $sizeFrom to $sizeTo bytes.',
|
|
);
|
|
} catch (e) {
|
|
Log.error(e);
|
|
// Log.error('Compression failed for the video with exit code $returnCode.');
|
|
// Log.error(await session.getAllLogsAsString());
|
|
// This should not happen, but in case "notify" the user that the video was not send... This is absolutely bad, but
|
|
// better this way then sending an uncompressed media file which potentially is 100MB big :/
|
|
// Hopefully the user will report the strange behavior <3
|
|
await twonlyDB.messagesDao.updateMessagesByMediaId(
|
|
media.mediaFile.mediaId,
|
|
const MessagesCompanion(isDeletedFromSender: Value(true)),
|
|
);
|
|
media.fullMediaRemoval();
|
|
await media.setUploadState(UploadState.uploaded);
|
|
}
|
|
}
|