|
|
|
@ -13,6 +13,8 @@ import {SortKey} from "../../models/SortKey";
|
|
|
|
|
export class FileService {
|
|
|
|
|
|
|
|
|
|
displayedFiles = new BehaviorSubject<File[]>([]);
|
|
|
|
|
pendingThumbnails: {[key:number]: BehaviorSubject<boolean>} = {};
|
|
|
|
|
thumbnailCache: {[key: number]: Thumbnail[]} = {};
|
|
|
|
|
|
|
|
|
|
constructor(@Inject(DomSanitizer) private sanitizer: DomSanitizer) {
|
|
|
|
|
|
|
|
|
@ -35,15 +37,59 @@ export class FileService {
|
|
|
|
|
return this.sanitizer.bypassSecurityTrustResourceUrl(once_uri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the thumbnail for a file with a specific size (allowing +-10%)
|
|
|
|
|
* If none can be found it asks the backend if it has one or generates one of that size
|
|
|
|
|
* @param {File} file
|
|
|
|
|
* @param {number} width
|
|
|
|
|
* @param {number} height
|
|
|
|
|
* @returns {Promise<SafeResourceUrl>}
|
|
|
|
|
*/
|
|
|
|
|
public async getFileThumbnail(file: File, width: number, height: number): Promise<SafeResourceUrl> {
|
|
|
|
|
let subject = this.pendingThumbnails[file.id];
|
|
|
|
|
if (subject && !await subject.toPromise()) { // avoid calling for the same thumbnail multiple times
|
|
|
|
|
await subject.toPromise();
|
|
|
|
|
}
|
|
|
|
|
subject = new BehaviorSubject<boolean>(false);
|
|
|
|
|
this.pendingThumbnails[file.id] = subject;
|
|
|
|
|
setTimeout(() => subject.next(true), 5000); // allow new request after 5 seconds max
|
|
|
|
|
const thumbnails = await this.getThumbnails(file);
|
|
|
|
|
const thumbnail = thumbnails.find(t => t.height >= height * 0.7 && t.width >= width * 0.7 && t.height <= height * 1.3 && t.width <= width * 1.3);
|
|
|
|
|
let url;
|
|
|
|
|
|
|
|
|
|
if (thumbnail) {
|
|
|
|
|
url = await this.readThumbnail(thumbnail);
|
|
|
|
|
} else {
|
|
|
|
|
url = await this.getThumbnailOfSize(file, height * 0.9, width * 0.9, height * 1.1, width * 1.1);
|
|
|
|
|
delete this.thumbnailCache[file.id];
|
|
|
|
|
}
|
|
|
|
|
this.pendingThumbnails[file.id].next(true);
|
|
|
|
|
delete this.pendingThumbnails[file.id];
|
|
|
|
|
|
|
|
|
|
return url;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async readThumbnail(thumbnail: Thumbnail): Promise<SafeResourceUrl> {
|
|
|
|
|
let once_uri = await invoke<string>("plugin:mediarepo|read_thumbnail",
|
|
|
|
|
{hash: thumbnail.hash, mimeType: thumbnail.mime_type});
|
|
|
|
|
return this.sanitizer.bypassSecurityTrustResourceUrl(once_uri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async getThumbnailOfSize(file: File, minHeight: number, minWidth: number, maxHeight: number, maxWidth: number): Promise<SafeResourceUrl> {
|
|
|
|
|
let once_uri = await invoke<string>("plugin:mediarepo|get_thumbnail_of_size", {fileId: file.id, minSize: [minHeight, minWidth], maxSize: [maxHeight, maxWidth]});
|
|
|
|
|
return this.sanitizer.bypassSecurityTrustResourceUrl(once_uri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async getThumbnails(file: File): Promise<Thumbnail[]> {
|
|
|
|
|
return await invoke<Thumbnail[]>("plugin:mediarepo|get_file_thumbnails",
|
|
|
|
|
const cachedThumbnails = this.thumbnailCache[file.id];
|
|
|
|
|
if (cachedThumbnails) {
|
|
|
|
|
return cachedThumbnails;
|
|
|
|
|
}
|
|
|
|
|
const thumbnails = await invoke<Thumbnail[]>("plugin:mediarepo|get_file_thumbnails",
|
|
|
|
|
{id: file.id});
|
|
|
|
|
this.thumbnailCache[file.id] = thumbnails;
|
|
|
|
|
|
|
|
|
|
return thumbnails;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async updateFileName(file: File, name: string): Promise<File> {
|
|
|
|
|