1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2024-11-03 21:04:03 +08:00

Merge branch 'bpatrik:master' into master
Some checks failed
pigallery2 / pigallery2-Gitea-Actions (push) Failing after 5m28s

This commit is contained in:
xuthus 2024-07-03 17:07:55 +08:00 committed by GitHub
commit 35f76a4d36
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 125 additions and 79 deletions

View File

@ -17,21 +17,13 @@ jobs:
strategy: strategy:
matrix: matrix:
node-version: [18.x] node-version: [18.x]
services:
mariadb:
image: mariadb:lts
ports:
- 3306
env:
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_DATABASE: pigallery_test
MYSQL_ROOT_PASSWORD: password
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
steps: steps:
- uses: getong/mariadb-action@v1.11
with:
mysql database: 'pigallery_test'
mysql root password: 'password'
mysql user: 'user'
mysql password: 'password'
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4 uses: actions/setup-node@v4

View File

@ -35,7 +35,7 @@ VOLUME ["/app/data/config", "/app/data/db", "/app/data/images", "/app/data/tmp"]
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"]
HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \ HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \
CMD wget --quiet --tries=1 --no-check-certificate --spider \ 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 # 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 # Exec form entrypoint is need otherwise (using shell form) ENV variables are not properly passed down to the app

View File

@ -36,7 +36,7 @@ VOLUME ["/app/data/config", "/app/data/db", "/app/data/images", "/app/data/tmp"]
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"]
HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \ HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \
CMD wget --quiet --tries=1 --no-check-certificate --spider \ 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 # 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 # Exec form entrypoint is need otherwise (using shell form) ENV variables are not properly passed down to the app

View File

@ -36,7 +36,7 @@ VOLUME ["/app/data/config", "/app/data/db", "/app/data/images", "/app/data/tmp"]
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"]
HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \ HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \
CMD wget --quiet --tries=1 --no-check-certificate --spider \ 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 # 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 # Exec form entrypoint is need otherwise (using shell form) ENV variables are not properly passed down to the app

View File

@ -36,7 +36,7 @@ VOLUME ["/app/data/config", "/app/data/db", "/app/data/images", "/app/data/tmp"]
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"]
HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \ HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \
CMD wget --quiet --tries=1 --no-check-certificate --spider \ 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 # 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 # Exec form entrypoint is need otherwise (using shell form) ENV variables are not properly passed down to the app

View File

@ -39,7 +39,7 @@ VOLUME ["/app/data/config", "/app/data/db", "/app/data/images", "/app/data/tmp"]
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"]
HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \ HEALTHCHECK --interval=40s --timeout=30s --retries=3 --start-period=60s \
CMD wget --quiet --tries=1 --no-check-certificate --spider \ 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 # 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 # Exec form entrypoint is need otherwise (using shell form) ENV variables are not properly passed down to the app

View File

@ -365,7 +365,7 @@ export class SearchManager {
switch (sort.method) { switch (sort.method) {
case SortByTypes.Date: case SortByTypes.Date:
if (Config.Gallery.ignoreTimestampOffset === true) { if (Config.Gallery.ignoreTimestampOffset === true) {
query.addOrderBy('media.metadata.creationDate + (media.metadata.creationDateOffset * 60000)', sort.ascending ? 'ASC' : 'DESC'); query.addOrderBy('media.metadata.creationDate + (coalesce(media.metadata.creationDateOffset,0) * 60000)', sort.ascending ? 'ASC' : 'DESC');
} else { } else {
query.addOrderBy('media.metadata.creationDate', sort.ascending ? 'ASC' : 'DESC'); query.addOrderBy('media.metadata.creationDate', sort.ascending ? 'ASC' : 'DESC');
} }
@ -568,7 +568,7 @@ export class SearchManager {
textParam['from' + queryId] = (query as FromDateSearch).value; textParam['from' + queryId] = (query as FromDateSearch).value;
if (Config.Gallery.ignoreTimestampOffset === true) { if (Config.Gallery.ignoreTimestampOffset === true) {
q.where( q.where(
`(media.metadata.creationDate + (media.metadata.creationDateOffset * 60000)) ${relation} :from${queryId}`, `(media.metadata.creationDate + (coalesce(media.metadata.creationDateOffset,0) * 60000)) ${relation} :from${queryId}`,
textParam textParam
); );
} else { } else {
@ -597,7 +597,7 @@ export class SearchManager {
textParam['to' + queryId] = (query as ToDateSearch).value; textParam['to' + queryId] = (query as ToDateSearch).value;
if (Config.Gallery.ignoreTimestampOffset === true) { if (Config.Gallery.ignoreTimestampOffset === true) {
q.where( q.where(
`(media.metadata.creationDate + (media.metadata.creationDateOffset * 60000)) ${relation} :to${queryId}`, `(media.metadata.creationDate + (coalesce(media.metadata.creationDateOffset,0) * 60000)) ${relation} :to${queryId}`,
textParam textParam
); );
} else { } else {
@ -809,9 +809,9 @@ export class SearchManager {
if (tq.negate) { if (tq.negate) {
if (Config.Gallery.ignoreTimestampOffset === true) { if (Config.Gallery.ignoreTimestampOffset === true) {
q.where( q.where(
`(media.metadata.creationDate + (media.metadata.creationDateOffset * 60000)) >= :to${queryId}`, `(media.metadata.creationDate + (coalesce(media.metadata.creationDateOffset,0) * 60000)) >= :to${queryId}`,
textParam textParam
).orWhere(`(media.metadata.creationDate + (media.metadata.creationDateOffset * 60000)) < :from${queryId}`, ).orWhere(`(media.metadata.creationDate + (coalesce(media.metadata.creationDateOffset,0) * 60000)) < :from${queryId}`,
textParam); textParam);
} else { } else {
q.where( q.where(
@ -824,9 +824,9 @@ export class SearchManager {
} else { } else {
if (Config.Gallery.ignoreTimestampOffset === true) { if (Config.Gallery.ignoreTimestampOffset === true) {
q.where( q.where(
`(media.metadata.creationDate + (media.metadata.creationDateOffset * 60000)) < :to${queryId}`, `(media.metadata.creationDate + (coalesce(media.metadata.creationDateOffset,0) * 60000)) < :to${queryId}`,
textParam textParam
).andWhere(`(media.metadata.creationDate + (media.metadata.creationDateOffset * 60000)) >= :from${queryId}`, ).andWhere(`(media.metadata.creationDate + (coalesce(media.metadata.creationDateOffset,0) * 60000)) >= :from${queryId}`,
textParam); textParam);
} else { } else {
q.where( q.where(

View File

@ -10,7 +10,10 @@ export class PersonEntry implements PersonDTO {
@PrimaryGeneratedColumn({unsigned: true}) @PrimaryGeneratedColumn({unsigned: true})
id: number; id: number;
@Column(columnCharsetCS) @Column({
charset: columnCharsetCS.charset,
collation: columnCharsetCS.collation,
})
name: string; name: string;
@Column('int', {unsigned: true, default: 0}) @Column('int', {unsigned: true, default: 0})

View File

@ -3,12 +3,14 @@ import {Logger} from '../../Logger';
import {NotificationManager} from '../NotifocationManager'; import {NotificationManager} from '../NotifocationManager';
import {SQLConnection} from '../database/SQLConnection'; import {SQLConnection} from '../database/SQLConnection';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path';
import {FFmpegFactory} from '../FFmpegFactory'; import {FFmpegFactory} from '../FFmpegFactory';
import { import {
ClientAlbumConfig, ClientAlbumConfig,
ClientFacesConfig, ClientFacesConfig,
ClientMapConfig, ClientMapConfig,
ClientMetaFileConfig, ClientMetaFileConfig,
ClientPhotoConfig,
ClientRandomPhotoConfig, ClientRandomPhotoConfig,
ClientSearchConfig, ClientSearchConfig,
ClientSharingConfig, ClientSharingConfig,
@ -29,6 +31,8 @@ import {Utils} from '../../../common/Utils';
import {JobRepository} from '../jobs/JobRepository'; import {JobRepository} from '../jobs/JobRepository';
import {ConfigClassBuilder} from '../../../../node_modules/typeconfig/node'; 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]'; const LOG_TAG = '[ConfigDiagnostics]';
@ -292,6 +296,46 @@ 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)) {
continue;
}
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> { static async testConfig(config: PrivateConfigClass): Promise<void> {
await ConfigDiagnostics.testDatabase(config.Database); await ConfigDiagnostics.testDatabase(config.Database);
@ -310,7 +354,6 @@ export class ConfigDiagnostics {
await ConfigDiagnostics.testRandomPhotoConfig(config.Sharing, config); await ConfigDiagnostics.testRandomPhotoConfig(config.Sharing, config);
await ConfigDiagnostics.testMapConfig(config.Map); await ConfigDiagnostics.testMapConfig(config.Map);
await ConfigDiagnostics.testJobsConfig(config.Jobs); await ConfigDiagnostics.testJobsConfig(config.Jobs);
} }
@ -575,6 +618,8 @@ export class ConfigDiagnostics {
Config.Jobs.scheduled = pc.Jobs.scheduled; Config.Jobs.scheduled = pc.Jobs.scheduled;
} }
await this.removeUnsupportedPhotoExtensions(Config.Media.Photo);
} }
} }

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); throw new Error('Unsupported media type to render thumbnail:' + input.type);
} }
public static renderFromImage(input: SvgRendererInput | MediaRendererInput): Promise<void> { public static renderFromImage(input: SvgRendererInput | MediaRendererInput, dryRun = false): Promise<void> {
return ImageRendererFactory.render(input); return ImageRendererFactory.render(input, dryRun);
} }
public static renderFromVideo(input: MediaRendererInput): Promise<void> { public static renderFromVideo(input: MediaRendererInput): Promise<void> {
@ -43,8 +43,8 @@ export enum ThumbnailSourceType {
interface RendererInput { interface RendererInput {
type: ThumbnailSourceType; type: ThumbnailSourceType;
size: number; size: number;
makeSquare: boolean; makeSquare?: boolean;
outPath: string; outPath?: string;
quality: number; quality: number;
useLanczos3: boolean; useLanczos3: boolean;
animate: boolean; // animates the output. Used for Gifs animate: boolean; // animates the output. Used for Gifs
@ -80,14 +80,14 @@ export class VideoRendererFactory {
let width = null; let width = null;
let height = null; let height = null;
for (const stream of data.streams) { for (const stream of data.streams) {
if (stream.width) { if (stream.width && stream.height && !isNaN(stream.width) && !isNaN(stream.height)) {
width = stream.width; width = stream.width;
height = stream.height; height = stream.height;
break; break;
} }
} }
if (!width || !height) { if (!width || !height || isNaN(width) || isNaN(height)) {
return reject('[FFmpeg] Can not read video dimension'); return reject(`[FFmpeg] Can not read video dimension. Found: ${{width}}x${{height}}`);
} }
const command: FfmpegCommand = ffmpeg(input.mediaPath); const command: FfmpegCommand = ffmpeg(input.mediaPath);
const fileName = path.basename(input.outPath); const fileName = path.basename(input.outPath);
@ -132,7 +132,7 @@ export class VideoRendererFactory {
export class ImageRendererFactory { export class ImageRendererFactory {
@ExtensionDecorator(e => e.gallery.ImageRenderer.render) @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; let image: Sharp;
if ((input as MediaRendererInput).mediaPath) { if ((input as MediaRendererInput).mediaPath) {
@ -174,17 +174,24 @@ export class ImageRendererFactory {
fit: 'cover', fit: 'cover',
}); });
} }
let processedImg: sharp.Sharp;
if ((input as MediaRendererInput).mediaPath) { if ((input as MediaRendererInput).mediaPath) {
await image.webp({ processedImg = image.webp({
effort: 6, effort: 6,
quality: input.quality, quality: input.quality,
smartSubsample: (input as MediaRendererInput).smartSubsample smartSubsample: (input as MediaRendererInput).smartSubsample
}).toFile(input.outPath); });
} else { } else {
if ((input as SvgRendererInput).svgString) { 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,31 +10,30 @@ if (typeof window !== 'undefined') {
Config = require('./config/private/Config').Config; Config = require('./config/private/Config').Config;
} }
export const SupportedFormats = { export class SupportedFormats {
Photos: Config.Media.Photo.supportedFormats, static Photos = Config.Media.Photo.supportedFormats;
// Browser supported video formats // Browser supported video formats
// Read more: https://www.w3schools.com/html/html5_video.asp // Read more: https://www.w3schools.com/html/html5_video.asp
Videos: Config.Media.Video.supportedFormats, static Videos = Config.Media.Video.supportedFormats;
MetaFiles: Config.MetaFile.supportedFormats, static MetaFiles = Config.MetaFile.supportedFormats;
// These formats need to be transcoded (with the build-in ffmpeg support) // These formats need to be transcoded (with the build-in ffmpeg support)
TranscodeNeed: { static TranscodeNeed = {
// based on libvips, all supported formats for sharp: https://github.com/libvips/libvips // based on libvips, all supported formats for sharp: https://github.com/libvips/libvips
Photos: [] as string[], Photos: [] as string[],
Videos: Config.Media.Video.supportedFormatsWithTranscoding, Videos: Config.Media.Video.supportedFormatsWithTranscoding,
}, };
// -------------------------------------------- // --------------------------------------------
// Below this, it is autogenerated, DO NOT EDIT // Below this, it is autogenerated, DO NOT EDIT
WithDots: { static WithDots = {
Photos: [] as string[], Photos: [] as string[],
Videos: [] as string[], Videos: [] as string[],
MetaFiles: [] as string[], MetaFiles: [] as string[],
TranscodeNeed: { TranscodeNeed: {
Photos: [] as string[], Photos: [] as string[],
Videos: [] as string[], Videos: [] as string[],
}, }
},
}; };
static init(){
SupportedFormats.Photos = SupportedFormats.Photos.concat( SupportedFormats.Photos = SupportedFormats.Photos.concat(
SupportedFormats.TranscodeNeed.Photos SupportedFormats.TranscodeNeed.Photos
); );
@ -50,4 +49,6 @@ SupportedFormats.WithDots.TranscodeNeed.Photos =
SupportedFormats.TranscodeNeed.Photos.map((f) => '.' + f); SupportedFormats.TranscodeNeed.Photos.map((f) => '.' + f);
SupportedFormats.WithDots.TranscodeNeed.Videos = SupportedFormats.WithDots.TranscodeNeed.Videos =
SupportedFormats.TranscodeNeed.Videos.map((f) => '.' + f); SupportedFormats.TranscodeNeed.Videos.map((f) => '.' + f);
}
}
SupportedFormats.init();

View File

@ -1084,7 +1084,7 @@ export class ClientGalleryConfig {
@ConfigProperty({ @ConfigProperty({
tags: { tags: {
name: $localize`Ignore timestamp offsets`, name: $localize`Ignore timestamp offsets (use local time)`,
priority: ConfigPriority.advanced, priority: ConfigPriority.advanced,
}, },
description: $localize`If enabled, timestamp offsets are ignored, meaning that the local times of pictures are used for searching, sorting and grouping. If disabled, global time is used and pictures with no timestamp are assumed to be in UTC (offset +00:00).` description: $localize`If enabled, timestamp offsets are ignored, meaning that the local times of pictures are used for searching, sorting and grouping. If disabled, global time is used and pictures with no timestamp are assumed to be in UTC (offset +00:00).`
@ -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.`, 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'];
} }
@SubConfigClass({tags: {client: true}, softReadonly: true}) @SubConfigClass({tags: {client: true}, softReadonly: true})

View File

@ -199,9 +199,6 @@ export class TestHelper {
} as FaceRegion, { } as FaceRegion, {
box: {height: 10, width: 10, left: 104, top: 104}, box: {height: 10, width: 10, left: 104, top: 104},
name: 'Unkle Ben' 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, { } as FaceRegion, {
box: {height: 10, width: 10, left: 201, top: 201}, box: {height: 10, width: 10, left: 201, top: 201},
name: 'R2-D2' name: 'R2-D2'

View File

@ -1387,7 +1387,7 @@ describe('SearchManager', (sqlHelper: DBTestHelper) => {
resultOverflow: false resultOverflow: false
} as SearchResultDTO)); } 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))) expect(Utils.clone(await sm.search(query)))
.to.deep.equalInAnyOrder(removeDir({ .to.deep.equalInAnyOrder(removeDir({
searchQuery: query, searchQuery: query,

View File

@ -24,7 +24,8 @@ describe('DiskMangerWorker', () => {
ProjectPath.ImageFolder = path.join(__dirname, '/../../../assets'); ProjectPath.ImageFolder = path.join(__dirname, '/../../../assets');
const dir = await DiskManager.scanDirectory('/'); const dir = await DiskManager.scanDirectory('/');
// should match the number of media (photo/video) files in the assets folder // 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 // eslint-disable-next-line @typescript-eslint/no-var-requires
const expected = require(path.join(__dirname, '/../../../assets/test image öüóőúéáű-.,.json')); const expected = require(path.join(__dirname, '/../../../assets/test image öüóőúéáű-.,.json'));
const i = dir.media.findIndex(m => m.name === 'test image öüóőúéáű-.,.jpg'); const i = dir.media.findIndex(m => m.name === 'test image öüóőúéáű-.,.jpg');