Split Flysystem extensions into their own standalone library.
This commit is contained in:
parent
10f6ba8df1
commit
286786978c
|
@ -18,6 +18,7 @@
|
|||
"ext-xml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"azuracast/azuraforms": "dev-main",
|
||||
"azuracast/flysystem-v2-extensions": "dev-main",
|
||||
"azuracast/nowplaying": "dev-main",
|
||||
"bacon/bacon-qr-code": "^2.0",
|
||||
"beberlei/doctrineextensions": "^1.2",
|
||||
|
@ -36,7 +37,6 @@
|
|||
"james-heinrich/getid3": "^1.9.9",
|
||||
"laminas/laminas-config": "^3.3",
|
||||
"league/csv": "^9.6",
|
||||
"league/flysystem": "^2.0",
|
||||
"league/flysystem-aws-s3-v3": "^2.0",
|
||||
"league/mime-type-detection": "^1.7",
|
||||
"league/plates": "^3.1",
|
||||
|
|
|
@ -4,20 +4,20 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "e7db03c2700220e7e79750abf73add84",
|
||||
"content-hash": "26509ecde178c3363ca8a49fa1b33b3e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.176.2",
|
||||
"version": "3.176.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "cfd62d9d159df12e8e1fc3c486e0a010a4c39f80"
|
||||
"reference": "776b944988167fa3d563d2cbc5fcb6763424a9f0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/cfd62d9d159df12e8e1fc3c486e0a010a4c39f80",
|
||||
"reference": "cfd62d9d159df12e8e1fc3c486e0a010a4c39f80",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/776b944988167fa3d563d2cbc5fcb6763424a9f0",
|
||||
"reference": "776b944988167fa3d563d2cbc5fcb6763424a9f0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -92,9 +92,9 @@
|
|||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.176.2"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.176.8"
|
||||
},
|
||||
"time": "2021-03-26T18:16:22+00:00"
|
||||
"time": "2021-04-05T18:16:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "azuracast/azuraforms",
|
||||
|
@ -151,6 +151,69 @@
|
|||
},
|
||||
"time": "2021-02-24T03:51:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "azuracast/flysystem-v2-extensions",
|
||||
"version": "dev-main",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/AzuraCast/flysystem-v2-extensions.git",
|
||||
"reference": "1032d9a8dfee321cdd36f1a6002560ecd53526ff"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/AzuraCast/flysystem-v2-extensions/zipball/1032d9a8dfee321cdd36f1a6002560ecd53526ff",
|
||||
"reference": "1032d9a8dfee321cdd36f1a6002560ecd53526ff",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"league/flysystem": "^2.0",
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"league/flysystem-aws-s3-v3": "^2.0",
|
||||
"overtrue/phplint": "^2.0",
|
||||
"phpstan/phpstan": "^0.12.26",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"spatie/flysystem-dropbox": "^2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"league/flysystem-aws-s3-v3": "AWS S3 API version 3 adapter for Flysystem V2.",
|
||||
"spatie/flysystem-dropbox": "Dropbox adapter for Flysystem V2."
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Azura\\Files\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Buster Neece",
|
||||
"email": "buster@busterneece.com"
|
||||
}
|
||||
],
|
||||
"description": "Extensions to Flysystem V2 functionality.",
|
||||
"keywords": [
|
||||
"aws",
|
||||
"cloud",
|
||||
"file",
|
||||
"files",
|
||||
"filesystem",
|
||||
"filesystems",
|
||||
"s3",
|
||||
"storage"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/AzuraCast/flysystem-v2-extensions/issues",
|
||||
"source": "https://github.com/AzuraCast/flysystem-v2-extensions/tree/main"
|
||||
},
|
||||
"time": "2021-04-05T23:13:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "azuracast/nowplaying",
|
||||
"version": "dev-main",
|
||||
|
@ -934,16 +997,16 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/common",
|
||||
"version": "3.1.1",
|
||||
"version": "3.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/common.git",
|
||||
"reference": "2afde5a9844126bc311cd5f548b5475e75f800d3"
|
||||
"reference": "a036d90c303f3163b5be8b8fde9b6755b2be4a3a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/common/zipball/2afde5a9844126bc311cd5f548b5475e75f800d3",
|
||||
"reference": "2afde5a9844126bc311cd5f548b5475e75f800d3",
|
||||
"url": "https://api.github.com/repos/doctrine/common/zipball/a036d90c303f3163b5be8b8fde9b6755b2be4a3a",
|
||||
"reference": "a036d90c303f3163b5be8b8fde9b6755b2be4a3a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -956,7 +1019,8 @@
|
|||
"phpstan/phpstan-phpunit": "^0.12",
|
||||
"phpunit/phpunit": "^7.5.20 || ^8.5 || ^9.0",
|
||||
"squizlabs/php_codesniffer": "^3.0",
|
||||
"symfony/phpunit-bridge": "^4.0.5"
|
||||
"symfony/phpunit-bridge": "^4.0.5",
|
||||
"vimeo/psalm": "^4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -1003,7 +1067,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/common/issues",
|
||||
"source": "https://github.com/doctrine/common/tree/3.1.1"
|
||||
"source": "https://github.com/doctrine/common/tree/3.1.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1019,7 +1083,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-01-20T19:58:05+00:00"
|
||||
"time": "2021-02-10T20:18:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/data-fixtures",
|
||||
|
@ -1100,32 +1164,32 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "2.12.1",
|
||||
"version": "2.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal.git",
|
||||
"reference": "adce7a954a1c2f14f85e94aed90c8489af204086"
|
||||
"reference": "67d56d3203b33db29834e6b2fcdbfdc50535d796"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/adce7a954a1c2f14f85e94aed90c8489af204086",
|
||||
"reference": "adce7a954a1c2f14f85e94aed90c8489af204086",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/67d56d3203b33db29834e6b2fcdbfdc50535d796",
|
||||
"reference": "67d56d3203b33db29834e6b2fcdbfdc50535d796",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/cache": "^1.0",
|
||||
"doctrine/deprecations": "^0.5.3",
|
||||
"doctrine/event-manager": "^1.0",
|
||||
"ext-pdo": "*",
|
||||
"php": "^7.3 || ^8"
|
||||
"php": "^7.1 || ^8"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^8.1",
|
||||
"jetbrains/phpstorm-stubs": "^2019.1",
|
||||
"phpstan/phpstan": "^0.12.40",
|
||||
"phpunit/phpunit": "^9.4",
|
||||
"psalm/plugin-phpunit": "^0.10.0",
|
||||
"doctrine/coding-standard": "8.2.0",
|
||||
"jetbrains/phpstorm-stubs": "2020.2",
|
||||
"phpstan/phpstan": "0.12.81",
|
||||
"phpunit/phpunit": "^7.5.20|^8.5|9.5.0",
|
||||
"symfony/console": "^2.0.5|^3.0|^4.0|^5.0",
|
||||
"vimeo/psalm": "^3.17.2"
|
||||
"vimeo/psalm": "4.6.4"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For helpful console commands such as SQL execution and import of files."
|
||||
|
@ -1134,11 +1198,6 @@
|
|||
"bin/doctrine-dbal"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\DBAL\\": "lib/Doctrine/DBAL"
|
||||
|
@ -1191,7 +1250,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/dbal/issues",
|
||||
"source": "https://github.com/doctrine/dbal/tree/2.12.1"
|
||||
"source": "https://github.com/doctrine/dbal/tree/2.13.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1207,7 +1266,50 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-14T20:26:58+00:00"
|
||||
"time": "2021-03-28T18:10:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
"version": "v0.5.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/deprecations.git",
|
||||
"reference": "9504165960a1f83cc1480e2be1dd0a0478561314"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/9504165960a1f83cc1480e2be1dd0a0478561314",
|
||||
"reference": "9504165960a1f83cc1480e2be1dd0a0478561314",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^6.0|^7.0|^8.0",
|
||||
"phpunit/phpunit": "^7.0|^8.0|^9.0",
|
||||
"psr/log": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
|
||||
"homepage": "https://www.doctrine-project.org/",
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/deprecations/issues",
|
||||
"source": "https://github.com/doctrine/deprecations/tree/v0.5.3"
|
||||
},
|
||||
"time": "2021-03-21T12:59:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/event-manager",
|
||||
|
@ -1656,16 +1758,16 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/orm",
|
||||
"version": "2.8.2",
|
||||
"version": "2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/orm.git",
|
||||
"reference": "ebae57eb9637acd8252b398df3121b120688ed5c"
|
||||
"reference": "657a30f8ceef2a78c2ff36a9fe6c6a6717c1c448"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/orm/zipball/ebae57eb9637acd8252b398df3121b120688ed5c",
|
||||
"reference": "ebae57eb9637acd8252b398df3121b120688ed5c",
|
||||
"url": "https://api.github.com/repos/doctrine/orm/zipball/657a30f8ceef2a78c2ff36a9fe6c6a6717c1c448",
|
||||
"reference": "657a30f8ceef2a78c2ff36a9fe6c6a6717c1c448",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1698,11 +1800,6 @@
|
|||
"bin/doctrine"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\ORM\\": "lib/Doctrine/ORM"
|
||||
|
@ -1742,9 +1839,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/orm/issues",
|
||||
"source": "https://github.com/doctrine/orm/tree/2.8.2"
|
||||
"source": "https://github.com/doctrine/orm/tree/2.8.3"
|
||||
},
|
||||
"time": "2021-02-16T22:10:18+00:00"
|
||||
"time": "2021-04-01T21:16:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/persistence",
|
||||
|
@ -1832,16 +1929,16 @@
|
|||
},
|
||||
{
|
||||
"name": "egulias/email-validator",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/egulias/EmailValidator.git",
|
||||
"reference": "62c3b73c581c834885acf6e120b412b76acc495a"
|
||||
"reference": "c81f18a3efb941d8c4d2e025f6183b5c6d697307"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/62c3b73c581c834885acf6e120b412b76acc495a",
|
||||
"reference": "62c3b73c581c834885acf6e120b412b76acc495a",
|
||||
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/c81f18a3efb941d8c4d2e025f6183b5c6d697307",
|
||||
"reference": "c81f18a3efb941d8c4d2e025f6183b5c6d697307",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1888,7 +1985,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/egulias/EmailValidator/issues",
|
||||
"source": "https://github.com/egulias/EmailValidator/tree/3.1.0"
|
||||
"source": "https://github.com/egulias/EmailValidator/tree/3.1.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1896,7 +1993,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-07T14:33:28+00:00"
|
||||
"time": "2021-04-01T18:37:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/proxy-manager-lts",
|
||||
|
@ -9057,16 +9154,16 @@
|
|||
},
|
||||
{
|
||||
"name": "codeception/codeception",
|
||||
"version": "4.1.19",
|
||||
"version": "4.1.20",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Codeception/Codeception.git",
|
||||
"reference": "138dc9345a81ec994dcd6b9680c501a752a37b00"
|
||||
"reference": "d8b16e13e1781dbc3a7ae8292117d520c89a9c5a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/138dc9345a81ec994dcd6b9680c501a752a37b00",
|
||||
"reference": "138dc9345a81ec994dcd6b9680c501a752a37b00",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/d8b16e13e1781dbc3a7ae8292117d520c89a9c5a",
|
||||
"reference": "d8b16e13e1781dbc3a7ae8292117d520c89a9c5a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -9140,7 +9237,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Codeception/Codeception/issues",
|
||||
"source": "https://github.com/Codeception/Codeception/tree/4.1.19"
|
||||
"source": "https://github.com/Codeception/Codeception/tree/4.1.20"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -9148,7 +9245,7 @@
|
|||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-28T13:26:08+00:00"
|
||||
"time": "2021-04-02T16:41:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "codeception/lib-asserts",
|
||||
|
@ -9691,16 +9788,16 @@
|
|||
},
|
||||
{
|
||||
"name": "filp/whoops",
|
||||
"version": "2.11.0",
|
||||
"version": "2.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filp/whoops.git",
|
||||
"reference": "f6e14679f948d8a5cfb866fa7065a30c66bd64d3"
|
||||
"reference": "d501fd2658d55491a2295ff600ae5978eaad7403"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/f6e14679f948d8a5cfb866fa7065a30c66bd64d3",
|
||||
"reference": "f6e14679f948d8a5cfb866fa7065a30c66bd64d3",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/d501fd2658d55491a2295ff600ae5978eaad7403",
|
||||
"reference": "d501fd2658d55491a2295ff600ae5978eaad7403",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -9750,7 +9847,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/filp/whoops/issues",
|
||||
"source": "https://github.com/filp/whoops/tree/2.11.0"
|
||||
"source": "https://github.com/filp/whoops/tree/2.12.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -9758,7 +9855,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-19T12:00:00+00:00"
|
||||
"time": "2021-03-30T12:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hamcrest/hamcrest-php",
|
||||
|
@ -10400,16 +10497,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "0.12.82",
|
||||
"version": "0.12.83",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11"
|
||||
"reference": "4a967cec6efb46b500dd6d768657336a3ffe699f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/3920f0fb0aff39263d3a4cb0bca120a67a1a6a11",
|
||||
"reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/4a967cec6efb46b500dd6d768657336a3ffe699f",
|
||||
"reference": "4a967cec6efb46b500dd6d768657336a3ffe699f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -10440,7 +10537,7 @@
|
|||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/0.12.82"
|
||||
"source": "https://github.com/phpstan/phpstan/tree/0.12.83"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -10456,7 +10553,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-19T06:08:17+00:00"
|
||||
"time": "2021-04-03T15:35:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-doctrine",
|
||||
|
@ -12845,6 +12942,7 @@
|
|||
"minimum-stability": "dev",
|
||||
"stability-flags": {
|
||||
"azuracast/azuraforms": 20,
|
||||
"azuracast/flysystem-v2-extensions": 20,
|
||||
"azuracast/nowplaying": 20,
|
||||
"lstrojny/fxmlrpc": 20,
|
||||
"supervisorphp/supervisor": 20,
|
||||
|
|
|
@ -6,7 +6,6 @@ use App\Config;
|
|||
use App\Controller\AbstractLogViewerController;
|
||||
use App\Entity;
|
||||
use App\Exception\NotFoundException;
|
||||
use App\Flysystem\FilesystemInterface;
|
||||
use App\Form\BackupSettingsForm;
|
||||
use App\Form\Form;
|
||||
use App\Http\Response;
|
||||
|
@ -15,8 +14,9 @@ use App\Message\BackupMessage;
|
|||
use App\Session\Flash;
|
||||
use App\Sync\Task\RunBackupTask;
|
||||
use App\Utilities\File;
|
||||
use Azura\Files\Attributes\FileAttributes;
|
||||
use Azura\Files\ExtendedFilesystemInterface;
|
||||
use InvalidArgumentException;
|
||||
use League\Flysystem\FileAttributes;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Symfony\Component\Messenger\MessageBus;
|
||||
|
@ -184,8 +184,10 @@ class BackupsController extends AbstractLogViewerController
|
|||
): ResponseInterface {
|
||||
[$path, $fs] = $this->getFile($path);
|
||||
|
||||
/** @var FilesystemInterface $fs */
|
||||
return $fs->streamToResponse($response->withNoCache(), $path);
|
||||
/** @var ExtendedFilesystemInterface $fs */
|
||||
return $response
|
||||
->withNoCache()
|
||||
->streamFilesystemFile($fs, $response, $path);
|
||||
}
|
||||
|
||||
public function deleteAction(ServerRequest $request, Response $response, $path, $csrf): ResponseInterface
|
||||
|
@ -194,7 +196,7 @@ class BackupsController extends AbstractLogViewerController
|
|||
|
||||
[$path, $fs] = $this->getFile($path);
|
||||
|
||||
/** @var FilesystemInterface $fs */
|
||||
/** @var ExtendedFilesystemInterface $fs */
|
||||
$fs->delete($path);
|
||||
|
||||
$request->getFlash()->addMessage('<b>' . __('Backup deleted.') . '</b>', Flash::SUCCESS);
|
||||
|
@ -204,7 +206,7 @@ class BackupsController extends AbstractLogViewerController
|
|||
/**
|
||||
* @param string $rawPath
|
||||
*
|
||||
* @return array{0: string, 1: FilesystemInterface}
|
||||
* @return array{0: string, 1: ExtendedFilesystemInterface}
|
||||
*/
|
||||
protected function getFile(string $rawPath): array
|
||||
{
|
||||
|
|
|
@ -65,7 +65,7 @@ class GetArtAction
|
|||
}
|
||||
|
||||
if ($fsMedia->fileExists($mediaPath)) {
|
||||
return $fsMedia->streamToResponse($response, $mediaPath, null, 'inline');
|
||||
return $response->streamFilesystemFile($fsMedia, $mediaPath, null, 'inline');
|
||||
}
|
||||
|
||||
return $defaultArtRedirect;
|
||||
|
|
|
@ -4,7 +4,6 @@ namespace App\Controller\Api\Stations\Files;
|
|||
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Entity;
|
||||
use App\Flysystem\FilesystemInterface;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
|
@ -12,10 +11,9 @@ use App\Message;
|
|||
use App\MessageQueue\QueueManager;
|
||||
use App\Radio\Backend\Liquidsoap;
|
||||
use App\Utilities\File;
|
||||
use Azura\Files\ExtendedFilesystemInterface;
|
||||
use DoctrineBatchUtils\BatchProcessing\SimpleBatchIteratorAggregate;
|
||||
use Exception;
|
||||
use Jhofm\FlysystemIterator\Filter\FilterFactory;
|
||||
use Jhofm\FlysystemIterator\Options\Options;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Symfony\Component\Messenger\MessageBus;
|
||||
|
@ -106,7 +104,7 @@ class BatchAction
|
|||
ServerRequest $request,
|
||||
Entity\Station $station,
|
||||
Entity\StorageLocation $storageLocation,
|
||||
FilesystemInterface $fs
|
||||
ExtendedFilesystemInterface $fs
|
||||
): Entity\Api\BatchResult {
|
||||
$result = $this->parseRequest($request, $fs, true);
|
||||
|
||||
|
@ -167,7 +165,7 @@ class BatchAction
|
|||
ServerRequest $request,
|
||||
Entity\Station $station,
|
||||
Entity\StorageLocation $storageLocation,
|
||||
FilesystemInterface $fs
|
||||
ExtendedFilesystemInterface $fs
|
||||
): Entity\Api\BatchResult {
|
||||
$result = $this->parseRequest($request, $fs, true);
|
||||
|
||||
|
@ -257,7 +255,7 @@ class BatchAction
|
|||
ServerRequest $request,
|
||||
Entity\Station $station,
|
||||
Entity\StorageLocation $storageLocation,
|
||||
FilesystemInterface $fs
|
||||
ExtendedFilesystemInterface $fs
|
||||
): Entity\Api\BatchResult {
|
||||
$result = $this->parseRequest($request, $fs, false);
|
||||
|
||||
|
@ -317,7 +315,7 @@ class BatchAction
|
|||
ServerRequest $request,
|
||||
Entity\Station $station,
|
||||
Entity\StorageLocation $storageLocation,
|
||||
FilesystemInterface $fs
|
||||
ExtendedFilesystemInterface $fs
|
||||
): Entity\Api\BatchResult {
|
||||
$result = $this->parseRequest($request, $fs, true);
|
||||
|
||||
|
@ -342,7 +340,7 @@ class BatchAction
|
|||
ServerRequest $request,
|
||||
Entity\Station $station,
|
||||
Entity\StorageLocation $storageLocation,
|
||||
FilesystemInterface $fs
|
||||
ExtendedFilesystemInterface $fs
|
||||
): Entity\Api\BatchResult {
|
||||
$result = $this->parseRequest($request, $fs, true);
|
||||
|
||||
|
@ -390,7 +388,7 @@ class BatchAction
|
|||
|
||||
protected function parseRequest(
|
||||
ServerRequest $request,
|
||||
FilesystemInterface $fs,
|
||||
ExtendedFilesystemInterface $fs,
|
||||
bool $recursive = false
|
||||
): Entity\Api\BatchResult {
|
||||
$files = array_values((array)$request->getParam('files', []));
|
||||
|
|
|
@ -27,6 +27,6 @@ class DownloadAction
|
|||
->withJson(new Error(404, 'File not found.'));
|
||||
}
|
||||
|
||||
return $fsMedia->streamToResponse($response, $path);
|
||||
return $response->streamFilesystemFile($fsMedia, $path);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\FilesystemManager;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
|
@ -13,7 +12,6 @@ use Doctrine\Common\Collections\ArrayCollection;
|
|||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
use Jhofm\FlysystemIterator\Options\Options;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
|
|
|
@ -30,6 +30,6 @@ class PlayAction
|
|||
$fsStation = new StationFilesystems($station);
|
||||
$fsMedia = $fsStation->getMediaFilesystem();
|
||||
|
||||
return $fsMedia->streamToResponse($response, $media->getPath());
|
||||
return $response->streamFilesystemFile($fsMedia, $media->getPath());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,6 @@ class DownloadAction
|
|||
$fsMedia = $fsStation->getMediaFilesystem();
|
||||
|
||||
set_time_limit(600);
|
||||
return $fsMedia->streamToResponse($response, $media->getPath());
|
||||
return $response->streamFilesystemFile($fsMedia, $media->getPath());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,8 +131,8 @@ class BroadcastsController extends AbstractApiCrudController
|
|||
$fsStation = new StationFilesystems($station);
|
||||
$fsRecordings = $fsStation->getRecordingsFilesystem();
|
||||
|
||||
return $fsRecordings->streamToResponse(
|
||||
$response,
|
||||
return $response->streamFilesystemFile(
|
||||
$fsRecordings,
|
||||
$recordingPath,
|
||||
File::sanitizeFileName($broadcast->getStreamer()->getDisplayName()) . '_' . $filename
|
||||
);
|
||||
|
|
|
@ -31,7 +31,7 @@ class GetWaveformAction
|
|||
if (StationMedia::UNIQUE_ID_LENGTH === strlen($media_id)) {
|
||||
$waveformPath = StationMedia::getWaveformPath($media_id);
|
||||
if ($fsMedia->fileExists($waveformPath)) {
|
||||
return $fsMedia->streamToResponse($response, $waveformPath, null, 'inline');
|
||||
return $response->streamFilesystemFile($fsMedia, $waveformPath, null, 'inline');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,6 @@ class GetWaveformAction
|
|||
$mediaRepo->updateWaveform($media);
|
||||
}
|
||||
|
||||
return $fsMedia->streamToResponse($response, $waveformPath, null, 'inline');
|
||||
return $response->streamFilesystemFile($fsMedia, $waveformPath, null, 'inline');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ use App\Entity;
|
|||
use App\Entity\StationPlaylist;
|
||||
use App\Environment;
|
||||
use App\Exception\CannotProcessMediaException;
|
||||
use App\Flysystem\FilesystemInterface;
|
||||
use App\Media\MetadataManager;
|
||||
use App\Service\AudioWaveform;
|
||||
use Azura\Files\ExtendedFilesystemInterface;
|
||||
use Exception;
|
||||
use Generator;
|
||||
use Intervention\Image\Constraint;
|
||||
|
@ -254,12 +254,12 @@ class StationMediaRepository extends Repository
|
|||
*
|
||||
* @param Entity\StationMedia $media
|
||||
* @param string $filePath
|
||||
* @param FilesystemInterface|null $fs
|
||||
* @param ExtendedFilesystemInterface|null $fs
|
||||
*/
|
||||
public function loadFromFile(
|
||||
Entity\StationMedia $media,
|
||||
string $filePath,
|
||||
?FilesystemInterface $fs = null
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
// Load metadata from supported files.
|
||||
$metadata = $this->metadataManager->getMetadata($media, $filePath);
|
||||
|
@ -337,7 +337,7 @@ class StationMediaRepository extends Repository
|
|||
public function writeAlbumArt(
|
||||
Entity\StationMedia $media,
|
||||
string $rawArtString,
|
||||
?FilesystemInterface $fs = null
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$fs ??= $this->getFilesystem($media);
|
||||
|
||||
|
@ -361,7 +361,7 @@ class StationMediaRepository extends Repository
|
|||
|
||||
public function removeAlbumArt(
|
||||
Entity\StationMedia $media,
|
||||
?FilesystemInterface $fs = null
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$fs ??= $this->getFilesystem($media);
|
||||
|
||||
|
@ -377,7 +377,7 @@ class StationMediaRepository extends Repository
|
|||
|
||||
public function writeToFile(
|
||||
Entity\StationMedia $media,
|
||||
?FilesystemInterface $fs = null
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): bool {
|
||||
$fs ??= $this->getFilesystem($media);
|
||||
|
||||
|
@ -407,7 +407,7 @@ class StationMediaRepository extends Repository
|
|||
|
||||
public function updateWaveform(
|
||||
Entity\StationMedia $media,
|
||||
?FilesystemInterface $fs = null
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$fs ??= $this->getFilesystem($media);
|
||||
$fs->withLocalFile(
|
||||
|
@ -421,7 +421,7 @@ class StationMediaRepository extends Repository
|
|||
public function writeWaveform(
|
||||
Entity\StationMedia $media,
|
||||
string $path,
|
||||
?FilesystemInterface $fs = null
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$fs ??= $this->getFilesystem($media);
|
||||
|
||||
|
@ -440,14 +440,14 @@ class StationMediaRepository extends Repository
|
|||
/**
|
||||
* @param Entity\StationMedia $media
|
||||
* @param bool $deleteFile Whether to remove the media file itself (disabled for batch operations).
|
||||
* @param FilesystemInterface|null $fs
|
||||
* @param ExtendedFilesystemInterface|null $fs
|
||||
*
|
||||
* @return StationPlaylist[] The IDs as keys and records as values for all affected playlists.
|
||||
*/
|
||||
public function remove(
|
||||
Entity\StationMedia $media,
|
||||
bool $deleteFile = false,
|
||||
?FilesystemInterface $fs = null
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): array {
|
||||
$fs ??= $this->getFilesystem($media);
|
||||
|
||||
|
@ -476,7 +476,7 @@ class StationMediaRepository extends Repository
|
|||
return $affectedPlaylists;
|
||||
}
|
||||
|
||||
protected function getFilesystem(Entity\StationMedia $media): FilesystemInterface
|
||||
protected function getFilesystem(Entity\StationMedia $media): ExtendedFilesystemInterface
|
||||
{
|
||||
return $media->getStorageLocation()->getFilesystem();
|
||||
}
|
||||
|
|
|
@ -5,16 +5,17 @@
|
|||
namespace App\Entity;
|
||||
|
||||
use App\Annotations\AuditLog;
|
||||
use App\Flysystem\Adapter\AdapterInterface;
|
||||
use App\Flysystem\Adapter\AwsS3Adapter;
|
||||
use App\Flysystem\Adapter\DropboxAdapter;
|
||||
use App\Flysystem\Adapter\LocalAdapter;
|
||||
use App\Flysystem\FilesystemInterface;
|
||||
use App\Flysystem\LocalFilesystem;
|
||||
use App\Flysystem\RemoteFilesystem;
|
||||
use App\Radio\Quota;
|
||||
use App\Validator\Constraints as AppAssert;
|
||||
use Aws\S3\S3Client;
|
||||
use Azura\Files\Adapter\AwsS3\AwsS3Adapter;
|
||||
use Azura\Files\Adapter\Dropbox\DropboxAdapter;
|
||||
use Azura\Files\Adapter\ExtendedAdapterInterface;
|
||||
use Azura\Files\Adapter\Local\LocalFilesystemAdapter;
|
||||
use Azura\Files\Adapter\LocalAdapterInterface;
|
||||
use Azura\Files\ExtendedFilesystemInterface;
|
||||
use Azura\Files\LocalFilesystem;
|
||||
use Azura\Files\RemoteFilesystem;
|
||||
use Brick\Math\BigInteger;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
@ -477,7 +478,7 @@ class StorageLocation
|
|||
$adapter->fileExists('/test');
|
||||
}
|
||||
|
||||
public function getStorageAdapter(): AdapterInterface
|
||||
public function getStorageAdapter(): ExtendedAdapterInterface
|
||||
{
|
||||
switch ($this->adapter) {
|
||||
case self::ADAPTER_S3:
|
||||
|
@ -489,7 +490,7 @@ class StorageLocation
|
|||
|
||||
case self::ADAPTER_LOCAL:
|
||||
default:
|
||||
return new LocalAdapter($this->path);
|
||||
return new LocalFilesystemAdapter($this->path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,11 +523,11 @@ class StorageLocation
|
|||
return new Client($this->dropboxAuthToken);
|
||||
}
|
||||
|
||||
public function getFilesystem(): FilesystemInterface
|
||||
public function getFilesystem(): ExtendedFilesystemInterface
|
||||
{
|
||||
$adapter = $this->getStorageAdapter();
|
||||
|
||||
return ($adapter instanceof LocalAdapter)
|
||||
return ($adapter instanceof LocalAdapterInterface)
|
||||
? new LocalFilesystem($adapter)
|
||||
: new RemoteFilesystem($adapter);
|
||||
}
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Flysystem;
|
||||
|
||||
use App\Flysystem\Adapter\AdapterInterface;
|
||||
use App\Http\Response;
|
||||
use League\Flysystem\Filesystem;
|
||||
use League\Flysystem\PathNormalizer;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use League\MimeTypeDetection\FinfoMimeTypeDetector;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
abstract class AbstractFilesystem extends Filesystem implements FilesystemInterface
|
||||
{
|
||||
protected AdapterInterface $adapter;
|
||||
|
||||
public function __construct(AdapterInterface $adapter, array $config = [], PathNormalizer $pathNormalizer = null)
|
||||
{
|
||||
$this->adapter = $adapter;
|
||||
|
||||
parent::__construct($adapter, $config, $pathNormalizer);
|
||||
}
|
||||
|
||||
public function getAdapter(): AdapterInterface
|
||||
{
|
||||
return $this->adapter;
|
||||
}
|
||||
|
||||
public function getMetadata(string $path): StorageAttributes
|
||||
{
|
||||
return $this->adapter->getMetadata($path);
|
||||
}
|
||||
|
||||
public function uploadAndDeleteOriginal(string $localPath, string $to): void
|
||||
{
|
||||
$this->upload($localPath, $to);
|
||||
@unlink($localPath);
|
||||
}
|
||||
|
||||
public function streamToResponse(
|
||||
Response $response,
|
||||
string $path,
|
||||
string $fileName = null,
|
||||
string $disposition = 'attachment'
|
||||
): ResponseInterface {
|
||||
$localPath = $this->getLocalPath($path);
|
||||
|
||||
$mime = new FinfoMimeTypeDetector();
|
||||
$mimeType = $mime->detectMimeTypeFromFile($localPath);
|
||||
|
||||
$fileName ??= basename($localPath);
|
||||
|
||||
if ('attachment' === $disposition) {
|
||||
/*
|
||||
* The regex used below is to ensure that the $fileName contains only
|
||||
* characters ranging from ASCII 128-255 and ASCII 0-31 and 127 are replaced with an empty string
|
||||
*/
|
||||
$disposition .= '; filename="' . preg_replace('/[\x00-\x1F\x7F\"]/', ' ', $fileName) . '"';
|
||||
$disposition .= "; filename*=UTF-8''" . rawurlencode($fileName);
|
||||
}
|
||||
|
||||
$response = $response->withHeader('Content-Disposition', $disposition)
|
||||
->withHeader('Content-Length', filesize($localPath))
|
||||
->withHeader('X-Accel-Buffering', 'no');
|
||||
|
||||
// Special internal nginx routes to use X-Accel-Redirect for far more performant file serving.
|
||||
$specialPaths = [
|
||||
'/var/azuracast/backups' => '/internal/backups',
|
||||
'/var/azuracast/stations' => '/internal/stations',
|
||||
];
|
||||
|
||||
foreach ($specialPaths as $diskPath => $nginxPath) {
|
||||
if (0 === strpos($localPath, $diskPath)) {
|
||||
$accelPath = str_replace($diskPath, $nginxPath, $localPath);
|
||||
|
||||
return $response->withHeader('Content-Type', $mimeType)
|
||||
->withHeader('X-Accel-Redirect', $accelPath);
|
||||
}
|
||||
}
|
||||
|
||||
return $response->withFile($localPath, $mimeType);
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Flysystem\Adapter;
|
||||
|
||||
use League\Flysystem\FilesystemAdapter;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
|
||||
interface AdapterInterface extends FilesystemAdapter
|
||||
{
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
*/
|
||||
public function getMetadata(string $path): StorageAttributes;
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Flysystem\Adapter;
|
||||
|
||||
use Aws\Api\DateTimeResult;
|
||||
use Aws\S3\S3ClientInterface;
|
||||
use League\Flysystem\AwsS3V3\AwsS3V3Adapter;
|
||||
use League\Flysystem\AwsS3V3\VisibilityConverter;
|
||||
use League\Flysystem\DirectoryAttributes;
|
||||
use League\Flysystem\FileAttributes;
|
||||
use League\Flysystem\PathPrefixer;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use League\Flysystem\UnableToRetrieveMetadata;
|
||||
use League\MimeTypeDetection\MimeTypeDetector;
|
||||
use Throwable;
|
||||
|
||||
class AwsS3Adapter extends AwsS3V3Adapter implements AdapterInterface
|
||||
{
|
||||
protected S3ClientInterface $client;
|
||||
|
||||
protected string $bucket;
|
||||
|
||||
protected PathPrefixer $prefixer;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected const EXTRA_METADATA_FIELDS = [
|
||||
'Metadata',
|
||||
'StorageClass',
|
||||
'ETag',
|
||||
'VersionId',
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
S3ClientInterface $client,
|
||||
string $bucket,
|
||||
string $prefix = '',
|
||||
VisibilityConverter $visibility = null,
|
||||
MimeTypeDetector $mimeTypeDetector = null,
|
||||
array $options = [],
|
||||
bool $streamReads = true
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->bucket = $bucket;
|
||||
$this->prefixer = new PathPrefixer($prefix);
|
||||
|
||||
parent::__construct($client, $bucket, $prefix, $visibility, $mimeTypeDetector, $options, $streamReads);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getMetadata(string $path): StorageAttributes
|
||||
{
|
||||
$arguments = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];
|
||||
$command = $this->client->getCommand('HeadObject', $arguments);
|
||||
|
||||
try {
|
||||
$metadata = $this->client->execute($command);
|
||||
} catch (Throwable $exception) {
|
||||
throw UnableToRetrieveMetadata::create($path, 'metadata', '', $exception);
|
||||
}
|
||||
|
||||
if (substr($path, -1) === '/') {
|
||||
return new DirectoryAttributes(rtrim($path, '/'));
|
||||
}
|
||||
|
||||
$mimetype = $metadata['ContentType'] ?? null;
|
||||
$fileSize = $metadata['ContentLength'] ?? $metadata['Size'] ?? null;
|
||||
$fileSize = $fileSize === null ? null : (int)$fileSize;
|
||||
$dateTime = $metadata['LastModified'] ?? null;
|
||||
$lastModified = $dateTime instanceof DateTimeResult ? $dateTime->getTimeStamp() : null;
|
||||
|
||||
return new FileAttributes(
|
||||
$path,
|
||||
$fileSize,
|
||||
null,
|
||||
$lastModified,
|
||||
$mimetype
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Flysystem\Adapter;
|
||||
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use League\Flysystem\UnableToRetrieveMetadata;
|
||||
use Spatie\Dropbox\Exceptions\BadRequest;
|
||||
|
||||
class DropboxAdapter extends \Spatie\FlysystemDropbox\DropboxAdapter implements AdapterInterface
|
||||
{
|
||||
/** @inheritDoc */
|
||||
public function getMetadata(string $path): StorageAttributes
|
||||
{
|
||||
$location = $this->applyPathPrefix($path);
|
||||
|
||||
try {
|
||||
$response = $this->client->getMetadata($location);
|
||||
} catch (BadRequest $e) {
|
||||
throw UnableToRetrieveMetadata::create($location, 'metadata', $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->normalizeResponse($response);
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Flysystem\Adapter;
|
||||
|
||||
use League\Flysystem\DirectoryAttributes;
|
||||
use League\Flysystem\FileAttributes;
|
||||
use League\Flysystem\Local\LocalFilesystemAdapter;
|
||||
use League\Flysystem\PathPrefixer;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use League\Flysystem\UnableToRetrieveMetadata;
|
||||
use League\Flysystem\UnixVisibility\PortableVisibilityConverter;
|
||||
use League\Flysystem\UnixVisibility\VisibilityConverter;
|
||||
use League\MimeTypeDetection\MimeTypeDetector;
|
||||
|
||||
class LocalAdapter extends LocalFilesystemAdapter implements AdapterInterface
|
||||
{
|
||||
protected PathPrefixer $pathPrefixer;
|
||||
|
||||
protected VisibilityConverter $visibility;
|
||||
|
||||
public function __construct(
|
||||
string $location,
|
||||
VisibilityConverter $visibility = null,
|
||||
int $writeFlags = LOCK_EX,
|
||||
int $linkHandling = self::DISALLOW_LINKS,
|
||||
MimeTypeDetector $mimeTypeDetector = null
|
||||
) {
|
||||
$this->pathPrefixer = new PathPrefixer($location, DIRECTORY_SEPARATOR);
|
||||
|
||||
$this->visibility = $visibility ?: new PortableVisibilityConverter();
|
||||
|
||||
parent::__construct($location, $visibility, $writeFlags, $linkHandling, $mimeTypeDetector);
|
||||
}
|
||||
|
||||
public function getFullPath(string $path): string
|
||||
{
|
||||
return $this->pathPrefixer->prefixPath($path);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getMetadata(string $path): StorageAttributes
|
||||
{
|
||||
$location = $this->pathPrefixer->prefixPath($path);
|
||||
|
||||
if (!file_exists($location)) {
|
||||
throw UnableToRetrieveMetadata::create($location, 'metadata', 'File not found');
|
||||
}
|
||||
|
||||
$fileInfo = new \SplFileInfo($location);
|
||||
|
||||
$lastModified = $fileInfo->getMTime();
|
||||
$isDirectory = $fileInfo->isDir();
|
||||
|
||||
$permissions = $fileInfo->getPerms();
|
||||
$visibility = $isDirectory
|
||||
? $this->visibility->inverseForDirectory($permissions)
|
||||
: $this->visibility->inverseForFile($permissions);
|
||||
|
||||
return $isDirectory
|
||||
? new DirectoryAttributes($path, $visibility, $lastModified)
|
||||
: new FileAttributes($path, $fileInfo->getSize(), $visibility, $lastModified);
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Flysystem;
|
||||
|
||||
use App\Flysystem\Adapter\AdapterInterface;
|
||||
use App\Http\Response;
|
||||
use League\Flysystem\FilesystemOperator;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface FilesystemInterface extends FilesystemOperator
|
||||
{
|
||||
/**
|
||||
* @return AdapterInterface The underlying filesystem adapter.
|
||||
*/
|
||||
public function getAdapter(): AdapterInterface;
|
||||
|
||||
/**
|
||||
* @return bool Whether this filesystem is directly located on disk.
|
||||
*/
|
||||
public function isLocal(): bool;
|
||||
|
||||
/**
|
||||
* @param string $path The original path of the file on the filesystem.
|
||||
*
|
||||
* @return string A path that will be guaranteed to be local to the filesystem.
|
||||
*/
|
||||
public function getLocalPath(string $path): string;
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return StorageAttributes Metadata for the specified path.
|
||||
*/
|
||||
public function getMetadata(string $path): StorageAttributes;
|
||||
|
||||
/**
|
||||
* Call a callable function with a path that is guaranteed to be a local path, even if
|
||||
* this filesystem is a remote one, by copying to a temporary directory first in the
|
||||
* case of remote filesystems.
|
||||
*
|
||||
* @param string $path
|
||||
* @param callable $function
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function withLocalFile(string $path, callable $function);
|
||||
|
||||
/**
|
||||
* @param string $localPath
|
||||
* @param string $to
|
||||
*/
|
||||
public function uploadAndDeleteOriginal(string $localPath, string $to): void;
|
||||
|
||||
/**
|
||||
* @param string $localPath
|
||||
* @param string $to
|
||||
*/
|
||||
public function upload(string $localPath, string $to): void;
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $localPath
|
||||
*/
|
||||
public function download(string $from, string $localPath): void;
|
||||
|
||||
/**
|
||||
* Read a stream from the filesystem and directly write it to a PSR-7-compatible response object.
|
||||
*
|
||||
* @param Response $response The original PSR-7 response.
|
||||
* @param string $path The path on the filesystem to stream.
|
||||
* @param string|null $fileName
|
||||
* @param string $disposition
|
||||
*
|
||||
* @return ResponseInterface The modified PSR-7 response.
|
||||
*/
|
||||
public function streamToResponse(
|
||||
Response $response,
|
||||
string $path,
|
||||
string $fileName = null,
|
||||
string $disposition = 'attachment'
|
||||
): ResponseInterface;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Flysystem;
|
||||
|
||||
use App\Flysystem\Adapter\LocalAdapter;
|
||||
use League\Flysystem\PathNormalizer;
|
||||
|
||||
class LocalFilesystem extends AbstractFilesystem
|
||||
{
|
||||
protected LocalAdapter $localAdapter;
|
||||
|
||||
public function __construct(LocalAdapter $adapter, array $config = [], PathNormalizer $pathNormalizer = null)
|
||||
{
|
||||
$this->localAdapter = $adapter;
|
||||
|
||||
parent::__construct($adapter, $config, $pathNormalizer);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function isLocal(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getLocalPath(string $path): string
|
||||
{
|
||||
return $this->localAdapter->getFullPath($path);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function upload(string $localPath, string $to): void
|
||||
{
|
||||
$destPath = $this->getLocalPath($to);
|
||||
copy($localPath, $destPath);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function download(string $from, string $localPath): void
|
||||
{
|
||||
$sourcePath = $this->getLocalPath($from);
|
||||
copy($sourcePath, $localPath);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function withLocalFile(string $path, callable $function)
|
||||
{
|
||||
$localPath = $this->getLocalPath($path);
|
||||
return $function($localPath);
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Flysystem;
|
||||
|
||||
use App\Flysystem\Adapter\AdapterInterface;
|
||||
use League\Flysystem\PathNormalizer;
|
||||
use League\Flysystem\PathPrefixer;
|
||||
use Spatie\FlysystemDropbox\DropboxAdapter;
|
||||
|
||||
class RemoteFilesystem extends AbstractFilesystem
|
||||
{
|
||||
protected AdapterInterface $remoteAdapter;
|
||||
|
||||
protected PathPrefixer $localPath;
|
||||
|
||||
public function __construct(
|
||||
AdapterInterface $remoteAdapter,
|
||||
string $localPath = null,
|
||||
array $config = [],
|
||||
PathNormalizer $pathNormalizer = null
|
||||
) {
|
||||
if ($remoteAdapter instanceof DropboxAdapter) {
|
||||
$config['case_sensitive'] = false;
|
||||
}
|
||||
|
||||
$this->localPath = new PathPrefixer($localPath ?? sys_get_temp_dir());
|
||||
parent::__construct($remoteAdapter, $config, $pathNormalizer);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function isLocal(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getLocalPath(string $path): string
|
||||
{
|
||||
$tempLocalPath = $this->localPath->prefixPath(
|
||||
substr(md5($path), 0, 10) . '_' . basename($path),
|
||||
);
|
||||
|
||||
$this->download($path, $tempLocalPath);
|
||||
return $tempLocalPath;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function withLocalFile(string $path, callable $function)
|
||||
{
|
||||
$localPath = $this->getLocalPath($path);
|
||||
|
||||
try {
|
||||
$returnVal = $function($localPath);
|
||||
} finally {
|
||||
unlink($localPath);
|
||||
}
|
||||
|
||||
return $returnVal;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function upload(string $localPath, string $to): void
|
||||
{
|
||||
if (!file_exists($localPath)) {
|
||||
throw new \RuntimeException(sprintf('Source upload file not found at path: %s', $localPath));
|
||||
}
|
||||
|
||||
$stream = fopen($localPath, 'rb');
|
||||
|
||||
try {
|
||||
$this->writeStream($to, $stream);
|
||||
} finally {
|
||||
if (is_resource($stream)) {
|
||||
fclose($stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function download(string $from, string $localPath): void
|
||||
{
|
||||
if (file_exists($localPath)) {
|
||||
if (filemtime($localPath) >= $this->lastModified($from)) {
|
||||
touch($localPath);
|
||||
}
|
||||
unlink($localPath);
|
||||
}
|
||||
|
||||
$stream = $this->readStream($from);
|
||||
|
||||
file_put_contents($localPath, $stream);
|
||||
|
||||
if (is_resource($stream)) {
|
||||
fclose($stream);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,15 +3,19 @@
|
|||
namespace App\Flysystem;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\Adapter\LocalAdapter;
|
||||
use Azura\Files\Adapter\Local\LocalFilesystemAdapter;
|
||||
use Azura\Files\Adapter\LocalAdapterInterface;
|
||||
use Azura\Files\ExtendedFilesystemInterface;
|
||||
use Azura\Files\LocalFilesystem;
|
||||
use Azura\Files\RemoteFilesystem;
|
||||
|
||||
class StationFilesystems
|
||||
{
|
||||
protected Entity\Station $station;
|
||||
|
||||
protected FilesystemInterface $fsMedia;
|
||||
protected ExtendedFilesystemInterface $fsMedia;
|
||||
|
||||
protected FilesystemInterface $fsRecordings;
|
||||
protected ExtendedFilesystemInterface $fsRecordings;
|
||||
|
||||
protected LocalFilesystem $fsPlaylists;
|
||||
|
||||
|
@ -24,11 +28,11 @@ class StationFilesystems
|
|||
$this->station = $station;
|
||||
}
|
||||
|
||||
public function getMediaFilesystem(): FilesystemInterface
|
||||
public function getMediaFilesystem(): ExtendedFilesystemInterface
|
||||
{
|
||||
if (!isset($this->fsMedia)) {
|
||||
$mediaAdapter = $this->station->getMediaStorageLocation()->getStorageAdapter();
|
||||
if ($mediaAdapter instanceof LocalAdapter) {
|
||||
if ($mediaAdapter instanceof LocalAdapterInterface) {
|
||||
$this->fsMedia = new LocalFilesystem($mediaAdapter);
|
||||
} else {
|
||||
$tempDir = $this->station->getRadioTempDir();
|
||||
|
@ -39,11 +43,11 @@ class StationFilesystems
|
|||
return $this->fsMedia;
|
||||
}
|
||||
|
||||
public function getRecordingsFilesystem(): FilesystemInterface
|
||||
public function getRecordingsFilesystem(): ExtendedFilesystemInterface
|
||||
{
|
||||
if (!isset($this->fsRecordings)) {
|
||||
$recordingsAdapter = $this->station->getRecordingsStorageLocation()->getStorageAdapter();
|
||||
if ($recordingsAdapter instanceof LocalAdapter) {
|
||||
if ($recordingsAdapter instanceof LocalAdapterInterface) {
|
||||
$this->fsRecordings = new LocalFilesystem($recordingsAdapter);
|
||||
} else {
|
||||
$tempDir = $this->station->getRadioTempDir();
|
||||
|
@ -58,7 +62,7 @@ class StationFilesystems
|
|||
{
|
||||
if (!isset($this->fsPlaylists)) {
|
||||
$playlistsDir = $this->station->getRadioPlaylistsDir();
|
||||
$this->fsPlaylists = new LocalFilesystem(new LocalAdapter($playlistsDir));
|
||||
$this->fsPlaylists = new LocalFilesystem(new LocalFilesystemAdapter($playlistsDir));
|
||||
}
|
||||
|
||||
return $this->fsPlaylists;
|
||||
|
@ -68,7 +72,7 @@ class StationFilesystems
|
|||
{
|
||||
if (!isset($this->fsConfig)) {
|
||||
$configDir = $this->station->getRadioConfigDir();
|
||||
$this->fsConfig = new LocalFilesystem(new LocalAdapter($configDir));
|
||||
$this->fsConfig = new LocalFilesystem(new LocalFilesystemAdapter($configDir));
|
||||
}
|
||||
|
||||
return $this->fsConfig;
|
||||
|
@ -78,7 +82,7 @@ class StationFilesystems
|
|||
{
|
||||
if (!isset($this->fsTemp)) {
|
||||
$tempDir = $this->station->getRadioTempDir();
|
||||
$this->fsTemp = new LocalFilesystem(new LocalAdapter($tempDir));
|
||||
$this->fsTemp = new LocalFilesystem(new LocalFilesystemAdapter($tempDir));
|
||||
}
|
||||
|
||||
return $this->fsTemp;
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace App\Http;
|
||||
|
||||
use Azura\Files\ExtendedFilesystemInterface;
|
||||
use Azura\Files\FilesystemInterface;
|
||||
use League\MimeTypeDetection\FinfoMimeTypeDetector;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
|
@ -160,4 +163,48 @@ final class Response extends \Slim\Http\Response
|
|||
|
||||
return new static($response, $this->streamFactory);
|
||||
}
|
||||
|
||||
public function streamFilesystemFile(
|
||||
ExtendedFilesystemInterface $filesystem,
|
||||
string $path,
|
||||
string $fileName = null,
|
||||
string $disposition = 'attachment'
|
||||
): ResponseInterface {
|
||||
$localPath = $filesystem->getLocalPath($path);
|
||||
|
||||
$mime = new FinfoMimeTypeDetector();
|
||||
$mimeType = $mime->detectMimeTypeFromFile($localPath);
|
||||
|
||||
$fileName ??= basename($localPath);
|
||||
|
||||
if ('attachment' === $disposition) {
|
||||
/*
|
||||
* The regex used below is to ensure that the $fileName contains only
|
||||
* characters ranging from ASCII 128-255 and ASCII 0-31 and 127 are replaced with an empty string
|
||||
*/
|
||||
$disposition .= '; filename="' . preg_replace('/[\x00-\x1F\x7F\"]/', ' ', $fileName) . '"';
|
||||
$disposition .= "; filename*=UTF-8''" . rawurlencode($fileName);
|
||||
}
|
||||
|
||||
$response = $this->withHeader('Content-Disposition', $disposition)
|
||||
->withHeader('Content-Length', filesize($localPath))
|
||||
->withHeader('X-Accel-Buffering', 'no');
|
||||
|
||||
// Special internal nginx routes to use X-Accel-Redirect for far more performant file serving.
|
||||
$specialPaths = [
|
||||
'/var/azuracast/backups' => '/internal/backups',
|
||||
'/var/azuracast/stations' => '/internal/stations',
|
||||
];
|
||||
|
||||
foreach ($specialPaths as $diskPath => $nginxPath) {
|
||||
if (0 === strpos($localPath, $diskPath)) {
|
||||
$accelPath = str_replace($diskPath, $nginxPath, $localPath);
|
||||
|
||||
return $response->withHeader('Content-Type', $mimeType)
|
||||
->withHeader('X-Accel-Redirect', $accelPath);
|
||||
}
|
||||
}
|
||||
|
||||
return $response->withFile($localPath, $mimeType);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue