This commit is contained in:
Heiko Mathes 2023-12-05 07:05:35 +01:00 committed by GitHub
commit 3f4cab25b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 92 additions and 155 deletions

View file

@ -27,8 +27,6 @@ import PhotoSwipe from "photoswipe";
import PhotoSwipeUI_Default from "photoswipe/dist/photoswipe-ui-default.js";
import Event from "pubsub-js";
import Util from "util.js";
import Api from "./api";
import Thumb from "model/thumb";
const thumbs = window.__CONFIG__.thumbs;
@ -219,85 +217,6 @@ class Viewer {
return "fit_7680";
}
static show(ctx, index) {
if (ctx.loading || !ctx.listen || ctx.viewer.loading || !ctx.results[index]) {
return false;
}
const selected = ctx.results[index];
if (!ctx.viewer.dirty && ctx.viewer.results && ctx.viewer.results.length > index) {
// Reuse existing viewer result if possible.
let i = -1;
if (ctx.viewer.results[index] && ctx.viewer.results[index].UID === selected.UID) {
i = index;
} else {
i = ctx.viewer.results.findIndex((p) => p.UID === selected.UID);
}
if (
i > -1 &&
(((ctx.viewer.complete || ctx.complete) &&
ctx.viewer.results.length >= ctx.results.length) ||
i + ctx.viewer.batchSize <= ctx.viewer.results.length)
) {
ctx.$viewer.show(ctx.viewer.results, i);
return;
}
}
// Fetch photos from server API.
ctx.viewer.loading = true;
const params = ctx.searchParams();
params.count = params.offset + ctx.viewer.batchSize;
params.offset = 0;
// Fetch viewer results from API.
return Api.get("photos/view", { params })
.then((response) => {
const count = response && response.data ? response.data.length : 0;
if (count === 0) {
ctx.$notify.warn(ctx.$gettext("No pictures found"));
ctx.viewer.dirty = true;
ctx.viewer.complete = false;
return;
}
// Process response.
if (response.headers && response.headers["x-count"]) {
const c = parseInt(response.headers["x-count"]);
const l = parseInt(response.headers["x-limit"]);
ctx.viewer.complete = c < l;
} else {
ctx.viewer.complete = ctx.complete;
}
let i;
if (response.data[index] && response.data[index].UID === selected.UID) {
i = index;
} else {
i = response.data.findIndex((p) => p.UID === selected.UID);
}
ctx.viewer.results = Thumb.wrap(response.data);
// Show photos.
ctx.$viewer.show(ctx.viewer.results, i);
ctx.viewer.dirty = false;
})
.catch(() => {
ctx.viewer.dirty = true;
ctx.viewer.complete = false;
})
.finally(() => {
// Unblock.
ctx.viewer.loading = false;
});
}
}
export default Viewer;

View file

@ -71,6 +71,7 @@ export const TimeZoneUTC = "UTC";
const num = "numeric";
const short = "short";
const long = "long";
const thumbs = window.__CONFIG__.thumbs;
export const DATE_FULL = {
year: num,
@ -96,6 +97,51 @@ export let BatchSize = 120;
export class Photo extends RestModel {
constructor(values) {
super(values);
let mainFile;
if (this.Files) {
mainFile = this.mainFile();
}
const mainFileHash = this.generateMainFileHash(mainFile, this.Hash);
this.Thumbs = this.generateThumbs(mainFile, mainFileHash);
this.DownloadUrl = this.getDownloadUrl(mainFileHash);
}
generateThumbs(mainFile, mainFileHash) {
let sourceWidth = this.Width;
let sourceHeight = this.Height;
if (mainFile) {
sourceWidth = mainFile.Width;
sourceHeight = mainFile.Height;
}
if (!this.Hash) {
return {};
}
const result = {};
for (let i = 0; i < thumbs.length; i++) {
let t = thumbs[i];
const size = this.calculateSizeFromProps(t.w, t.h, sourceWidth, sourceHeight);
// we know the thumbnail url can't be cached because the size-parameter changes on every call
const url = this.generateThumbnailUrlUnmemoized(
mainFileHash,
this.videoFile(),
config.staticUri,
config.contentUri,
config.previewToken,
t.size
);
result[t.size] = {
src: url,
w: size.width,
h: size.height,
};
}
return result;
}
getDefaults() {
@ -195,6 +241,8 @@ export class Photo extends RestModel {
EditedAt: null,
CheckedAt: null,
DeletedAt: null,
Thumbs: {},
DownloadUrl: "",
};
}
@ -656,24 +704,39 @@ export class Photo extends RestModel {
);
}
generateThumbnailUrl = memoizeOne(
(mainFileHash, videoFile, staticUri, contentUri, previewToken, size) => {
let hash = mainFileHash;
/**
* use this one if you know the parameters changed AND yout task is so
* performance critical, that you benefit from skipping the parameter-changed
* -check from memoizeOne.
*
* If you don't know wether the parameters changed or if your task is not
* incredibly performance critical, use the memoized 'generateThumbnailUrl'
*/
generateThumbnailUrlUnmemoized = (
mainFileHash,
videoFile,
staticUri,
contentUri,
previewToken,
size
) => {
let hash = mainFileHash;
if (!hash) {
if (videoFile && videoFile.Hash) {
return `${contentUri}/t/${videoFile.Hash}/${previewToken}/${size}`;
}
return `${staticUri}/img/404.jpg`;
if (!hash) {
if (videoFile && videoFile.Hash) {
return `${contentUri}/t/${videoFile.Hash}/${previewToken}/${size}`;
}
return `${contentUri}/t/${hash}/${previewToken}/${size}`;
return `${staticUri}/img/404.jpg`;
}
);
getDownloadUrl() {
return `${config.apiUri}/dl/${this.mainFileHash()}?t=${config.downloadToken}`;
return `${contentUri}/t/${hash}/${previewToken}/${size}`;
};
generateThumbnailUrl = memoizeOne(this.generateThumbnailUrlUnmemoized);
getDownloadUrl(mainFileHash = this.mainFileHash()) {
return `${config.apiUri}/dl/${mainFileHash}?t=${config.downloadToken}`;
}
downloadAll() {
@ -734,13 +797,13 @@ export class Photo extends RestModel {
});
}
calculateSize(width, height) {
if (width >= this.Width && height >= this.Height) {
calculateSizeFromProps(width, height, sourceWidth, sourceHeight) {
if (width >= sourceWidth && height >= sourceHeight) {
// Smaller
return { width: this.Width, height: this.Height };
return { width: sourceWidth, height: sourceHeight };
}
const srcAspectRatio = this.Width / this.Height;
const srcAspectRatio = sourceWidth / sourceHeight;
const maxAspectRatio = width / height;
let newW, newH;
@ -756,6 +819,10 @@ export class Photo extends RestModel {
return { width: newW, height: newH };
}
calculateSize(width, height) {
return this.calculateSizeFromProps(width, height, this.Width, this.Height);
}
getDateString(showTimeZone) {
return this.generateDateString(
showTimeZone,

View file

@ -95,53 +95,6 @@ export class Thumb extends Model {
return result;
}
static fromPhotos(photos) {
let result = [];
const n = photos.length;
for (let i = 0; i < n; i++) {
result.push(this.fromPhoto(photos[i]));
}
return result;
}
static fromPhoto(photo) {
if (photo.Files) {
return this.fromFile(photo, photo.mainFile());
}
if (!photo || !photo.Hash) {
return this.notFound();
}
const result = {
UID: photo.UID,
Title: photo.Title,
TakenAtLocal: photo.getDateString(),
Description: photo.Description,
Favorite: photo.Favorite,
Playable: photo.isPlayable(),
DownloadUrl: this.downloadUrl(photo),
Width: photo.Width,
Height: photo.Height,
Thumbs: {},
};
for (let i = 0; i < thumbs.length; i++) {
let t = thumbs[i];
let size = photo.calculateSize(t.w, t.h);
result.Thumbs[t.size] = {
src: photo.thumbnailUrl(t.size),
w: size.width,
h: size.height,
};
}
return new this(result);
}
static fromFile(photo, file) {
if (!photo || !file || !file.Hash) {
return this.notFound();

View file

@ -53,7 +53,6 @@ import {Photo, MediaLive, MediaRaw, MediaVideo, MediaAnimated} from "model/photo
import Album from "model/album";
import Thumb from "model/thumb";
import Event from "pubsub-js";
import Viewer from "common/viewer";
export default {
name: 'PPageAlbumPhotos',
@ -244,12 +243,12 @@ export default {
if (selected.isPlayable()) {
this.$viewer.play({video: selected, album: this.album});
} else {
this.$viewer.show(Thumb.fromPhotos(this.results), index);
this.$viewer.show(this.results, index);
}
} else if (showMerged) {
this.$viewer.show(Thumb.fromFiles([selected]), 0);
} else {
Viewer.show(this, index);
this.$viewer.show(this.results, index);
}
return true;

View file

@ -56,7 +56,6 @@
<script>
import {MediaAnimated, MediaLive, MediaRaw, MediaVideo, Photo} from "model/photo";
import Thumb from "model/thumb";
import Viewer from "common/viewer";
import Event from "pubsub-js";
export default {
@ -353,12 +352,12 @@ export default {
if (selected.isPlayable()) {
this.$viewer.play({video: selected});
} else {
this.$viewer.show(Thumb.fromPhotos(this.results), index);
this.$viewer.show(this.results, index);
}
} else if (showMerged) {
this.$viewer.show(Thumb.fromFiles([selected]), 0);
} else {
Viewer.show(this, index);
this.$viewer.show(this.results, index);
}
return true;

View file

@ -198,7 +198,7 @@ describe("model/thumb", () => {
],
};
const photo = new Photo(values);
const result = Thumb.fromPhoto(photo);
const result = photo;
assert.equal(result.UID, "ABC123");
assert.equal(result.Description, "Nice description 3");
assert.equal(result.Width, 500);
@ -208,7 +208,7 @@ describe("model/thumb", () => {
Description: "Nice description 3",
};
const photo3 = new Photo(values3);
const result2 = Thumb.fromPhoto(photo3);
const result2 = photo3;
assert.equal(result2.UID, "");
const values2 = {
ID: 8,
@ -221,7 +221,7 @@ describe("model/thumb", () => {
Hash: "xdf45m",
};
const photo2 = new Photo(values2);
const result3 = Thumb.fromPhoto(photo2);
const result3 = photo2;
assert.equal(result3.UID, "ABC123");
assert.equal(result3.Title, "Crazy Cat");
assert.equal(result3.Description, "Nice description");
@ -247,7 +247,7 @@ describe("model/thumb", () => {
};
const photo = new Photo(values);
const Photos = [photo];
const result = Thumb.fromPhotos(Photos);
const result = Photos;
assert.equal(result[0].UID, "ABC123");
assert.equal(result[0].Description, "Nice description 3");
assert.equal(result[0].Width, 500);