1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2025-01-14 14:43:17 +08:00

Merge branch 'master' of https://github.com/grasdk/pigallery2 into feature/docker-update

This commit is contained in:
Chris 2024-10-26 00:04:09 +02:00
commit 7a613ecfe1
25 changed files with 6073 additions and 169 deletions

View File

@ -22,7 +22,7 @@ jobs:
with:
mysql database: 'pigallery_test'
mysql root password: 'password'
mysql user: 'user'
mysql user: 'user'
mysql password: 'password'
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
@ -100,12 +100,10 @@ jobs:
needs: [ create-release ]
strategy:
matrix:
container: [alpine, debian-buster, debian-bullseye, debian-bookworm ]
container: [alpine, debian-bullseye, debian-bookworm ]
include:
- container: alpine
platforms: linux/amd64,linux/arm64,linux/arm/v7
- container: debian-buster
platforms: linux/amd64,linux/arm64,linux/arm/v7
- container: debian-bullseye
platforms: linux/amd64,linux/arm64,linux/arm/v7
- container: debian-bookworm

File diff suppressed because one or more lines are too long

View File

@ -135,7 +135,7 @@ apt-get install build-essential libkrb5-dev gcc g++
## 2. Translate the page to your own language
1. [Install Pigallery2](#121-b-install-from-source) from source (with the release it won't work)
2. add your language e.g: fr
* copy `src/frontend/translate/messages.en.xls` to `src/frontend/translate/messages.fr.xls`
* copy `src/frontend/translate/messages.en.xlf` to `src/frontend/translate/messages.fr.xlf`
* add the new translation to the `angular.json` `projects->pigallery2->i18n->locales` section
3. translate the file by updating the `<target>` tags
4. test if it works:

View File

@ -62,6 +62,10 @@
"baseHref": "",
"translation": "src/frontend/translate/messages.ru.xlf"
},
"sk": {
"baseHref": "",
"translation": "src/frontend/translate/messages.sk.xlf"
},
"sv": {
"baseHref": "",
"translation": "src/frontend/translate/messages.sv.xlf"

View File

@ -1,9 +1,8 @@
#-----------------BUILDER-----------------
#-----------------------------------------
FROM node:18-alpine3.17 AS builder
RUN apk add --no-cache --repository https://alpine.global.ssl.fastly.net/alpine/v3.17/community/ \
python3 build-base sqlite-dev sqlite-libs vips-dev vips-heif fftw-dev gcc g++ make libc6-compat && ln -snf /usr/bin/python3 /usr/bin/python && \
rm /var/cache/apk/*
RUN apk add --update-cache --repository https://alpine.global.ssl.fastly.net/alpine/v3.17/community/ \
python3 build-base sqlite-dev sqlite-libs imagemagick-dev libraw-dev vips-dev vips-heif vips-magick fftw-dev gcc g++ make libc6-compat && ln -snf /usr/bin/python3 /usr/bin/python
COPY pigallery2-release /app
WORKDIR /app
RUN npm install --unsafe-perm --fetch-timeout=90000
@ -27,16 +26,15 @@ ENV NODE_ENV=production \
PI_DOCKER=true
EXPOSE 80
RUN apk add --no-cache --repository https://alpine.global.ssl.fastly.net/alpine/v3.17/community/ \
vips vips-cpp vips-heif ffmpeg && \
rm /var/cache/apk/*
RUN apk add --update-cache --repository https://alpine.global.ssl.fastly.net/alpine/v3.17/community/ \
vips vips-cpp vips-heif vips-magick ffmpeg
COPY --from=builder /app /app
# Run build time diagnostics to make sure the app would work after build is finished
RUN ["node", "./src/backend/index", "--expose-gc", "--run-diagnostics", "--config-path=/app/diagnostics-config.json"]
RUN ["node", "./src/backend/index", "--expose-gc", "--run-diagnostics", "--config-path=/app/diagnostics-config.json", "--Server-Log-level=silly"]
HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \
CMD wget --quiet --tries=1 --no-check-certificate --spider \
http://localhost:80/heartbeat || exit 1
http://127.0.0.1:80/heartbeat || exit 1
# after a extensive job (like video converting), pigallery calls gc, to clean up everthing as fast as possible
# Exec form entrypoint is need otherwise (using shell form) ENV variables are not properly passed down to the app

View File

@ -1,7 +1,7 @@
#-----------------BUILDER-----------------
#-----------------------------------------
FROM node:18.19-bookworm AS builder
RUN apt-get update && apt-get install -y --no-install-recommends libvips-dev python3
FROM node:18-bookworm AS builder
RUN apt update && apt install -y --no-install-recommends libvips-dev python3
COPY pigallery2-release /app
WORKDIR /app
RUN npm install --unsafe-perm --fetch-timeout=90000
@ -32,10 +32,10 @@ RUN apt-get update \
COPY --from=builder /app /app
# Run build time diagnostics to make sure the app would work after build is finished
RUN ["node", "./src/backend/index", "--expose-gc", "--run-diagnostics", "--config-path=/app/diagnostics-config.json"]
RUN ["node", "./src/backend/index", "--expose-gc", "--run-diagnostics", "--config-path=/app/diagnostics-config.json", "--Server-Log-level=silly"]
HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \
CMD wget --quiet --tries=1 --no-check-certificate --spider \
http://localhost:80/heartbeat || exit 1
http://127.0.0.1:80/heartbeat || exit 1
# after a extensive job (like video converting), pigallery calls gc, to clean up everthing as fast as possible
# Exec form entrypoint is need otherwise (using shell form) ENV variables are not properly passed down to the app

View File

@ -1,7 +1,7 @@
#-----------------BUILDER-----------------
#-----------------------------------------
FROM node:18.19-bullseye AS builder
RUN apt-get update && apt-get install -y --no-install-recommends libvips-dev python3
FROM node:18-bullseye AS builder
RUN apt update && apt install -y --no-install-recommends libvips-dev python3
COPY pigallery2-release /app
WORKDIR /app
RUN npm install --unsafe-perm --fetch-timeout=90000
@ -32,10 +32,10 @@ RUN apt-get update \
COPY --from=builder /app /app
# Run build time diagnostics to make sure the app would work after build is finished
RUN ["node", "./src/backend/index", "--expose-gc", "--run-diagnostics", "--config-path=/app/diagnostics-config.json"]
RUN ["node", "./src/backend/index", "--expose-gc", "--run-diagnostics", "--config-path=/app/diagnostics-config.json", "--Server-Log-level=silly"]
HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \
CMD wget --quiet --tries=1 --no-check-certificate --spider \
http://localhost:80/heartbeat || exit 1
http://127.0.0.1:80/heartbeat || exit 1
# after a extensive job (like video converting), pigallery calls gc, to clean up everthing as fast as possible
# Exec form entrypoint is need otherwise (using shell form) ENV variables are not properly passed down to the app

View File

@ -1,6 +1,6 @@
#-----------------BUILDER-----------------
#-----------------------------------------
FROM node:18-buster AS builder
FROM node:18-bullseye AS builder
# LABEL maintainer="Patrik J. Braun"
# copying only package{-lock}.json to make node_modules cachable
RUN git clone https://github.com/bpatrik/pigallery2.git /build
@ -16,7 +16,7 @@ RUN npm install --unsafe-perm
#-----------------MAIN--------------------
#-----------------------------------------
FROM node:18-buster-slim AS main
FROM node:18-bullseye-slim AS main
WORKDIR /app
ENV NODE_ENV=production \
# overrides only the default value of the settings (the actualy value can be overwritten through config.json)
@ -38,7 +38,7 @@ COPY --from=builder /build/release /app
RUN ["node", "./src/backend/index", "--expose-gc", "--run-diagnostics", "--config-path=/app/diagnostics-config.json"]
HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \
CMD wget --quiet --tries=1 --no-check-certificate --spider \
http://localhost:80/heartbeat || exit 1
http://127.0.0.1:80/heartbeat || exit 1
# after a extensive job (like video converting), pigallery calls gc, to clean up everthing as fast as possible
# Exec form entrypoint is need otherwise (using shell form) ENV variables are not properly passed down to the app

View File

@ -1,42 +0,0 @@
#-----------------BUILDER-----------------
#-----------------------------------------
FROM node:18.19-buster AS builder
RUN apt-get update && apt-get install -y --no-install-recommends libvips-dev python3
COPY pigallery2-release /app
WORKDIR /app
RUN npm install --unsafe-perm --fetch-timeout=90000
RUN mkdir -p /app/data/config && \
mkdir -p /app/data/db && \
mkdir -p /app/data/images && \
mkdir -p /app/data/tmp
#-----------------MAIN--------------------
#-----------------------------------------
FROM node:18-buster-slim AS main
WORKDIR /app
ENV NODE_ENV=production \
# overrides only the default value of the settings (the actualy value can be overwritten through config.json)
default-Database-dbFolder=/app/data/db \
default-Media-folder=/app/data/images \
default-Media-tempFolder=/app/data/tmp \
default-Extensions-folder=/app/data/config/extensions \
# flagging dockerized environemnt
PI_DOCKER=true
EXPOSE 80
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates wget ffmpeg libvips42 \
&& apt-get clean -q -y \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /app /app
# Run build time diagnostics to make sure the app would work after build is finished
RUN ["node", "./src/backend/index", "--expose-gc", "--run-diagnostics", "--config-path=/app/diagnostics-config.json"]
HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \
CMD wget --quiet --tries=1 --no-check-certificate --spider \
http://localhost:80/heartbeat || exit 1
# after a extensive job (like video converting), pigallery calls gc, to clean up everthing as fast as possible
# Exec form entrypoint is need otherwise (using shell form) ENV variables are not properly passed down to the app
ENTRYPOINT ["node", "./src/backend/index", "--expose-gc", "--config-path=/app/data/config/config.json"]

View File

@ -167,6 +167,7 @@ gulp.task('copy-static', (): any =>
gulp
.src(
[
'src/backend/model/diagnostics/image_formats/**',
'src/backend/model/diagnostics/blank.jpg',
'README.md',
// 'package-lock.json', should not add, it keeps optional packages optional even with --force-opt-packages.

View File

@ -3,12 +3,14 @@ import {Logger} from '../../Logger';
import {NotificationManager} from '../NotifocationManager';
import {SQLConnection} from '../database/SQLConnection';
import * as fs from 'fs';
import * as path from 'path';
import {FFmpegFactory} from '../FFmpegFactory';
import {
ClientAlbumConfig,
ClientFacesConfig,
ClientMapConfig,
ClientMetaFileConfig,
ClientPhotoConfig,
ClientRandomPhotoConfig,
ClientSearchConfig,
ClientSharingConfig,
@ -28,7 +30,9 @@ import {SearchQueryTypes, TextSearch,} from '../../../common/entities/SearchQuer
import {Utils} from '../../../common/Utils';
import {JobRepository} from '../jobs/JobRepository';
import {ConfigClassBuilder} from '../../../../node_modules/typeconfig/node';
import { Config } from '../../../common/config/private/Config';
import {Config} from '../../../common/config/private/Config';
import {SupportedFormats} from '../../../common/SupportedFormats';
import {MediaRendererInput, PhotoWorker, ThumbnailSourceType} from '../fileaccess/PhotoWorker';
const LOG_TAG = '[ConfigDiagnostics]';
@ -78,9 +82,9 @@ export class ConfigDiagnostics {
jobsConfig: ServerJobConfig
): Promise<void> {
Logger.debug(LOG_TAG, 'Testing jobs config');
for(let i = 0; i< jobsConfig.scheduled.length; ++i){
for (let i = 0; i < jobsConfig.scheduled.length; ++i) {
const j = jobsConfig.scheduled[i];
if(!JobRepository.Instance.exists(j.name)){
if (!JobRepository.Instance.exists(j.name)) {
throw new Error('Unknown Job :' + j.name);
}
}
@ -292,6 +296,48 @@ export class ConfigDiagnostics {
}
}
/**
* Removes unsupported image formats.
* It is possible that some OS support one or the other image formats (like Mac os does with HEIC)
* , but others not.
* Those formats are added to the config, but dynamically removed.
* @param config
*/
static async removeUnsupportedPhotoExtensions(config: ClientPhotoConfig): Promise<void> {
Logger.verbose(LOG_TAG, 'Checking for supported image formats');
let removedSome = false;
let i = config.supportedFormats.length;
while (i--) {
const ext = config.supportedFormats[i].toLowerCase();
const testImage = path.join(__dirname, 'image_formats', 'test.' + ext);
// Check if a test available for this image format.
// if not probably because it is trivial
if (!fs.existsSync(testImage)) {
Logger.silly(LOG_TAG, `No test for ${ext} image format. skipping.`);
continue;
}
Logger.silly(LOG_TAG, `Testing ${ext} image formats.`);
try {
await PhotoWorker.renderFromImage({
type: ThumbnailSourceType.Photo,
mediaPath: testImage,
size: 10,
useLanczos3: Config.Media.Photo.useLanczos3,
quality: Config.Media.Photo.quality,
smartSubsample: Config.Media.Photo.smartSubsample,
} as MediaRendererInput, true
);
} catch (e) {
Logger.verbose(LOG_TAG, 'The current OS does not support the following photo format:' + ext + ', removing it form config.');
config.supportedFormats.splice(i, 1);
removedSome = true;
}
}
if (removedSome) {
SupportedFormats.init();
}
}
static async testConfig(config: PrivateConfigClass): Promise<void> {
await ConfigDiagnostics.testDatabase(config.Database);
@ -310,7 +356,6 @@ export class ConfigDiagnostics {
await ConfigDiagnostics.testRandomPhotoConfig(config.Sharing, config);
await ConfigDiagnostics.testMapConfig(config.Map);
await ConfigDiagnostics.testJobsConfig(config.Jobs);
}
@ -562,7 +607,7 @@ export class ConfigDiagnostics {
const err: Error = ex;
NotificationManager.warning(
'Jobs error. Resetting to default for now to let the app start up. ' +
'Please adjust the config properly.',
'Please adjust the config properly.',
err.toString()
);
Logger.warn(
@ -575,6 +620,8 @@ export class ConfigDiagnostics {
Config.Jobs.scheduled = pc.Jobs.scheduled;
}
await this.removeUnsupportedPhotoExtensions(Config.Media.Photo);
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

View File

@ -23,8 +23,8 @@ export class PhotoWorker {
throw new Error('Unsupported media type to render thumbnail:' + input.type);
}
public static renderFromImage(input: SvgRendererInput | MediaRendererInput): Promise<void> {
return ImageRendererFactory.render(input);
public static renderFromImage(input: SvgRendererInput | MediaRendererInput, dryRun = false): Promise<void> {
return ImageRendererFactory.render(input, dryRun);
}
public static renderFromVideo(input: MediaRendererInput): Promise<void> {
@ -43,8 +43,8 @@ export enum ThumbnailSourceType {
interface RendererInput {
type: ThumbnailSourceType;
size: number;
makeSquare: boolean;
outPath: string;
makeSquare?: boolean;
outPath?: string;
quality: number;
useLanczos3: boolean;
animate: boolean; // animates the output. Used for Gifs
@ -132,7 +132,7 @@ export class VideoRendererFactory {
export class ImageRendererFactory {
@ExtensionDecorator(e => e.gallery.ImageRenderer.render)
public static async render(input: MediaRendererInput | SvgRendererInput): Promise<void> {
public static async render(input: MediaRendererInput | SvgRendererInput, dryRun = false): Promise<void> {
let image: Sharp;
if ((input as MediaRendererInput).mediaPath) {
@ -174,17 +174,24 @@ export class ImageRendererFactory {
fit: 'cover',
});
}
let processedImg: sharp.Sharp;
if ((input as MediaRendererInput).mediaPath) {
await image.webp({
processedImg = image.webp({
effort: 6,
quality: input.quality,
smartSubsample: (input as MediaRendererInput).smartSubsample
}).toFile(input.outPath);
});
} else {
if ((input as SvgRendererInput).svgString) {
await image.png({effort: 6, quality: input.quality}).toFile(input.outPath);
processedImg = image.png({effort: 6, quality: input.quality});
}
}
// do not save to file
if (dryRun) {
await processedImg.toBuffer();
return;
}
await processedImg.toFile(input.outPath);
}
}

View File

@ -10,44 +10,45 @@ if (typeof window !== 'undefined') {
Config = require('./config/private/Config').Config;
}
export const SupportedFormats = {
Photos: Config.Media.Photo.supportedFormats,
export class SupportedFormats {
static Photos = Config.Media.Photo.supportedFormats;
// Browser supported video formats
// Read more: https://www.w3schools.com/html/html5_video.asp
Videos: Config.Media.Video.supportedFormats,
MetaFiles: Config.MetaFile.supportedFormats,
// These formats need to be transcoded (with the build-in ffmpeg support)
TranscodeNeed: {
static Videos = Config.Media.Video.supportedFormats;
static MetaFiles = Config.MetaFile.supportedFormats;
// These formats need to be transcoded (with the built-in ffmpeg support)
static TranscodeNeed = {
// based on libvips, all supported formats for sharp: https://github.com/libvips/libvips
Photos: [] as string[],
Videos: Config.Media.Video.supportedFormatsWithTranscoding,
},
};
// --------------------------------------------
// Below this, it is autogenerated, DO NOT EDIT
WithDots: {
static WithDots = {
Photos: [] as string[],
Videos: [] as string[],
MetaFiles: [] as string[],
TranscodeNeed: {
Photos: [] as string[],
Videos: [] as string[],
},
},
};
SupportedFormats.Photos = SupportedFormats.Photos.concat(
SupportedFormats.TranscodeNeed.Photos
);
SupportedFormats.Videos = SupportedFormats.Videos.concat(
SupportedFormats.TranscodeNeed.Videos
);
SupportedFormats.WithDots.Photos = SupportedFormats.Photos.map((f) => '.' + f);
SupportedFormats.WithDots.Videos = SupportedFormats.Videos.map((f) => '.' + f);
SupportedFormats.WithDots.MetaFiles = SupportedFormats.MetaFiles.map(
(f) => '.' + f
);
SupportedFormats.WithDots.TranscodeNeed.Photos =
SupportedFormats.TranscodeNeed.Photos.map((f) => '.' + f);
SupportedFormats.WithDots.TranscodeNeed.Videos =
SupportedFormats.TranscodeNeed.Videos.map((f) => '.' + f);
}
};
static init(){
SupportedFormats.Photos = SupportedFormats.Photos.concat(
SupportedFormats.TranscodeNeed.Photos
);
SupportedFormats.Videos = SupportedFormats.Videos.concat(
SupportedFormats.TranscodeNeed.Videos
);
SupportedFormats.WithDots.Photos = SupportedFormats.Photos.map((f) => '.' + f);
SupportedFormats.WithDots.Videos = SupportedFormats.Videos.map((f) => '.' + f);
SupportedFormats.WithDots.MetaFiles = SupportedFormats.MetaFiles.map(
(f) => '.' + f
);
SupportedFormats.WithDots.TranscodeNeed.Photos =
SupportedFormats.TranscodeNeed.Photos.map((f) => '.' + f);
SupportedFormats.WithDots.TranscodeNeed.Videos =
SupportedFormats.TranscodeNeed.Videos.map((f) => '.' + f);
}
}
SupportedFormats.init();

View File

@ -525,7 +525,7 @@ export class ServerLogConfig {
name: $localize`Server timing`,
priority: ConfigPriority.underTheHood,
},
description: $localize`If enabled, the app ads "Server-Timing" http header to the response.`
description: $localize`If enabled, the app adds "Server-Timing" http header to the response.`
})
logServerTiming: boolean = false;
}
@ -638,7 +638,7 @@ export class ServerJobConfig {
name: $localize`Processing batch size`,
priority: ConfigPriority.underTheHood
},
description: $localize`Jobs load this many photos or videos form the DB for processing at once.`
description: $localize`Jobs load this many photos or videos from the DB for processing at once.`
})
mediaProcessingBatchSize: number = 1000;
@ConfigProperty({
@ -698,7 +698,7 @@ export class VideoTranscodingConfig {
priority: ConfigPriority.advanced,
unit: 'bps'
},
description: $localize`Target bit rate of the output video will be scaled down this this. This should be less than the upload rate of your home server.`
description: $localize`Target bit rate of the output video will be scaled down to this. This should be less than the upload rate of your home server.`
})
bitRate: number = 5 * 1024 * 1024;
@ConfigProperty({
@ -721,7 +721,7 @@ export class VideoTranscodingConfig {
priority: ConfigPriority.underTheHood,
uiOptions: [24, 25, 30, 48, 50, 60]
},
description: $localize`Target frame per second (fps) of the output video will be scaled down this this.`
description: $localize`Target frame per second (fps) of the output video will be scaled down to this.`
})
fps: number = 25;
@ConfigProperty({
@ -810,7 +810,7 @@ export class ServerVideoConfig extends ClientVideoConfig {
priority: ConfigPriority.advanced,
uiDisabled: (sb: ClientVideoConfig) => !sb.enabled
},
description: $localize`To ensure smooth video playback, video transcoding is recommended to a lower bit rate than the server's upload rate. The transcoded videos will be save to the thumbnail folder. You can trigger the transcoding manually, but you can also create an automatic encoding job in advanced settings mode.`
description: $localize`To ensure smooth video playback, video transcoding is recommended to a lower bit rate than the server's upload rate. The transcoded videos will be saved to the thumbnail folder. You can trigger the transcoding manually, but you can also create an automatic encoding job in advanced settings mode.`
})
transcoding: VideoTranscodingConfig = new VideoTranscodingConfig();
}

View File

@ -97,7 +97,7 @@ export class AutoCompleteItemsPerCategoryConfig {
name: $localize`Maximum items`,
priority: ConfigPriority.underTheHood
},
description: $localize`Maximum number autocomplete items shown at once. If there is not enough items to reach this value, it takes upto double of the individual items.`
description: $localize`Maximum number autocomplete items shown at once. If there is not enough items to reach this value, it takes up to double of the individual items.`
})
maxItems: number = 20;
@ -573,31 +573,31 @@ export class ClientMapConfig {
)]),
new MapPathGroupConfig('Sport',
[new MapPathGroupThemeConfig(
['run'],
['(\b|_|-)run'],
new PathThemeConfig('var(--bs-primary)',
'',
new SVGIconConfig('0 0 417 512', '<path d="M320 48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM125.7 175.5c9.9-9.9 23.4-15.5 37.5-15.5c1.9 0 3.8 .1 5.6 .3L137.6 254c-9.3 28 1.7 58.8 26.8 74.5l86.2 53.9-25.4 88.8c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l28.7-100.4c5.9-20.6-2.6-42.6-20.7-53.9L238 299l30.9-82.4 5.1 12.3C289 264.7 323.9 288 362.7 288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H362.7c-12.9 0-24.6-7.8-29.5-19.7l-6.3-15c-14.6-35.1-44.1-61.9-80.5-73.1l-48.7-15c-11.1-3.4-22.7-5.2-34.4-5.2c-31 0-60.8 12.3-82.7 34.3L57.4 153.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l23.1-23.1zM91.2 352H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h69.6c19 0 36.2-11.2 43.9-28.5L157 361.6l-9.5-6c-17.5-10.9-30.5-26.8-37.9-44.9L91.2 352z"/>')
)
), new MapPathGroupThemeConfig(
['walk'],
['(\b|_|-)walk'],
new PathThemeConfig('var(--bs-primary)',
'',
new SVGIconConfig('0 0 320 512', '<path d="M160 48a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zM126.5 199.3c-1 .4-1.9 .8-2.9 1.2l-8 3.5c-16.4 7.3-29 21.2-34.7 38.2l-2.6 7.8c-5.6 16.8-23.7 25.8-40.5 20.2s-25.8-23.7-20.2-40.5l2.6-7.8c11.4-34.1 36.6-61.9 69.4-76.5l8-3.5c20.8-9.2 43.3-14 66.1-14c44.6 0 84.8 26.8 101.9 67.9L281 232.7l21.4 10.7c15.8 7.9 22.2 27.1 14.3 42.9s-27.1 22.2-42.9 14.3L247 287.3c-10.3-5.2-18.4-13.8-22.8-24.5l-9.6-23-19.3 65.5 49.5 54c5.4 5.9 9.2 13 11.2 20.8l23 92.1c4.3 17.1-6.1 34.5-23.3 38.8s-34.5-6.1-38.8-23.3l-22-88.1-70.7-77.1c-14.8-16.1-20.3-38.6-14.7-59.7l16.9-63.5zM68.7 398l25-62.4c2.1 3 4.5 5.8 7 8.6l40.7 44.4-14.5 36.2c-2.4 6-6 11.5-10.6 16.1L54.6 502.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L68.7 398z"/>')
)
), new MapPathGroupThemeConfig(
['hike', 'hiking'],
['(\b|_|-)hike', '(\b|_|-)hiking'],
new PathThemeConfig('var(--bs-primary)',
'',
new SVGIconConfig('0 0 384 512', '<path d="M192 48a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zm51.3 182.7L224.2 307l49.7 49.7c9 9 14.1 21.2 14.1 33.9V480c0 17.7-14.3 32-32 32s-32-14.3-32-32V397.3l-73.9-73.9c-15.8-15.8-22.2-38.6-16.9-60.3l20.4-84c8.3-34.1 42.7-54.9 76.7-46.4c19 4.8 35.6 16.4 46.4 32.7L305.1 208H336V184c0-13.3 10.7-24 24-24s24 10.7 24 24v55.8c0 .1 0 .2 0 .2s0 .2 0 .2V488c0 13.3-10.7 24-24 24s-24-10.7-24-24V272H296.6c-16 0-31-8-39.9-21.4l-13.3-20zM81.1 471.9L117.3 334c3 4.2 6.4 8.2 10.1 11.9l41.9 41.9L142.9 488.1c-4.5 17.1-22 27.3-39.1 22.8s-27.3-22-22.8-39.1zm55.5-346L101.4 266.5c-3 12.1-14.9 19.9-27.2 17.9l-47.9-8c-14-2.3-22.9-16.3-19.2-30L31.9 155c9.5-34.8 41.1-59 77.2-59h4.2c15.6 0 27.1 14.7 23.3 29.8z"/>')
)
), new MapPathGroupThemeConfig(
['bike', 'biking', 'cycling'],
['(\b|_|-)bike', '(\b|_|-)biking', '(\b|_|-)cycling'],
new PathThemeConfig('var(--bs-primary)',
'',
new SVGIconConfig('0 0 640 512', '<path d="M400 96a48 48 0 1 0 0-96 48 48 0 1 0 0 96zm27.2 64l-61.8-48.8c-17.3-13.6-41.7-13.8-59.1-.3l-83.1 64.2c-30.7 23.8-28.5 70.8 4.3 91.6L288 305.1V416c0 17.7 14.3 32 32 32s32-14.3 32-32V288c0-10.7-5.3-20.7-14.2-26.6L295 232.9l60.3-48.5L396 217c5.7 4.5 12.7 7 20 7h64c17.7 0 32-14.3 32-32s-14.3-32-32-32H427.2zM56 384a72 72 0 1 1 144 0A72 72 0 1 1 56 384zm200 0A128 128 0 1 0 0 384a128 128 0 1 0 256 0zm184 0a72 72 0 1 1 144 0 72 72 0 1 1 -144 0zm200 0a128 128 0 1 0 -256 0 128 128 0 1 0 256 0z"/>')
)
), new MapPathGroupThemeConfig(
['skiing', 'ski'],
['(\b|_|-)skiing', '(\b|_|-)ski'],
new PathThemeConfig('var(--bs-primary)',
'',
new SVGIconConfig('0 0 512 512', '<path d="M380.7 48a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zM2.7 268.9c6.1-11.8 20.6-16.3 32.4-10.2L232.7 361.3l46.2-69.2-75.1-75.1c-14.6-14.6-20.4-33.9-18.4-52.1l108.8 52 39.3 39.3c16.2 16.2 18.7 41.5 6 60.6L289.8 391l128.7 66.8c13.6 7.1 29.8 7.2 43.6 .3l15.2-7.6c11.9-5.9 26.3-1.1 32.2 10.7s1.1 26.3-10.7 32.2l-15.2 7.6c-27.5 13.7-59.9 13.5-87.2-.7L12.9 301.3C1.2 295.2-3.4 280.7 2.7 268.9zM118.9 65.6L137 74.2l8.7-17.4c4-7.9 13.6-11.1 21.5-7.2s11.1 13.6 7.2 21.5l-8.5 16.9 54.7 26.2c1.5-.7 3.1-1.4 4.7-2.1l83.4-33.4c34.2-13.7 72.8 4.2 84.5 39.2l17.1 51.2 52.1 26.1c15.8 7.9 22.2 27.1 14.3 42.9s-27.1 22.2-42.9 14.3l-58.1-29c-11.4-5.7-20-15.7-24.1-27.8l-5.8-17.3-27.3 12.1-6.8 3-6.7-3.2L151.5 116.7l-9.2 18.4c-4 7.9-13.6 11.1-21.5 7.2s-11.1-13.6-7.2-21.5l9-18-17.6-8.4c-8-3.8-11.3-13.4-7.5-21.3s13.4-11.3 21.3-7.5z"/>')
@ -789,7 +789,7 @@ export class NavBarConfig {
experimental: true,
githubIssue: 174
},
description: $localize`Adds a button to flattens the file structure, by listing the content of all subdirectories. (Won't work if the gallery has multiple folders with the same path.)`
description: $localize`Adds a button to flatten the file structure, by listing the content of all subdirectories. (Won't work if the gallery has multiple folders with the same path.)`
})
enableDirectoryFlattening: boolean = false;
@ -1091,8 +1091,8 @@ export class ClientGalleryConfig {
})
//DEVELOPER NOTE: The Database model stores the timestamp (creationDate) as milliseconds since 1970-01-01 UTC (global time). And stores and offset (creationDateOffset) as minutes.
//Ignoring timestamp for the user is the opposite for the database. If the user wants to ignore the offset, we have to add the offset to the creationDate to give the user the right experience.
ignoreTimestampOffset: boolean = true;
ignoreTimestampOffset: boolean = true;
@ConfigProperty({
tags: {
@ -1145,7 +1145,7 @@ export class ClientGalleryConfig {
priority: ConfigPriority.advanced,
githubIssue: 711
},
description: $localize`Makes inline blog (*.md files content) to be auto open.`
description: $localize`Makes inline blog (*.md files content) auto-open.`
})
InlineBlogStartsOpen: boolean = false;
@ -1155,7 +1155,7 @@ export class ClientGalleryConfig {
priority: ConfigPriority.advanced,
githubIssue: 711
},
description: $localize`Makes inline blog (*.md files content) to be auto open.`
description: $localize`Makes top blog (*.md files content) auto-open.`
})
TopBlogStartsOpen: boolean = false;
}
@ -1178,7 +1178,7 @@ export class ClientVideoConfig {
uiDisabled: (sb: ClientVideoConfig) => !sb.enabled,
uiResetNeeded: {db: true}
} as TAGS,
description: $localize`Video formats that are supported after transcoding (with the build-in ffmpeg support).`
description: $localize`Video formats that are supported after transcoding (with the built-in ffmpeg support).`
})
supportedFormatsWithTranscoding: string[] = ['avi', 'mkv', 'mov', 'wmv', 'flv', 'mts', 'm2ts', 'mpg', '3gp', 'm4v', 'mpeg', 'vob', 'divx', 'xvid', 'ts'];
// Browser supported video formats
@ -1266,7 +1266,7 @@ export class ClientPhotoConfig {
},
description: $localize`Photo formats that are supported. Browser needs to support these formats natively. Also sharp (libvips) package should be able to convert these formats.`,
})
supportedFormats: string[] = ['gif', 'jpeg', 'jpg', 'jpe', 'png', 'webp', 'svg'];
supportedFormats: string[] = ['gif', 'jpeg', 'jpg', 'jpe', 'png', 'webp', 'svg', 'avif', 'heic', 'dng', 'arw'];
}
@SubConfigClass({tags: {client: true}, softReadonly: true})
@ -1402,7 +1402,7 @@ export class ClientServiceConfig {
applicationTitle: string = 'PiGallery 2';
@ConfigProperty({
description: $localize`If you access the page from local network its good to know the public url for creating sharing link.`,
description: $localize`If you access the page from local network it's good to know the public url for creating sharing link.`,
tags: {
name: $localize`Page public url`,
hint: typeof window !== 'undefined' ? window?.origin : '',
@ -1418,8 +1418,9 @@ export class ClientServiceConfig {
hint: '/myGallery',
uiResetNeeded: {server: true},
priority: ConfigPriority.advanced,
uiOptional: true
}
uiOptional: true,
githubIssue: 854
} as TAGS
})
urlBase: string = '';
@ -1437,7 +1438,7 @@ export class ClientServiceConfig {
languages: string[] | undefined;
@ConfigProperty({
description: $localize`Injects the content of this between the <head></head> HTML tags of the app. (You can use it add analytics or custom code to the app).`,
description: $localize`Injects the content of this between the <head></head> HTML tags of the app. (You can use it to add analytics or custom code to the app).`,
tags: {
name: $localize`Custom HTML Head`,
priority: ConfigPriority.advanced,

View File

@ -27,7 +27,7 @@
</button>
</div>
<div class="modal-body">
<span i18n>Are you sue you want to run this job? This will have the following effect:</span>
<span i18n>Are you sure you want to run this job? This will have the following effect:</span>
<div class="alert alert-secondary" role="alert">
{{ backendTextService.getJobDescription(jobName) }}
</div>

File diff suppressed because it is too large Load Diff

View File

@ -199,9 +199,6 @@ export class TestHelper {
} as FaceRegion, {
box: {height: 10, width: 10, left: 104, top: 104},
name: 'Unkle Ben'
} as FaceRegion, {
box: {height: 10, width: 10, left: 105, top: 105},
name: 'Arvíztűrő Tükörfúrógép'
} as FaceRegion, {
box: {height: 10, width: 10, left: 201, top: 201},
name: 'R2-D2'

View File

@ -1387,7 +1387,7 @@ describe('SearchManager', (sqlHelper: DBTestHelper) => {
resultOverflow: false
} as SearchResultDTO));
query = ({value: 6, type: SearchQueryTypes.min_person_count} as MinPersonCountSearch);
query = ({value: 5, type: SearchQueryTypes.min_person_count} as MinPersonCountSearch);
expect(Utils.clone(await sm.search(query)))
.to.deep.equalInAnyOrder(removeDir({
searchQuery: query,

View File

@ -24,7 +24,8 @@ describe('DiskMangerWorker', () => {
ProjectPath.ImageFolder = path.join(__dirname, '/../../../assets');
const dir = await DiskManager.scanDirectory('/');
// should match the number of media (photo/video) files in the assets folder
expect(dir.media.length).to.be.equals(16);
// TODO: make this test less flaky. Every time a new image is added to the folder, it fails.
expect(dir.media.length).to.be.equals(17);
// eslint-disable-next-line @typescript-eslint/no-var-requires
const expected = require(path.join(__dirname, '/../../../assets/test image öüóőúéáű-.,.json'));
const i = dir.media.findIndex(m => m.name === 'test image öüóőúéáű-.,.jpg');