thumbnailUrl
This commit is contained in:
@@ -14,3 +14,4 @@ exports.lyrics = require("./src/lyrics");
|
|||||||
exports.cover = require("./src/cover");
|
exports.cover = require("./src/cover");
|
||||||
exports.projects = require("./src/project");
|
exports.projects = require("./src/project");
|
||||||
exports.hls = require("./src/hls");
|
exports.hls = require("./src/hls");
|
||||||
|
exports.thumbnail = require("./src/thumbnail");
|
||||||
|
|||||||
Generated
+138
-46
@@ -6,12 +6,14 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "functions",
|
"name": "functions",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
||||||
"@genkit-ai/googleai": "^1.18.0",
|
"@genkit-ai/googleai": "^1.18.0",
|
||||||
|
"@google-cloud/storage": "^7.17.1",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
"ffmpeg-static": "^5.2.0",
|
"ffmpeg-static": "^5.2.0",
|
||||||
"firebase-admin": "^12.7.0",
|
"firebase-admin": "^12.7.0",
|
||||||
"firebase-functions": "^6.4.0",
|
"firebase-functions": "^6.4.0",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
"fluent-ffmpeg": "^2.1.3",
|
||||||
"genkit": "^1.18.0"
|
"genkit": "^1.18.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -128,6 +130,132 @@
|
|||||||
"integrity": "sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==",
|
"integrity": "sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/darwin-arm64": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-arm64/-/darwin-arm64-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-hYqTiP63mXz7wSQfuqfFwfLOfwwFChUedeCVKkBtl/cliaTM7/ePI9bVzfZ2c+dWu3TqCwLDRWNSJ5pqZl8otA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "https://git.ffmpeg.org/gitweb/ffmpeg.git/blob_plain/HEAD:/LICENSE.md",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/darwin-x64": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-x64/-/darwin-x64-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Z4EyG3cIFjdhlY8wI9aLUXuH8nVt7E9SlMVZtWvSPnm2sm37/yC2CwjUzyCQbJbySnef1tQwGG2Sx+uWhd9IAw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "LGPL-2.1",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/ffmpeg": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/ffmpeg/-/ffmpeg-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-Uq4rmwkdGxIa9A6Bd/VqqYbT7zqh1GrT5/rFwCwKM70b42W5gIjWeVETq6SdcL0zXqDtY081Ws/iJWhr1+xvQg==",
|
||||||
|
"license": "LGPL-2.1",
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@ffmpeg-installer/darwin-arm64": "4.1.5",
|
||||||
|
"@ffmpeg-installer/darwin-x64": "4.1.0",
|
||||||
|
"@ffmpeg-installer/linux-arm": "4.1.3",
|
||||||
|
"@ffmpeg-installer/linux-arm64": "4.1.4",
|
||||||
|
"@ffmpeg-installer/linux-ia32": "4.1.0",
|
||||||
|
"@ffmpeg-installer/linux-x64": "4.1.0",
|
||||||
|
"@ffmpeg-installer/win32-ia32": "4.1.0",
|
||||||
|
"@ffmpeg-installer/win32-x64": "4.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/linux-arm": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm/-/linux-arm-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-NDf5V6l8AfzZ8WzUGZ5mV8O/xMzRag2ETR6+TlGIsMHp81agx51cqpPItXPib/nAZYmo55Bl2L6/WOMI3A5YRg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "GPLv3",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/linux-arm64": {
|
||||||
|
"version": "4.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm64/-/linux-arm64-4.1.4.tgz",
|
||||||
|
"integrity": "sha512-dljEqAOD0oIM6O6DxBW9US/FkvqvQwgJ2lGHOwHDDwu/pX8+V0YsDL1xqHbj1DMX/+nP9rxw7G7gcUvGspSoKg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "GPLv3",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/linux-ia32": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-ia32/-/linux-ia32-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-0LWyFQnPf+Ij9GQGD034hS6A90URNu9HCtQ5cTqo5MxOEc7Rd8gLXrJvn++UmxhU0J5RyRE9KRYstdCVUjkNOQ==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "GPLv3",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/linux-x64": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-x64/-/linux-x64-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Y5BWhGLU/WpQjOArNIgXD3z5mxxdV8c41C+U15nsE5yF8tVcdCGet5zPs5Zy3Ta6bU7haGpIzryutqCGQA/W8A==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "GPLv3",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/win32-ia32": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-ia32/-/win32-ia32-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-FV2D7RlaZv/lrtdhaQ4oETwoFUsUjlUiasiZLDxhEUPdNDWcH1OU9K1xTvqz+OXLdsmYelUDuBS/zkMOTtlUAw==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"license": "GPLv3",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/win32-x64": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-x64/-/win32-x64-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Drt5u2vzDnIONf4ZEkKtFlbvwj6rI3kxw1Ck9fpudmtgaZIHD4ucsWB2lCZBXRxJgXR+2IMSti+4rtM4C4rXgg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "GPLv3",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/@firebase/app-check-interop-types": {
|
"node_modules/@firebase/app-check-interop-types": {
|
||||||
"version": "0.3.2",
|
"version": "0.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2.tgz",
|
||||||
@@ -521,7 +649,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-5.0.2.tgz",
|
||||||
"integrity": "sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg==",
|
"integrity": "sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"arrify": "^2.0.0",
|
"arrify": "^2.0.0",
|
||||||
"extend": "^3.0.2"
|
"extend": "^3.0.2"
|
||||||
@@ -545,7 +672,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz",
|
||||||
"integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==",
|
"integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
@@ -555,17 +681,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz",
|
||||||
"integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==",
|
"integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@google-cloud/storage": {
|
"node_modules/@google-cloud/storage": {
|
||||||
"version": "7.17.0",
|
"version": "7.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.17.1.tgz",
|
||||||
"integrity": "sha512-5m9GoZqKh52a1UqkxDBu/+WVFDALNtHg5up5gNmNbXQWBcV813tzJKsyDtKjOPrlR1em1TxtD7NSPCrObH7koQ==",
|
"integrity": "sha512-2FMQbpU7qK+OtBPaegC6n+XevgZksobUGo6mGKnXNmeZpvLiAo1gTAE3oTKsrMGDV4VtL8Zzpono0YsK/Q7Iqg==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google-cloud/paginator": "^5.0.0",
|
"@google-cloud/paginator": "^5.0.0",
|
||||||
"@google-cloud/projectify": "^4.0.0",
|
"@google-cloud/projectify": "^4.0.0",
|
||||||
@@ -592,7 +716,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
@@ -2240,7 +2363,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
|
||||||
"integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
|
"integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
@@ -2276,8 +2398,7 @@
|
|||||||
"version": "0.12.5",
|
"version": "0.12.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz",
|
||||||
"integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==",
|
"integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/connect": {
|
"node_modules/@types/connect": {
|
||||||
"version": "3.4.38",
|
"version": "3.4.38",
|
||||||
@@ -2440,7 +2561,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.13.tgz",
|
||||||
"integrity": "sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==",
|
"integrity": "sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/caseless": "*",
|
"@types/caseless": "*",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@@ -2453,7 +2573,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz",
|
||||||
"integrity": "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==",
|
"integrity": "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.8",
|
"combined-stream": "^1.0.8",
|
||||||
@@ -2507,8 +2626,7 @@
|
|||||||
"version": "4.0.5",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
|
||||||
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
|
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/triple-beam": {
|
"node_modules/@types/triple-beam": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@@ -2529,7 +2647,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"event-target-shim": "^5.0.0"
|
"event-target-shim": "^5.0.0"
|
||||||
},
|
},
|
||||||
@@ -2696,7 +2813,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
|
||||||
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
|
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@@ -2722,7 +2838,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz",
|
||||||
"integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==",
|
"integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"retry": "0.13.1"
|
"retry": "0.13.1"
|
||||||
}
|
}
|
||||||
@@ -3239,7 +3354,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz",
|
||||||
"integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==",
|
"integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"end-of-stream": "^1.4.1",
|
"end-of-stream": "^1.4.1",
|
||||||
"inherits": "^2.0.3",
|
"inherits": "^2.0.3",
|
||||||
@@ -3289,7 +3403,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
||||||
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
|
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"once": "^1.4.0"
|
"once": "^1.4.0"
|
||||||
}
|
}
|
||||||
@@ -3563,7 +3676,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
@@ -3714,7 +3826,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"strnum": "^1.1.1"
|
"strnum": "^1.1.1"
|
||||||
},
|
},
|
||||||
@@ -4520,8 +4631,7 @@
|
|||||||
"url": "https://patreon.com/mdevils"
|
"url": "https://patreon.com/mdevils"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/http-errors": {
|
"node_modules/http-errors": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -4550,7 +4660,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
|
||||||
"integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
|
"integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tootallnate/once": "2",
|
"@tootallnate/once": "2",
|
||||||
"agent-base": "6",
|
"agent-base": "6",
|
||||||
@@ -4565,7 +4674,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "4"
|
"debug": "4"
|
||||||
},
|
},
|
||||||
@@ -5163,7 +5271,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
|
||||||
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
|
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"mime": "cli.js"
|
"mime": "cli.js"
|
||||||
},
|
},
|
||||||
@@ -5348,7 +5455,6 @@
|
|||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||||
"devOptional": true,
|
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
@@ -5395,7 +5501,6 @@
|
|||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||||
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
||||||
"devOptional": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"yocto-queue": "^0.1.0"
|
"yocto-queue": "^0.1.0"
|
||||||
@@ -5832,7 +5937,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
|
||||||
"integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
|
"integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
@@ -5842,7 +5946,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz",
|
||||||
"integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==",
|
"integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/request": "^2.48.8",
|
"@types/request": "^2.48.8",
|
||||||
"extend": "^3.0.2",
|
"extend": "^3.0.2",
|
||||||
@@ -6177,7 +6280,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz",
|
||||||
"integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==",
|
"integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"stubs": "^3.0.0"
|
"stubs": "^3.0.0"
|
||||||
}
|
}
|
||||||
@@ -6186,8 +6288,7 @@
|
|||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz",
|
||||||
"integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==",
|
"integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/string_decoder": {
|
"node_modules/string_decoder": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
@@ -6252,15 +6353,13 @@
|
|||||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/stubs": {
|
"node_modules/stubs": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz",
|
||||||
"integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==",
|
"integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/supports-color": {
|
"node_modules/supports-color": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
@@ -6292,7 +6391,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz",
|
||||||
"integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==",
|
"integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"http-proxy-agent": "^5.0.0",
|
"http-proxy-agent": "^5.0.0",
|
||||||
"https-proxy-agent": "^5.0.0",
|
"https-proxy-agent": "^5.0.0",
|
||||||
@@ -6309,7 +6407,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "4"
|
"debug": "4"
|
||||||
},
|
},
|
||||||
@@ -6322,7 +6419,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"agent-base": "6",
|
"agent-base": "6",
|
||||||
"debug": "4"
|
"debug": "4"
|
||||||
@@ -6336,7 +6432,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"whatwg-url": "^5.0.0"
|
"whatwg-url": "^5.0.0"
|
||||||
},
|
},
|
||||||
@@ -6361,7 +6456,6 @@
|
|||||||
"https://github.com/sponsors/ctavan"
|
"https://github.com/sponsors/ctavan"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
@@ -6708,7 +6802,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||||
"devOptional": true,
|
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/xorshift": {
|
"node_modules/xorshift": {
|
||||||
@@ -6784,7 +6877,6 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||||
"devOptional": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
|
|||||||
@@ -14,13 +14,15 @@
|
|||||||
},
|
},
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
||||||
"@genkit-ai/googleai": "^1.18.0",
|
"@genkit-ai/googleai": "^1.18.0",
|
||||||
|
"@google-cloud/storage": "^7.17.1",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
|
"ffmpeg-static": "^5.2.0",
|
||||||
"firebase-admin": "^12.7.0",
|
"firebase-admin": "^12.7.0",
|
||||||
"firebase-functions": "^6.4.0",
|
"firebase-functions": "^6.4.0",
|
||||||
"genkit": "^1.18.0",
|
"fluent-ffmpeg": "^2.1.3",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
"genkit": "^1.18.0"
|
||||||
"ffmpeg-static": "^5.2.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8.15.0",
|
"eslint": "^8.15.0",
|
||||||
|
|||||||
+43
-43
@@ -1,20 +1,20 @@
|
|||||||
const { onObjectFinalized } = require('firebase-functions/v2/storage');
|
const { onObjectFinalized } = require("firebase-functions/v2/storage");
|
||||||
const functions = require('firebase-functions');
|
const functions = require("firebase-functions");
|
||||||
const admin = require('firebase-admin');
|
const admin = require("firebase-admin");
|
||||||
const path = require('path');
|
const path = require("path");
|
||||||
const os = require('os');
|
const os = require("os");
|
||||||
const fs = require('fs');
|
const fs = require("fs");
|
||||||
|
|
||||||
// These deps must be installed in functions/: ffmpeg-static, fluent-ffmpeg
|
// These deps must be installed in functions/: ffmpeg-static, fluent-ffmpeg
|
||||||
let ffmpeg;
|
let ffmpeg;
|
||||||
let ffmpegPath;
|
let ffmpegPath;
|
||||||
try {
|
try {
|
||||||
ffmpeg = require('fluent-ffmpeg');
|
ffmpeg = require("fluent-ffmpeg");
|
||||||
ffmpegPath = require('ffmpeg-static');
|
ffmpegPath = require("ffmpeg-static");
|
||||||
ffmpeg.setFfmpegPath(ffmpegPath);
|
ffmpeg.setFfmpegPath(ffmpegPath);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(
|
console.log(
|
||||||
'ffmpeg modules not installed yet — deploy after npm i',
|
"ffmpeg modules not installed yet — deploy after npm i",
|
||||||
e?.message
|
e?.message
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -23,56 +23,56 @@ const bucket = admin.storage().bucket();
|
|||||||
|
|
||||||
exports.transcodePlaybackToHLS = onObjectFinalized(
|
exports.transcodePlaybackToHLS = onObjectFinalized(
|
||||||
{
|
{
|
||||||
region: 'europe-west1',
|
region: "europe-west1",
|
||||||
memory: '2GiB',
|
memory: "2GiB",
|
||||||
timeoutSeconds: 540,
|
timeoutSeconds: 540,
|
||||||
cpu: 2,
|
cpu: 2,
|
||||||
},
|
},
|
||||||
async (event) => {
|
async (event) => {
|
||||||
const object = event.data;
|
const object = event.data;
|
||||||
const filePath = object?.name || ''; // e.g., musics/{projectId}/source.mp4
|
const filePath = object?.name || ""; // e.g., musics/{projectId}/source.mp4
|
||||||
const contentType = object?.contentType || '';
|
const contentType = object?.contentType || "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Only process our target path + video files
|
// Only process our target path + video files
|
||||||
const match = filePath.match(/^musics\/(.+?)\/source\.mp4$/i);
|
const match = filePath.match(/^musics\/(.+?)\/source\.mp4$/i);
|
||||||
if (!match || !contentType.startsWith('video/')) {
|
if (!match || !contentType.startsWith("video/")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const projectId = match[1];
|
const projectId = match[1];
|
||||||
const tempDir = fs.mkdtempSync(
|
const tempDir = fs.mkdtempSync(
|
||||||
path.join(os.tmpdir(), `hls_${projectId}_`)
|
path.join(os.tmpdir(), `hls_${projectId}_`)
|
||||||
);
|
);
|
||||||
const localSource = path.join(tempDir, 'source.mp4');
|
const localSource = path.join(tempDir, "source.mp4");
|
||||||
const hlsDir = path.join(tempDir, 'hls');
|
const hlsDir = path.join(tempDir, "hls");
|
||||||
fs.mkdirSync(hlsDir);
|
fs.mkdirSync(hlsDir);
|
||||||
|
|
||||||
// Download source
|
// Download source
|
||||||
await bucket.file(filePath).download({ destination: localSource });
|
await bucket.file(filePath).download({ destination: localSource });
|
||||||
|
|
||||||
if (!ffmpeg) {
|
if (!ffmpeg) {
|
||||||
console.warn('ffmpeg not available; skip transcode');
|
console.warn("ffmpeg not available; skip transcode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transcode to HLS (single rendition for simplicity)
|
// Transcode to HLS (single rendition for simplicity)
|
||||||
const masterPath = path.join(hlsDir, 'master.m3u8');
|
const masterPath = path.join(hlsDir, "master.m3u8");
|
||||||
const segmentPattern = path.join(hlsDir, 'segment_%03d.ts');
|
const segmentPattern = path.join(hlsDir, "segment_%03d.ts");
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
ffmpeg(localSource)
|
ffmpeg(localSource)
|
||||||
.outputOptions([
|
.outputOptions([
|
||||||
'-profile:v baseline',
|
"-profile:v baseline",
|
||||||
'-level 3.0',
|
"-level 3.0",
|
||||||
'-start_number 0',
|
"-start_number 0",
|
||||||
'-hls_time 4',
|
"-hls_time 4",
|
||||||
'-hls_list_size 0',
|
"-hls_list_size 0",
|
||||||
'-f hls',
|
"-f hls",
|
||||||
`-hls_segment_filename ${segmentPattern}`,
|
`-hls_segment_filename ${segmentPattern}`,
|
||||||
])
|
])
|
||||||
.output(masterPath)
|
.output(masterPath)
|
||||||
.on('end', resolve)
|
.on("end", resolve)
|
||||||
.on('error', reject)
|
.on("error", reject)
|
||||||
.run();
|
.run();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,28 +82,28 @@ exports.transcodePlaybackToHLS = onObjectFinalized(
|
|||||||
|
|
||||||
// Upload all segments first
|
// Upload all segments first
|
||||||
const uploads = fileNames
|
const uploads = fileNames
|
||||||
.filter((n) => n.endsWith('.ts'))
|
.filter((n) => n.endsWith(".ts"))
|
||||||
.map((name) => {
|
.map((name) => {
|
||||||
const local = path.join(hlsDir, name);
|
const local = path.join(hlsDir, name);
|
||||||
const dest = `${destPrefix}${name}`;
|
const dest = `${destPrefix}${name}`;
|
||||||
return bucket.upload(local, {
|
return bucket.upload(local, {
|
||||||
destination: dest,
|
destination: dest,
|
||||||
metadata: {
|
metadata: {
|
||||||
contentType: 'video/MP2T',
|
contentType: "video/MP2T",
|
||||||
cacheControl: 'public, max-age=3600',
|
cacheControl: "public, max-age=3600",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
await Promise.all(uploads);
|
await Promise.all(uploads);
|
||||||
|
|
||||||
// Generate signed URLs for segments and rewrite playlist with absolute URLs
|
// Generate signed URLs for segments and rewrite playlist with absolute URLs
|
||||||
const segmentNames = fileNames.filter((n) => n.endsWith('.ts'));
|
const segmentNames = fileNames.filter((n) => n.endsWith(".ts"));
|
||||||
const signedSegments = {};
|
const signedSegments = {};
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
segmentNames.map(async (name) => {
|
segmentNames.map(async (name) => {
|
||||||
const file = bucket.file(`${destPrefix}${name}`);
|
const file = bucket.file(`${destPrefix}${name}`);
|
||||||
const [url] = await file.getSignedUrl({
|
const [url] = await file.getSignedUrl({
|
||||||
action: 'read',
|
action: "read",
|
||||||
expires: Date.now() + 1000 * 60 * 60 * 24 * 365,
|
expires: Date.now() + 1000 * 60 * 60 * 24 * 365,
|
||||||
});
|
});
|
||||||
signedSegments[name] = url;
|
signedSegments[name] = url;
|
||||||
@@ -111,24 +111,24 @@ exports.transcodePlaybackToHLS = onObjectFinalized(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Rewrite master playlist to use absolute signed segment URLs
|
// Rewrite master playlist to use absolute signed segment URLs
|
||||||
let masterContent = fs.readFileSync(masterPath, 'utf8');
|
let masterContent = fs.readFileSync(masterPath, "utf8");
|
||||||
masterContent = masterContent
|
masterContent = masterContent
|
||||||
.split(/\r?\n/)
|
.split(/\r?\n/)
|
||||||
.map((line) =>
|
.map((line) =>
|
||||||
line.endsWith('.ts') && signedSegments[line]
|
line.endsWith(".ts") && signedSegments[line]
|
||||||
? signedSegments[line]
|
? signedSegments[line]
|
||||||
: line
|
: line
|
||||||
)
|
)
|
||||||
.join('\n');
|
.join("\n");
|
||||||
const rewrittenMasterLocal = path.join(hlsDir, 'master.abs.m3u8');
|
const rewrittenMasterLocal = path.join(hlsDir, "master.abs.m3u8");
|
||||||
fs.writeFileSync(rewrittenMasterLocal, masterContent, 'utf8');
|
fs.writeFileSync(rewrittenMasterLocal, masterContent, "utf8");
|
||||||
|
|
||||||
// Upload rewritten playlist
|
// Upload rewritten playlist
|
||||||
await bucket.upload(rewrittenMasterLocal, {
|
await bucket.upload(rewrittenMasterLocal, {
|
||||||
destination: `${destPrefix}master.m3u8`,
|
destination: `${destPrefix}master.m3u8`,
|
||||||
metadata: {
|
metadata: {
|
||||||
contentType: 'application/vnd.apple.mpegurl',
|
contentType: "application/vnd.apple.mpegurl",
|
||||||
cacheControl: 'public, max-age=3600',
|
cacheControl: "public, max-age=3600",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -136,15 +136,15 @@ exports.transcodePlaybackToHLS = onObjectFinalized(
|
|||||||
const [signedUrl] = await bucket
|
const [signedUrl] = await bucket
|
||||||
.file(`${destPrefix}master.m3u8`)
|
.file(`${destPrefix}master.m3u8`)
|
||||||
.getSignedUrl({
|
.getSignedUrl({
|
||||||
action: 'read',
|
action: "read",
|
||||||
expires: Date.now() + 1000 * 60 * 60 * 24 * 365,
|
expires: Date.now() + 1000 * 60 * 60 * 24 * 365,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update Firestore project doc with playbackUrl
|
// Update Firestore project doc with playbackUrl
|
||||||
await admin.firestore().collection('projects').doc(projectId).set(
|
await admin.firestore().collection("projects").doc(projectId).set(
|
||||||
{
|
{
|
||||||
playbackUrl: signedUrl,
|
playbackUrl: signedUrl,
|
||||||
playbackStatus: 'ready',
|
playbackStatus: "ready",
|
||||||
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
||||||
},
|
},
|
||||||
{ merge: true }
|
{ merge: true }
|
||||||
@@ -155,7 +155,7 @@ exports.transcodePlaybackToHLS = onObjectFinalized(
|
|||||||
fs.rmSync(tempDir, { recursive: true, force: true });
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('HLS transcode error', e);
|
console.error("HLS transcode error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
const { onObjectFinalized } = require("firebase-functions/v2/storage");
|
||||||
|
const logger = require("firebase-functions/logger");
|
||||||
|
const admin = require("firebase-admin");
|
||||||
|
const ffmpeg = require("fluent-ffmpeg");
|
||||||
|
const ffmpegInstaller = require("@ffmpeg-installer/ffmpeg");
|
||||||
|
const fs = require("node:fs/promises");
|
||||||
|
const os = require("node:os");
|
||||||
|
const path = require("node:path");
|
||||||
|
const crypto = require("node:crypto");
|
||||||
|
|
||||||
|
ffmpeg.setFfmpegPath(ffmpegInstaller.path);
|
||||||
|
|
||||||
|
exports.generateVideoThumbnail = onObjectFinalized(
|
||||||
|
{
|
||||||
|
region: "europe-west1",
|
||||||
|
timeoutSeconds: 180,
|
||||||
|
memory: "1GiB",
|
||||||
|
cpu: 1,
|
||||||
|
},
|
||||||
|
async (event) => {
|
||||||
|
const file = event.data || {};
|
||||||
|
const bucketName = file.bucket;
|
||||||
|
const objectName = file.name || "";
|
||||||
|
const contentType = file.contentType || "";
|
||||||
|
|
||||||
|
if (!bucketName) return;
|
||||||
|
if (!contentType.startsWith("video/")) return;
|
||||||
|
if (!objectName) return;
|
||||||
|
if (/_thumb9x16\.jpg$/i.test(objectName)) return;
|
||||||
|
|
||||||
|
const bucket = admin.storage().bucket(bucketName);
|
||||||
|
const playbackMatch = objectName.match(/^musics\/([^/]+)\/playback\.mp4$/i);
|
||||||
|
const projectId = playbackMatch ? playbackMatch[1] : null;
|
||||||
|
|
||||||
|
// Use unique folder under /tmp to avoid name collisions
|
||||||
|
const tmpDir = path.join(
|
||||||
|
os.tmpdir(),
|
||||||
|
`thumb-${Date.now()}-${Math.round(Math.random() * 1000)}`
|
||||||
|
);
|
||||||
|
const baseName = path.basename(objectName);
|
||||||
|
const dirName = path.posix.dirname(objectName);
|
||||||
|
const localVideoPath = path.join(tmpDir, baseName);
|
||||||
|
|
||||||
|
const thumbBase = baseName.replace(/\.[^.]+$/, "") + "_thumb9x16.jpg";
|
||||||
|
const localThumbPath = path.join(tmpDir, thumbBase);
|
||||||
|
const remoteThumbPath =
|
||||||
|
dirName && dirName !== "."
|
||||||
|
? path.posix.join(dirName, thumbBase)
|
||||||
|
: thumbBase;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await fs.mkdir(tmpDir, { recursive: true });
|
||||||
|
|
||||||
|
// Télécharger la vidéo depuis le bucket
|
||||||
|
await bucket.file(objectName).download({ destination: localVideoPath });
|
||||||
|
|
||||||
|
// Extraire 1 frame à 1 seconde, forcer 9:16 (1080x1920) par scale+crop centré
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
ffmpeg(localVideoPath)
|
||||||
|
.inputOptions(["-ss 1"])
|
||||||
|
.frames(1)
|
||||||
|
.outputOptions([
|
||||||
|
"-vf",
|
||||||
|
"scale='if(gt(a,9/16),1080,-2)':'if(gt(a,9/16),-2,1920)',crop=1080:1920",
|
||||||
|
"-q:v",
|
||||||
|
"2",
|
||||||
|
])
|
||||||
|
.output(localThumbPath)
|
||||||
|
.on("end", resolve)
|
||||||
|
.on("error", reject)
|
||||||
|
.run();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Upload du thumbnail avec un token de téléchargement public Firebase
|
||||||
|
const downloadToken = crypto.randomUUID();
|
||||||
|
await bucket.upload(localThumbPath, {
|
||||||
|
destination: remoteThumbPath,
|
||||||
|
metadata: {
|
||||||
|
contentType: "image/jpeg",
|
||||||
|
cacheControl: "public, max-age=86400",
|
||||||
|
metadata: {
|
||||||
|
original: objectName,
|
||||||
|
aspect: "9:16",
|
||||||
|
t: "1s",
|
||||||
|
firebaseStorageDownloadTokens: downloadToken,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const encodedPath = encodeURIComponent(remoteThumbPath);
|
||||||
|
const thumbnailUrl = `https://firebasestorage.googleapis.com/v0/b/${bucketName}/o/${encodedPath}?alt=media&token=${downloadToken}`;
|
||||||
|
|
||||||
|
if (projectId) {
|
||||||
|
await admin.firestore().collection("projects").doc(projectId).set(
|
||||||
|
{
|
||||||
|
thumbnailUrl,
|
||||||
|
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
||||||
|
},
|
||||||
|
{ merge: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("✅ [Thumbnail] Uploaded", {
|
||||||
|
objectName,
|
||||||
|
remoteThumbPath,
|
||||||
|
projectId,
|
||||||
|
thumbnailUrl,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error("❌ [Thumbnail] Failed", {
|
||||||
|
objectName,
|
||||||
|
error: error?.message || String(error),
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user