Release 2.21.5: hide generated image copies from media library
This commit is contained in:
1 parent
b80d4aa9c7
commit
9e988c307e
7 files changed
+32
-7
No files matched your search
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## 2.21.5 - 2026-10-27
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Generated image crop and playback copies no longer appear as separate Media Library assets.
|
||||||
|
|
||||||
## 2.21.4 - 2026-10-27
|
## 2.21.4 - 2026-10-27
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pulse-signage-player",
|
"name": "pulse-signage-player",
|
||||||
"version": "2.21.4",
|
"version": "2.21.5",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "Pulse Signage player application bundle",
|
"description": "Pulse Signage player application bundle",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pulse-signage-web",
|
"name": "pulse-signage-web",
|
||||||
"version": "2.21.4",
|
"version": "2.21.5",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "Pulse Signage web and bridge application bundle",
|
"description": "Pulse Signage web and bridge application bundle",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "pulse-signage",
|
"name": "pulse-signage",
|
||||||
"version": "2.21.4",
|
"version": "2.21.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "pulse-signage",
|
"name": "pulse-signage",
|
||||||
"version": "2.21.4",
|
"version": "2.21.5",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@better-auth/passkey": "^1.7.13",
|
"@better-auth/passkey": "^1.7.13",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pulse-signage",
|
"name": "pulse-signage",
|
||||||
"version": "2.21.4",
|
"version": "2.21.5",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "Pulse Signage application with MySQL and media storage",
|
"description": "Pulse Signage application with MySQL and media storage",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ const IMAGE_VARIANT_DIMENSIONS = [2048, 4096, 8192, 16384];
|
|||||||
const IMAGE_THUMBNAIL_EXTENSIONS = new Set(['.jpg', '.jpeg', '.png', '.webp', '.gif', '.svg']);
|
const IMAGE_THUMBNAIL_EXTENSIONS = new Set(['.jpg', '.jpeg', '.png', '.webp', '.gif', '.svg']);
|
||||||
const IMAGE_THUMBNAIL_MAX_DIMENSION = 480;
|
const IMAGE_THUMBNAIL_MAX_DIMENSION = 480;
|
||||||
|
|
||||||
|
function isGeneratedImageCopyName(name) {
|
||||||
|
return /^image-(?:crop|playback)-[a-f0-9]{64}\.(?:jpe?g|png|webp|gif)$/i.test(String(name || ''));
|
||||||
|
}
|
||||||
|
|
||||||
function getImageVariantPath(filePath, dimension) {
|
function getImageVariantPath(filePath, dimension) {
|
||||||
const extension = path.extname(filePath);
|
const extension = path.extname(filePath);
|
||||||
const baseName = path.basename(filePath, extension);
|
const baseName = path.basename(filePath, extension);
|
||||||
@@ -352,7 +356,7 @@ async function fetchMediaAssets(pool) {
|
|||||||
WHERE is_published = 1
|
WHERE is_published = 1
|
||||||
ORDER BY created_at DESC, id DESC`
|
ORDER BY created_at DESC, id DESC`
|
||||||
);
|
);
|
||||||
return rows || [];
|
return (rows || []).filter(asset => !isGeneratedImageCopyName(path.basename(String(asset.media_path || ''))));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function syncMediaAssetsFromDirectory(pool, uploadDir, userId) {
|
async function syncMediaAssetsFromDirectory(pool, uploadDir, userId) {
|
||||||
@@ -377,7 +381,7 @@ async function syncMediaAssetsFromDirectory(pool, uploadDir, userId) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const originalName = String(entry.name || '').trim();
|
const originalName = String(entry.name || '').trim();
|
||||||
if (/\.variant-\d+\.(?:jpe?g|png|webp)$/i.test(originalName) || /\.(?:thumb|poster)\.webp$/i.test(originalName)) {
|
if (isGeneratedImageCopyName(originalName) || /\.variant-\d+\.(?:jpe?g|png|webp)$/i.test(originalName) || /\.(?:thumb|poster)\.webp$/i.test(originalName)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const mimeType = MEDIA_MIME_TYPES[path.extname(originalName).toLowerCase()];
|
const mimeType = MEDIA_MIME_TYPES[path.extname(originalName).toLowerCase()];
|
||||||
|
|||||||
@@ -737,6 +737,7 @@ test('media library backfills existing image and video uploads', async () => {
|
|||||||
const uploadDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'pulse-media-library-'));
|
const uploadDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'pulse-media-library-'));
|
||||||
await fs.promises.writeFile(path.join(uploadDir, 'legacy.png'), Buffer.from('image'));
|
await fs.promises.writeFile(path.join(uploadDir, 'legacy.png'), Buffer.from('image'));
|
||||||
await fs.promises.writeFile(path.join(uploadDir, 'legacy.thumb.webp'), Buffer.from('thumbnail'));
|
await fs.promises.writeFile(path.join(uploadDir, 'legacy.thumb.webp'), Buffer.from('thumbnail'));
|
||||||
|
await fs.promises.writeFile(path.join(uploadDir, 'image-playback-' + 'a'.repeat(64) + '.png'), Buffer.from('generated'));
|
||||||
await fs.promises.writeFile(path.join(uploadDir, 'legacy.mp4'), Buffer.from('video'));
|
await fs.promises.writeFile(path.join(uploadDir, 'legacy.mp4'), Buffer.from('video'));
|
||||||
await fs.promises.writeFile(path.join(uploadDir, 'ignore.txt'), Buffer.from('other'));
|
await fs.promises.writeFile(path.join(uploadDir, 'ignore.txt'), Buffer.from('other'));
|
||||||
const queries = [];
|
const queries = [];
|
||||||
@@ -760,6 +761,20 @@ test('media library backfills existing image and video uploads', async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('media library omits generated image copies from published asset results', async () => {
|
||||||
|
const generated = 'image-crop-' + 'b'.repeat(64) + '.png';
|
||||||
|
const pool = {
|
||||||
|
async query() {
|
||||||
|
return [[
|
||||||
|
{ id: 1, media_path: '/media/uploads/source.png' },
|
||||||
|
{ id: 2, media_path: '/media/uploads/' + generated }
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.deepEqual((await mediaLibrary.fetchMediaAssets(pool)).map(asset => asset.id), [1]);
|
||||||
|
});
|
||||||
|
|
||||||
test('media library counts slide, template background, and region default references', async () => {
|
test('media library counts slide, template background, and region default references', async () => {
|
||||||
const queries = [];
|
const queries = [];
|
||||||
const pool = {
|
const pool = {
|
||||||
|
|||||||
Reference in new issue
Block a user