221 lines
5.9 KiB
TypeScript
221 lines
5.9 KiB
TypeScript
import { Injectable } from '@angular/core';
|
|
import {
|
|
ImageDeleteRequest,
|
|
ImageDeleteResponse,
|
|
ImageListRequest,
|
|
ImageListResponse,
|
|
ImageUpdateRequest,
|
|
ImageUpdateResponse,
|
|
ImageUploadResponse
|
|
} from 'picsur-shared/dist/dto/api/image-manage.dto';
|
|
import {
|
|
ImageMetaResponse,
|
|
ImageRequestParams
|
|
} from 'picsur-shared/dist/dto/api/image.dto';
|
|
import { ImageLinks } from 'picsur-shared/dist/dto/image-links.class';
|
|
import { FileType2Ext } from 'picsur-shared/dist/dto/mimes.dto';
|
|
import { EImage } from 'picsur-shared/dist/entities/image.entity';
|
|
import { AsyncFailable } from 'picsur-shared/dist/types';
|
|
import {
|
|
Fail,
|
|
FT,
|
|
HasFailed,
|
|
HasSuccess,
|
|
Open
|
|
} from 'picsur-shared/dist/types/failable';
|
|
import { ImagesUploadRequest } from 'src/app/models/dto/images-upload-request.dto';
|
|
import { ImageUploadRequest } from '../../models/dto/image-upload-request.dto';
|
|
import { ApiService } from './api.service';
|
|
import { InfoService } from './info.service';
|
|
import { UserService } from './user.service';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class ImageService {
|
|
constructor(
|
|
private readonly api: ApiService,
|
|
private readonly infoService: InfoService,
|
|
private readonly userService: UserService,
|
|
) {}
|
|
|
|
public async UploadImage(image: File): AsyncFailable<string> {
|
|
const result = await this.api.postForm(
|
|
ImageUploadResponse,
|
|
'/api/image/upload',
|
|
new ImageUploadRequest(image),
|
|
).result;
|
|
|
|
return Open(result, 'id');
|
|
}
|
|
|
|
public async UploadImages(images: File[]): AsyncFailable<string[]> {
|
|
console.log('Uploading images', images);
|
|
|
|
// Split into chunks of 20
|
|
const groups = this.chunks(images, 20);
|
|
|
|
const result = await this.api.postForm(
|
|
ImageUploadResponse,
|
|
'/api/image/upload/bulk',
|
|
new ImagesUploadRequest(images),
|
|
);
|
|
|
|
return [];
|
|
}
|
|
|
|
public async GetImageMeta(image: string): AsyncFailable<ImageMetaResponse> {
|
|
return await this.api.get(ImageMetaResponse, `/i/meta/${image}`).result;
|
|
}
|
|
|
|
public async ListAllImages(
|
|
count: number,
|
|
page: number,
|
|
userID?: string,
|
|
): AsyncFailable<ImageListResponse> {
|
|
return await this.api.post(
|
|
ImageListRequest,
|
|
ImageListResponse,
|
|
'/api/image/list',
|
|
{
|
|
count,
|
|
page,
|
|
user_id: userID,
|
|
},
|
|
).result;
|
|
}
|
|
|
|
public async ListMyImages(
|
|
count: number,
|
|
page: number,
|
|
): AsyncFailable<ImageListResponse> {
|
|
const userID = await this.userService.snapshot?.id;
|
|
if (userID === undefined) {
|
|
return Fail(FT.Authentication, 'User not logged in');
|
|
}
|
|
|
|
return await this.ListAllImages(count, page, userID);
|
|
}
|
|
|
|
public async UpdateImage(
|
|
id: string,
|
|
settings: Partial<Pick<EImage, 'file_name' | 'expires_at'>>,
|
|
): AsyncFailable<EImage> {
|
|
return await this.api.post(
|
|
ImageUpdateRequest,
|
|
ImageUpdateResponse,
|
|
'/api/image/update',
|
|
{
|
|
id,
|
|
...settings,
|
|
},
|
|
).result;
|
|
}
|
|
|
|
public async DeleteImages(
|
|
images: string[],
|
|
): AsyncFailable<ImageDeleteResponse> {
|
|
return await this.api.post(
|
|
ImageDeleteRequest,
|
|
ImageDeleteResponse,
|
|
'/api/image/delete',
|
|
{
|
|
ids: images,
|
|
},
|
|
).result;
|
|
}
|
|
|
|
public async DeleteImage(image: string): AsyncFailable<EImage> {
|
|
const result = await this.DeleteImages([image]);
|
|
if (HasFailed(result)) return result;
|
|
|
|
if (result.images.length !== 1) {
|
|
return Fail(
|
|
FT.Unknown,
|
|
`Image ${image} was not deleted, probably lacking permissions`,
|
|
);
|
|
}
|
|
|
|
return result.images[0];
|
|
}
|
|
|
|
// Non api calls
|
|
|
|
// Use for native images
|
|
public GetImageURL(
|
|
image: string,
|
|
filetype: string | null,
|
|
allowOverride = false,
|
|
): string {
|
|
const baseURL = this.infoService.getHostname(allowOverride);
|
|
const extension = FileType2Ext(filetype ?? '');
|
|
|
|
return `${baseURL}/i/${image}${
|
|
HasSuccess(extension) ? '.' + extension : ''
|
|
}`;
|
|
}
|
|
|
|
// Use for user facing urls
|
|
public CreateImageLinks(imageURL: string, name?: string): ImageLinks {
|
|
return {
|
|
source: imageURL,
|
|
markdown: `![image](${imageURL})`,
|
|
html: `<img src="${imageURL}" alt="${name ?? 'image'}">`,
|
|
rst: `.. image:: ${imageURL}`,
|
|
bbcode: `[img]${imageURL}[/img]`,
|
|
};
|
|
}
|
|
|
|
public GetImageURLCustomized(
|
|
image: string,
|
|
filetype: string | null,
|
|
options: ImageRequestParams,
|
|
): string {
|
|
const baseURL = this.GetImageURL(image, filetype, true);
|
|
const betterOptions = ImageRequestParams.zodSchema.safeParse(options);
|
|
|
|
if (!betterOptions.success) return baseURL;
|
|
|
|
let queryParams: string[] = [];
|
|
|
|
if (options.height !== undefined)
|
|
queryParams.push(`height=${options.height}`);
|
|
if (options.width !== undefined) queryParams.push(`width=${options.width}`);
|
|
if (options.rotate !== undefined)
|
|
queryParams.push(`rotate=${options.rotate}`);
|
|
if (options.flipx !== undefined) queryParams.push(`flipx=${options.flipx}`);
|
|
if (options.flipy !== undefined) queryParams.push(`flipy=${options.flipy}`);
|
|
if (options.shrinkonly !== undefined)
|
|
queryParams.push(`shrinkonly=${options.shrinkonly}`);
|
|
if (options.greyscale !== undefined)
|
|
queryParams.push(`greyscale=${options.greyscale}`);
|
|
if (options.noalpha !== undefined)
|
|
queryParams.push(`noalpha=${options.noalpha}`);
|
|
if (options.negative !== undefined)
|
|
queryParams.push(`negative=${options.negative}`);
|
|
if (options.quality !== undefined)
|
|
queryParams.push(`quality=${options.quality}`);
|
|
|
|
if (queryParams.length === 0) return baseURL;
|
|
|
|
return baseURL + '?' + queryParams.join('&');
|
|
}
|
|
|
|
public CreateImageLinksFromID(
|
|
imageID: string,
|
|
mime: string | null,
|
|
name?: string,
|
|
): ImageLinks {
|
|
return this.CreateImageLinks(this.GetImageURL(imageID, mime, true), name);
|
|
}
|
|
|
|
private chunks<T>(arr: T[], size: number): T[][] {
|
|
let result = [];
|
|
for (let i = 0; i < arr.length; i += size) {
|
|
result.push(arr.slice(i, size + i));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|