Compare commits
8 Commits
v1.28.1_39
...
v1.28.3_41
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4271e24e59 | ||
|
|
9e4ed2214b | ||
|
|
011332e509 | ||
|
|
5403ef4d84 | ||
|
|
31739aca02 | ||
|
|
8f2e7b6f65 | ||
|
|
4ed647c43d | ||
|
|
f88ff4fb5c |
25
install.sh
25
install.sh
@@ -6,10 +6,6 @@ RED='\033[0;31m'
|
|||||||
GREEN='\032[0;31m'
|
GREEN='\032[0;31m'
|
||||||
NC='\033[0m' # No Color
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
machine_has() {
|
|
||||||
type "$1" >/dev/null 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
create_immich_directory() {
|
create_immich_directory() {
|
||||||
echo "Creating Immich directory..."
|
echo "Creating Immich directory..."
|
||||||
mkdir -p ./immich-app/immich-data
|
mkdir -p ./immich-app/immich-data
|
||||||
@@ -45,18 +41,21 @@ populate_upload_location() {
|
|||||||
start_docker_compose() {
|
start_docker_compose() {
|
||||||
echo "Starting Immich's docker containers"
|
echo "Starting Immich's docker containers"
|
||||||
|
|
||||||
if machine_has "docker compose"; then {
|
if docker compose &> /dev/null; then
|
||||||
docker compose up --remove-orphans -d
|
docker_bin="docker compose"
|
||||||
|
elif docker-compose &> /dev/null; then
|
||||||
show_friendly_message
|
docker_bin="docker-compose"
|
||||||
exit 0
|
else
|
||||||
}; fi
|
echo 'Cannot find `docker compose` or `docker-compose`.'
|
||||||
|
exit 1
|
||||||
if machine_has "docker-compose"; then
|
fi
|
||||||
docker-compose up --remove-orphans -d
|
|
||||||
|
|
||||||
|
if $docker_bin up --remove-orphans -d; then
|
||||||
show_friendly_message
|
show_friendly_message
|
||||||
exit 0
|
exit 0
|
||||||
|
else
|
||||||
|
echo "Could not start. Check for errors above."
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ platform :android do
|
|||||||
task: 'bundle',
|
task: 'bundle',
|
||||||
build_type: 'Release',
|
build_type: 'Release',
|
||||||
properties: {
|
properties: {
|
||||||
"android.injected.version.code" => 39,
|
"android.injected.version.code" => 41,
|
||||||
"android.injected.version.name" => "1.28.1",
|
"android.injected.version.name" => "1.28.3",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
* Fix background service cannot run in release build
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
* Fixed oversize play button on video
|
||||||
|
* Fixed app crashing when swipe between assets
|
||||||
@@ -5,17 +5,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000222">
|
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.00023">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="55.311329">
|
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="58.722434">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="30.070842">
|
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="36.768014">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|||||||
@@ -360,7 +360,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 52;
|
CURRENT_PROJECT_VERSION = 55;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -495,7 +495,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 52;
|
CURRENT_PROJECT_VERSION = 55;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -522,7 +522,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 52;
|
CURRENT_PROJECT_VERSION = 55;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.27.0</string>
|
<string>1.28.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>52</string>
|
<string>55</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true />
|
<true />
|
||||||
<key>MGLMapboxMetricsEnabledSettingShownInApp</key>
|
<key>MGLMapboxMetricsEnabledSettingShownInApp</key>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ platform :ios do
|
|||||||
desc "iOS Beta"
|
desc "iOS Beta"
|
||||||
lane :beta do
|
lane :beta do
|
||||||
increment_version_number(
|
increment_version_number(
|
||||||
version_number: "1.28.1"
|
version_number: "1.28.3"
|
||||||
)
|
)
|
||||||
increment_build_number(
|
increment_build_number(
|
||||||
build_number: latest_testflight_build_number + 1,
|
build_number: latest_testflight_build_number + 1,
|
||||||
|
|||||||
@@ -5,32 +5,32 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000269">
|
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000199">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.499192">
|
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.594905">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="30.057077">
|
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="4.207648">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.438506">
|
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.391989">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="4: build_app" time="91.259106">
|
<testcase classname="fastlane.lanes" name="4: build_app" time="77.835137">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="102.092139">
|
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="70.775758">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ class _RemotePhotoViewState extends State<RemotePhotoView> {
|
|||||||
bool _zoomedIn = false;
|
bool _zoomedIn = false;
|
||||||
|
|
||||||
static const int swipeThreshold = 100;
|
static const int swipeThreshold = 100;
|
||||||
|
late CachedNetworkImageProvider fullProvider;
|
||||||
|
late CachedNetworkImageProvider previewProvider;
|
||||||
|
late CachedNetworkImageProvider thumbnailProvider;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -65,7 +68,10 @@ class _RemotePhotoViewState extends State<RemotePhotoView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CachedNetworkImageProvider _authorizedImageProvider(
|
CachedNetworkImageProvider _authorizedImageProvider(
|
||||||
String url, String cacheKey, BaseCacheManager? cacheManager) {
|
String url,
|
||||||
|
String cacheKey,
|
||||||
|
BaseCacheManager? cacheManager,
|
||||||
|
) {
|
||||||
return CachedNetworkImageProvider(
|
return CachedNetworkImageProvider(
|
||||||
url,
|
url,
|
||||||
headers: {"Authorization": widget.authToken},
|
headers: {"Authorization": widget.authToken},
|
||||||
@@ -104,7 +110,7 @@ class _RemotePhotoViewState extends State<RemotePhotoView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _loadImages() {
|
void _loadImages() {
|
||||||
CachedNetworkImageProvider thumbnailProvider = _authorizedImageProvider(
|
thumbnailProvider = _authorizedImageProvider(
|
||||||
widget.thumbnailUrl,
|
widget.thumbnailUrl,
|
||||||
widget.cacheKey,
|
widget.cacheKey,
|
||||||
widget.thumbnailCacheManager,
|
widget.thumbnailCacheManager,
|
||||||
@@ -121,7 +127,7 @@ class _RemotePhotoViewState extends State<RemotePhotoView> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (widget.previewUrl != null) {
|
if (widget.previewUrl != null) {
|
||||||
CachedNetworkImageProvider previewProvider = _authorizedImageProvider(
|
previewProvider = _authorizedImageProvider(
|
||||||
widget.previewUrl!,
|
widget.previewUrl!,
|
||||||
"${widget.cacheKey}_previewStage",
|
"${widget.cacheKey}_previewStage",
|
||||||
widget.previewCacheManager,
|
widget.previewCacheManager,
|
||||||
@@ -133,7 +139,7 @@ class _RemotePhotoViewState extends State<RemotePhotoView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedNetworkImageProvider fullProvider = _authorizedImageProvider(
|
fullProvider = _authorizedImageProvider(
|
||||||
widget.imageUrl,
|
widget.imageUrl,
|
||||||
"${widget.cacheKey}_fullStage",
|
"${widget.cacheKey}_fullStage",
|
||||||
widget.fullCacheManager,
|
widget.fullCacheManager,
|
||||||
@@ -150,6 +156,19 @@ class _RemotePhotoViewState extends State<RemotePhotoView> {
|
|||||||
_loadImages();
|
_loadImages();
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() async {
|
||||||
|
super.dispose();
|
||||||
|
await thumbnailProvider.evict();
|
||||||
|
await fullProvider.evict();
|
||||||
|
|
||||||
|
if (widget.previewUrl != null) {
|
||||||
|
await previewProvider.evict();
|
||||||
|
}
|
||||||
|
|
||||||
|
_imageProvider.evict();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RemotePhotoView extends StatefulWidget {
|
class RemotePhotoView extends StatefulWidget {
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class _VideoThumbnailPlayerState extends State<VideoThumbnailPlayer> {
|
|||||||
_createChewieController() {
|
_createChewieController() {
|
||||||
chewieController = ChewieController(
|
chewieController = ChewieController(
|
||||||
showOptions: true,
|
showOptions: true,
|
||||||
showControlsOnInitialize: true,
|
showControlsOnInitialize: false,
|
||||||
videoPlayerController: videoPlayerController,
|
videoPlayerController: videoPlayerController,
|
||||||
autoPlay: true,
|
autoPlay: true,
|
||||||
autoInitialize: true,
|
autoInitialize: true,
|
||||||
|
|||||||
@@ -173,7 +173,8 @@ class BackgroundService {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
debugPrint(
|
debugPrint(
|
||||||
"[_clearErrorNotifications] failed to communicate with plugin");
|
"[_clearErrorNotifications] failed to communicate with plugin",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -344,7 +345,9 @@ class BackgroundService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _runBackup(
|
Future<bool> _runBackup(
|
||||||
BackupService backupService, HiveBackupAlbums backupAlbumInfo) async {
|
BackupService backupService,
|
||||||
|
HiveBackupAlbums backupAlbumInfo,
|
||||||
|
) async {
|
||||||
_errorGracePeriodExceeded = _isErrorGracePeriodExceeded();
|
_errorGracePeriodExceeded = _isErrorGracePeriodExceeded();
|
||||||
|
|
||||||
if (_canceledBySystem) {
|
if (_canceledBySystem) {
|
||||||
@@ -445,6 +448,7 @@ class BackgroundService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// entry point called by Kotlin/Java code; needs to be a top-level function
|
/// entry point called by Kotlin/Java code; needs to be a top-level function
|
||||||
|
@pragma('vm:entry-point')
|
||||||
void _nativeEntry() {
|
void _nativeEntry() {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
BackgroundService backgroundService = BackgroundService();
|
BackgroundService backgroundService = BackgroundService();
|
||||||
|
|||||||
@@ -173,19 +173,19 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
).tr(),
|
).tr(),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
OutlinedButton(
|
||||||
onPressed: () => launchUrl(
|
onPressed: () => launchUrl(
|
||||||
Uri.parse('https://dontkillmyapp.com'),
|
Uri.parse('https://dontkillmyapp.com'),
|
||||||
mode: LaunchMode.externalApplication),
|
mode: LaunchMode.externalApplication,
|
||||||
child: Text(
|
),
|
||||||
|
child: const Text(
|
||||||
"backup_controller_page_background_battery_info_link",
|
"backup_controller_page_background_battery_info_link",
|
||||||
style: TextStyle(color: buttonTextColor),
|
|
||||||
).tr(),
|
).tr(),
|
||||||
),
|
),
|
||||||
TextButton(
|
ElevatedButton(
|
||||||
child: Text(
|
child: const Text(
|
||||||
'backup_controller_page_background_battery_info_ok',
|
'backup_controller_page_background_battery_info_ok',
|
||||||
style: TextStyle(color: buttonTextColor),
|
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
|
||||||
).tr(),
|
).tr(),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
@@ -636,8 +636,8 @@ class BackupControllerPage extends HookConsumerWidget {
|
|||||||
backupState.backupProgress == BackUpProgressEnum.inProgress
|
backupState.backupProgress == BackUpProgressEnum.inProgress
|
||||||
? ElevatedButton(
|
? ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
primary: Colors.red[300],
|
foregroundColor: Colors.grey[50],
|
||||||
onPrimary: Colors.grey[50],
|
backgroundColor: Colors.red[300],
|
||||||
// padding: const EdgeInsets.all(14),
|
// padding: const EdgeInsets.all(14),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ packages:
|
|||||||
name: chewie
|
name: chewie
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.3.5"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -238,7 +238,7 @@ packages:
|
|||||||
name: cupertino_icons
|
name: cupertino_icons
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.5"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -839,7 +839,7 @@ packages:
|
|||||||
name: provider
|
name: provider
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.2"
|
version: "6.0.3"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1223,27 +1223,20 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.2"
|
||||||
very_good_analysis:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: very_good_analysis
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.4.0"
|
|
||||||
video_player:
|
video_player:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: video_player
|
name: video_player
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.2"
|
version: "2.4.7"
|
||||||
video_player_android:
|
video_player_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: video_player_android
|
name: video_player_android
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.3"
|
version: "2.3.9"
|
||||||
video_player_avfoundation:
|
video_player_avfoundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1271,7 +1264,7 @@ packages:
|
|||||||
name: wakelock
|
name: wakelock
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.1+2"
|
version: "0.6.2"
|
||||||
wakelock_macos:
|
wakelock_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ name: immich_mobile
|
|||||||
description: Immich - selfhosted backup media file on mobile phone
|
description: Immich - selfhosted backup media file on mobile phone
|
||||||
|
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
version: 1.28.1+39
|
version: 1.28.3+41
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.17.0 <3.0.0"
|
sdk: ">=2.17.0 <3.0.0"
|
||||||
@@ -26,7 +26,7 @@ dependencies:
|
|||||||
flutter_launcher_icons: "^0.9.2"
|
flutter_launcher_icons: "^0.9.2"
|
||||||
fluttertoast: ^8.0.8
|
fluttertoast: ^8.0.8
|
||||||
video_player: ^2.2.18
|
video_player: ^2.2.18
|
||||||
chewie: ^1.2.2
|
chewie: ^1.3.5
|
||||||
badges: ^2.0.2
|
badges: ^2.0.2
|
||||||
photo_view: ^0.14.0
|
photo_view: ^0.14.0
|
||||||
socket_io_client: ^2.0.0-beta.4-nullsafety.0
|
socket_io_client: ^2.0.0-beta.4-nullsafety.0
|
||||||
|
|||||||
@@ -50,9 +50,14 @@ export class AlbumRepository implements IAlbumRepository {
|
|||||||
where: { sharedUserId: userId },
|
where: { sharedUserId: userId },
|
||||||
});
|
});
|
||||||
|
|
||||||
const sharingAlbums = ownedAlbums.map((album) => album.sharedUsers?.length || 0).reduce((a, b) => a + b, 0);
|
let sharedAlbumCount = 0;
|
||||||
|
ownedAlbums.map((album) => {
|
||||||
|
if (album.sharedUsers?.length) {
|
||||||
|
sharedAlbumCount += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return new AlbumCountResponseDto(ownedAlbums.length, sharedAlbums, sharingAlbums);
|
return new AlbumCountResponseDto(ownedAlbums.length, sharedAlbums, sharedAlbumCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(ownerId: string, createAlbumDto: CreateAlbumDto): Promise<AlbumEntity> {
|
async create(ownerId: string, createAlbumDto: CreateAlbumDto): Promise<AlbumEntity> {
|
||||||
|
|||||||
@@ -11,6 +11,6 @@ export interface IServerVersion {
|
|||||||
export const serverVersion: IServerVersion = {
|
export const serverVersion: IServerVersion = {
|
||||||
major: 1,
|
major: 1,
|
||||||
minor: 28,
|
minor: 28,
|
||||||
patch: 1,
|
patch: 3,
|
||||||
build: 39,
|
build: 41,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import cookieParser from 'cookie-parser';
|
|||||||
import { writeFileSync } from 'fs';
|
import { writeFileSync } from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
|
import { serverVersion } from './constants/server_version.constant';
|
||||||
import { RedisIoAdapter } from './middlewares/redis-io.adapter.middleware';
|
import { RedisIoAdapter } from './middlewares/redis-io.adapter.middleware';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
@@ -52,11 +53,17 @@ async function bootstrap() {
|
|||||||
// Generate API Documentation only in development mode
|
// Generate API Documentation only in development mode
|
||||||
const outputPath = path.resolve(process.cwd(), 'immich-openapi-specs.json');
|
const outputPath = path.resolve(process.cwd(), 'immich-openapi-specs.json');
|
||||||
writeFileSync(outputPath, JSON.stringify(apiDocument), { encoding: 'utf8' });
|
writeFileSync(outputPath, JSON.stringify(apiDocument), { encoding: 'utf8' });
|
||||||
Logger.log('Running Immich Server in DEVELOPMENT environment', 'ImmichServer');
|
Logger.log(
|
||||||
|
`Running Immich Server in DEVELOPMENT environment - version ${serverVersion.major}.${serverVersion.minor}.${serverVersion.patch}`,
|
||||||
|
'ImmichServer',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.NODE_ENV == 'production') {
|
if (process.env.NODE_ENV == 'production') {
|
||||||
Logger.log('Running Immich Server in PRODUCTION environment', 'ImmichServer');
|
Logger.log(
|
||||||
|
`Running Immich Server in PRODUCTION environment - version ${serverVersion.major}.${serverVersion.minor}.${serverVersion.patch}`,
|
||||||
|
'ImmichServer',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Logger } from '@nestjs/common';
|
import { Logger } from '@nestjs/common';
|
||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
|
import { serverVersion } from 'apps/immich/src/constants/server_version.constant';
|
||||||
import { RedisIoAdapter } from '../../immich/src/middlewares/redis-io.adapter.middleware';
|
import { RedisIoAdapter } from '../../immich/src/middlewares/redis-io.adapter.middleware';
|
||||||
import { MicroservicesModule } from './microservices.module';
|
import { MicroservicesModule } from './microservices.module';
|
||||||
|
|
||||||
@@ -10,11 +11,17 @@ async function bootstrap() {
|
|||||||
|
|
||||||
await app.listen(3002, () => {
|
await app.listen(3002, () => {
|
||||||
if (process.env.NODE_ENV == 'development') {
|
if (process.env.NODE_ENV == 'development') {
|
||||||
Logger.log('Running Immich Microservices in DEVELOPMENT environment', 'ImmichMicroservice');
|
Logger.log(
|
||||||
|
`Running Immich Microservices in DEVELOPMENT environment - version ${serverVersion.major}.${serverVersion.minor}.${serverVersion.patch}`,
|
||||||
|
'ImmichMicroservice',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.NODE_ENV == 'production') {
|
if (process.env.NODE_ENV == 'production') {
|
||||||
Logger.log('Running Immich Microservices in PRODUCTION environment', 'ImmichMicroservice');
|
Logger.log(
|
||||||
|
`Running Immich Microservices in PRODUCTION environment - version ${serverVersion.major}.${serverVersion.minor}.${serverVersion.patch}`,
|
||||||
|
'ImmichMicroservice',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Logger } from '@nestjs/common';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { createHash } from 'node:crypto';
|
import { createHash } from 'node:crypto';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import { IsNull, Repository } from 'typeorm';
|
import { FindOptionsWhere, IsNull, MoreThan, QueryFailedError, Repository } from 'typeorm';
|
||||||
|
|
||||||
// TODO: just temporary task to generate previous uploaded assets.
|
// TODO: just temporary task to generate previous uploaded assets.
|
||||||
@Processor(generateChecksumQueueName)
|
@Processor(generateChecksumQueueName)
|
||||||
@@ -17,15 +17,23 @@ export class GenerateChecksumProcessor {
|
|||||||
|
|
||||||
@Process()
|
@Process()
|
||||||
async generateChecksum() {
|
async generateChecksum() {
|
||||||
let hasNext = true;
|
|
||||||
const pageSize = 200;
|
const pageSize = 200;
|
||||||
|
let hasNext = true;
|
||||||
|
let lastErrAssetId: string | undefined = undefined;
|
||||||
|
|
||||||
while (hasNext) {
|
while (hasNext) {
|
||||||
|
const whereStat: FindOptionsWhere<AssetEntity> = {
|
||||||
|
checksum: IsNull(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (lastErrAssetId) {
|
||||||
|
whereStat.id = MoreThan(lastErrAssetId);
|
||||||
|
}
|
||||||
|
|
||||||
const assets = await this.assetRepository.find({
|
const assets = await this.assetRepository.find({
|
||||||
where: {
|
where: whereStat,
|
||||||
checksum: IsNull()
|
|
||||||
},
|
|
||||||
take: pageSize,
|
take: pageSize,
|
||||||
|
order: { id: 'ASC' }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!assets?.length) {
|
if (!assets?.length) {
|
||||||
@@ -35,15 +43,24 @@ export class GenerateChecksumProcessor {
|
|||||||
try {
|
try {
|
||||||
await this.generateAssetChecksum(asset);
|
await this.generateAssetChecksum(asset);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
Logger.error(`Error generate checksum ${err}`);
|
lastErrAssetId = asset.id;
|
||||||
|
|
||||||
|
if (err instanceof QueryFailedError && (err as any).constraint === 'UQ_userid_checksum') {
|
||||||
|
Logger.error(`${asset.originalPath} duplicated`);
|
||||||
|
} else {
|
||||||
|
Logger.error(`checksum generation ${err}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// break when reach to the last page
|
||||||
if (assets.length < pageSize) {
|
if (assets.length < pageSize) {
|
||||||
hasNext = false;
|
hasNext = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.log(`checksum generation done!`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async generateAssetChecksum(asset: AssetEntity) {
|
private async generateAssetChecksum(asset: AssetEntity) {
|
||||||
|
|||||||
Reference in New Issue
Block a user