Compare commits

...

6 Commits

Author SHA1 Message Date
github-actions
ce9b32a61a chore: version v2.6.2 2026-03-24 02:51:55 +00:00
Yaros
4ddc288cd1 fix(mobile/web): album cover buttons consistency (#27213)
* fix(mobile/web): album cover buttons consistency

* test: adjust test
2026-03-23 21:40:17 -05:00
Yaros
94b15b8678 fix(server): album permissions for editors (#27214)
* fix(server): album permissions for editors

* test: adjust e2e test

* test: fix test
2026-03-23 21:39:30 -05:00
Daniel Dietzler
ff9ae24219 fix: album picker show all albums (#27211) 2026-03-23 19:08:57 -05:00
Matthew Momjian
b456f78771 fix(docs): clarify ML CPU architecture (#27187)
* ML architecture

* format

* clarify amd/arm
2026-03-23 18:29:58 -04:00
Mert
1506776891 fix(mobile): add cookie for auxiliary url (#27209)
add cookie before validating
2026-03-23 16:22:46 -05:00
24 changed files with 62 additions and 36 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@immich/cli",
"version": "2.6.1",
"version": "2.6.2",
"description": "Command Line Interface (CLI) for Immich",
"type": "module",
"exports": "./dist/index.js",

View File

@@ -8,7 +8,7 @@ Hardware and software requirements for Immich:
## Hardware
- **OS**: Recommended Linux or \*nix operating system (Ubuntu, Debian, etc).
- **OS**: Recommended Linux or \*nix 64-bit operating system (Ubuntu, Debian, etc).
- Non-Linux OSes tend to provide a poor Docker experience and are strongly discouraged.
Our ability to assist with setup or troubleshooting on non-Linux OSes will be severely reduced.
If you still want to try to use a non-Linux OS, you can set it up as follows:
@@ -19,6 +19,10 @@ Hardware and software requirements for Immich:
If you have issues, we recommend that you switch to a supported VM deployment.
- **RAM**: Minimum 6GB, recommended 8GB.
- **CPU**: Minimum 2 cores, recommended 4 cores.
- Immich runs on the `amd64` and `arm64` platforms.
Since `v2.6`, the machine learning container on `amd64` requires the `>= x86-64-v2` [microarchitecture level](https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels).
Most CPUs released since ~2012 support this microarchitecture.
If you are using a virtual machine, ensure you have selected a [supported microarchitecture](https://pve.proxmox.com/pve-docs/chapter-qm.html#_qemu_cpu_types).
- **Storage**: Recommended Unix-compatible filesystem (EXT4, ZFS, APFS, etc.) with support for user/group ownership and permissions.
- The generation of thumbnails and transcoded video can increase the size of the photo library by 10-20% on average.

View File

@@ -1,7 +1,7 @@
[
{
"label": "v2.6.1",
"url": "https://docs.v2.6.1.archive.immich.app"
"label": "v2.6.2",
"url": "https://docs.v2.6.2.archive.immich.app"
},
{
"label": "v2.5.6",

View File

@@ -1,6 +1,6 @@
{
"name": "immich-e2e",
"version": "2.6.1",
"version": "2.6.2",
"description": "",
"main": "index.js",
"type": "module",

View File

@@ -524,14 +524,19 @@ describe('/albums', () => {
expect(body).toEqual(errorDto.badRequest('Not found or no album.update access'));
});
it('should not be able to update as an editor', async () => {
it('should be able to update as an editor', async () => {
const { status, body } = await request(app)
.patch(`/albums/${user1Albums[0].id}`)
.set('Authorization', `Bearer ${user2.accessToken}`)
.send({ albumName: 'New album name' });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest('Not found or no album.update access'));
expect(status).toBe(200);
expect(body).toEqual(
expect.objectContaining({
id: user1Albums[0].id,
albumName: 'New album name',
}),
);
});
});

View File

@@ -1,6 +1,6 @@
{
"name": "immich-i18n",
"version": "2.6.1",
"version": "2.6.2",
"private": true,
"scripts": {
"format": "prettier --cache --check .",

View File

@@ -1,6 +1,6 @@
[project]
name = "immich-ml"
version = "2.6.1"
version = "2.6.2"
description = ""
authors = [{ name = "Hau Tran", email = "alex.tran1502@gmail.com" }]
requires-python = ">=3.11,<4.0"

View File

@@ -898,7 +898,7 @@ wheels = [
[[package]]
name = "immich-ml"
version = "2.6.1"
version = "2.6.2"
source = { editable = "." }
dependencies = [
{ name = "aiocache" },

View File

@@ -35,8 +35,8 @@ platform :android do
task: 'bundle',
build_type: 'Release',
properties: {
"android.injected.version.code" => 3039,
"android.injected.version.name" => "2.6.1",
"android.injected.version.code" => 3040,
"android.injected.version.name" => "2.6.2",
}
)
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')

View File

@@ -80,7 +80,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.6.1</string>
<string>2.6.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@@ -67,6 +67,9 @@ class AuthService {
bool isValid = false;
try {
final urls = ApiService.getServerUrls();
urls.add(url);
await NetworkRepository.setHeaders(ApiService.getRequestHeaders(), urls);
final uri = Uri.parse('$url/users/me');
final response = await NetworkRepository.client.get(uri);
if (response.statusCode == 200) {

View File

@@ -143,8 +143,7 @@ enum ActionButtonType {
!context.isInLockedView && //
context.currentAlbum != null,
ActionButtonType.setAlbumCover =>
context.isOwner && //
!context.isInLockedView && //
!context.isInLockedView && //
context.currentAlbum != null && //
context.selectedCount == 1,
ActionButtonType.unstack =>

View File

@@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 2.6.1
- API version: 2.6.2
- Generator version: 7.8.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen

View File

@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone
publish_to: 'none'
version: 2.6.1+3039
version: 2.6.2+3040
environment:
sdk: '>=3.8.0 <4.0.0'

View File

@@ -727,7 +727,7 @@ void main() {
expect(ActionButtonType.setAlbumCover.shouldShow(context), isTrue);
});
test('should not show when not owner', () {
test('should show when not owner', () {
final album = createRemoteAlbum();
final context = ActionButtonContext(
asset: mergedAsset,
@@ -742,7 +742,7 @@ void main() {
selectedCount: 1,
);
expect(ActionButtonType.setAlbumCover.shouldShow(context), isFalse);
expect(ActionButtonType.setAlbumCover.shouldShow(context), isTrue);
});
test('should not show when in locked view', () {

View File

@@ -15166,7 +15166,7 @@
"info": {
"title": "Immich",
"description": "Immich API",
"version": "2.6.1",
"version": "2.6.2",
"contact": {}
},
"tags": [

View File

@@ -1,6 +1,6 @@
{
"name": "@immich/sdk",
"version": "2.6.1",
"version": "2.6.2",
"description": "Auto-generated TypeScript SDK for the Immich API",
"type": "module",
"main": "./build/index.js",

View File

@@ -1,6 +1,6 @@
/**
* Immich
* 2.6.1
* 2.6.2
* DO NOT MODIFY - This file has been generated using oazapfts.
* See https://www.npmjs.com/package/oazapfts
*/

View File

@@ -1,6 +1,6 @@
{
"name": "immich-monorepo",
"version": "2.6.1",
"version": "2.6.2",
"description": "Monorepo for Immich",
"private": true,
"packageManager": "pnpm@10.30.3+sha512.c961d1e0a2d8e354ecaa5166b822516668b7f44cb5bd95122d590dd81922f606f5473b6d23ec4a5be05e7fcd18e8488d47d978bbe981872f1145d06e9a740017",

View File

@@ -1,6 +1,6 @@
{
"name": "immich",
"version": "2.6.1",
"version": "2.6.2",
"description": "",
"author": "",
"private": true,

View File

@@ -190,7 +190,13 @@ const checkOtherAccess = async (access: AccessRepository, request: OtherAccessRe
}
case Permission.AlbumUpdate: {
return await access.album.checkOwnerAccess(auth.user.id, ids);
const isOwner = await access.album.checkOwnerAccess(auth.user.id, ids);
const isShared = await access.album.checkSharedAlbumAccess(
auth.user.id,
setDifference(ids, isOwner),
AlbumUserRole.Editor,
);
return setUnion(isOwner, isShared);
}
case Permission.AlbumDelete: {
@@ -198,7 +204,13 @@ const checkOtherAccess = async (access: AccessRepository, request: OtherAccessRe
}
case Permission.AlbumShare: {
return await access.album.checkOwnerAccess(auth.user.id, ids);
const isOwner = await access.album.checkOwnerAccess(auth.user.id, ids);
const isShared = await access.album.checkSharedAlbumAccess(
auth.user.id,
setDifference(ids, isOwner),
AlbumUserRole.Editor,
);
return setUnion(isOwner, isShared);
}
case Permission.AlbumDownload: {

View File

@@ -1,6 +1,6 @@
{
"name": "immich-web",
"version": "2.6.1",
"version": "2.6.2",
"license": "GNU Affero General Public License version 3",
"type": "module",
"scripts": {

View File

@@ -28,7 +28,10 @@
let { onClose }: Props = $props();
onMount(async () => {
albums = await getAllAlbums({});
// TODO the server should *really* just return all albums (paginated ideally)
const ownedAlbums = await getAllAlbums({ shared: false });
ownedAlbums.push.apply(ownedAlbums, await getAllAlbums({ shared: true }));
albums = ownedAlbums;
recentAlbums = albums.sort((a, b) => (new Date(a.updatedAt) > new Date(b.updatedAt) ? -1 : 1)).slice(0, 3);
loading = false;
});

View File

@@ -476,13 +476,6 @@
<ChangeDate menuItem />
<ChangeDescription menuItem />
<ChangeLocation menuItem />
{#if assetInteraction.selectedAssets.length === 1}
<MenuOption
text={$t('set_as_album_cover')}
icon={mdiImageOutline}
onClick={() => updateThumbnailUsingCurrentSelection()}
/>
{/if}
<ArchiveAction
menuItem
unarchive={assetInteraction.isAllArchived}
@@ -490,6 +483,13 @@
/>
<SetVisibilityAction menuItem onVisibilitySet={handleSetVisibility} />
{/if}
{#if assetInteraction.selectedAssets.length === 1}
<MenuOption
text={$t('set_as_album_cover')}
icon={mdiImageOutline}
onClick={() => updateThumbnailUsingCurrentSelection()}
/>
{/if}
{#if $preferences.tags.enabled && assetInteraction.isAllUserOwned}
<TagAction menuItem />