Merge pull request #15189 from annando/ffmpeg

Fetch additional video information (dimensions, preview, blurhash) when FFmpeg is installed
This commit is contained in:
Philipp 2025-10-09 21:35:32 +02:00 committed by GitHub
commit ba74c0803f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 1094 additions and 322 deletions

View file

@ -68,6 +68,7 @@
"paragonie/hidden-string": "^1.0",
"patrickschur/language-detection": "^5.0.0",
"pear/console_table": "^1.3",
"php-ffmpeg/php-ffmpeg": "^0.19.0",
"phpseclib/phpseclib": "^3.0.47",
"phrity/websocket": "^1.7",
"pragmarx/google2fa": "^5.0",

1273
composer.lock generated
View file

@ -4,8 +4,74 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f4fabf0821f6dea14a637187e585ba6c",
"content-hash": "b1e969f4be6ba6ed11d303a326333125",
"packages": [
{
"name": "alchemy/binary-driver",
"version": "v5.2.0",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/BinaryDriver.git",
"reference": "e0615cdff315e6b4b05ada67906df6262a020d22"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/BinaryDriver/zipball/e0615cdff315e6b4b05ada67906df6262a020d22",
"reference": "e0615cdff315e6b4b05ada67906df6262a020d22",
"shasum": ""
},
"require": {
"evenement/evenement": "^3.0|^2.0|^1.0",
"php": ">=5.5",
"psr/log": "^1.0",
"symfony/process": "^2.3|^3.0|^4.0|^5.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0|^5.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Alchemy": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Le Goff",
"email": "legoff.n@gmail.com"
},
{
"name": "Romain Neutron",
"email": "imprec@gmail.com",
"homepage": "http://www.lickmychip.com/"
},
{
"name": "Phraseanet Team",
"email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/"
},
{
"name": "Jens Hausdorf",
"email": "mail@jens-hausdorf.de",
"homepage": "https://jens-hausdorf.de",
"role": "Maintainer"
}
],
"description": "A set of tools to build binary drivers",
"keywords": [
"binary",
"driver"
],
"support": {
"issues": "https://github.com/alchemy-fr/BinaryDriver/issues",
"source": "https://github.com/alchemy-fr/BinaryDriver/tree/master"
},
"time": "2020-02-12T19:35:11+00:00"
},
{
"name": "asika/simple-console",
"version": "1.0.4",
@ -707,6 +773,53 @@
},
"time": "2021-09-21T17:03:36+00:00"
},
{
"name": "evenement/evenement",
"version": "v3.0.2",
"source": {
"type": "git",
"url": "https://github.com/igorw/evenement.git",
"reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc",
"reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc",
"shasum": ""
},
"require": {
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "^9 || ^6"
},
"type": "library",
"autoload": {
"psr-4": {
"Evenement\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch"
}
],
"description": "Événement is a very simple event dispatching library for PHP",
"keywords": [
"event-dispatcher",
"event-emitter"
],
"support": {
"issues": "https://github.com/igorw/evenement/issues",
"source": "https://github.com/igorw/evenement/tree/v3.0.2"
},
"time": "2023-08-08T05:53:35+00:00"
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.18.0",
@ -1992,6 +2105,50 @@
],
"time": "2025-01-04T06:07:59+00:00"
},
{
"name": "neutron/temporary-filesystem",
"version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/romainneutron/Temporary-Filesystem.git",
"reference": "55f3d4896eff3bf070e491916e6c564db5e640b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/romainneutron/Temporary-Filesystem/zipball/55f3d4896eff3bf070e491916e6c564db5e640b5",
"reference": "55f3d4896eff3bf070e491916e6c564db5e640b5",
"shasum": ""
},
"require": {
"php": ">=5.6",
"symfony/filesystem": "^2.3 || ^3.0 || ^4.0 || ^5.0 || ^6.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^5.0.4 || ^6.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Neutron": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com"
}
],
"description": "Symfony filesystem extension to handle temporary files",
"support": {
"issues": "https://github.com/romainneutron/Temporary-Filesystem/issues",
"source": "https://github.com/romainneutron/Temporary-Filesystem/tree/3.0.1"
},
"time": "2021-12-14T07:30:33+00:00"
},
{
"name": "nikic/fast-route",
"version": "v1.3.0",
@ -2904,6 +3061,93 @@
},
"time": "2018-01-25T20:47:17+00:00"
},
{
"name": "php-ffmpeg/php-ffmpeg",
"version": "v0.19.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-FFMpeg/PHP-FFMpeg.git",
"reference": "22b71931fd1a97207788636b283eee1c0067eff7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-FFMpeg/PHP-FFMpeg/zipball/22b71931fd1a97207788636b283eee1c0067eff7",
"reference": "22b71931fd1a97207788636b283eee1c0067eff7",
"shasum": ""
},
"require": {
"alchemy/binary-driver": "^1.5 || ~2.0.0 || ^5.0",
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
"neutron/temporary-filesystem": "^2.1.1 || ^3.0",
"php": ">=5.5.9",
"symfony/cache": "^3.1 || ^4.0 || ^5.0 || ^6.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^5.0.4",
"symfony/process": "2.8 || 3.3"
},
"suggest": {
"php-ffmpeg/extras": "A compilation of common audio & video drivers for PHP-FFMpeg"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.x-dev"
}
},
"autoload": {
"psr-0": {
"FFMpeg": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com",
"homepage": "http://www.lickmychip.com/"
},
{
"name": "Phraseanet Team",
"email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/"
},
{
"name": "Patrik Karisch",
"email": "patrik@karisch.guru",
"homepage": "http://www.karisch.guru"
},
{
"name": "Romain Biard",
"email": "romain.biard@gmail.com",
"homepage": "https://www.strime.io/"
},
{
"name": "Jens Hausdorf",
"email": "hello@jens-hausdorf.de",
"homepage": "https://jens-hausdorf.de"
}
],
"description": "FFMpeg PHP, an Object Oriented library to communicate with AVconv / ffmpeg",
"keywords": [
"audio",
"audio processing",
"avconv",
"avprobe",
"ffmpeg",
"ffprobe",
"video",
"video processing"
],
"support": {
"issues": "https://github.com/PHP-FFMpeg/PHP-FFMpeg/issues",
"source": "https://github.com/PHP-FFMpeg/PHP-FFMpeg/tree/v0.19.0"
},
"time": "2021-12-20T11:51:26+00:00"
},
{
"name": "php-http/discovery",
"version": "1.20.0",
@ -4156,6 +4400,182 @@
],
"time": "2020-11-03T09:10:25+00:00"
},
{
"name": "symfony/cache",
"version": "v5.4.46",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/0fe08ee32cec2748fbfea10c52d3ee02049e0f6b",
"reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"psr/cache": "^1.0|^2.0",
"psr/log": "^1.1|^2|^3",
"symfony/cache-contracts": "^1.1.7|^2",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-php73": "^1.9",
"symfony/polyfill-php80": "^1.16",
"symfony/service-contracts": "^1.1|^2|^3",
"symfony/var-exporter": "^4.4|^5.0|^6.0"
},
"conflict": {
"doctrine/dbal": "<2.13.1",
"symfony/dependency-injection": "<4.4",
"symfony/http-kernel": "<4.4",
"symfony/var-dumper": "<4.4"
},
"provide": {
"psr/cache-implementation": "1.0|2.0",
"psr/simple-cache-implementation": "1.0|2.0",
"symfony/cache-implementation": "1.0|2.0"
},
"require-dev": {
"cache/integration-tests": "dev-master",
"doctrine/cache": "^1.6|^2.0",
"doctrine/dbal": "^2.13.1|^3|^4",
"predis/predis": "^1.1|^2.0",
"psr/simple-cache": "^1.0|^2.0",
"symfony/config": "^4.4|^5.0|^6.0",
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/filesystem": "^4.4|^5.0|^6.0",
"symfony/http-kernel": "^4.4|^5.0|^6.0",
"symfony/messenger": "^4.4|^5.0|^6.0",
"symfony/var-dumper": "^4.4|^5.0|^6.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Cache\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides extended PSR-6, PSR-16 (and tags) implementations",
"homepage": "https://symfony.com",
"keywords": [
"caching",
"psr6"
],
"support": {
"source": "https://github.com/symfony/cache/tree/v5.4.46"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-11-04T11:43:55+00:00"
},
{
"name": "symfony/cache-contracts",
"version": "v2.5.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache-contracts.git",
"reference": "517c3a3619dadfa6952c4651767fcadffb4df65e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache-contracts/zipball/517c3a3619dadfa6952c4651767fcadffb4df65e",
"reference": "517c3a3619dadfa6952c4651767fcadffb4df65e",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"psr/cache": "^1.0|^2.0|^3.0"
},
"suggest": {
"symfony/cache-implementation": ""
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "2.5-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Cache\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to caching",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/cache-contracts/tree/v2.5.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-25T14:11:13+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.5.4",
@ -4387,6 +4807,241 @@
],
"time": "2024-09-25T14:11:13+00:00"
},
{
"name": "symfony/filesystem",
"version": "v5.4.45",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "57c8294ed37d4a055b77057827c67f9558c95c54"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/57c8294ed37d4a055b77057827c67f9558c95c54",
"reference": "57c8294ed37d4a055b77057827c67f9558c95c54",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"symfony/process": "^5.4|^6.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v5.4.45"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-10-22T13:05:35+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": ">=7.2"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-12-23T08:48:59+00:00"
},
{
"name": "symfony/polyfill-php56",
"version": "v1.20.0",
@ -4455,6 +5110,86 @@
],
"time": "2020-10-23T14:02:19+00:00"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
"reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php73\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php73/tree/v1.33.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.33.0",
@ -4539,6 +5274,224 @@
],
"time": "2025-01-02T08:10:11+00:00"
},
{
"name": "symfony/process",
"version": "v5.4.47",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "5d1662fb32ebc94f17ddb8d635454a776066733d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/5d1662fb32ebc94f17ddb8d635454a776066733d",
"reference": "5d1662fb32ebc94f17ddb8d635454a776066733d",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-php80": "^1.16"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v5.4.47"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-11-06T11:36:42+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v2.5.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "f37b419f7aea2e9abf10abd261832cace12e3300"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300",
"reference": "f37b419f7aea2e9abf10abd261832cace12e3300",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"psr/container": "^1.1",
"symfony/deprecation-contracts": "^2.1|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
},
"suggest": {
"symfony/service-implementation": ""
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "2.5-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to writing services",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v2.5.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-25T14:11:13+00:00"
},
{
"name": "symfony/var-exporter",
"version": "v5.4.45",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-exporter.git",
"reference": "862700068db0ddfd8c5b850671e029a90246ec75"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/862700068db0ddfd8c5b850671e029a90246ec75",
"reference": "862700068db0ddfd8c5b850671e029a90246ec75",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"symfony/var-dumper": "^4.4.9|^5.0.9|^6.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\VarExporter\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Allows exporting any serializable PHP data structure to plain PHP code",
"homepage": "https://symfony.com",
"keywords": [
"clone",
"construct",
"export",
"hydrate",
"instantiate",
"serialize"
],
"support": {
"source": "https://github.com/symfony/var-exporter/tree/v5.4.45"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-25T14:11:13+00:00"
},
{
"name": "ua-parser/uap-php",
"version": "v3.10.0",
@ -7849,241 +8802,6 @@
],
"time": "2024-11-20T10:51:57+00:00"
},
{
"name": "symfony/filesystem",
"version": "v5.4.45",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "57c8294ed37d4a055b77057827c67f9558c95c54"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/57c8294ed37d4a055b77057827c67f9558c95c54",
"reference": "57c8294ed37d4a055b77057827c67f9558c95c54",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"symfony/process": "^5.4|^6.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v5.4.45"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-10-22T13:05:35+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": ">=7.2"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-12-23T08:48:59+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.33.0",
@ -8164,89 +8882,6 @@
],
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v2.5.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "f37b419f7aea2e9abf10abd261832cace12e3300"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300",
"reference": "f37b419f7aea2e9abf10abd261832cace12e3300",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"psr/container": "^1.1",
"symfony/deprecation-contracts": "^2.1|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
},
"suggest": {
"symfony/service-implementation": ""
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "2.5-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to writing services",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v2.5.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-25T14:11:13+00:00"
},
{
"name": "theseer/tokenizer",
"version": "1.2.3",

View file

@ -388,7 +388,7 @@ class PostMedia extends BaseRepository
public function getVideoAttachment(PostMediaEntity $postMedia, int $uid): string
{
if ($postMedia->preview || $postMedia->blurhash) {
if ($postMedia->preview || ($postMedia->blurhash && $this->config->get('system', 'ffmpeg_installed'))) {
$preview_url = $this->baseURL . $postMedia->getPreviewPath(Proxy::SIZE_MEDIUM);
} else {
$preview_url = '';

View file

@ -23,6 +23,7 @@ use Friendica\Model\Post;
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
use Friendica\Object\Image;
use Friendica\Protocol\ActivityPub;
use Friendica\Protocol\ATProtocol;
use Friendica\Util\DateTimeFormat;
@ -254,7 +255,8 @@ class Media
}
if ($media['type'] === self::VIDEO) {
$media = self::getVideoDimensions($media, false);
$media = self::getVideoInformationByFFMPEG($media);
$media = self::getVideoDimensionsByID3($media, false);
}
if (in_array($media['type'], [self::TEXT, self::ACTIVITY, self::LD, self::JSON, self::HTML, self::XML, self::PLAIN])) {
@ -628,6 +630,37 @@ class Media
return $type;
}
/**
* Fetch video information (dimensions and blurhash) using ffmpeg
*
* @param array $media Media array
* @return array media with added dimensions and blurhash
*/
private static function getVideoInformationByFFMPEG(array $media): array
{
if (!DI::config()->get('system', 'ffmpeg_installed')) {
return $media;
}
if (isset($media['width']) && isset($media['height']) && $media['width'] > 0 && $media['height'] > 0 && isset($media['blurhash'])) {
return $media;
}
DI::logger()->debug('Fetch video information', ['uri-id' => $media['uri-id'], 'url' => $media['url']]);
$image = new Image('');
$image->getFromVideoUrl($media['url']);
if ($image->isValid()) {
$media['blurhash'] = $image->getBlurHash();
$media['width'] = $image->getWidth();
$media['height'] = $image->getHeight();
DI::logger()->debug('Detected video dimensions via FFMpeg preview', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'width' => $media['width'], 'height' => $media['height']]);
return $media;
}
return $media;
}
/**
* Fetch video dimensions using getID3
*
@ -635,7 +668,7 @@ class Media
* @param bool $full_file If true, the whole video will be fetched
* @return array media with added dimensions
*/
private static function getVideoDimensions(array $media, bool $full_file): array
private static function getVideoDimensionsByID3(array $media, bool $full_file): array
{
if (isset($media['width']) && isset($media['height']) && $media['width'] > 0 && $media['height'] > 0) {
return $media;

View file

@ -272,6 +272,14 @@ class Photo extends BaseApi
$height = $media['height'];
}
if (empty($url) && ($media['type'] == Post\Media::VIDEO) && DI::config()->get('system', 'ffmpeg_installed')) {
$image = new Image('', image_type_to_mime_type(IMAGETYPE_JPEG));
$image->getFromVideoUrl($media['url']);
if ($image->isValid()) {
return MPhoto::createPhotoForImageData($image->asString());
}
}
if (empty($url) && isset($media['blurhash']) && isset($media['width']) && isset($media['height'])) {
$image = new Image('', image_type_to_mime_type(IMAGETYPE_WEBP));
$image->getFromBlurHash($media['blurhash'], $media['width'], $media['height']);

View file

@ -8,6 +8,10 @@
namespace Friendica\Object;
use Exception;
use FFMpeg\Coordinate\TimeCode;
use FFMpeg\FFMpeg;
use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\System;
use Friendica\DI;
use Friendica\Util\Images;
use Imagick;
@ -859,4 +863,90 @@ class Image
$this->scaleUp(min($width, $height));
}
/**
* Create a preview image for the provided video URL using ffmpeg.
* The result is cached for one day.
*
* @param string $url Video URL
* @return string binary image data or empty string
*/
private function getPreviewImageForVideoUrlCached(string $url): string
{
$cacheKey = 'getPreviewImageForVideoUrl:' . sha1($url);
$preview = DI::cache()->get($cacheKey);
if (!$preview) {
$preview = $this->getPreviewImageForVideoUrl($url);
if (!$preview) {
return '';
}
DI::cache()->set($cacheKey, base64_encode($preview), Duration::DAY);
} else {
$preview = base64_decode($preview);
}
return $preview;
}
/**
* Create a preview image for the provided video URL using ffmpeg
*
* @param string $url Video URL
* @return string binary image data or empty string
*/
private function getPreviewImageForVideoUrl($url): string
{
$preview = '';
$timestamp = microtime(true);
try {
$ffmpeg = FFMpeg::create();
/** @var \FFMpeg\Media\Video $video */
$video = $ffmpeg->open($url);
$frame = $video->frame(TimeCode::fromSeconds(0));
$tempfile = tempnam(System::getTempPath(), 'videopreview-');
$frame->save($tempfile);
$preview = file_get_contents($tempfile);
unlink($tempfile);
$runtime = number_format(microtime(true) - $timestamp, 3);
DI::logger()->debug('Created video preview', ['runtime' => $runtime, 'url' => $url]);
} catch (\Throwable $th) {
$runtime = number_format(microtime(true) - $timestamp, 3);
DI::logger()->notice('Got exception', ['runtime' => $runtime, 'url' => $url, 'code' => $th->getCode(), 'message' => $th->getMessage()]);
}
return $preview;
}
/**
* Create a preview image for the provided video URL using ffmpeg
*
* @param string $url Video URL
* @param bool $cached optional, default true
* @return boolean Success
*/
public function getFromVideoUrl(string $url, bool $cached = true): bool
{
if (!$url) {
return false;
}
if (!DI::config()->get('system', 'ffmpeg_installed')) {
return false;
}
if ($cached) {
$data = $this->getPreviewImageForVideoUrlCached($url);
} else {
$data = $this->getPreviewImageForVideoUrl($url);
}
return($this->loadData($data));
}
}

View file

@ -278,6 +278,11 @@ return [
// Fetch featured posts from all contacts
'fetch_featured_posts' => false,
// ffmpeg_installed (Boolean)
// When FFMpeg is installed, video thumbnails will be generated.
// We will also be able to fetch video dimensions in a more ressource-friendly way.
'ffmpeg_installed' => false,
// free_crawls (Integer)
// Number of "free" searches when system => permit_crawling is enabled.
'free_crawls' => 10,