mirror of
https://github.com/immich-app/immich.git
synced 2026-02-09 19:29:27 +03:00
fix: album thumbnail refresh
This commit is contained in:
@@ -2221,6 +2221,71 @@
|
||||
"x-immich-state": "Stable"
|
||||
}
|
||||
},
|
||||
"/albums/{id}/thumbnail": {
|
||||
"get": {
|
||||
"description": "Virtual route that redirects to the thumbnail of the album cover asset.",
|
||||
"operationId": "getAlbumThumbnailRedirect",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"format": "uuid",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "key",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "slug",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
},
|
||||
{
|
||||
"cookie": []
|
||||
},
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"summary": "Redirect to album thumbnail",
|
||||
"tags": [
|
||||
"Albums"
|
||||
],
|
||||
"x-immich-history": [
|
||||
{
|
||||
"version": "v2.6.0",
|
||||
"state": "Added"
|
||||
},
|
||||
{
|
||||
"version": "v2.6.0",
|
||||
"state": "Beta"
|
||||
}
|
||||
],
|
||||
"x-immich-permission": "album.read",
|
||||
"x-immich-state": "Beta"
|
||||
}
|
||||
},
|
||||
"/albums/{id}/user/{userId}": {
|
||||
"delete": {
|
||||
"description": "Remove a user from an album. Use an ID of \"me\" to leave a shared album.",
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Patch, Post, Put, Query } from '@nestjs/common';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Patch,
|
||||
Post,
|
||||
Put,
|
||||
Query,
|
||||
Redirect,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { Endpoint, HistoryBuilder } from 'src/decorators';
|
||||
import {
|
||||
@@ -73,6 +86,19 @@ export class AlbumController {
|
||||
return this.service.get(auth, id, dto);
|
||||
}
|
||||
|
||||
@Authenticated({ permission: Permission.AlbumRead, sharedLink: true })
|
||||
@Get(':id/thumbnail')
|
||||
@Redirect()
|
||||
@Endpoint({
|
||||
summary: 'Redirect to album thumbnail',
|
||||
description: 'Virtual route that redirects to the thumbnail of the album cover asset.',
|
||||
history: new HistoryBuilder().added('v2.6.0').beta('v2.6.0'),
|
||||
})
|
||||
async getAlbumThumbnailRedirect(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto) {
|
||||
const url = await this.service.getThumbnailRedirectUrl(auth, id);
|
||||
return { url, status: 307 };
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@Authenticated({ permission: Permission.AlbumUpdate })
|
||||
@Endpoint({
|
||||
|
||||
@@ -87,6 +87,16 @@ export class AlbumRepository {
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] })
|
||||
async getForThumbnailRedirect(id: string) {
|
||||
return this.db
|
||||
.selectFrom('asset')
|
||||
.innerJoin('album', 'album.albumThumbnailAssetId', 'asset.id')
|
||||
.where('album.id', '=', id)
|
||||
.select(['asset.id', 'asset.thumbhash'])
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID] })
|
||||
async getByAssetId(ownerId: string, assetId: string) {
|
||||
return this.db
|
||||
|
||||
@@ -21,6 +21,7 @@ import { Permission } from 'src/enum';
|
||||
import { AlbumAssetCount, AlbumInfoOptions } from 'src/repositories/album.repository';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
import { addAssets, removeAssets } from 'src/utils/asset.util';
|
||||
import { hexOrBufferToBase64 } from 'src/utils/bytes';
|
||||
import { getPreferences } from 'src/utils/preferences';
|
||||
|
||||
@Injectable()
|
||||
@@ -93,6 +94,23 @@ export class AlbumService extends BaseService {
|
||||
};
|
||||
}
|
||||
|
||||
async getThumbnailRedirectUrl(auth: AuthDto, id: string) {
|
||||
await this.requireAccess({ auth, permission: Permission.AlbumRead, ids: [id] });
|
||||
|
||||
const asset = await this.albumRepository.getForThumbnailRedirect(id);
|
||||
if (!asset) {
|
||||
throw new BadRequestException('Album has no thumbnail');
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.append('edited', 'true');
|
||||
if (asset.thumbhash) {
|
||||
params.append('c', hexOrBufferToBase64(asset.thumbhash));
|
||||
}
|
||||
|
||||
return `/api/assets/${asset.id}/thumbnail?${params.toString()}`;
|
||||
}
|
||||
|
||||
async create(auth: AuthDto, dto: CreateAlbumDto): Promise<AlbumResponseDto> {
|
||||
const albumUsers = dto.albumUsers || [];
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import AssetCover from '$lib/components/sharedlinks-page/covers/asset-cover.svelte';
|
||||
import NoCover from '$lib/components/sharedlinks-page/covers/no-cover.svelte';
|
||||
import { getAssetMediaUrl } from '$lib/utils';
|
||||
import { type AlbumResponseDto } from '@immich/sdk';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
@@ -14,9 +13,7 @@
|
||||
let { album, preload = false, class: className = '' }: Props = $props();
|
||||
|
||||
let alt = $derived(album.albumName || $t('unnamed_album'));
|
||||
let thumbnailUrl = $derived(
|
||||
album.albumThumbnailAssetId ? getAssetMediaUrl({ id: album.albumThumbnailAssetId }) : null,
|
||||
);
|
||||
let thumbnailUrl = $derived(album.albumThumbnailAssetId ? `/api/albums/${album.id}/thumbnail` : null);
|
||||
</script>
|
||||
|
||||
{#if thumbnailUrl}
|
||||
|
||||
Reference in New Issue
Block a user