0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-21 00:52:43 -05:00

success upload

This commit is contained in:
Alex 2024-06-18 14:27:04 -07:00
parent fbe2fc52d9
commit 5619955eb7
No known key found for this signature in database
GPG key ID: 53CD082B3A5E1082
5 changed files with 107 additions and 174 deletions

View file

@ -1,7 +1,11 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
import 'package:background_downloader/background_downloader.dart';
import 'package:cancellation_token_http/http.dart';
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:immich_mobile/models/backup/available_album.model.dart';
@ -18,178 +22,38 @@ enum BackUpProgressEnum {
class BackUpState {
// enum
final BackUpProgressEnum backupProgress;
final List<String> allAssetsInDatabase;
final double progressInPercentage;
final String progressInFileSize;
final double progressInFileSpeed;
final List<double> progressInFileSpeeds;
final DateTime progressInFileSpeedUpdateTime;
final int progressInFileSpeedUpdateSentBytes;
final double iCloudDownloadProgress;
final CancellationToken cancelToken;
final ServerDiskInfo serverInfo;
final bool autoBackup;
final bool backgroundBackup;
final bool backupRequireWifi;
final bool backupRequireCharging;
final int backupTriggerDelay;
final BackUpProgressEnum progress;
/// All available albums on the device
final List<AvailableAlbum> availableAlbums;
final Set<AvailableAlbum> selectedBackupAlbums;
final Set<AvailableAlbum> excludedBackupAlbums;
final List<UploadTask> uploadTasks;
/// Assets that are not overlapping in selected backup albums and excluded backup albums
final Set<AssetEntity> allUniqueAssets;
/// All assets from the selected albums that have been backup
final Set<String> selectedAlbumsBackupAssetsIds;
// Current Backup Asset
final CurrentUploadAsset currentUploadAsset;
const BackUpState({
required this.backupProgress,
required this.allAssetsInDatabase,
required this.progressInPercentage,
required this.progressInFileSize,
required this.progressInFileSpeed,
required this.progressInFileSpeeds,
required this.progressInFileSpeedUpdateTime,
required this.progressInFileSpeedUpdateSentBytes,
required this.iCloudDownloadProgress,
required this.cancelToken,
required this.serverInfo,
required this.autoBackup,
required this.backgroundBackup,
required this.backupRequireWifi,
required this.backupRequireCharging,
required this.backupTriggerDelay,
required this.availableAlbums,
required this.selectedBackupAlbums,
required this.excludedBackupAlbums,
required this.allUniqueAssets,
required this.selectedAlbumsBackupAssetsIds,
required this.currentUploadAsset,
BackUpState({
required this.progress,
required this.uploadTasks,
});
BackUpState copyWith({
BackUpProgressEnum? backupProgress,
List<String>? allAssetsInDatabase,
double? progressInPercentage,
String? progressInFileSize,
double? progressInFileSpeed,
List<double>? progressInFileSpeeds,
DateTime? progressInFileSpeedUpdateTime,
int? progressInFileSpeedUpdateSentBytes,
double? iCloudDownloadProgress,
CancellationToken? cancelToken,
ServerDiskInfo? serverInfo,
bool? autoBackup,
bool? backgroundBackup,
bool? backupRequireWifi,
bool? backupRequireCharging,
int? backupTriggerDelay,
List<AvailableAlbum>? availableAlbums,
Set<AvailableAlbum>? selectedBackupAlbums,
Set<AvailableAlbum>? excludedBackupAlbums,
Set<AssetEntity>? allUniqueAssets,
Set<String>? selectedAlbumsBackupAssetsIds,
CurrentUploadAsset? currentUploadAsset,
BackUpProgressEnum? progress,
List<UploadTask>? uploadTasks,
}) {
return BackUpState(
backupProgress: backupProgress ?? this.backupProgress,
allAssetsInDatabase: allAssetsInDatabase ?? this.allAssetsInDatabase,
progressInPercentage: progressInPercentage ?? this.progressInPercentage,
progressInFileSize: progressInFileSize ?? this.progressInFileSize,
progressInFileSpeed: progressInFileSpeed ?? this.progressInFileSpeed,
progressInFileSpeeds: progressInFileSpeeds ?? this.progressInFileSpeeds,
progressInFileSpeedUpdateTime:
progressInFileSpeedUpdateTime ?? this.progressInFileSpeedUpdateTime,
progressInFileSpeedUpdateSentBytes: progressInFileSpeedUpdateSentBytes ??
this.progressInFileSpeedUpdateSentBytes,
iCloudDownloadProgress:
iCloudDownloadProgress ?? this.iCloudDownloadProgress,
cancelToken: cancelToken ?? this.cancelToken,
serverInfo: serverInfo ?? this.serverInfo,
autoBackup: autoBackup ?? this.autoBackup,
backgroundBackup: backgroundBackup ?? this.backgroundBackup,
backupRequireWifi: backupRequireWifi ?? this.backupRequireWifi,
backupRequireCharging:
backupRequireCharging ?? this.backupRequireCharging,
backupTriggerDelay: backupTriggerDelay ?? this.backupTriggerDelay,
availableAlbums: availableAlbums ?? this.availableAlbums,
selectedBackupAlbums: selectedBackupAlbums ?? this.selectedBackupAlbums,
excludedBackupAlbums: excludedBackupAlbums ?? this.excludedBackupAlbums,
allUniqueAssets: allUniqueAssets ?? this.allUniqueAssets,
selectedAlbumsBackupAssetsIds:
selectedAlbumsBackupAssetsIds ?? this.selectedAlbumsBackupAssetsIds,
currentUploadAsset: currentUploadAsset ?? this.currentUploadAsset,
progress: progress ?? this.progress,
uploadTasks: uploadTasks ?? this.uploadTasks,
);
}
@override
String toString() {
return 'BackUpState(backupProgress: $backupProgress, allAssetsInDatabase: $allAssetsInDatabase, progressInPercentage: $progressInPercentage, progressInFileSize: $progressInFileSize, progressInFileSpeed: $progressInFileSpeed, progressInFileSpeeds: $progressInFileSpeeds, progressInFileSpeedUpdateTime: $progressInFileSpeedUpdateTime, progressInFileSpeedUpdateSentBytes: $progressInFileSpeedUpdateSentBytes, iCloudDownloadProgress: $iCloudDownloadProgress, cancelToken: $cancelToken, serverInfo: $serverInfo, autoBackup: $autoBackup, backgroundBackup: $backgroundBackup, backupRequireWifi: $backupRequireWifi, backupRequireCharging: $backupRequireCharging, backupTriggerDelay: $backupTriggerDelay, availableAlbums: $availableAlbums, selectedBackupAlbums: $selectedBackupAlbums, excludedBackupAlbums: $excludedBackupAlbums, allUniqueAssets: $allUniqueAssets, selectedAlbumsBackupAssetsIds: $selectedAlbumsBackupAssetsIds, currentUploadAsset: $currentUploadAsset)';
}
String toString() =>
'BackUpState(progress: $progress, uploadTasks: $uploadTasks)';
@override
bool operator ==(covariant BackUpState other) {
if (identical(this, other)) return true;
final collectionEquals = const DeepCollectionEquality().equals;
final listEquals = const DeepCollectionEquality().equals;
return other.backupProgress == backupProgress &&
collectionEquals(other.allAssetsInDatabase, allAssetsInDatabase) &&
other.progressInPercentage == progressInPercentage &&
other.progressInFileSize == progressInFileSize &&
other.progressInFileSpeed == progressInFileSpeed &&
collectionEquals(other.progressInFileSpeeds, progressInFileSpeeds) &&
other.progressInFileSpeedUpdateTime == progressInFileSpeedUpdateTime &&
other.progressInFileSpeedUpdateSentBytes ==
progressInFileSpeedUpdateSentBytes &&
other.iCloudDownloadProgress == iCloudDownloadProgress &&
other.cancelToken == cancelToken &&
other.serverInfo == serverInfo &&
other.autoBackup == autoBackup &&
other.backgroundBackup == backgroundBackup &&
other.backupRequireWifi == backupRequireWifi &&
other.backupRequireCharging == backupRequireCharging &&
other.backupTriggerDelay == backupTriggerDelay &&
collectionEquals(other.availableAlbums, availableAlbums) &&
collectionEquals(other.selectedBackupAlbums, selectedBackupAlbums) &&
collectionEquals(other.excludedBackupAlbums, excludedBackupAlbums) &&
collectionEquals(other.allUniqueAssets, allUniqueAssets) &&
collectionEquals(
other.selectedAlbumsBackupAssetsIds,
selectedAlbumsBackupAssetsIds,
) &&
other.currentUploadAsset == currentUploadAsset;
return other.progress == progress &&
listEquals(other.uploadTasks, uploadTasks);
}
@override
int get hashCode {
return backupProgress.hashCode ^
allAssetsInDatabase.hashCode ^
progressInPercentage.hashCode ^
progressInFileSize.hashCode ^
progressInFileSpeed.hashCode ^
progressInFileSpeeds.hashCode ^
progressInFileSpeedUpdateTime.hashCode ^
progressInFileSpeedUpdateSentBytes.hashCode ^
iCloudDownloadProgress.hashCode ^
cancelToken.hashCode ^
serverInfo.hashCode ^
autoBackup.hashCode ^
backgroundBackup.hashCode ^
backupRequireWifi.hashCode ^
backupRequireCharging.hashCode ^
backupTriggerDelay.hashCode ^
availableAlbums.hashCode ^
selectedBackupAlbums.hashCode ^
excludedBackupAlbums.hashCode ^
allUniqueAssets.hashCode ^
selectedAlbumsBackupAssetsIds.hashCode ^
currentUploadAsset.hashCode;
}
int get hashCode => progress.hashCode ^ uploadTasks.hashCode;
}

View file

@ -15,21 +15,31 @@ class BackupPage extends StatefulHookConsumerWidget {
class _BackupPageState extends ConsumerState<BackupPage> {
@override
void initState() {
ref.read(backupNotifierProvider.notifier).backup();
ref.read(backupNotifierProvider.notifier).getBackupCandidates();
super.initState();
}
@override
Widget build(BuildContext context) {
final provider = ref.watch(backupNotifierProvider);
return Scaffold(
appBar: AppBar(
title: const Text("Backup"),
actions: [
IconButton(
icon: const Icon(Icons.play_circle_outline_rounded),
onPressed: () {
ref.read(backupNotifierProvider.notifier).startBackup();
},
),
],
),
body: const Center(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Test"),
Text("Test ${provider.uploadTasks.length}"),
],
),
),

View file

@ -1,25 +1,35 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/models/backup/backup_state.model.dart';
import 'package:immich_mobile/services/backup.service.dart';
import 'package:logging/logging.dart';
class BackupNotifier extends StateNotifier<bool> {
class BackupNotifier extends StateNotifier<BackUpState> {
BackupNotifier(
this._backupService,
) : super(
true,
BackUpState(
progress: BackUpProgressEnum.idle,
uploadTasks: [],
),
);
final log = Logger('BackupNotifier');
final BackupService _backupService;
Future<void> backup() async {
_backupService.buildBackupCandidates();
Future<void> getBackupCandidates() async {
state = state.copyWith(
uploadTasks: await _backupService.getBackupCandidates(),
);
}
Future<void> startBackup() async {
await _backupService.startBackup(state.uploadTasks);
}
}
final backupNotifierProvider =
StateNotifierProvider<BackupNotifier, bool>((ref) {
StateNotifierProvider<BackupNotifier, BackUpState>((ref) {
return BackupNotifier(ref.watch(backupServiceProvider));
});

View file

@ -30,9 +30,23 @@ class BackupService {
final _fileDownloader = FileDownloader();
final ApiService _apiService;
BackupService(this._apiService);
BackupService(this._apiService) {
debugPrint("BackupService created");
// final subscription = FileDownloader().updates.listen((update) {
// switch (update) {
// case TaskStatusUpdate():
// print(
// 'Status update for ${update.task} with status ${update.status}',
// );
// case TaskProgressUpdate():
// print(
// 'Progress update for ${update.task} with progress ${update.progress}',
// );
// }
// });
}
buildBackupCandidates() async {
Future<List<UploadTask>> getBackupCandidates() async {
// Get assets on devices
final albums = await PhotoManager.getAssetPathList(hasAll: true);
List<AssetEntity> assetsOnDevice = await _getAssetsOnDevice(albums);
@ -45,13 +59,15 @@ class BackupService {
// Get assets not on server
if (assetsOnServer != null && assetsOnServer.isNotEmpty) {
assetsOnDevice.removeWhere(
(asset) => !assetsOnServer.contains(asset.id),
(asset) => assetsOnServer.contains(asset.id),
);
}
// Remvove duplicate
assetsOnDevice = assetsOnDevice.toSet().toList();
// Build UploadTask
final uploadTasks = await _constructUploadTask(assetsOnDevice);
print(uploadTasks);
return await _constructUploadTask(assetsOnDevice);
}
Future<List<UploadTask>> _constructUploadTask(
@ -61,7 +77,7 @@ class BackupService {
final String savedEndpoint = Store.get(StoreKey.serverEndpoint);
final String deviceId = Store.get(StoreKey.deviceId);
final url = '$savedEndpoint/asset/upload';
final url = '$savedEndpoint/assets';
final headers = {
'x-immich-user-token': Store.get(StoreKey.accessToken),
'Transfer-Encoding': 'chunked',
@ -69,8 +85,17 @@ class BackupService {
for (final entity in assets) {
final file = await entity.originFile;
final fileName = await entity.titleAsync;
final (baseDirectory, directory, _) = await Task.split(file: file);
if (file == null) {
continue;
}
final originalFileName = await entity.titleAsync;
// final filePath = file.path;
// final split = filePath.split('/');
// final filename = split.last;
// final directory = split.take(split.length - 1).join('/');
final (baseDirectory, directory, filename) = await Task.split(file: file);
final fields = {
'deviceAssetId': entity.id,
@ -79,13 +104,14 @@ class BackupService {
'fileModifiedAt': entity.modifiedDateTime.toUtc().toIso8601String(),
'isFavorite': entity.isFavorite.toString(),
'duration': entity.videoDuration.toString(),
'originalFileName': originalFileName,
};
final task = UploadTask(
url: url,
baseDirectory: baseDirectory,
directory: directory,
filename: fileName,
filename: filename,
group: 'backup',
fileField: 'assetData',
taskId: entity.id,
@ -125,4 +151,27 @@ class BackupService {
return result;
}
Future<void> startBackup(List<UploadTask> tasks) async {
try {
debugPrint("Start backup ${tasks.length} tasks");
for (final task in tasks) {
final result = await _fileDownloader.upload(
task,
onProgress: (percent) => print('${percent * 100} done'),
onStatus: (status) => print('Status for ${task.taskId} is $status)'),
onElapsedTime: (t) => print('time is $t'),
elapsedTimeInterval: const Duration(seconds: 1),
);
print("--------------------");
print('Result Status Code ${result.responseStatusCode}');
print('$result is done with ${result.status}');
print('result ${result.responseBody}');
print('result ${result.responseHeaders}');
}
} catch (e) {
debugPrint("Error uploading tasks: $e");
}
}
}

View file

@ -341,10 +341,10 @@ packages:
dependency: transitive
description:
name: dart_style
sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55"
sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.3.6"
dartx:
dependency: transitive
description: