1
0
mirror of https://github.com/immich-app/immich.git synced 2025-01-17 16:25:03 +02:00

Support HEIC/HEIF (#16)

* Support HEIC/HEIF backup
* Storing backup directly from original file from the phone
* Directly read and backup video file - Improve performance on video backup
This commit is contained in:
Alex 2022-02-09 20:48:06 -06:00 committed by GitHub
parent f578ca6d47
commit 38c968d47e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 252 additions and 232 deletions

View File

@ -36,11 +36,13 @@ This project is under heavy development, there will be continous functions, feat
[x] Auto Backup [x] Auto Backup
[x] Support HEIC
# Development # Development
You can use docker compose for development, there are several services that compose Immich You can use docker compose for development, there are several services that compose Immich
1. The server 1. NestJs
2. PostgreSQL 2. PostgreSQL
3. Redis 3. Redis
4. Nginx 4. Nginx

View File

@ -49,7 +49,6 @@ class ThumbnailImage extends HookConsumerWidget {
} else if (isMultiSelectEnable && !selectedAsset.contains(asset)) { } else if (isMultiSelectEnable && !selectedAsset.contains(asset)) {
ref.watch(homePageStateProvider.notifier).addSingleSelectedItem(asset); ref.watch(homePageStateProvider.notifier).addSingleSelectedItem(asset);
} else { } else {
print(asset.id);
if (asset.type == 'IMAGE') { if (asset.type == 'IMAGE') {
AutoRouter.of(context).push( AutoRouter.of(context).push(
ImageViewerRoute( ImageViewerRoute(

View File

@ -126,7 +126,7 @@ class LoginButton extends ConsumerWidget {
} else { } else {
ImmichToast.show( ImmichToast.show(
context: context, context: context,
msg: "Error logging you in, check server url, emald and password!", msg: "Error logging you in, check server url, email and password!",
toastType: ToastType.error); toastType: ToastType.error);
} }
}, },

View File

@ -37,20 +37,12 @@ class BackupService {
for (var entity in assetList) { for (var entity in assetList) {
try { try {
if (entity.type == AssetType.video) { if (entity.type == AssetType.video) {
file = await entity.file; file = await entity.originFile;
} else { } else {
file = await entity.file.timeout(const Duration(seconds: 5)); file = await entity.originFile.timeout(const Duration(seconds: 5));
} }
if (file != null) { if (file != null) {
// reading exif
// var exifData = await readExifFromFile(file);
// for (String key in exifData.keys) {
// debugPrint("- $key (${exifData[key]?.tagType}): ${exifData[key]}");
// }
// debugPrint("------------------");
String originalFileName = await entity.titleAsync; String originalFileName = await entity.titleAsync;
String fileNameWithoutPath = originalFileName.toString().split(".")[0]; String fileNameWithoutPath = originalFileName.toString().split(".")[0];
var fileExtension = p.extension(file.path); var fileExtension = p.extension(file.path);

View File

@ -1,9 +1,7 @@
import 'package:flutter/material.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
class FileHelper { class FileHelper {
static getMimeType(String filePath) { static getMimeType(String filePath) {
debugPrint(filePath);
var fileExtension = p.extension(filePath).split(".")[1]; var fileExtension = p.extension(filePath).split(".")[1];
switch (fileExtension.toLowerCase()) { switch (fileExtension.toLowerCase()) {
@ -28,6 +26,12 @@ class FileHelper {
case 'avi': case 'avi':
return {"type": "video", "subType": "x-msvideo"}; return {"type": "video", "subType": "x-msvideo"};
case 'heic':
return {"type": "image", "subType": "heic"};
case 'heif':
return {"type": "image", "subType": "heif"};
default: default:
return {"type": "unsupport", "subType": "unsupport"}; return {"type": "unsupport", "subType": "unsupport"};
} }

View File

@ -513,6 +513,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.11" version: "0.12.11"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
meta: meta:
dependency: transitive dependency: transitive
description: description:
@ -818,7 +825,7 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.3" version: "0.4.8"
timing: timing:
dependency: transitive dependency: transitive
description: description:

View File

@ -1,7 +1,7 @@
################################## ##################################
# DEVELOPMENT # DEVELOPMENT
################################## ##################################
FROM node:16-bullseye-slim AS development FROM node:16-alpine3.14 AS development
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
@ -9,8 +9,7 @@ WORKDIR /usr/src/app
COPY package.json package-lock.json ./ COPY package.json package-lock.json ./
RUN apt-get update RUN apk add --update-cache build-base python3 libheif vips-dev vips ffmpeg
RUN apt-get install gcc g++ make cmake python3 python3-pip ffmpeg -y
RUN npm install RUN npm install
@ -18,15 +17,6 @@ COPY . .
RUN npm run build RUN npm run build
# Clean up commands
RUN apt-get autoremove -y && apt-get clean && \
rm -rf /usr/local/src/*
RUN apt-get clean && \
rm -rf /var/lib/apt/lists/*
################################## ##################################
# PRODUCTION # PRODUCTION
################################## ##################################

316
server/package-lock.json generated
View File

@ -19,17 +19,13 @@
"@nestjs/platform-express": "^8.0.0", "@nestjs/platform-express": "^8.0.0",
"@nestjs/platform-fastify": "^8.2.6", "@nestjs/platform-fastify": "^8.2.6",
"@nestjs/typeorm": "^8.0.3", "@nestjs/typeorm": "^8.0.3",
"@tensorflow-models/coco-ssd": "^2.2.2",
"@tensorflow/tfjs": "^3.13.0",
"@tensorflow/tfjs-converter": "^3.13.0",
"@tensorflow/tfjs-core": "^3.13.0",
"@tensorflow/tfjs-node": "^3.13.0",
"bcrypt": "^5.0.1", "bcrypt": "^5.0.1",
"bull": "^4.4.0", "bull": "^4.4.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.13.2", "class-validator": "^0.13.2",
"dotenv": "^14.2.0", "dotenv": "^14.2.0",
"fluent-ffmpeg": "^2.1.2", "fluent-ffmpeg": "^2.1.2",
"heic-convert": "^1.2.4",
"joi": "^17.5.0", "joi": "^17.5.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"passport": "^0.5.2", "passport": "^0.5.2",
@ -38,7 +34,7 @@
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rxjs": "^7.2.0", "rxjs": "^7.2.0",
"sharp": "^0.29.3", "sharp": "0.28",
"systeminformation": "^5.11.0", "systeminformation": "^5.11.0",
"typeorm": "^0.2.41" "typeorm": "^0.2.41"
}, },
@ -3723,12 +3719,12 @@
"dev": true "dev": true
}, },
"node_modules/color": { "node_modules/color": {
"version": "4.2.0", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.0.tgz", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
"integrity": "sha512-hHTcrbvEnGjC7WBMk6ibQWFVDgEFTVmjrz2Q5HlU6ltwxv0JJN2Z8I7uRbWeQLF04dikxs8zgyZkazRJvSMtyQ==", "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
"dependencies": { "dependencies": {
"color-convert": "^2.0.1", "color-convert": "^1.9.3",
"color-string": "^1.9.0" "color-string": "^1.6.0"
} }
}, },
"node_modules/color-convert": { "node_modules/color-convert": {
@ -3756,6 +3752,19 @@
"simple-swizzle": "^0.2.2" "simple-swizzle": "^0.2.2"
} }
}, },
"node_modules/color/node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dependencies": {
"color-name": "1.1.3"
}
},
"node_modules/color/node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"node_modules/colors": { "node_modules/colors": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
@ -4069,17 +4078,14 @@
"dev": true "dev": true
}, },
"node_modules/decompress-response": { "node_modules/decompress-response": {
"version": "6.0.0", "version": "4.2.1",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
"dependencies": { "dependencies": {
"mimic-response": "^3.1.0" "mimic-response": "^2.0.0"
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/dedent": { "node_modules/dedent": {
@ -5650,6 +5656,30 @@
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
}, },
"node_modules/heic-convert": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/heic-convert/-/heic-convert-1.2.4.tgz",
"integrity": "sha512-klJHyv+BqbgKiCQvCqI9IKIvweCcohDuDl0Jphearj8+16+v8eff2piVevHqq4dW9TK0r1onTR6PKHP1I4hdbA==",
"dependencies": {
"heic-decode": "^1.1.2",
"jpeg-js": "^0.4.1",
"pngjs": "^3.4.0"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/heic-decode": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/heic-decode/-/heic-decode-1.1.2.tgz",
"integrity": "sha512-UF8teegxvzQPdSTcx5frIUhitNDliz/9Pui0JFdIqVRE00spVE33DcCYtZqaLNyd4y5RP/QQWZFIc1YWVKKm2A==",
"dependencies": {
"libheif-js": "^1.10.0"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/hexoid": { "node_modules/hexoid": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
@ -6864,6 +6894,11 @@
"@sideway/pinpoint": "^2.0.0" "@sideway/pinpoint": "^2.0.0"
} }
}, },
"node_modules/jpeg-js": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz",
"integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q=="
},
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -7076,6 +7111,14 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/libheif-js": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/libheif-js/-/libheif-js-1.12.0.tgz",
"integrity": "sha512-hDs6xQ7028VOwAFwEtM0Q+B2x2NW69Jb2MhQFUbk3rUrHzz4qo5mqS8VrqNgYnSc8TiUGnR691LnO4uIfEE23w==",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/libphonenumber-js": { "node_modules/libphonenumber-js": {
"version": "1.9.48", "version": "1.9.48",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.48.tgz", "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.48.tgz",
@ -7419,11 +7462,11 @@
} }
}, },
"node_modules/mimic-response": { "node_modules/mimic-response": {
"version": "3.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
"engines": { "engines": {
"node": ">=10" "node": ">=8"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
@ -7574,14 +7617,19 @@
"dev": true "dev": true
}, },
"node_modules/node-abi": { "node_modules/node-abi": {
"version": "3.8.0", "version": "2.30.1",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz",
"integrity": "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==", "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==",
"dependencies": { "dependencies": {
"semver": "^7.3.5" "semver": "^5.4.1"
}, }
"engines": { },
"node": ">=10" "node_modules/node-abi/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"bin": {
"semver": "bin/semver"
} }
}, },
"node_modules/node-addon-api": { "node_modules/node-addon-api": {
@ -8196,6 +8244,14 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/pngjs": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
"integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/postgres-array": { "node_modules/postgres-array": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
@ -8232,21 +8288,21 @@
} }
}, },
"node_modules/prebuild-install": { "node_modules/prebuild-install": {
"version": "7.0.1", "version": "6.1.4",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.0.1.tgz", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz",
"integrity": "sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg==", "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==",
"dependencies": { "dependencies": {
"detect-libc": "^2.0.0", "detect-libc": "^1.0.3",
"expand-template": "^2.0.3", "expand-template": "^2.0.3",
"github-from-package": "0.0.0", "github-from-package": "0.0.0",
"minimist": "^1.2.3", "minimist": "^1.2.3",
"mkdirp-classic": "^0.5.3", "mkdirp-classic": "^0.5.3",
"napi-build-utils": "^1.0.1", "napi-build-utils": "^1.0.1",
"node-abi": "^3.3.0", "node-abi": "^2.21.0",
"npmlog": "^4.0.1", "npmlog": "^4.0.1",
"pump": "^3.0.0", "pump": "^3.0.0",
"rc": "^1.2.7", "rc": "^1.2.7",
"simple-get": "^4.0.0", "simple-get": "^3.0.3",
"tar-fs": "^2.0.0", "tar-fs": "^2.0.0",
"tunnel-agent": "^0.6.0" "tunnel-agent": "^0.6.0"
}, },
@ -8254,15 +8310,7 @@
"prebuild-install": "bin.js" "prebuild-install": "bin.js"
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=6"
}
},
"node_modules/prebuild-install/node_modules/detect-libc": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.0.tgz",
"integrity": "sha512-S55LzUl8HUav8l9E2PBTlC5PAJrHK7tkM+XXFGD+fbsbkTzhCpG6K05LxJcUOEWzMa4v6ptcMZ9s3fOdJDu0Zw==",
"engines": {
"node": ">=8"
} }
}, },
"node_modules/prelude-ls": { "node_modules/prelude-ls": {
@ -8922,32 +8970,27 @@
} }
}, },
"node_modules/sharp": { "node_modules/sharp": {
"version": "0.29.3", "version": "0.28.3",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.29.3.tgz", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.28.3.tgz",
"integrity": "sha512-fKWUuOw77E4nhpyzCCJR1ayrttHoFHBT2U/kR/qEMRhvPEcluG4BKj324+SCO1e84+knXHwhJ1HHJGnUt4ElGA==", "integrity": "sha512-21GEP45Rmr7q2qcmdnjDkNP04Ooh5v0laGS5FDpojOO84D1DJwUijLiSq8XNNM6e8aGXYtoYRh3sVNdm8NodMA==",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"color": "^4.0.1", "color": "^3.1.3",
"detect-libc": "^1.0.3", "detect-libc": "^1.0.3",
"node-addon-api": "^4.2.0", "node-addon-api": "^3.2.0",
"prebuild-install": "^7.0.0", "prebuild-install": "^6.1.2",
"semver": "^7.3.5", "semver": "^7.3.5",
"simple-get": "^4.0.0", "simple-get": "^3.1.0",
"tar-fs": "^2.1.1", "tar-fs": "^2.1.1",
"tunnel-agent": "^0.6.0" "tunnel-agent": "^0.6.0"
}, },
"engines": { "engines": {
"node": ">=12.13.0" "node": ">=10"
}, },
"funding": { "funding": {
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
} }
}, },
"node_modules/sharp/node_modules/node-addon-api": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
"integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
},
"node_modules/shebang-command": { "node_modules/shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -9025,25 +9068,11 @@
] ]
}, },
"node_modules/simple-get": { "node_modules/simple-get": {
"version": "4.0.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": { "dependencies": {
"decompress-response": "^6.0.0", "decompress-response": "^4.2.0",
"once": "^1.3.1", "once": "^1.3.1",
"simple-concat": "^1.0.0" "simple-concat": "^1.0.0"
} }
@ -13491,12 +13520,27 @@
"dev": true "dev": true
}, },
"color": { "color": {
"version": "4.2.0", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.0.tgz", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
"integrity": "sha512-hHTcrbvEnGjC7WBMk6ibQWFVDgEFTVmjrz2Q5HlU6ltwxv0JJN2Z8I7uRbWeQLF04dikxs8zgyZkazRJvSMtyQ==", "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
"requires": { "requires": {
"color-convert": "^2.0.1", "color-convert": "^1.9.3",
"color-string": "^1.9.0" "color-string": "^1.6.0"
},
"dependencies": {
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
}
} }
}, },
"color-convert": { "color-convert": {
@ -13783,11 +13827,11 @@
"dev": true "dev": true
}, },
"decompress-response": { "decompress-response": {
"version": "6.0.0", "version": "4.2.1",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
"requires": { "requires": {
"mimic-response": "^3.1.0" "mimic-response": "^2.0.0"
} }
}, },
"dedent": { "dedent": {
@ -15001,6 +15045,24 @@
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
}, },
"heic-convert": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/heic-convert/-/heic-convert-1.2.4.tgz",
"integrity": "sha512-klJHyv+BqbgKiCQvCqI9IKIvweCcohDuDl0Jphearj8+16+v8eff2piVevHqq4dW9TK0r1onTR6PKHP1I4hdbA==",
"requires": {
"heic-decode": "^1.1.2",
"jpeg-js": "^0.4.1",
"pngjs": "^3.4.0"
}
},
"heic-decode": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/heic-decode/-/heic-decode-1.1.2.tgz",
"integrity": "sha512-UF8teegxvzQPdSTcx5frIUhitNDliz/9Pui0JFdIqVRE00spVE33DcCYtZqaLNyd4y5RP/QQWZFIc1YWVKKm2A==",
"requires": {
"libheif-js": "^1.10.0"
}
},
"hexoid": { "hexoid": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
@ -15922,6 +15984,11 @@
"@sideway/pinpoint": "^2.0.0" "@sideway/pinpoint": "^2.0.0"
} }
}, },
"jpeg-js": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz",
"integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q=="
},
"js-tokens": { "js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -16097,6 +16164,11 @@
"type-check": "~0.4.0" "type-check": "~0.4.0"
} }
}, },
"libheif-js": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/libheif-js/-/libheif-js-1.12.0.tgz",
"integrity": "sha512-hDs6xQ7028VOwAFwEtM0Q+B2x2NW69Jb2MhQFUbk3rUrHzz4qo5mqS8VrqNgYnSc8TiUGnR691LnO4uIfEE23w=="
},
"libphonenumber-js": { "libphonenumber-js": {
"version": "1.9.48", "version": "1.9.48",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.48.tgz", "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.48.tgz",
@ -16376,9 +16448,9 @@
"dev": true "dev": true
}, },
"mimic-response": { "mimic-response": {
"version": "3.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="
}, },
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
@ -16506,11 +16578,18 @@
"dev": true "dev": true
}, },
"node-abi": { "node-abi": {
"version": "3.8.0", "version": "2.30.1",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz",
"integrity": "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==", "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==",
"requires": { "requires": {
"semver": "^7.3.5" "semver": "^5.4.1"
},
"dependencies": {
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
}
} }
}, },
"node-addon-api": { "node-addon-api": {
@ -16968,6 +17047,11 @@
"integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==",
"dev": true "dev": true
}, },
"pngjs": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
"integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w=="
},
"postgres-array": { "postgres-array": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
@ -16992,30 +17076,23 @@
} }
}, },
"prebuild-install": { "prebuild-install": {
"version": "7.0.1", "version": "6.1.4",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.0.1.tgz", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz",
"integrity": "sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg==", "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==",
"requires": { "requires": {
"detect-libc": "^2.0.0", "detect-libc": "^1.0.3",
"expand-template": "^2.0.3", "expand-template": "^2.0.3",
"github-from-package": "0.0.0", "github-from-package": "0.0.0",
"minimist": "^1.2.3", "minimist": "^1.2.3",
"mkdirp-classic": "^0.5.3", "mkdirp-classic": "^0.5.3",
"napi-build-utils": "^1.0.1", "napi-build-utils": "^1.0.1",
"node-abi": "^3.3.0", "node-abi": "^2.21.0",
"npmlog": "^4.0.1", "npmlog": "^4.0.1",
"pump": "^3.0.0", "pump": "^3.0.0",
"rc": "^1.2.7", "rc": "^1.2.7",
"simple-get": "^4.0.0", "simple-get": "^3.0.3",
"tar-fs": "^2.0.0", "tar-fs": "^2.0.0",
"tunnel-agent": "^0.6.0" "tunnel-agent": "^0.6.0"
},
"dependencies": {
"detect-libc": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.0.tgz",
"integrity": "sha512-S55LzUl8HUav8l9E2PBTlC5PAJrHK7tkM+XXFGD+fbsbkTzhCpG6K05LxJcUOEWzMa4v6ptcMZ9s3fOdJDu0Zw=="
}
} }
}, },
"prelude-ls": { "prelude-ls": {
@ -17497,25 +17574,18 @@
} }
}, },
"sharp": { "sharp": {
"version": "0.29.3", "version": "0.28.3",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.29.3.tgz", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.28.3.tgz",
"integrity": "sha512-fKWUuOw77E4nhpyzCCJR1ayrttHoFHBT2U/kR/qEMRhvPEcluG4BKj324+SCO1e84+knXHwhJ1HHJGnUt4ElGA==", "integrity": "sha512-21GEP45Rmr7q2qcmdnjDkNP04Ooh5v0laGS5FDpojOO84D1DJwUijLiSq8XNNM6e8aGXYtoYRh3sVNdm8NodMA==",
"requires": { "requires": {
"color": "^4.0.1", "color": "^3.1.3",
"detect-libc": "^1.0.3", "detect-libc": "^1.0.3",
"node-addon-api": "^4.2.0", "node-addon-api": "^3.2.0",
"prebuild-install": "^7.0.0", "prebuild-install": "^6.1.2",
"semver": "^7.3.5", "semver": "^7.3.5",
"simple-get": "^4.0.0", "simple-get": "^3.1.0",
"tar-fs": "^2.1.1", "tar-fs": "^2.1.1",
"tunnel-agent": "^0.6.0" "tunnel-agent": "^0.6.0"
},
"dependencies": {
"node-addon-api": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
"integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
}
} }
}, },
"shebang-command": { "shebang-command": {
@ -17566,11 +17636,11 @@
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
}, },
"simple-get": { "simple-get": {
"version": "4.0.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
"requires": { "requires": {
"decompress-response": "^6.0.0", "decompress-response": "^4.2.0",
"once": "^1.3.1", "once": "^1.3.1",
"simple-concat": "^1.0.0" "simple-concat": "^1.0.0"
} }

View File

@ -50,7 +50,7 @@
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rxjs": "^7.2.0", "rxjs": "^7.2.0",
"sharp": "^0.29.3", "sharp": "0.28",
"systeminformation": "^5.11.0", "systeminformation": "^5.11.0",
"typeorm": "^0.2.41" "typeorm": "^0.2.41"
}, },

View File

@ -17,14 +17,6 @@ import { BullModule } from '@nestjs/bull';
removeOnFail: false, removeOnFail: false,
}, },
}), }),
BullModule.registerQueue({
name: 'machine-learning',
defaultJobOptions: {
attempts: 3,
removeOnComplete: true,
removeOnFail: false,
},
}),
TypeOrmModule.forFeature([AssetEntity]), TypeOrmModule.forFeature([AssetEntity]),
ImageOptimizeModule, ImageOptimizeModule,
], ],

View File

@ -8,7 +8,6 @@ import { AssetEntity, AssetType } from './entities/asset.entity';
import _ from 'lodash'; import _ from 'lodash';
import { GetAllAssetQueryDto } from './dto/get-all-asset-query.dto'; import { GetAllAssetQueryDto } from './dto/get-all-asset-query.dto';
import { GetAllAssetReponseDto } from './dto/get-all-asset-response.dto'; import { GetAllAssetReponseDto } from './dto/get-all-asset-response.dto';
import { Greater } from '@tensorflow/tfjs-core';
@Injectable() @Injectable()
export class AssetService { export class AssetService {

View File

@ -11,7 +11,7 @@ export const multerConfig = {
export const multerOption: MulterOptions = { export const multerOption: MulterOptions = {
fileFilter: (req: Request, file: any, cb: any) => { fileFilter: (req: Request, file: any, cb: any) => {
if (file.mimetype.match(/\/(jpg|jpeg|png|gif|mp4|x-msvideo|quicktime)$/)) { if (file.mimetype.match(/\/(jpg|jpeg|png|gif|mp4|x-msvideo|quicktime|heic|heif)$/)) {
cb(null, true); cb(null, true);
} else { } else {
cb(new HttpException(`Unsupported file type ${extname(file.originalname)}`, HttpStatus.BAD_REQUEST), false); cb(new HttpException(`Unsupported file type ${extname(file.originalname)}`, HttpStatus.BAD_REQUEST), false);

View File

@ -7,7 +7,6 @@ import { AssetService } from '../../api-v1/asset/asset.service';
import { AssetEntity } from '../../api-v1/asset/entities/asset.entity'; import { AssetEntity } from '../../api-v1/asset/entities/asset.entity';
import { ImageOptimizeProcessor } from './image-optimize.processor'; import { ImageOptimizeProcessor } from './image-optimize.processor';
import { AssetOptimizeService } from './image-optimize.service'; import { AssetOptimizeService } from './image-optimize.service';
import { MachineLearningProcessor } from './machine-learning.processor';
@Module({ @Module({
imports: [ imports: [
@ -19,18 +18,10 @@ import { MachineLearningProcessor } from './machine-learning.processor';
removeOnFail: false, removeOnFail: false,
}, },
}), }),
BullModule.registerQueue({
name: 'machine-learning',
defaultJobOptions: {
attempts: 3,
removeOnComplete: true,
removeOnFail: false,
},
}),
TypeOrmModule.forFeature([AssetEntity]), TypeOrmModule.forFeature([AssetEntity]),
], ],
providers: [AssetOptimizeService, ImageOptimizeProcessor, MachineLearningProcessor], providers: [AssetOptimizeService, ImageOptimizeProcessor],
exports: [AssetOptimizeService], exports: [AssetOptimizeService],
}) })
export class ImageOptimizeModule {} export class ImageOptimizeModule {}

View File

@ -4,16 +4,16 @@ import { Job, Queue } from 'bull';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { AssetEntity } from '../../api-v1/asset/entities/asset.entity'; import { AssetEntity } from '../../api-v1/asset/entities/asset.entity';
import sharp from 'sharp'; import sharp from 'sharp';
import fs, { existsSync, mkdirSync } from 'fs'; import { existsSync, mkdirSync, readFile } from 'fs';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import ffmpeg from 'fluent-ffmpeg'; import ffmpeg from 'fluent-ffmpeg';
import { Logger } from '@nestjs/common';
@Processor('optimize') @Processor('optimize')
export class ImageOptimizeProcessor { export class ImageOptimizeProcessor {
constructor( constructor(
@InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>, @InjectRepository(AssetEntity)
@InjectQueue('machine-learning') private machineLearningQueue: Queue, private assetRepository: Repository<AssetEntity>,
private configService: ConfigService, private configService: ConfigService,
) {} ) {}
@ -32,30 +32,42 @@ export class ImageOptimizeProcessor {
mkdirSync(resizeDir, { recursive: true }); mkdirSync(resizeDir, { recursive: true });
} }
fs.readFile(savedAsset.originalPath, (err, data) => { readFile(savedAsset.originalPath, async (err, data) => {
if (err) { if (err) {
console.error('Error Reading File'); console.error('Error Reading File');
} }
sharp(data) if (savedAsset.mimeType == 'image/heic' || savedAsset.mimeType == 'image/heif') {
.resize(512, 512, { fit: 'outside' }) let desitnation = '';
.toFile(resizePath, async (err, info) => { if (savedAsset.mimeType == 'image/heic') {
if (err) { desitnation = resizePath.replace('.HEIC', '.jpeg');
console.error('Error resizing file ', err); } else {
return; desitnation = resizePath.replace('.HEIF', '.jpeg');
} }
await this.assetRepository.update(savedAsset, { resizePath: resizePath }); sharp(data)
.toFormat('jpeg')
.resize(512, 512, { fit: 'outside' })
.toFile(desitnation, async (err, info) => {
if (err) {
console.error('Error resizing file ', err);
return;
}
// Send file to object detection after resizing await this.assetRepository.update(savedAsset, { resizePath: desitnation });
// const detectionJob = await this.machineLearningQueue.add( });
// 'object-detection', } else {
// { sharp(data)
// resizePath, .resize(512, 512, { fit: 'outside' })
// }, .toFile(resizePath, async (err, info) => {
// { jobId: randomUUID() }, if (err) {
// ); console.error('Error resizing file ', err);
}); return;
}
await this.assetRepository.update(savedAsset, { resizePath: resizePath });
});
}
}); });
return 'ok'; return 'ok';

View File

@ -1,38 +0,0 @@
import { Process, Processor } from '@nestjs/bull';
import { InjectRepository } from '@nestjs/typeorm';
import { Job } from 'bull';
import { Repository } from 'typeorm';
import { AssetEntity } from '../../api-v1/asset/entities/asset.entity';
import fs from 'fs';
import { ConfigService } from '@nestjs/config';
import * as tfnode from '@tensorflow/tfjs-node';
import * as cocoSsd from '@tensorflow-models/coco-ssd';
@Processor('machine-learning')
export class MachineLearningProcessor {
constructor(
@InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>,
private configService: ConfigService,
) {}
@Process('object-detection')
async handleOptimization(job: Job) {
try {
const { resizePath }: { resizePath: string } = job.data;
const image = fs.readFileSync(resizePath);
const decodedImage = tfnode.node.decodeImage(image, 3) as tfnode.Tensor3D;
const model = await cocoSsd.load();
const predictions = await model.detect(decodedImage);
console.log('\n\nstart predictions ------------------ ');
for (var result of predictions) {
console.log(`Found ${result.class} with score ${result.score}`);
}
console.log('end predictions ------------------\n\n');
return 'ok';
} catch (e) {
console.log('Error object detection ', e);
}
}
}