mirror of
https://github.com/immich-app/immich.git
synced 2025-01-01 11:37:06 +02:00
fa9bb8074c
* add packages * create download task * show progress * save video and image * show progress info * live photo wip * download and link live photos * Update list of assets * wip * correct progress * add state to download * revert unncessary change * repository pattern * translation * remove unused code * update method call from repository * remove unused variable * handle multiple livephotos download * remove logging statement * lint * not removing all records
194 lines
5.8 KiB
Dart
194 lines
5.8 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:background_downloader/background_downloader.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:immich_mobile/entities/store.entity.dart';
|
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
|
import 'package:immich_mobile/interfaces/download.interface.dart';
|
|
import 'package:immich_mobile/interfaces/file_media.interface.dart';
|
|
import 'package:immich_mobile/models/download/livephotos_medatada.model.dart';
|
|
import 'package:immich_mobile/repositories/download.repository.dart';
|
|
import 'package:immich_mobile/repositories/file_media.repository.dart';
|
|
import 'package:immich_mobile/services/api.service.dart';
|
|
import 'package:immich_mobile/utils/download.dart';
|
|
|
|
final downloadServiceProvider = Provider(
|
|
(ref) => DownloadService(
|
|
ref.watch(fileMediaRepositoryProvider),
|
|
ref.watch(downloadRepositoryProvider),
|
|
),
|
|
);
|
|
|
|
class DownloadService {
|
|
final IDownloadRepository _downloadRepository;
|
|
final IFileMediaRepository _fileMediaRepository;
|
|
void Function(TaskStatusUpdate)? onImageDownloadStatus;
|
|
void Function(TaskStatusUpdate)? onVideoDownloadStatus;
|
|
void Function(TaskStatusUpdate)? onLivePhotoDownloadStatus;
|
|
void Function(TaskProgressUpdate)? onTaskProgress;
|
|
|
|
DownloadService(
|
|
this._fileMediaRepository,
|
|
this._downloadRepository,
|
|
) {
|
|
_downloadRepository.onImageDownloadStatus = _onImageDownloadCallback;
|
|
_downloadRepository.onVideoDownloadStatus = _onVideoDownloadCallback;
|
|
_downloadRepository.onLivePhotoDownloadStatus =
|
|
_onLivePhotoDownloadCallback;
|
|
_downloadRepository.onTaskProgress = _onTaskProgressCallback;
|
|
}
|
|
|
|
void _onTaskProgressCallback(TaskProgressUpdate update) {
|
|
onTaskProgress?.call(update);
|
|
}
|
|
|
|
void _onImageDownloadCallback(TaskStatusUpdate update) {
|
|
onImageDownloadStatus?.call(update);
|
|
}
|
|
|
|
void _onVideoDownloadCallback(TaskStatusUpdate update) {
|
|
onVideoDownloadStatus?.call(update);
|
|
}
|
|
|
|
void _onLivePhotoDownloadCallback(TaskStatusUpdate update) {
|
|
onLivePhotoDownloadStatus?.call(update);
|
|
}
|
|
|
|
Future<bool> saveImage(Task task) async {
|
|
final filePath = await task.filePath();
|
|
final title = task.filename;
|
|
final relativePath = Platform.isAndroid ? 'DCIM/Immich' : null;
|
|
final data = await File(filePath).readAsBytes();
|
|
|
|
final Asset? resultAsset = await _fileMediaRepository.saveImage(
|
|
data,
|
|
title: title,
|
|
relativePath: relativePath,
|
|
);
|
|
|
|
return resultAsset != null;
|
|
}
|
|
|
|
Future<bool> saveVideo(Task task) async {
|
|
final filePath = await task.filePath();
|
|
final title = task.filename;
|
|
final relativePath = Platform.isAndroid ? 'DCIM/Immich' : null;
|
|
final file = File(filePath);
|
|
|
|
final Asset? resultAsset = await _fileMediaRepository.saveVideo(
|
|
file,
|
|
title: title,
|
|
relativePath: relativePath,
|
|
);
|
|
|
|
return resultAsset != null;
|
|
}
|
|
|
|
Future<bool> saveLivePhotos(
|
|
Task task,
|
|
String livePhotosId,
|
|
) async {
|
|
try {
|
|
final records = await _downloadRepository.getLiveVideoTasks();
|
|
if (records.length < 2) {
|
|
return false;
|
|
}
|
|
|
|
final imageRecord = records.firstWhere(
|
|
(record) {
|
|
final metadata = LivePhotosMetadata.fromJson(record.task.metaData);
|
|
return metadata.id == livePhotosId &&
|
|
metadata.part == LivePhotosPart.image;
|
|
},
|
|
);
|
|
|
|
final videoRecord = records.firstWhere((record) {
|
|
final metadata = LivePhotosMetadata.fromJson(record.task.metaData);
|
|
return metadata.id == livePhotosId &&
|
|
metadata.part == LivePhotosPart.video;
|
|
});
|
|
|
|
final imageFilePath = await imageRecord.task.filePath();
|
|
final videoFilePath = await videoRecord.task.filePath();
|
|
|
|
final resultAsset = await _fileMediaRepository.saveLivePhoto(
|
|
image: File(imageFilePath),
|
|
video: File(videoFilePath),
|
|
title: task.filename,
|
|
);
|
|
|
|
await _downloadRepository.deleteRecordsWithIds([
|
|
imageRecord.task.taskId,
|
|
videoRecord.task.taskId,
|
|
]);
|
|
|
|
return resultAsset != null;
|
|
} catch (error) {
|
|
debugPrint("Error saving live photo: $error");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<bool> cancelDownload(String id) async {
|
|
return await FileDownloader().cancelTaskWithId(id);
|
|
}
|
|
|
|
Future<void> download(Asset asset) async {
|
|
if (asset.isImage && asset.livePhotoVideoId != null && Platform.isIOS) {
|
|
await _downloadRepository.download(
|
|
_buildDownloadTask(
|
|
asset.remoteId!,
|
|
asset.fileName,
|
|
group: downloadGroupLivePhoto,
|
|
metadata: LivePhotosMetadata(
|
|
part: LivePhotosPart.image,
|
|
id: asset.remoteId!,
|
|
).toJson(),
|
|
),
|
|
);
|
|
|
|
await _downloadRepository.download(
|
|
_buildDownloadTask(
|
|
asset.livePhotoVideoId!,
|
|
asset.fileName.toUpperCase().replaceAll(".HEIC", '.MOV'),
|
|
group: downloadGroupLivePhoto,
|
|
metadata: LivePhotosMetadata(
|
|
part: LivePhotosPart.video,
|
|
id: asset.remoteId!,
|
|
).toJson(),
|
|
),
|
|
);
|
|
} else {
|
|
await _downloadRepository.download(
|
|
_buildDownloadTask(
|
|
asset.remoteId!,
|
|
asset.fileName,
|
|
group: asset.isImage ? downloadGroupImage : downloadGroupVideo,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
DownloadTask _buildDownloadTask(
|
|
String id,
|
|
String filename, {
|
|
String? group,
|
|
String? metadata,
|
|
}) {
|
|
final path = r'/assets/{id}/original'.replaceAll('{id}', id);
|
|
final serverEndpoint = Store.get(StoreKey.serverEndpoint);
|
|
final headers = ApiService.getRequestHeaders();
|
|
|
|
return DownloadTask(
|
|
taskId: id,
|
|
url: serverEndpoint + path,
|
|
headers: headers,
|
|
filename: filename,
|
|
updates: Updates.statusAndProgress,
|
|
group: group ?? '',
|
|
metaData: metadata ?? '',
|
|
);
|
|
}
|
|
}
|