diff --git a/composer.json b/composer.json deleted file mode 100644 index 94ce78c..0000000 --- a/composer.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "require": { - "flashwave/index": "^0.2410", - "sentry/sdk": "^4.0" - }, - "autoload": { - "psr-4": { - "Uiharu\\": "src" - } - } -} diff --git a/composer.lock b/composer.lock deleted file mode 100644 index f89c949..0000000 --- a/composer.lock +++ /dev/null @@ -1,1359 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "023574a93f076ef7a987151cdbfdb33e", - "packages": [ - { - "name": "flashwave/index", - "version": "v0.2410.191603", - "source": { - "type": "git", - "url": "https://patchii.net/flash/index.git", - "reference": "17cdb4d1c239241200d7e30968122a8cd8b26509" - }, - "require": { - "ext-mbstring": "*", - "php": ">=8.3", - "twig/html-extra": "^3.13", - "twig/twig": "^3.14" - }, - "require-dev": { - "phpstan/phpstan": "^1.11", - "phpunit/phpunit": "^11.2" - }, - "suggest": { - "ext-memcache": "Support for the Index\\Cache\\Memcached namespace (only if you can't use ext-memcached for some reason).", - "ext-memcached": "Support for the Index\\Cache\\Memcached namespace (you should use this instead of ext-memcache).", - "ext-mysqli": "Support for the Index\\Db\\MariaDb namespace (both mysqlnd and libmysql are supported).", - "ext-redis": "Support for the Index\\Cache\\Valkey namespace.", - "ext-sqlite3": "Support for the Index\\Db\\Sqlite namespace." - }, - "type": "library", - "autoload": { - "files": [ - "src/Cache/ArrayCache/_ndx.php", - "src/Cache/Memcached/_ndx.php", - "src/Cache/Valkey/_ndx.php", - "src/Db/MariaDb/_ndx.php", - "src/Db/NullDb/_ndx.php", - "src/Db/Sqlite/_ndx.php" - ], - "psr-4": { - "Index\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "bsd-3-clause-clear" - ], - "authors": [ - { - "name": "flashwave", - "email": "packagist@flash.moe", - "homepage": "https://flash.moe", - "role": "mom" - } - ], - "description": "Composer package for the common library for my projects.", - "homepage": "https://railgun.sh/index", - "time": "2024-10-19T16:04:17+00:00" - }, - { - "name": "guzzlehttp/psr7", - "version": "2.7.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 || ^2.0", - "ralouphie/getallheaders": "^3.0" - }, - "provide": { - "psr/http-factory-implementation": "1.0", - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" - }, - "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" - ], - "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.0" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", - "type": "tidelift" - } - ], - "time": "2024-07-18T11:15:46+00:00" - }, - { - "name": "jean85/pretty-package-versions", - "version": "2.0.6", - "source": { - "type": "git", - "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/f9fdd29ad8e6d024f52678b570e5593759b550b4", - "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2.0.0", - "php": "^7.1|^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "jean85/composer-provided-replaced-stub-package": "^1.0", - "phpstan/phpstan": "^1.4", - "phpunit/phpunit": "^7.5|^8.5|^9.4", - "vimeo/psalm": "^4.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Jean85\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Alessandro Lai", - "email": "alessandro.lai85@gmail.com" - } - ], - "description": "A library to get pretty versions strings of installed dependencies", - "keywords": [ - "composer", - "package", - "release", - "versions" - ], - "support": { - "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.6" - }, - "time": "2024-03-08T09:58:59+00:00" - }, - { - "name": "psr/http-factory", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory" - }, - "time": "2024-04-15T12:06:14+00:00" - }, - { - "name": "psr/http-message", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "time": "2023-04-04T09:54:51+00:00" - }, - { - "name": "psr/log", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", - "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/3.0.2" - }, - "time": "2024-09-11T13:17:53+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" - }, - "time": "2019-03-08T08:55:37+00:00" - }, - { - "name": "sentry/sdk", - "version": "4.0.0", - "source": { - "type": "git", - "url": "https://github.com/getsentry/sentry-php-sdk.git", - "reference": "fcbca864e8d1dc712f3ecfaa95ea89d024fb2e53" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php-sdk/zipball/fcbca864e8d1dc712f3ecfaa95ea89d024fb2e53", - "reference": "fcbca864e8d1dc712f3ecfaa95ea89d024fb2e53", - "shasum": "" - }, - "require": { - "sentry/sentry": "^4.0" - }, - "type": "metapackage", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Sentry", - "email": "accounts@sentry.io" - } - ], - "description": "This is a meta package of sentry/sentry. We recommend using sentry/sentry directly.", - "homepage": "http://sentry.io", - "keywords": [ - "crash-reporting", - "crash-reports", - "error-handler", - "error-monitoring", - "log", - "logging", - "sentry" - ], - "support": { - "issues": "https://github.com/getsentry/sentry-php-sdk/issues", - "source": "https://github.com/getsentry/sentry-php-sdk/tree/4.0.0" - }, - "funding": [ - { - "url": "https://sentry.io/", - "type": "custom" - }, - { - "url": "https://sentry.io/pricing/", - "type": "custom" - } - ], - "time": "2023-11-06T10:23:19+00:00" - }, - { - "name": "sentry/sentry", - "version": "4.9.0", - "source": { - "type": "git", - "url": "https://github.com/getsentry/sentry-php.git", - "reference": "788ec170f51ebb22f2809a1e3f78b19ccd39b70d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/788ec170f51ebb22f2809a1e3f78b19ccd39b70d", - "reference": "788ec170f51ebb22f2809a1e3f78b19ccd39b70d", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "ext-json": "*", - "ext-mbstring": "*", - "guzzlehttp/psr7": "^1.8.4|^2.1.1", - "jean85/pretty-package-versions": "^1.5|^2.0.4", - "php": "^7.2|^8.0", - "psr/log": "^1.0|^2.0|^3.0", - "symfony/options-resolver": "^4.4.30|^5.0.11|^6.0|^7.0" - }, - "conflict": { - "raven/raven": "*" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.4", - "guzzlehttp/promises": "^1.0|^2.0", - "guzzlehttp/psr7": "^1.8.4|^2.1.1", - "monolog/monolog": "^1.6|^2.0|^3.0", - "phpbench/phpbench": "^1.0", - "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^8.5.14|^9.4", - "symfony/phpunit-bridge": "^5.2|^6.0|^7.0", - "vimeo/psalm": "^4.17" - }, - "suggest": { - "monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler." - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "Sentry\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Sentry", - "email": "accounts@sentry.io" - } - ], - "description": "PHP SDK for Sentry (http://sentry.io)", - "homepage": "http://sentry.io", - "keywords": [ - "crash-reporting", - "crash-reports", - "error-handler", - "error-monitoring", - "log", - "logging", - "profiling", - "sentry", - "tracing" - ], - "support": { - "issues": "https://github.com/getsentry/sentry-php/issues", - "source": "https://github.com/getsentry/sentry-php/tree/4.9.0" - }, - "funding": [ - { - "url": "https://sentry.io/", - "type": "custom" - }, - { - "url": "https://sentry.io/pricing/", - "type": "custom" - } - ], - "time": "2024-08-08T14:40:50+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v3.5.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "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": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" - }, - "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-04-18T09:32:20+00:00" - }, - { - "name": "symfony/mime", - "version": "v7.1.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/mime.git", - "reference": "711d2e167e8ce65b05aea6b258c449671cdd38ff" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/711d2e167e8ce65b05aea6b258c449671cdd38ff", - "reference": "711d2e167e8ce65b05aea6b258c449671cdd38ff", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" - }, - "conflict": { - "egulias/email-validator": "~3.0.0", - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", - "symfony/mailer": "<6.4", - "symfony/serializer": "<6.4.3|>7.0,<7.0.3" - }, - "require-dev": { - "egulias/email-validator": "^2.1.10|^3.1|^4", - "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Mime\\": "" - }, - "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": "Allows manipulating MIME messages", - "homepage": "https://symfony.com", - "keywords": [ - "mime", - "mime-type" - ], - "support": { - "source": "https://github.com/symfony/mime/tree/v7.1.5" - }, - "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-20T08:28:38+00:00" - }, - { - "name": "symfony/options-resolver", - "version": "v7.1.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/47aa818121ed3950acd2b58d1d37d08a94f9bf55", - "reference": "47aa818121ed3950acd2b58d1d37d08a94f9bf55", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "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 an improved replacement for the array_replace PHP function", - "homepage": "https://symfony.com", - "keywords": [ - "config", - "configuration", - "options" - ], - "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.1.1" - }, - "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-05-31T14:57:53+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.31.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": { - "name": "symfony/polyfill", - "url": "https://github.com/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.31.0" - }, - "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-09T11:45:10+00:00" - }, - { - "name": "symfony/polyfill-intl-idn", - "version": "v1.31.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", - "shasum": "" - }, - "require": { - "php": ">=7.2", - "symfony/polyfill-intl-normalizer": "^1.10" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Laurent Bassin", - "email": "laurent@bassin.info" - }, - { - "name": "Trevor Rowbotham", - "email": "trevor.rowbotham@pm.me" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "idn", - "intl", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" - }, - "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-09T11:45:10+00:00" - }, - { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.31.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "3833d7255cc303546435cb650316bff708a1c75c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", - "reference": "3833d7255cc303546435cb650316bff708a1c75c", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "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 for intl's Normalizer class and related functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" - }, - "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-09T11:45:10+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/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.31.0" - }, - "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-09T11:45:10+00:00" - }, - { - "name": "symfony/polyfill-php81", - "version": "v1.31.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, - "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 8.1+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" - }, - "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-09T11:45:10+00:00" - }, - { - "name": "twig/html-extra", - "version": "v3.13.0", - "source": { - "type": "git", - "url": "https://github.com/twigphp/html-extra.git", - "reference": "8229e750091171c1f11801a525927811c7ac5a7e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/html-extra/zipball/8229e750091171c1f11801a525927811c7ac5a7e", - "reference": "8229e750091171c1f11801a525927811c7ac5a7e", - "shasum": "" - }, - "require": { - "php": ">=8.0.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/mime": "^5.4|^6.4|^7.0", - "twig/twig": "^3.13|^4.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "files": [ - "Resources/functions.php" - ], - "psr-4": { - "Twig\\Extra\\Html\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - } - ], - "description": "A Twig extension for HTML", - "homepage": "https://twig.symfony.com", - "keywords": [ - "html", - "twig" - ], - "support": { - "source": "https://github.com/twigphp/html-extra/tree/v3.13.0" - }, - "funding": [ - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/twig/twig", - "type": "tidelift" - } - ], - "time": "2024-09-03T13:08:40+00:00" - }, - { - "name": "twig/twig", - "version": "v3.14.0", - "source": { - "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/126b2c97818dbff0cdf3fbfc881aedb3d40aae72", - "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72", - "shasum": "" - }, - "require": { - "php": ">=8.0.2", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php81": "^1.29" - }, - "require-dev": { - "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" - }, - "type": "library", - "autoload": { - "files": [ - "src/Resources/core.php", - "src/Resources/debug.php", - "src/Resources/escaper.php", - "src/Resources/string_loader.php" - ], - "psr-4": { - "Twig\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Twig Team", - "role": "Contributors" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" - } - ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "https://twig.symfony.com", - "keywords": [ - "templating" - ], - "support": { - "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.14.0" - }, - "funding": [ - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/twig/twig", - "type": "tidelift" - } - ], - "time": "2024-09-09T17:55:12+00:00" - } - ], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": [], - "platform-dev": [], - "plugin-api-version": "2.6.0" -} diff --git a/public/index.php b/public/index.php deleted file mode 100644 index a54a208..0000000 --- a/public/index.php +++ /dev/null @@ -1,21 +0,0 @@ -registerLookup(new \Uiharu\Lookup\EEPROMLookup('eeprom', 'eeprom.flashii.net', ['i.fii.moe', 'i.flashii.net'])); -if(UIH_DEBUG) - $ctx->registerLookup(new \Uiharu\Lookup\EEPROMLookup('devrom', 'eeprom.edgii.net', ['i.edgii.net'])); - -$ctx->registerLookup(new \Uiharu\Lookup\YouTubeLookup($cfg->scopeTo('google'))); -$ctx->registerLookup(new \Uiharu\Lookup\NicoNicoLookup); - -// this should always come AFTER other lookups involved http(s) -$ctx->registerLookup(new \Uiharu\Lookup\WebLookup); - -$ctx->setupHttp(); - -$ctx->registerApi(new \Uiharu\Apis\v1_0($ctx)); -$ctx->matchApi(filter_input(INPUT_SERVER, 'REQUEST_URI')); - -$ctx->dispatchHttp(); diff --git a/src/Apis/v1_0.php b/src/Apis/v1_0.php deleted file mode 100644 index bf75193..0000000 --- a/src/Apis/v1_0.php +++ /dev/null @@ -1,349 +0,0 @@ -ctx = $ctx; - $this->cache = $ctx->getCache(); - } - - public function match(string $url): string { - return !str_starts_with($url, '/v'); - } - - #[HttpGet('/metadata/thumb/audio')] - public function getThumbAudio($response, $request) { - $targetUrl = (string)$request->getParam('url'); - - if(empty($targetUrl)) - return 400; - - try { - $parsedUrl = Url::parse($targetUrl); - } catch(InvalidArgumentException $ex) { - return 404; - } - - if(!$parsedUrl->isWeb()) - return 400; - - $response->setContentType('image/png'); - $response->setCacheControl('public', 'max-age=31536000', 'immutable'); - $response->setContent(FFMPEG::grabFirstAudioCover($parsedUrl)); - } - - #[HttpGet('/metadata/thumb/video')] - public function getThumbVideo($response, $request) { - $targetUrl = (string)$request->getParam('url'); - - if(empty($targetUrl)) - return 400; - - try { - $parsedUrl = Url::parse($targetUrl); - } catch(InvalidArgumentException $ex) { - return 404; - } - - if(!$parsedUrl->isWeb()) - return 400; - - $response->setContentType('image/png'); - $response->setCacheControl('public', 'max-age=31536000', 'immutable'); - $response->setContent(FFMPEG::grabFirstVideoFrame($parsedUrl)); - } - - #[HttpGet('/metadata')] - public function getMetadata($response, $request) { - if($request->getMethod() === 'HEAD') { - $response->setTypeJson(); - return; - } - - return $this->handleMetadata( - $response, $request, - (string)$request->getParam('url') - ); - } - - #[HttpPost('/metadata')] - public function postMetadata($response, $request) { - if(!$request->isStringContent()) - return 400; - - return $this->handleMetadata( - $response, $request, - (string)$request->getContent() - ); - } - - #[HttpGet('/metadata/batch')] - public function getMetadataBatch($response, $request) { - if($request->getMethod() === 'HEAD') { - $response->setTypeJson(); - return; - } - - return $this->handleMetadataBatch( - $response, $request, - $request->getParam('url', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY) - ); - } - - #[HttpPost('/metadata/batch')] - public function postMetadataBatch($response, $request) { - if(!$request->isFormContent()) - return 400; - - return $this->handleMetadataBatch( - $response, $request, - $request->getContent()->getParam('url', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY) - ); - } - - private function metadataLookup(string $targetUrl) { - $sw = Stopwatch::startNew(); - $resp = new stdClass; - - if(empty($targetUrl)) - return 400; - - try { - $parsedUrl = Url::parse($targetUrl); - } catch(InvalidArgumentException $ex) { - $resp->status = 400; - $resp->error = 'metadata:uri'; - return $resp; - } - - // if no scheme is specified, try https - if(!$parsedUrl->hasScheme()) - $parsedUrl->setScheme('https'); - - $resp->url = (string)$parsedUrl; - $resp->cached = false; - - $urlHash = $parsedUrl->calculateHash(false); - $cacheKey = sprintf('uiharu:metadata:%s', $urlHash); - - $cacheResp = $this->cache->get($cacheKey); - if(is_string($cacheResp)) { - $cacheResp = json_decode($cacheResp); - if($cacheResp !== null) { - $resp = $cacheResp; - $resp->cached = true; - } - } - - if(empty($resp->type)) { - $lookup = $this->ctx->matchLookup($parsedUrl); - - if($lookup !== null) - try { - $result = $lookup->lookup($parsedUrl); - - $resp->type = $result->getObjectType(); - - if($result->hasMediaType()) - $resp->content_type = MediaTypeExts::toV1($result->getMediaType()); - if($result->hasColour()) { - $colour = $result->getColour(); - if($colour->getAlpha() < 1.0) - $colour = new ColourRgb( - $colour->getRed(), - $colour->getGreen(), - $colour->getBlue() - ); - - $resp->color = (string)$colour; - } - if($result->hasTitle()) - $resp->title = $result->getTitle(); - if($result->hasSiteName()) - $resp->site_name = $result->getSiteName(); - if($result->hasDescription()) - $resp->description = $result->getDescription(); - if($result->hasPreviewImage()) - $resp->image = $result->getPreviewImage(); - - if($result instanceof YouTubeLookupResult) { - $resp->youtube_video_id = $result->getYouTubeVideoId(); - - if($result->hasYouTubeVideoStartTime()) - $resp->youtube_start_time = $result->getYouTubeVideoStartTime(); - if($result->hasYouTubePlayListId()) - $resp->youtube_playlist = $result->getYouTubePlayListId(); - if($result->hasYouTubePlayListIndex()) - $resp->youtube_playlist_index = $result->getYouTubePlayListIndex(); - - if(UIH_DEBUG) { - $resp->dbg_youtube_info = $result->getYouTubeVideoInfo(); - $resp->dbg_youtube_query = $result->getYouTubeUrlQuery(); - } - } - - if($result instanceof NicoNicoLookupResult) { - $resp->nicovideo_video_id = $result->getNicoNicoVideoId(); - - if($result->hasNicoNicoVideoStartTime()) - $resp->nicovideo_start_time = $result->getNicoNicoVideoStartTime(); - - if(UIH_DEBUG) { - $resp->dbg_nicovideo_thumb_info = $result->getNicoNicoThumbInfo()->ownerDocument->saveXML(); - $resp->dbg_nicovideo_query = $result->getNicoNicoUrlQuery(); - } - } - - if($result instanceof IHasMediaInfo) { - if($result->isMedia()) { - $resp->is_image = $result->isImage(); - $resp->is_audio = $result->isAudio(); - $resp->is_video = $result->isVideo(); - - if($result->hasDimensions()) { - $resp->width = $result->getWidth(); - $resp->height = $result->getHeight(); - } - - $resp->media = new stdClass; - $resp->media->confidence = $result->getConfidence(); - - if($result->hasAspectRatio()) - $resp->media->aspect_ratio = $result->getAspectRatio(); - if($result->hasDuration()) - $resp->media->duration = $result->getDuration(); - if($result->hasSize()) - $resp->media->size = $result->getSize(); - if($result->hasBitRate()) - $resp->media->bitrate = $result->getBitRate(); - - if($result->hasAudioTags()) { - $audioTags = $result->getAudioTags(); - $resp->media->tags = new stdClass; - if($audioTags->hasTitle()) - $resp->media->tags->title = $audioTags->getTitle(); - if($audioTags->hasArtist()) - $resp->media->tags->artist = $audioTags->getArtist(); - if($audioTags->hasAlbum()) - $resp->media->tags->album = $audioTags->getAlbum(); - if($audioTags->hasDate()) - $resp->media->tags->date = $audioTags->getDate(); - if($audioTags->hasComment()) - $resp->media->tags->comment = $audioTags->getComment(); - if($audioTags->hasGenre()) - $resp->media->tags->genre = $audioTags->getGenre(); - } - } - - if($result instanceof EEPROMLookupResult) { - $resp->eeprom_file_id = $result->getEEPROMId(); - $resp->eeprom_file_info = $result->getEEPROMInfo(); - } - - if(UIH_DEBUG && $result->hasMediaInfo()) - $resp->dbg_media_info = $result->getMediaInfo(); - } - } catch(Exception $ex) { - $resp->status = 500; - $resp->error = 'metadata:lookup'; - if(UIH_DEBUG) { - $resp->dbg_msg = $ex->getMessage(); - $resp->dbg_ex = (string)$ex; - } - return $resp; - } - - $sw->stop(); - $resp->took = $sw->getElapsedTime() / 1000; - $respJson = json_encode($resp); - - $this->cache->set($cacheKey, $respJson, 10 * 60); - } - - if(!empty($respJson)) - return $respJson; - - return $resp; - } - - private function handleMetadata($response, $request, string $targetUrl) { - $result = $this->metadataLookup($targetUrl); - if(is_int($result)) - return $result; - - if(is_object($result)) { - if(!empty($result->status)) - $response->setStatusCode($result->status); - } elseif(is_string($result)) { - $response->setTypeJson(); - } - - return $result; - } - - private function handleMetadataBatch($response, $request, array $urls) { - $sw = Stopwatch::startNew(); - - if(count($urls) > 20) - return 400; - - $handled = []; - $results = []; - - foreach($urls as $url) { - if(!is_string($url)) - continue; - - $cleanUrl = trim($url, '/?&# '); - if(in_array($cleanUrl, $handled)) - continue; - $handled[] = $cleanUrl; - - $result = $this->metadataLookup($url); - if(is_int($result)) { - $status = $result; - $result = new stdClass; - $result->status = $status; - $result->error = 'batch:status'; - } elseif(is_string($result)) { - $result = json_decode($result); - } - - $results[] = [ - 'url' => $url, - 'info' => $result, - ]; - } - - $sw->stop(); - - return [ - 'took' => $sw->getElapsedTime() / 1000, - 'results' => $results, - ]; - } -} diff --git a/src/AudioTags.php b/src/AudioTags.php deleted file mode 100644 index 2c5b425..0000000 --- a/src/AudioTags.php +++ /dev/null @@ -1,66 +0,0 @@ -title !== ''; - } - public function getTitle(): string { - return $this->title; - } - - public function hasArtist(): bool { - return $this->artist !== ''; - } - public function getArtist(): string { - return $this->artist; - } - - public function hasAlbum(): bool { - return $this->album !== ''; - } - public function getAlbum(): string { - return $this->album; - } - - public function hasDate(): bool { - return $this->date !== ''; - } - public function getDate(): string { - return $this->date; - } - - public function hasComment(): bool { - return $this->comment !== ''; - } - public function getComment(): string { - return $this->comment; - } - - public function hasGenre(): bool { - return $this->genre !== ''; - } - public function getGenre(): string { - return $this->genre; - } - - public static function fromMediaInfo(object $obj): AudioTags { - return new AudioTags( - $obj->tagTitle ?? '', - $obj->tagArtist ?? '', - $obj->tagAlbum ?? '', - $obj->tagDate ?? '', - $obj->tagComment ?? '', - $obj->tagGenre ?? '', - ); - } -} diff --git a/src/FFMPEG.php b/src/FFMPEG.php deleted file mode 100644 index e310cf8..0000000 --- a/src/FFMPEG.php +++ /dev/null @@ -1,175 +0,0 @@ -/dev/null -', escapeshellarg($url)), 'rb'); - return stream_get_contents($file); - } finally { - if(isset($file) && is_resource($file)) - pclose($file); - } - } - - public static function grabFirstAudioCover(string $url): string { - try { - $file = popen(sprintf('ffmpeg -i %s -an -f image2pipe -c:v copy -frames:v 1 2>/dev/null -', escapeshellarg($url)), 'rb'); - return stream_get_contents($file); - } finally { - if(isset($file) && is_resource($file)) - pclose($file); - } - } - - public static function probe(string $url): ?object { - $command = sprintf( - 'ffprobe -show_streams -show_format -print_format json -v quiet -i %s', - escapeshellarg($url) - ); - - $ffprobe = proc_open($command, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes); - if(!is_resource($ffprobe)) - throw new RuntimeException('Could not open ffprobe.'); - - try { - $stderr = trim(stream_get_contents($pipes[2])); - if(!empty($stderr)) - throw new RuntimeException('ffprobe: ' . $stderr); - - $stdout = trim(stream_get_contents($pipes[1])); - if(empty($stdout)) - throw new RuntimeException('ffprobe did not report any errors but exited without any output'); - } finally { - proc_close($ffprobe); - } - - return json_decode($stdout); - } - - public static function cleanProbe(string $url): ?object { - return self::cleanProbeResult(self::probe($url)); - } - - public static function cleanProbeResult(?object $in): object { - $out = new stdClass; - - if(!empty($in->format)) { - $out->confidence = empty($in->format->probe_score) ? 0 : (intval($in->format->probe_score) / 100); - - if(!empty($in->format->duration)) - $out->duration = floatval($in->format->duration); - - if(!empty($in->format->size)) - $out->size = intval($in->format->size); - - if(!empty($in->format->bit_rate)) - $out->bitRate = intval($in->format->bit_rate); - - if(!empty($in->format->tags)) { - if(!empty($in->format->tags->title)) { - $out->tagTitle = $in->format->tags->title; - } elseif(!empty($in->format->tags->TITLE)) { - $out->tagTitle = $in->format->tags->TITLE; - } elseif(!empty($in->format->tags->Title)) { - $out->tagTitle = $in->format->tags->Title; - } - - if(!empty($in->format->tags->artist)) { - $out->tagArtist = $in->format->tags->artist; - } elseif(!empty($in->format->tags->ARTIST)) { - $out->tagArtist = $in->format->tags->ARTIST; - } elseif(!empty($in->format->tags->Artist)) { - $out->tagArtist = $in->format->tags->Artist; - } - - if(!empty($in->format->tags->album)) { - $out->tagAlbum = $in->format->tags->album; - } elseif(!empty($in->format->tags->ALBUM)) { - $out->tagAlbum = $in->format->tags->ALBUM; - } elseif(!empty($in->format->tags->Album)) { - $out->tagAlbum = $in->format->tags->Album; - } - - if(!empty($in->format->tags->date)) { - $out->tagDate = $in->format->tags->date; - } elseif(!empty($in->format->tags->DATE)) { - $out->tagDate = $in->format->tags->DATE; - } elseif(!empty($in->format->tags->Date)) { - $out->tagDate = $in->format->tags->Date; - } - - if(!empty($in->format->tags->comment)) { - $out->tagComment = $in->format->tags->comment; - } elseif(!empty($in->format->tags->COMMENT)) { - $out->tagComment = $in->format->tags->COMMENT; - } elseif(!empty($in->format->tags->Comment)) { - $out->tagComment = $in->format->tags->Comment; - } - - if(!empty($in->format->tags->genre)) { - $out->tagGenre = $in->format->tags->genre; - } elseif(!empty($in->format->tags->GENRE)) { - $out->tagGenre = $in->format->tags->GENRE; - } elseif(!empty($in->format->tags->Genre)) { - $out->tagGenre = $in->format->tags->Genre; - } - } - } - - if(!empty($in->streams)) - foreach($in->streams as $stream) { - $codecType = $stream->codec_type ?? null; - - if($codecType === 'video') { - $out->width = intval($stream->coded_width ?? $stream->width ?? -1); - $out->height = intval($stream->coded_height ?? $stream->height ?? -1); - - if(!empty($stream->display_aspect_ratio)) - $out->aspectRatio = $stream->display_aspect_ratio; - } elseif($codecType === 'audio') { - if(!empty($stream->tags->title)) { - $out->tagTitle = $stream->tags->title; - } elseif(!empty($stream->tags->TITLE)) { - $out->tagTitle = $stream->tags->TITLE; - } - - if(!empty($stream->tags->artist)) { - $out->tagArtist = $stream->tags->artist; - } elseif(!empty($stream->tags->ARTIST)) { - $out->tagArtist = $stream->tags->ARTIST; - } - - if(!empty($stream->tags->album)) { - $out->tagAlbum = $stream->tags->album; - } elseif(!empty($stream->tags->ALBUM)) { - $out->tagAlbum = $stream->tags->ALBUM; - } - - if(!empty($stream->tags->date)) { - $out->tagDate = $stream->tags->date; - } elseif(!empty($stream->tags->DATE)) { - $out->tagDate = $stream->tags->DATE; - } - - if(!empty($stream->tags->comment)) { - $out->tagComment = $stream->tags->comment; - } elseif(!empty($stream->tags->COMMENT)) { - $out->tagComment = $stream->tags->COMMENT; - } - - if(!empty($stream->tags->genre)) { - $out->tagGenre = $stream->tags->genre; - } elseif(!empty($stream->tags->GENRE)) { - $out->tagGenre = $stream->tags->GENRE; - } - } - } - - return $out; - } -} diff --git a/src/IApi.php b/src/IApi.php deleted file mode 100644 index 3c9177d..0000000 --- a/src/IApi.php +++ /dev/null @@ -1,8 +0,0 @@ -getHost()); - return $url->getScheme() === $this->protocol || ( - $url->isWeb() && ( - in_array($urlHost, $this->shortDomains) || ( - $urlHost === $this->apiDomain && str_starts_with($url->getPath(), '/uploads') - ) - ) - ); - } - - private function rawLookup(string $fileId): ?object { - $curl = curl_init("https://{$this->apiDomain}/uploads/{$fileId}.json"); - curl_setopt_array($curl, [ - CURLOPT_AUTOREFERER => false, - CURLOPT_CERTINFO => false, - CURLOPT_FAILONERROR => false, - CURLOPT_FOLLOWLOCATION => false, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_TCP_FASTOPEN => true, - CURLOPT_CONNECTTIMEOUT => 2, - CURLOPT_PROTOCOLS => CURLPROTO_HTTPS, - CURLOPT_TIMEOUT => 2, - CURLOPT_USERAGENT => 'Uiharu/' . UIH_VERSION, - CURLOPT_HTTPHEADER => [ - 'Accept: application/json', - ], - ]); - $resp = curl_exec($curl); - curl_close($curl); - return json_decode($resp); - } - - public function lookup(Url $url): EEPROMLookupResult { - if($url->getScheme() === $this->protocol) { - $fileId = $url->getPath(); - } elseif($url->isWeb()) { - if($url->getHost() === $this->apiDomain) { - if(preg_match('#^/uploads/([A-Za-z0-9-_]+)/?$#', $url->getPath(), $matches)) - $fileId = $matches[1]; - } else { - $fileId = substr($url->getPath(), 1); - } - } - - if(!isset($fileId)) - throw new RuntimeException('Was unable to find EEPROM file id.'); - if(!preg_match('#^([A-Za-z0-9-_]+)$#', $fileId)) - throw new RuntimeException('Invalid EEPROM file id format.'); - - $fileInfo = $this->rawLookup($fileId); - if($fileInfo === null) - throw new RuntimeException('EEPROM file does not exist: ' . $fileId); - - $url = Url::parse('https://' . $this->shortDomains[0] . '/' . $fileId); - $mediaType = MediaType::parse($fileInfo->type); - $isMedia = MediaTypeExts::isMedia($mediaType); - $mediaInfo = $isMedia ? FFMPEG::cleanProbe($url) : null; - - return new EEPROMLookupResult($url, $mediaType, $fileInfo, $mediaInfo); - } -} diff --git a/src/Lookup/EEPROMLookupResult.php b/src/Lookup/EEPROMLookupResult.php deleted file mode 100644 index 3e940d5..0000000 --- a/src/Lookup/EEPROMLookupResult.php +++ /dev/null @@ -1,173 +0,0 @@ -url = $url; - $this->type = $type; - $this->fileInfo = $fileInfo; - $this->mediaInfo = $mediaInfo; - - if($this->isAudio() && $mediaInfo !== null) - $this->audioTags = AudioTags::fromMediaInfo($mediaInfo); - else - $this->audioTags = null; - } - - public function getUrl(): Url { - return $this->url; - } - public function getObjectType(): string { - return 'eeprom:file'; - } - - public function hasMediaType(): bool { - return true; - } - public function getMediaType(): MediaType { - return $this->type; - } - - public function getEEPROMId(): string { - return $this->fileInfo->id; - } - public function getEEPROMInfo(): object { - return $this->fileInfo; - } - - public function hasColour(): bool { - return true; - } - public function getColour(): Colour { - return ColourRgb::fromRawRgb(0x8559A5); - } - - public function hasTitle(): bool { - return true; - } - public function getTitle(): string { - if($this->audioTags !== null) { - $title = ''; - - if($this->audioTags->hasArtist()) - $title .= $this->audioTags->getArtist() . ' - '; - - if($this->audioTags->hasTitle()) - $title .= $this->audioTags->getTitle(); - - if($this->audioTags->hasDate()) - $title .= ' (' . $this->audioTags->getDate() . ')'; - - if(!empty($title)) - return $title; - } - - return $this->fileInfo->name; - } - - public function hasSiteName(): bool { - return true; - } - public function getSiteName(): string { - return 'EEPROM'; - } - - public function hasDescription(): bool { - return $this->audioTags !== null && $this->audioTags->hasComment(); - } - public function getDescription(): string { - return $this->audioTags->getComment(); - } - - public function hasPreviewImage(): bool { - return true; - } - public function getPreviewImage(): string { - return $this->fileInfo->thumb; - } - - public function getConfidence(): float { - return $this->mediaInfo->confidence ?? 0; - } - - public function isMedia(): bool { - return $this->mediaInfo !== null; - } - public function isImage(): bool { - return $this->type->matchCategory('image'); - } - public function isVideo(): bool { - return $this->type->matchCategory('video'); - } - public function isAudio(): bool { - return $this->type->matchCategory('audio'); - } - - public function hasDimensions(): bool { - return $this->isImage() || $this->isVideo(); - } - public function getWidth(): int { - return $this->mediaInfo->width ?? 0; - } - public function getHeight(): int { - return $this->mediaInfo->height ?? 0; - } - - public function hasAspectRatio(): bool { - return isset($this->mediaInfo->aspectRatio); - } - public function getAspectRatio(): string { - return $this->mediaInfo->aspectRatio; - } - - public function hasDuration(): bool { - return isset($this->mediaInfo->duration); - } - public function getDuration(): float { - return $this->mediaInfo->duration; - } - - public function hasSize(): bool { - return isset($this->mediaInfo->size); - } - public function getSize(): int { - return $this->mediaInfo->size; - } - - public function hasBitRate(): bool { - return isset($this->mediaInfo->bitRate); - } - public function getBitRate(): int { - return $this->mediaInfo->bitRate; - } - - public function hasAudioTags(): bool { - return $this->audioTags !== null; - } - public function getAudioTags(): AudioTags { - return $this->audioTags; - } - - public function hasMediaInfo(): bool { - return $this->mediaInfo !== null; - } - public function getMediaInfo(): object { - return $this->mediaInfo; - } -} diff --git a/src/Lookup/NicoNicoLookup.php b/src/Lookup/NicoNicoLookup.php deleted file mode 100644 index f7d69f5..0000000 --- a/src/Lookup/NicoNicoLookup.php +++ /dev/null @@ -1,92 +0,0 @@ -isWeb()) - return false; - - $urlHost = strtolower($url->getHost()); - - if(self::isShortDomain($urlHost)) - return true; - - if(self::isLongDomain($urlHost) && str_starts_with($url->getPath(), '/watch/sm')) - return true; - - return false; - } - - public function lookup(Url $url): NicoNicoLookupResult { - if(self::isShortDomain($url->getHost())) - $videoId = explode('/', trim($url->getPath(), '/'))[0] ?? ''; - else - $videoId = explode('/', trim($url->getPath(), '/'))[1] ?? ''; - - if(empty($videoId)) - throw new RuntimeException('Nico Nico Douga video id missing.'); - - $thumbDoc = self::lookupThumbInfo($videoId); - - $thumbResp = $thumbDoc->getElementsByTagName('nicovideo_thumb_response')[0] ?? null; - if(empty($thumbResp) || !$thumbResp->hasAttribute('status') || $thumbResp->getAttribute('status') !== 'ok') - throw new RuntimeException('Nico Nico Douga video with the given id could not be found.'); - - $thumbInfo = $thumbResp->getElementsByTagName('thumb')[0] ?? null; - if(empty($thumbInfo)) - throw new RuntimeException('Nico Nico Douga thumb info missing from API result????'); - - parse_str($url->getQuery(), $urlQuery); - - return new NicoNicoLookupResult($url, $videoId, $thumbInfo, $urlQuery); - } - - private static function lookupThumbInfo(string $videoId): DOMDocument { - $curl = curl_init("https://ext.nicovideo.jp/api/getthumbinfo/{$videoId}"); - curl_setopt_array($curl, [ - CURLOPT_AUTOREFERER => false, - CURLOPT_CERTINFO => false, - CURLOPT_FAILONERROR => false, - CURLOPT_FOLLOWLOCATION => false, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_TCP_FASTOPEN => true, - CURLOPT_CONNECTTIMEOUT => 2, - CURLOPT_PROTOCOLS => CURLPROTO_HTTPS, - CURLOPT_TIMEOUT => 3, - CURLOPT_USERAGENT => 'Uiharu/' . UIH_VERSION, - ]); - $resp = curl_exec($curl); - curl_close($curl); - - if(empty($resp)) - throw new RuntimeException('Nico Nico Douga API request failed.'); - - $doc = new DOMDocument; - if(!$doc->loadXML($resp)) - throw new RuntimeException('Failed to parse Nico Nico Douga API response.'); - - return $doc; - } -} diff --git a/src/Lookup/NicoNicoLookupResult.php b/src/Lookup/NicoNicoLookupResult.php deleted file mode 100644 index b6c1f3e..0000000 --- a/src/Lookup/NicoNicoLookupResult.php +++ /dev/null @@ -1,92 +0,0 @@ -url; - } - public function getObjectType(): string { - return 'niconico:video'; - } - - public function getNicoNicoVideoId(): string { - return $this->videoId; - } - public function getNicoNicoThumbInfo(): DOMElement { - return $this->thumbInfo; - } - public function getNicoNicoUrlQuery(): array { - return $this->urlQuery; - } - - public function hasNicoNicoVideoStartTime(): bool { - return isset($this->urlQuery['from']); - } - public function getNicoNicoVideoStartTime(): string { - return $this->urlQuery['from'] ?? ''; - } - - public function hasMediaType(): bool { - return false; - } - public function getMediaType(): MediaType { - throw new RuntimeException('Unsupported'); - } - - public function hasColour(): bool { - return true; - } - public function getColour(): Colour { - return ColourRgb::fromRawRgb(0x252525); - } - - public function hasTitle(): bool { - if($this->title === null) - $this->title = $this->thumbInfo->getElementsByTagName('title')[0] ?? false; - return $this->title !== false; - } - public function getTitle(): string { - return $this->hasTitle() ? trim($this->title->textContent) : 'No Title'; - } - - public function hasSiteName(): bool { - return true; - } - public function getSiteName(): string { - return 'ニコニコ動画'; - } - - public function hasDescription(): bool { - if($this->description === null) - $this->description = $this->thumbInfo->getElementsByTagName('description')[0] ?? false; - return $this->description !== false && !empty($this->description->textContent); - } - public function getDescription(): string { - return $this->hasDescription() ? trim($this->description->textContent) : ''; - } - - public function hasPreviewImage(): bool { - if($this->previewImage === null) - $this->previewImage = $this->thumbInfo->getElementsByTagName('thumbnail_url')[0] ?? false; - return $this->previewImage !== false && !empty($this->previewImage->textContent); - } - public function getPreviewImage(): string { - return $this->hasPreviewImage() ? (trim($this->previewImage->textContent) . '.L') : ''; - } -} diff --git a/src/Lookup/WebLookup.php b/src/Lookup/WebLookup.php deleted file mode 100644 index fd5f481..0000000 --- a/src/Lookup/WebLookup.php +++ /dev/null @@ -1,177 +0,0 @@ -isWeb(); - } - - private static function reqCreate(string $url) { - $curl = curl_init($url); - curl_setopt_array($curl, [ - CURLOPT_AUTOREFERER => true, - CURLOPT_CERTINFO => false, - CURLOPT_FAILONERROR => false, - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_MAXREDIRS => 5, - CURLOPT_PATH_AS_IS => true, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_TCP_FASTOPEN => true, - CURLOPT_CONNECTTIMEOUT => 2, - CURLOPT_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS, - CURLOPT_REDIR_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS, - CURLOPT_TIMEOUT => 5, - CURLOPT_DEFAULT_PROTOCOL => 'https', - CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; FlashiiBot/2.5; Uiharu/' . UIH_VERSION . '; +http://fii.moe/uiharu)', - CURLOPT_HTTPHEADER => [ - 'Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8', - 'Accept-Language: en-GB, en;q=0.9, ja-jp;q=0.6, *;q=0.5', - ], - ]); - return $curl; - } - - private static function reqHead($curl): array|null { - curl_setopt_array($curl, [ - CURLOPT_NOBODY => true, - CURLOPT_HEADER => true, - ]); - - $headers = curl_exec($curl); - if($headers === false) - return null; - - $headers = explode("\r\n", trim($headers)); - $status = 200; - $lines = []; - - foreach($headers as $header) { - if(empty($header)) - continue; - - if(strpos($header, ':') === false) { - $headParts = explode(' ', $header); - if(isset($headParts[1]) && is_numeric($headParts[1])) - $status = (int)$headParts[1]; - $lines = []; - continue; - } - - $parts = explode(':', $header, 2); - $parts[0] = mb_strtolower($parts[0]); - if(isset($lines[$parts[0]])) - $lines[$parts[0]] .= ', ' . trim($parts[1] ?? ''); - else - $lines[$parts[0]] = trim($parts[1] ?? ''); - } - - return compact('status', 'lines'); - } - - private static function reqBody($curl): string|false { - curl_setopt_array($curl, [ - CURLOPT_NOBODY => false, - CURLOPT_HEADER => false, - ]); - - return curl_exec($curl); - } - - private static function reqError($curl): string { - return curl_error($curl); - } - - private static function reqClose($curl): void { - curl_close($curl); - } - - public function lookup(Url $url): WebLookupResult { - $req = self::reqCreate($url); - $head = self::reqHead($req); - - if($head === null) - throw new RuntimeException('Web request timed out: ' . self::reqError($req)); - - $mediaType = MediaType::parse('application/octet-stream'); - $hasContentType = array_key_exists('content-type', $head['lines']); - - if($hasContentType) { - try { - $mediaType = MediaType::parse($head['lines']['content-type'] ?? ''); - } catch(InvalidArgumentException $ex) {} - - if(MediaTypeExts::isMedia($mediaType)) { - self::reqClose($req); - return $this->lookupMedia($url, $mediaType); - } - } - - $body = self::reqBody($req); - self::reqClose($req); - - if(!$hasContentType) - try { - $finfo = new finfo(FILEINFO_MIME); - $mediaType = MediaType::parse($finfo->buffer($body)); - } catch(InvalidArgumentException $ex) {} - - if($mediaType->equals('text/html') - || $mediaType->equals('application/xhtml+xml') - || $mediaType->equals('application/xml')) - return $this->lookupSite($url, $req, $mediaType, $body); - - return new WebLookupFallbackResult($url, $mediaType, $url->getHost() . ': ' . basename($url->getPath())); - } - - private function lookupSite(Url $url, $req, MediaType $mediaType, string $body): WebLookupResult { - // ok hear me out - // there's absolutely no good html scraping libraries for PHP - // DOMDocument Exists but kinda blows at catching weird encoding events like with pixiv - // and i'm not about to rewrite this whole fucking thing in nodejs - // also at this point Index should probably provide a wrapper for proc_open lol - $extract = proc_open( - sprintf('node %s/extract.mjs', UIH_ROOT), - [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']], - $pipes - ); - if(!is_resource($extract)) - throw new RuntimeException('Could not open extract.'); - - try { - fwrite($pipes[0], $body); - fclose($pipes[0]); - - $stderr = trim(stream_get_contents($pipes[2])); - if(!empty($stderr)) - throw new RuntimeException('extract: ' . $stderr); - - $stdout = trim(stream_get_contents($pipes[1])); - if(empty($stdout)) - throw new RuntimeException('extract did not report any errors but exited without any output'); - } finally { - proc_close($extract); - } - - $siteInfo = json_decode($stdout); - if(empty($siteInfo)) - throw new RuntimeException('Failed to parse extract output.'); - - return new WebLookupSiteResult($url, $mediaType, $siteInfo); - } - - private function lookupMedia(Url $url, MediaType $mediaType): WebLookupResult { - $mediaInfo = FFMPEG::cleanProbe($url); - return new WebLookupMediaResult($url, $mediaType, $mediaInfo); - } -} diff --git a/src/Lookup/WebLookupFallbackResult.php b/src/Lookup/WebLookupFallbackResult.php deleted file mode 100644 index 1591a4a..0000000 --- a/src/Lookup/WebLookupFallbackResult.php +++ /dev/null @@ -1,55 +0,0 @@ -title = $title; - } - - public function getObjectType(): string { - return 'unknown'; - } - - public function hasColour(): bool { - return false; - } - public function getColour(): Colour { - throw new RuntimeException('Unsupported.'); - } - - public function hasTitle(): bool { - return true; - } - public function getTitle(): string { - return $this->title; - } - - public function hasSiteName(): bool { - return false; - } - public function getSiteName(): string { - throw new RuntimeException('Unsupported.'); - } - - public function hasDescription(): bool { - return false; - } - public function getDescription(): string { - throw new RuntimeException('Unsupported.'); - } - - public function hasPreviewImage(): bool { - return false; - } - public function getPreviewImage(): string { - throw new RuntimeException('Unsupported.'); - } -} diff --git a/src/Lookup/WebLookupMediaResult.php b/src/Lookup/WebLookupMediaResult.php deleted file mode 100644 index 62e1572..0000000 --- a/src/Lookup/WebLookupMediaResult.php +++ /dev/null @@ -1,152 +0,0 @@ -mediaInfo = $mediaInfo; - - if($this->isAudio() && $mediaInfo !== null) - $this->audioTags = AudioTags::fromMediaInfo($mediaInfo); - else - $this->audioTags = null; - } - - public function getObjectType(): string { - return 'media'; - } - - public function hasColour(): bool { - return false; - } - public function getColour(): Colour { - throw new RuntimeException('Unsupported'); - } - - public function hasTitle(): bool { - return true; - } - public function getTitle(): string { - if($this->audioTags !== null) { - $title = ''; - - if($this->audioTags->hasArtist()) - $title .= $this->audioTags->getArtist() . ' - '; - - if($this->audioTags->hasTitle()) - $title .= $this->audioTags->getTitle(); - - if($this->audioTags->hasDate()) - $title .= ' (' . $this->audioTags->getDate() . ')'; - - if(!empty($title)) - return $title; - } - - return rawurldecode(basename($this->url->getPath())); - } - - public function hasSiteName(): bool { - return true; - } - public function getSiteName(): string { - return $this->url->getHost(); - } - - public function hasDescription(): bool { - return $this->audioTags !== null && $this->audioTags->hasComment(); - } - public function getDescription(): string { - return $this->audioTags->getComment(); - } - - public function hasPreviewImage(): bool { - return $this->isImage() || $this->isVideo() || $this->isAudio(); - } - public function getPreviewImage(): string { - $url = (string)$this->url; - if($this->isVideo()) - return '//' . $_SERVER['HTTP_HOST'] . '/metadata/thumb/video?url=' . rawurlencode($url); - if($this->isAudio()) - return '//' . $_SERVER['HTTP_HOST'] . '/metadata/thumb/audio?url=' . rawurlencode($url); - - return $url; - } - - public function getConfidence(): float { - return $this->mediaInfo->confidence; - } - - public function isMedia(): bool { - return true; - } - public function isImage(): bool { - return $this->mediaType->matchCategory('image'); - } - public function isVideo(): bool { - return $this->mediaType->matchCategory('video'); - } - public function isAudio(): bool { - return $this->mediaType->matchCategory('audio'); - } - - public function hasDimensions(): bool { - return $this->isImage() || $this->isVideo(); - } - public function getWidth(): int { - return $this->mediaInfo->width ?? 0; - } - public function getHeight(): int { - return $this->mediaInfo->height ?? 0; - } - - public function hasAspectRatio(): bool { - return isset($this->mediaInfo->aspectRatio); - } - public function getAspectRatio(): string { - return $this->mediaInfo->aspectRatio; - } - - public function hasDuration(): bool { - return isset($this->mediaInfo->duration); - } - public function getDuration(): float { - return $this->mediaInfo->duration; - } - - public function hasSize(): bool { - return isset($this->mediaInfo->size); - } - public function getSize(): int { - return $this->mediaInfo->size; - } - - public function hasBitRate(): bool { - return isset($this->mediaInfo->bitRate); - } - public function getBitRate(): int { - return $this->mediaInfo->bitRate; - } - - public function hasAudioTags(): bool { - return $this->audioTags !== null; - } - public function getAudioTags(): AudioTags { - return $this->audioTags; - } - - public function hasMediaInfo(): bool { - return true; - } - public function getMediaInfo(): object { - return $this->mediaInfo; - } -} diff --git a/src/Lookup/WebLookupResult.php b/src/Lookup/WebLookupResult.php deleted file mode 100644 index a82fd73..0000000 --- a/src/Lookup/WebLookupResult.php +++ /dev/null @@ -1,44 +0,0 @@ -url = $url; - $this->mediaType = $mediaType; - } - - public function getUrl(): Url { - return $this->url; - } - - public abstract function getObjectType(): string; - - public function hasMediaType(): bool { - return true; - } - public function getMediaType(): MediaType { - return $this->mediaType; - } - - public abstract function hasColour(): bool; - public abstract function getColour(): Colour; - - public abstract function hasTitle(): bool; - public abstract function getTitle(): string; - - public abstract function hasSiteName(): bool; - public abstract function getSiteName(): string; - - public abstract function hasDescription(): bool; - public abstract function getDescription(): string; - - public abstract function hasPreviewImage(): bool; - public abstract function getPreviewImage(): string; -} diff --git a/src/Lookup/WebLookupSiteResult.php b/src/Lookup/WebLookupSiteResult.php deleted file mode 100644 index 63bf5ce..0000000 --- a/src/Lookup/WebLookupSiteResult.php +++ /dev/null @@ -1,62 +0,0 @@ -siteInfo = $siteInfo; - } - - public function getObjectType(): string { - return $this->siteInfo->type; - } - - public function hasColour(): bool { - return !empty($this->siteInfo->colour); - } - public function getColour(): Colour { - return Colour::parse($this->siteInfo->colour); - } - - public function hasTitle(): bool { - return true; - } - public function getTitle(): string { - if(!empty($this->siteInfo->metaTitle)) - return $this->siteInfo->metaTitle; - if(!empty($this->siteInfo->title)) - return $this->siteInfo->title; - return $this->siteInfo->siteName; - } - - public function hasSiteName(): bool { - return !empty($this->siteInfo->siteName); - } - public function getSiteName(): string { - return $this->siteInfo->siteName; - } - - public function hasDescription(): bool { - return !empty($this->siteInfo->desc); - } - public function getDescription(): string { - return $this->siteInfo->desc; - } - - public function hasPreviewImage(): bool { - return !empty($this->siteInfo->image); - } - public function getPreviewImage(): string { - return $this->siteInfo->image; - } - - public function getWebSiteInfo(): object { - return $this->siteInfo; - } -} diff --git a/src/Lookup/YouTubeLookup.php b/src/Lookup/YouTubeLookup.php deleted file mode 100644 index 58316cd..0000000 --- a/src/Lookup/YouTubeLookup.php +++ /dev/null @@ -1,133 +0,0 @@ -isWeb()) - return false; - - $urlHost = strtolower($url->getHost()); - if(self::isShortDomain($urlHost)) - return true; - - $parts = array_reverse(explode('.', $urlHost)); - $partsCount = count($parts); - - if($partsCount < 2 || $partsCount > 4) - return false; - - if($parts[$partsCount - 1] === 'www') - array_pop($parts); - - if($parts[0] === 'com') { - if($parts[1] !== 'youtube' && $parts[1] !== 'youtube-nocookie') - return false; - } else { - if(array_pop($parts) !== 'youtube') - return false; - - $tld = implode('.', array_reverse($parts)); - if(!in_array($tld, self::VALID_TLDS)) - return false; - } - - $urlPath = $url->getPath(); - if($urlPath === '/watch') - return true; - - foreach(self::WATCH_PREFIXES as $prefix) - if(str_starts_with($urlPath, $prefix)) - return true; - - return false; - } - - private function lookupVideo(string $videoId): ?object { - $curl = curl_init("https://www.googleapis.com/youtube/v3/videos?part=snippet%2CcontentDetails%2Cstatistics&id={$videoId}&key=" . $this->config->getString('api_key')); - curl_setopt_array($curl, [ - CURLOPT_AUTOREFERER => false, - CURLOPT_CERTINFO => false, - CURLOPT_FAILONERROR => false, - CURLOPT_FOLLOWLOCATION => false, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_TCP_FASTOPEN => true, - CURLOPT_CONNECTTIMEOUT => 2, - CURLOPT_PROTOCOLS => CURLPROTO_HTTPS, - CURLOPT_TIMEOUT => 2, - CURLOPT_USERAGENT => 'Uiharu/' . UIH_VERSION, - CURLOPT_HTTPHEADER => [ - 'Accept: application/json', - ], - ]); - $resp = curl_exec($curl); - curl_close($curl); - return json_decode($resp); - } - - public function lookup(Url $url): YouTubeLookupResult { - $urlPath = $url->getPath(); - parse_str($url->getQuery(), $urlQuery); - - if(self::isShortDomain($url->getHost())) { - $videoId = substr($urlPath, 1); - } elseif(array_key_exists('v', $urlQuery)) { - $videoId = $urlQuery['v']; - } else { - $urlPathParts = explode('/', trim($urlPath, '/')); - if(count($urlPathParts) > 1) - $videoId = $urlPathParts[1]; - } - - if(empty($videoId)) - throw new RuntimeException('YouTube video id missing.'); - - $videoInfo = $this->lookupVideo($videoId); - if($videoInfo === null) - throw new RuntimeException('YouTube video with given id could not be found.'); - - unset($urlQuery['v']); - $url = Url::parse(trim('https://www.youtube.com/watch?v=' . $videoId . '&' . http_build_query($urlQuery), '&')); - - return new YouTubeLookupResult($url, $videoId, $videoInfo, $urlQuery); - } -} diff --git a/src/Lookup/YouTubeLookupResult.php b/src/Lookup/YouTubeLookupResult.php deleted file mode 100644 index 46d4b42..0000000 --- a/src/Lookup/YouTubeLookupResult.php +++ /dev/null @@ -1,96 +0,0 @@ -url; - } - public function getObjectType(): string { - return 'youtube:video'; - } - - public function getYouTubeVideoId(): string { - return $this->videoId; - } - public function getYouTubeVideoInfo(): object { - return $this->videoInfo; - } - public function getYouTubeUrlQuery(): array { - return $this->urlQuery; - } - - public function hasYouTubeVideoStartTime(): bool { - return isset($this->urlQuery['t']); - } - public function getYouTubeVideoStartTime(): string { - return $this->urlQuery['t'] ?? ''; - } - - public function hasYouTubePlayListId(): bool { - return isset($this->urlQuery['list']); - } - public function getYouTubePlayListId(): string { - return $this->urlQuery['list'] ?? ''; - } - - public function hasYouTubePlayListIndex(): bool { - return isset($this->urlQuery['index']); - } - public function getYouTubePlayListIndex(): string { - return $this->urlQuery['index'] ?? ''; - } - - public function hasMediaType(): bool { - return false; - } - public function getMediaType(): MediaType { - throw new RuntimeException('Unsupported'); - } - - public function hasColour(): bool { - return true; - } - public function getColour(): Colour { - return ColourRgb::fromRawRgb(0xFF0000); - } - - public function hasTitle(): bool { - return !empty($this->videoInfo->items[0]->snippet->title); - } - public function getTitle(): string { - return $this->videoInfo->items[0]->snippet->title; - } - - public function hasSiteName(): bool { - return true; - } - public function getSiteName(): string { - return 'YouTube'; - } - - public function hasDescription(): bool { - return !empty($this->videoInfo->items[0]->snippet->description); - } - public function getDescription(): string { - return $this->videoInfo->items[0]->snippet->description; - } - - public function hasPreviewImage(): bool { - return !empty($this->videoInfo->items[0]->snippet->thumbnails->medium->url); - } - public function getPreviewImage(): string { - return $this->videoInfo->items[0]->snippet->thumbnails->medium->url; - } -} diff --git a/src/MediaTypeExts.php b/src/MediaTypeExts.php deleted file mode 100644 index 8322bb8..0000000 --- a/src/MediaTypeExts.php +++ /dev/null @@ -1,28 +0,0 @@ - (string)$mediaType, - 'type' => $mediaType->getCategory(), - 'subtype' => $mediaType->getKind(), - ]; - - if(!empty($suffix = $mediaType->getSuffix())) - $parts['suffix'] = $suffix; - - if(!empty($params = $mediaType->getParams())) - $parts['params'] = $params; - - return $parts; - } - - public static function isMedia(MediaType $mediaType): bool { - return $mediaType->matchCategory('image') - || $mediaType->matchCategory('audio') - || $mediaType->matchCategory('video'); - } -} diff --git a/src/UihContext.php b/src/UihContext.php deleted file mode 100644 index 1d50af5..0000000 --- a/src/UihContext.php +++ /dev/null @@ -1,99 +0,0 @@ -cache = $cache; - $this->config = $config; - } - - public function getCache(): CacheProvider { - return $this->cache; - } - - public function getRouter(): HttpRouter { - return $this->router; - } - - public function isOriginAllowed(string $origin): bool { - $origin = mb_strtolower(parse_url($origin, PHP_URL_HOST)); - - if($origin === $_SERVER['HTTP_HOST']) - return true; - - $allowed = $this->config->getArray('cors:origins'); - if(empty($allowed)) - return true; - - return in_array($origin, $allowed); - } - - public function setupHttp(): void { - $this->router = new HttpRouter; - $this->router->use('/', function($response) { - $response->setPoweredBy('Uiharu'); - }); - - $this->router->use('/', function($response, $request) { - $origin = $request->getHeaderLine('Origin'); - - if(!empty($origin)) { - if(!$this->isOriginAllowed($origin)) - return 403; - - $response->setHeader('Access-Control-Allow-Origin', $origin); - $response->setHeader('Vary', 'Origin'); - } - }); - - $this->router->use('/', function($response, $request) { - if($request->getMethod() === 'OPTIONS') { - $response->setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST'); - return 204; - } - }); - - $this->router->get('/', function($response) { - $response->accelRedirect('/index.html'); - $response->setContentType('text/html; charset=utf-8'); - }); - } - - public function dispatchHttp(): void { - $this->router->dispatch(); - } - - public function registerApi(IApi $api): void { - $this->apis[] = $api; - } - - public function matchApi(string $reqPath): void { - $reqPath = '/' . trim(parse_url($reqPath, PHP_URL_PATH), '/'); - foreach($this->apis as $api) - if($api->match($reqPath)) { - $this->router->register($api); - break; - } - } - - public function registerLookup(ILookup $lookup): void { - $this->lookups[] = $lookup; - } - - public function matchLookup(Url $url): ?ILookup { - foreach($this->lookups as $lookup) - if($lookup->match($url)) - return $lookup; - return null; - } -} diff --git a/src/Url.php b/src/Url.php deleted file mode 100644 index a3f2dd0..0000000 --- a/src/Url.php +++ /dev/null @@ -1,218 +0,0 @@ -scheme = strtolower($parts['scheme']); - if(isset($parts['host'])) - $this->host = $parts['host']; - if(isset($parts['port'])) - $this->port = $parts['port']; - if(isset($parts['user'])) - $this->user = $parts['user']; - if(isset($parts['pass'])) - $this->pass = $parts['pass']; - if(isset($parts['path'])) - $this->path = $parts['path']; - if(isset($parts['query'])) - $this->query = $parts['query']; - if(isset($parts['fragment'])) - $this->fragment = $parts['fragment']; - } - - public static function parse(string $urlString): Url { - $parts = parse_url($urlString); - if($parts === false) - throw new InvalidArgumentException('Invalid URL provided.'); - return new Url($parts); - } - - public function resetString(): void { - $this->formatted = null; - } - public function setScheme(string $scheme): void { - $this->scheme = $scheme; - $this->resetString(); - } - public function discardFragment(): void { - $this->fragment = ''; - $this->resetString(); - } - - public function hasScheme(): bool { - return $this->scheme !== ''; - } - public function hasHost(): bool { - return $this->host !== ''; - } - public function hasPort(): bool { - return $this->port !== 0; - } - public function hasUser(): bool { - return $this->user !== ''; - } - public function hasPassword(): bool { - return $this->pass !== ''; - } - public function hasPath(): bool { - return $this->path !== ''; - } - public function hasQuery(): bool { - return $this->query !== ''; - } - public function hasFragment(): bool { - return $this->fragment !== ''; - } - - public function getScheme(): string { - return $this->scheme; - } - public function getHost(): string { - return $this->host; - } - public function getPort(): int { - return $this->port; - } - public function getUser(): string { - return $this->user; - } - public function getPassword(): string { - return $this->pass; - } - public function getPath(): string { - return $this->path; - } - public function getQuery(): string { - return $this->query; - } - public function getFragment(): string { - return $this->fragment; - } - - public function hasUserInfo(): bool { - return $this->hasUser() - || $this->hasPassword(); - } - public function hasAuthority(): bool { - return $this->hasUserInfo() - || $this->hasHost(); - } - - public function getUserInfo(): string { - $userInfo = $this->user; - if($this->pass !== '') - $userInfo .= ':' . $this->pass; - return $userInfo; - } - public function getAuthority(): string { - $authority = '//'; - - if($this->hasUserInfo()) - $authority .= $this->getUserInfo() . '@'; - - $authority .= $this->host; - - if($this->port !== 0) - $authority .= ':' . $this->port; - - return $authority; - } - - public function calculateHash(bool $raw = true): string { - return hash('sha256', (string)$this, $raw); - } - - public function isHTTP(): bool { - return $this->scheme === 'http'; - } - public function isHTTPS(): bool { - return $this->scheme === 'https'; - } - public function isWeb(): bool { - return $this->scheme === 'https' - || $this->scheme === 'http'; - } - - public function __toString(): string { - if($this->formatted === null) { - $string = ''; - - if($this->hasScheme()) - $string .= $this->getScheme() . ':'; - - $hasAuthority = $this->hasAuthority(); - if($hasAuthority) - $string .= $this->getAuthority(); - - $hasPath = $this->hasPath(); - $path = $this->getPath(); - - if($hasAuthority && (!$hasPath || $path[0] !== '/')) - $string .= '/'; - elseif(!$hasAuthority && $path[1] === '/') - $path = '/' . trim($path, '/'); - - $string .= $path; - - // is all this necessary...? - if($this->hasQuery()) { - $string .= '?'; - $parts = explode('&', $this->getQuery()); - - foreach($parts as $part) { - $param = explode('=', $part, 2); - $string .= rawurlencode($param[0]); - if(isset($param[1])) - $string .= '=' . rawurlencode($param[1]); - $string .= '&'; - } - - $string = substr($string, 0, -1); - } - - if($this->hasFragment()) - $string .= '#' . rawurlencode($this->getFragment()); - - $this->formatted = $string; - } - - return $this->formatted; - } - - public function toV1(): array { - $parts = ['uri' => (string)$this]; - - if($this->hasScheme()) - $parts['scheme'] = $this->getScheme(); - if($this->hasHost()) - $parts['host'] = $this->getHost(); - if($this->hasPort()) - $parts['port'] = $this->getPort(); - if($this->hasUser()) - $parts['user'] = $this->getUser(); - if($this->hasPassword()) - $parts['pass'] = $parts['password'] = $this->getPassword(); - if($this->hasPath()) - $parts['path'] = $this->getPath(); - if($this->hasQuery()) - $parts['query'] = $this->getQuery(); - if($this->hasFragment()) - $parts['fragment'] = $this->getFragment(); - - return $parts; - } -} diff --git a/uiharu.php b/uiharu.php deleted file mode 100644 index fa11c65..0000000 --- a/uiharu.php +++ /dev/null @@ -1,37 +0,0 @@ -hasValues('sentry:dsn')) - (function($cfg) { - \Sentry\init([ - 'dsn' => $cfg->getString('dsn'), - 'traces_sample_rate' => $cfg->getFloat('tracesRate', 0.2), - 'profiles_sample_rate' => $cfg->getFloat('profilesRate', 0.2), - ]); - - set_exception_handler(function(\Throwable $ex) { - \Sentry\captureException($ex); - }); - })($cfg->scopeTo('sentry')); - -$cache = CacheBackends::create($cfg->getString('cache:dsn', 'array:')); -$ctx = new UihContext($cache, $cfg);