From c46e1a0a5c37237b9c90f990a6c2b11c90040b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Guillot?= Date: Mon, 10 Jun 2024 13:57:50 +0200 Subject: [PATCH] - trop de trucs d'un coup... je vais faire attention ensuite ^^' --- .env | 5 + Dockerfile | 13 +- Makefile | 9 + assets/app.js | 3 + assets/controllers.json | 12 +- .../controllers/bootstrap-modal_controller.js | 21 + assets/controllers/search_controller.js | 15 + assets/controllers/table_controller.js | 24 + assets/styles/app.scss | 92 ++ compose.override.yaml | 3 - compose.yaml | 13 +- composer.json | 7 +- composer.lock | 489 +++++- config/bundles.php | 4 + config/packages/twig_component.yaml | 5 + config/routes/ux_live_component.yaml | 5 + config/services.yaml | 16 + frankenphp/conf.d/app.ini | 1 + package-lock.json | 1392 ++++++++++++++++- package.json | 4 + public/img/mangarr_logo.png | Bin 0 -> 105191 bytes public/puppeteer-script.js | 89 ++ src/Client/MangadexClient.php | 86 + src/Controller/MangaController.php | 33 +- src/Controller/TestController.php | 30 + src/Entity/Chapter.php | 67 +- src/Entity/ContentSource.php | 100 ++ src/Entity/Manga.php | 96 +- src/EventListener/ExceptionListener.php | 36 +- src/Factory/MangaFactory.php | 4 + src/Factory/PageFactory.php | 4 +- src/Interface/ClientInterface.php | 9 + src/Interface/ContentProviderInterface.php | 11 + .../MetadataProviderInterface.php} | 4 +- src/Repository/ContentSourceRepository.php | 48 + src/Repository/MangaRepository.php | 9 + src/Service/LelScansProviderService.php | 13 +- src/Service/MangaProviderFactory.php | 6 +- src/Service/MangaProviderInterface.php | 9 - src/Service/MangaScraperService.php | 315 ++-- src/Service/MangaScraperServiceOld.php | 157 ++ ...r.php => MangaUpdatesMetadataProvider.php} | 22 +- src/Service/MangadexProvider.php | 123 ++ src/Service/SushiScanProviderService.php | 89 +- .../Components/AddMangaModalComponent.php | 27 + src/Twig/Components/BootstrapModal.php | 11 + src/Twig/Components/DownloadChapter.php | 33 + src/Twig/Components/MangaSearch.php | 38 + src/Twig/Components/NewMangaForm.php | 79 + src/Twig/Components/Search.php | 28 + src/Twig/Components/ToolBarButton.php | 12 + src/Twig/Extension/TruncateExtension.php | 24 + src/Twig/Runtime/TruncateExtensionRuntime.php | 18 + symfony.lock | 41 + tailwind.config.js | 2 +- templates/base.html.twig | 60 +- .../TwigBundle/Exception/error404.html.twig | 9 + templates/components/AddMangaModal.html.twig | 12 + templates/components/BootstrapModal.html.twig | 33 + .../components/DownloadChapter.html.twig | 5 + templates/components/MangaSearch.html.twig | 65 + templates/components/NewMangaForm.html.twig | 40 + templates/components/Search.html.twig | 37 + templates/components/ToolBarButton.html.twig | 6 + templates/manga/add_new.html.twig | 78 +- templates/manga/index.html.twig | 40 +- templates/manga/show_chapters.html.twig | 185 ++- templates/menu/menu.html.twig | 11 +- webpack.config.js | 2 +- 69 files changed, 4004 insertions(+), 385 deletions(-) create mode 100644 assets/controllers/bootstrap-modal_controller.js create mode 100644 assets/controllers/search_controller.js create mode 100644 assets/controllers/table_controller.js create mode 100644 config/packages/twig_component.yaml create mode 100644 config/routes/ux_live_component.yaml create mode 100644 public/img/mangarr_logo.png create mode 100644 public/puppeteer-script.js create mode 100644 src/Client/MangadexClient.php create mode 100644 src/Controller/TestController.php create mode 100644 src/Entity/ContentSource.php create mode 100644 src/Interface/ClientInterface.php create mode 100644 src/Interface/ContentProviderInterface.php rename src/{Service/MangaDbProviderInterface.php => Interface/MetadataProviderInterface.php} (64%) create mode 100644 src/Repository/ContentSourceRepository.php delete mode 100644 src/Service/MangaProviderInterface.php create mode 100644 src/Service/MangaScraperServiceOld.php rename src/Service/{MangaUpdatesDbProvider.php => MangaUpdatesMetadataProvider.php} (72%) create mode 100644 src/Service/MangadexProvider.php create mode 100644 src/Twig/Components/AddMangaModalComponent.php create mode 100644 src/Twig/Components/BootstrapModal.php create mode 100644 src/Twig/Components/DownloadChapter.php create mode 100644 src/Twig/Components/MangaSearch.php create mode 100644 src/Twig/Components/NewMangaForm.php create mode 100644 src/Twig/Components/Search.php create mode 100644 src/Twig/Components/ToolBarButton.php create mode 100644 src/Twig/Extension/TruncateExtension.php create mode 100644 src/Twig/Runtime/TruncateExtensionRuntime.php create mode 100644 templates/bundles/TwigBundle/Exception/error404.html.twig create mode 100644 templates/components/AddMangaModal.html.twig create mode 100644 templates/components/BootstrapModal.html.twig create mode 100644 templates/components/DownloadChapter.html.twig create mode 100644 templates/components/MangaSearch.html.twig create mode 100644 templates/components/NewMangaForm.html.twig create mode 100644 templates/components/Search.html.twig create mode 100644 templates/components/ToolBarButton.html.twig diff --git a/.env b/.env index e6e1599..52ab6b9 100644 --- a/.env +++ b/.env @@ -27,3 +27,8 @@ POSTGRES_PORT=5432 ###> nelmio/cors-bundle ### CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$' ###< nelmio/cors-bundle ### + +MANGADEX_CLIENT_ID='personal-client-c6ea0ee7-8d48-41cd-8813-51b874177332-627526e7' +MANGADEX_CLIENT_SECRET='abMpCrSDYMWPjd24Pitl14t6RFqTs0cy' +MANGADEX_USERNAME='Colgora' +MANGADEX_PASSWORD='Hagaren666!' diff --git a/Dockerfile b/Dockerfile index 8f0dccb..ac8b458 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,7 +23,18 @@ RUN apk add --no-cache \ ; # Install Node.js and npm -RUN apk add --no-cache nodejs npm +ENV CHROME_BIN="/usr/bin/chromium-browser" \ + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD="true" +RUN set -x \ + && apk update \ + && apk upgrade \ + && apk add --no-cache \ + nodejs \ + npm \ + udev \ + ttf-freefont \ + chromium \ + && npm install puppeteer@1.10.0 RUN set -eux; \ install-php-extensions \ diff --git a/Makefile b/Makefile index 4bd11f9..9984cc3 100644 --- a/Makefile +++ b/Makefile @@ -126,6 +126,15 @@ state-processor: ## Create a new state processor state-provider: ## Create a new state provider @$(SYMFONY) make:state-provider +twig-component: ## Create a new twig component + @$(SYMFONY) make:twig-component + +twig-extension: ## Create a new twig extension + @$(SYMFONY) make:twig-extension + +stimulus: ## Create a new stimulus controller + @$(SYMFONY) make:stimulus-controller + ## —— Webpack Encore ————————————————————————————————————————————————————————————— npm-install: ## Install npm dependencies @$(DOCKER_COMP) exec php npm install diff --git a/assets/app.js b/assets/app.js index 2b5d790..e66af97 100644 --- a/assets/app.js +++ b/assets/app.js @@ -1,3 +1,6 @@ +import './bootstrap.js'; + +import '@fortawesome/fontawesome-free/js/all.js'; /* * Welcome to your app's main JavaScript file! * diff --git a/assets/controllers.json b/assets/controllers.json index a1c6e90..b980571 100644 --- a/assets/controllers.json +++ b/assets/controllers.json @@ -1,4 +1,14 @@ { - "controllers": [], + "controllers": { + "@symfony/ux-live-component": { + "live": { + "enabled": true, + "fetch": "eager", + "autoimport": { + "@symfony/ux-live-component/dist/live.min.css": true + } + } + } + }, "entrypoints": [] } diff --git a/assets/controllers/bootstrap-modal_controller.js b/assets/controllers/bootstrap-modal_controller.js new file mode 100644 index 0000000..8967945 --- /dev/null +++ b/assets/controllers/bootstrap-modal_controller.js @@ -0,0 +1,21 @@ +import { Controller } from '@hotwired/stimulus'; +import { Modal } from 'bootstrap'; + +/** + * Allows you to dispatch a "modal:close" JavaScript event to close it. + * + * This is useful inside a LiveComponent, where you can emit a browser event + * to open or close the modal. + * + * See templates/components/BootstrapModal.html.twig to see how this is + * attached to Bootstrap modal. + */ +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + modal = null; + + connect() { + this.modal = Modal.getOrCreateInstance(this.element); + document.addEventListener('modal:close', () => this.modal.hide()); + } +} diff --git a/assets/controllers/search_controller.js b/assets/controllers/search_controller.js new file mode 100644 index 0000000..e29e332 --- /dev/null +++ b/assets/controllers/search_controller.js @@ -0,0 +1,15 @@ +import { Controller } from '@hotwired/stimulus'; + +/* +* The following line makes this controller "lazy": it won't be downloaded until needed +* See https://github.com/symfony/stimulus-bridge#lazy-controllers +*/ +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + static targets = ['input'] + + clearSearch() { + this.inputTarget.value = ''; + this.inputTarget.focus(); + } +} diff --git a/assets/controllers/table_controller.js b/assets/controllers/table_controller.js new file mode 100644 index 0000000..ae125bc --- /dev/null +++ b/assets/controllers/table_controller.js @@ -0,0 +1,24 @@ +import {Controller} from '@hotwired/stimulus'; + +/* +* The following line makes this controller "lazy": it won't be downloaded until needed +* See https://github.com/symfony/stimulus-bridge#lazy-controllers +*/ +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + static targets = ['body'] + + // ... + collapse(event) { + if (this.bodyTarget.style.display === "none") { + this.bodyTarget.style.display = "block"; + event.currentTarget.classList.remove('fa-chevron-up'); + event.currentTarget.classList.add('fa-chevron-down'); + } else { + this.bodyTarget.style.display = "none"; + event.currentTarget.classList.remove('fa-chevron-down'); + event.currentTarget.classList.add('fa-chevron-up'); + } + + } +} diff --git a/assets/styles/app.scss b/assets/styles/app.scss index 9b49d48..8eba4cb 100644 --- a/assets/styles/app.scss +++ b/assets/styles/app.scss @@ -1,3 +1,4 @@ +//@import "bootstrap/scss/bootstrap"; @import "tailwindcss/base"; @import "tailwindcss/components"; @import "tailwindcss/utilities"; @@ -6,3 +7,94 @@ body { background-color: white; } +.modal { + z-index: 1072!important; + @apply hidden fixed top-0 left-0 w-full h-full outline-none +} + +.modal-dialog { + z-index: 1073!important; +} + +.modal.show { + @apply block +} + +.modal-backdrop { + z-index: 9!important; + width: 100vw; + height: 100vh; + @apply fixed bg-black top-0 left-0 +} + +.modal-backdrop.fade { + @apply opacity-0 +} + +.modal-backdrop.show { + @apply opacity-50 +} + +.modal.fade .modal-dialog { + transition: -webkit-transform .3s ease-out; + transition: transform .3s ease-out; + transition: transform .3s ease-out, -webkit-transform .3s ease-out; + -webkit-transform: translate(0, -50px); + transform: translate(0, -50px); +} + +.modal.show .modal-dialog { + -webkit-transform: none; + transform: none; +} + +::-webkit-scrollbar { + @apply w-2 h-1; + /* Ajuster la largeur et la hauteur de la scrollbar */ +} + +::-webkit-scrollbar-thumb { + @apply bg-green-600; +} + +::-webkit-scrollbar-thumb:hover { + @apply bg-green-700; +} + +::-webkit-scrollbar-track { + @apply bg-white; +} + +#searchResults::-webkit-scrollbar { + @apply w-2 h-1; + /* Ajuster la largeur et la hauteur de la scrollbar */ +} + +#searchResults::-webkit-scrollbar-thumb { + @apply bg-green-600 rounded-r-sm; +} + +#searchResults::-webkit-scrollbar-thumb:hover { + @apply bg-green-700; +} + +#searchResults::-webkit-scrollbar-track { + @apply bg-gray-700; +} + +///* Custom styles for the scrollbar buttons */ +//::-webkit-scrollbar-button { +// @apply bg-gray-700; +// height: 10px; /* Adjust the height of the scrollbar buttons */ +// width: 10px; /* Adjust the width of the scrollbar buttons */ +//} +// +//::-webkit-scrollbar-button:vertical:decrement { +// @apply bg-gray-700; +// background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M12 8l6 6H6z'/%3E%3C/svg%3E"); +//} +// +//::-webkit-scrollbar-button:vertical:increment { +// @apply bg-gray-700; +// background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M12 16l-6-6h12z'/%3E%3C/svg%3E"); +//} diff --git a/compose.override.yaml b/compose.override.yaml index 177a547..1fe84cd 100644 --- a/compose.override.yaml +++ b/compose.override.yaml @@ -20,9 +20,6 @@ services: - host.docker.internal:host-gateway tty: true -###> symfony/mercure-bundle ### -###< symfony/mercure-bundle ### - ###> doctrine/doctrine-bundle ### database: ports: diff --git a/compose.yaml b/compose.yaml index 1b668a2..1bb6c99 100644 --- a/compose.yaml +++ b/compose.yaml @@ -20,6 +20,8 @@ services: volumes: - caddy_data:/data - caddy_config:/config + networks: + - mangarr_network ports: # HTTP - target: 80 @@ -35,11 +37,11 @@ services: protocol: udp # Mercure is installed as a Caddy module, prevent the Flex recipe from installing another service -###> symfony/mercure-bundle ### -###< symfony/mercure-bundle ### ###> doctrine/doctrine-bundle ### database: + hostname: database + container_name: database image: postgres:${POSTGRES_VERSION:-16}-alpine environment: POSTGRES_DB: ${POSTGRES_DB:-app} @@ -48,6 +50,8 @@ services: POSTGRES_USER: ${POSTGRES_USER:-app} volumes: - database_data:/var/lib/postgresql/data:rw + networks: + - mangarr_network ports: - '5432:5432' # You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data! @@ -63,9 +67,10 @@ services: volumes: caddy_data: caddy_config: -###> symfony/mercure-bundle ### -###< symfony/mercure-bundle ### ###> doctrine/doctrine-bundle ### database_data: ###< doctrine/doctrine-bundle ### +networks: + mangarr_network: + external: true diff --git a/composer.json b/composer.json index ec820c3..71b31f9 100644 --- a/composer.json +++ b/composer.json @@ -27,16 +27,21 @@ "symfony/flex": "^2", "symfony/framework-bundle": "7.0.*", "symfony/http-client": "7.0.*", + "symfony/mime": "7.0.*", "symfony/monolog-bundle": "^3.10", "symfony/property-access": "7.0.*", "symfony/property-info": "7.0.*", "symfony/runtime": "7.0.*", "symfony/security-bundle": "7.0.*", "symfony/serializer": "7.0.*", + "symfony/stimulus-bundle": "^2.17", "symfony/twig-bundle": "7.0.*", + "symfony/ux-live-component": "^2.17", "symfony/validator": "7.0.*", "symfony/webpack-encore-bundle": "^2.1", - "symfony/yaml": "7.0.*" + "symfony/yaml": "7.0.*", + "twig/extra-bundle": "^2.12|^3.0", + "twig/twig": "^2.12|^3.0" }, "config": { "allow-plugins": { diff --git a/composer.lock b/composer.lock index 8158457..1e17a2f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "721e53091aa5df1279e1b346d6a8e9b7", + "content-hash": "08c76de0049c9ace64fab221e185979c", "packages": [ { "name": "api-platform/core", @@ -4561,6 +4561,90 @@ ], "time": "2023-12-30T15:41:17+00:00" }, + { + "name": "symfony/mime", + "version": "v7.0.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "3426d1e95f432c82ceef57e9943383116800f406" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/3426d1e95f432c82ceef57e9943383116800f406", + "reference": "3426d1e95f432c82ceef57e9943383116800f406", + "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" + }, + "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|^7.0" + }, + "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.0.8" + }, + "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-06-02T15:49:03+00:00" + }, { "name": "symfony/monolog-bridge", "version": "v7.0.3", @@ -4873,6 +4957,90 @@ ], "time": "2023-01-26T09:26:14+00:00" }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "a287ed7475f85bf6f61890146edbc932c0fff919" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919", + "reference": "a287ed7475f85bf6f61890146edbc932c0fff919", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^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.29.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-01-29T20:11:03+00:00" + }, { "name": "symfony/polyfill-intl-normalizer", "version": "v1.28.0", @@ -5966,6 +6134,75 @@ ], "time": "2023-12-26T14:02:43+00:00" }, + { + "name": "symfony/stimulus-bundle", + "version": "v2.17.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/stimulus-bundle.git", + "reference": "b828a32fe9f75500d26b563cc01874657162c413" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/b828a32fe9f75500d26b563cc01874657162c413", + "reference": "b828a32fe9f75500d26b563cc01874657162c413", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.0|^3.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "twig/twig": "^2.15.3|^3.8" + }, + "require-dev": { + "symfony/asset-mapper": "^6.3|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "zenstruck/browser": "^1.4" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\UX\\StimulusBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Integration with your Symfony app & Stimulus!", + "keywords": [ + "symfony-ux" + ], + "support": { + "source": "https://github.com/symfony/stimulus-bundle/tree/v2.17.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-21T10:23:35+00:00" + }, { "name": "symfony/stopwatch", "version": "v7.0.0", @@ -6384,6 +6621,182 @@ ], "time": "2024-01-23T15:02:46+00:00" }, + { + "name": "symfony/ux-live-component", + "version": "v2.17.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-live-component.git", + "reference": "65947f886b3835a504dd86951b5d07ccc4dcb5e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-live-component/zipball/65947f886b3835a504dd86951b5d07ccc4dcb5e1", + "reference": "65947f886b3835a504dd86951b5d07ccc4dcb5e1", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/property-access": "^5.4.5|^6.0|^7.0", + "symfony/ux-twig-component": "^2.8", + "twig/twig": "^3.8.0" + }, + "conflict": { + "symfony/config": "<5.4.0" + }, + "require-dev": { + "doctrine/annotations": "^1.0", + "doctrine/collections": "^1.6.8|^2.0", + "doctrine/doctrine-bundle": "^2.4.3", + "doctrine/orm": "^2.9.4", + "doctrine/persistence": "^2.5.2|^3.0", + "phpdocumentor/reflection-docblock": "5.x-dev", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/options-resolver": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^6.1|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/security-bundle": "^5.4|^6.0|^7.0", + "symfony/serializer": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/validator": "^5.4|^6.0|^7.0", + "zenstruck/browser": "^1.2.0", + "zenstruck/foundry": "1.37.*" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "name": "symfony/ux", + "url": "https://github.com/symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\LiveComponent\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Live components for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "components", + "symfony-ux", + "twig" + ], + "support": { + "source": "https://github.com/symfony/ux-live-component/tree/v2.17.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-22T18:53:03+00:00" + }, + { + "name": "symfony/ux-twig-component", + "version": "v2.17.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-twig-component.git", + "reference": "fb3d978b7f19e9a94533a3bf30d68269908ffae1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/fb3d978b7f19e9a94533a3bf30d68269908ffae1", + "reference": "fb3d978b7f19e9a94533a3bf30d68269908ffae1", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.2|^3.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "twig/twig": "^3.8" + }, + "conflict": { + "symfony/config": "<5.4.0" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^6.0|^7.0", + "symfony/stimulus-bundle": "^2.9.1", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/webpack-encore-bundle": "^1.15" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "name": "symfony/ux", + "url": "https://github.com/symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\TwigComponent\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Twig components for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "components", + "symfony-ux", + "twig" + ], + "support": { + "source": "https://github.com/symfony/ux-twig-component/tree/v2.17.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-19T16:14:05+00:00" + }, { "name": "symfony/validator", "version": "v7.0.3", @@ -6860,6 +7273,80 @@ ], "time": "2023-11-07T10:26:03+00:00" }, + { + "name": "twig/extra-bundle", + "version": "v3.10.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/twig-extra-bundle.git", + "reference": "cdc6e23aeb7f4953c1039568c3439aab60c56454" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/cdc6e23aeb7f4953c1039568c3439aab60c56454", + "reference": "cdc6e23aeb7f4953c1039568c3439aab60c56454", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/framework-bundle": "^5.4|^6.4|^7.0", + "symfony/twig-bundle": "^5.4|^6.4|^7.0", + "twig/twig": "^3.0" + }, + "require-dev": { + "league/commonmark": "^1.0|^2.0", + "symfony/phpunit-bridge": "^6.4|^7.0", + "twig/cache-extra": "^3.0", + "twig/cssinliner-extra": "^3.0", + "twig/html-extra": "^3.0", + "twig/inky-extra": "^3.0", + "twig/intl-extra": "^3.0", + "twig/markdown-extra": "^3.0", + "twig/string-extra": "^3.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Twig\\Extra\\TwigExtraBundle\\": "" + }, + "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 Symfony bundle for extra Twig extensions", + "homepage": "https://twig.symfony.com", + "keywords": [ + "bundle", + "extra", + "twig" + ], + "support": { + "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.10.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2024-05-11T07:35:57+00:00" + }, { "name": "twig/twig", "version": "v3.8.0", diff --git a/config/bundles.php b/config/bundles.php index ed6283d..867e0e9 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -14,4 +14,8 @@ return [ Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true], + Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true], + Symfony\UX\LiveComponent\LiveComponentBundle::class => ['all' => true], + Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true], + Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true], ]; diff --git a/config/packages/twig_component.yaml b/config/packages/twig_component.yaml new file mode 100644 index 0000000..fd17ac6 --- /dev/null +++ b/config/packages/twig_component.yaml @@ -0,0 +1,5 @@ +twig_component: + anonymous_template_directory: 'components/' + defaults: + # Namespace & directory for components + App\Twig\Components\: 'components/' diff --git a/config/routes/ux_live_component.yaml b/config/routes/ux_live_component.yaml new file mode 100644 index 0000000..e56523a --- /dev/null +++ b/config/routes/ux_live_component.yaml @@ -0,0 +1,5 @@ +live_component: + resource: '@LiveComponentBundle/config/routes.php' + prefix: '/_components' + # adjust prefix to add localization to your components + #prefix: '/{_locale}/_components' diff --git a/config/services.yaml b/config/services.yaml index 5bc44d9..827ce74 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -41,6 +41,10 @@ services: track_redirects: true + App\Service\MangaScraperServiceOld: + arguments: + $projectDir: '%kernel.project_dir%' + App\Service\MangaScraperService: arguments: $projectDir: '%kernel.project_dir%' @@ -55,3 +59,15 @@ services: App\Controller\MenuController: tags: [ 'controller.service_arguments' ] + + App\Client\MangadexClient: + arguments: + $httpClient: '@GuzzleHttp\Client' + $clientId: '%env(MANGADEX_CLIENT_ID)%' + $clientSecret: '%env(MANGADEX_CLIENT_SECRET)%' + $username: '%env(MANGADEX_USERNAME)%' + $password: '%env(MANGADEX_PASSWORD)%' + + App\Service\MangadexProvider: + arguments: + $client: '@App\Client\MangadexClient' diff --git a/frankenphp/conf.d/app.ini b/frankenphp/conf.d/app.ini index 501fa84..a99c9b8 100644 --- a/frankenphp/conf.d/app.ini +++ b/frankenphp/conf.d/app.ini @@ -12,3 +12,4 @@ opcache.interned_strings_buffer = 16 opcache.max_accelerated_files = 20000 opcache.memory_consumption = 256 opcache.enable_file_override = 1 +max_execution_time = 60 diff --git a/package-lock.json b/package-lock.json index 5457366..dea7531 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,9 +6,12 @@ "": { "license": "UNLICENSED", "dependencies": { + "@fortawesome/fontawesome-free": "^6.5.2", "alpinejs": "^3.13.3", "autoprefixer": "^10.4.14", + "bootstrap": "^5.3.3", "postcss-loader": "^7.1.0", + "puppeteer": "^22.10.0", "tailwindcss": "^3.2.7" }, "devDependencies": { @@ -16,6 +19,7 @@ "@babel/preset-env": "^7.16.0", "@hotwired/stimulus": "^3.0.0", "@symfony/stimulus-bridge": "^3.2.0", + "@symfony/ux-live-component": "file:vendor/symfony/ux-live-component/assets", "@symfony/webpack-encore": "^4.0.0", "core-js": "^3.23.0", "daisyui": "^4.4.2", @@ -1669,6 +1673,25 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.24.6.tgz", + "integrity": "sha512-tbC3o8uHK9xMgMsvUm9qGqxVpbv6yborMBLbDteHIc7JDNHsTV0vDMQ5j1O1NXvO+BDELtL9KgoWYaUVIVGt8w==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3/node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, "node_modules/@babel/runtime/node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", @@ -1733,6 +1756,15 @@ "node": ">=10.0.0" } }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.5.2.tgz", + "integrity": "sha512-hRILoInAx8GNT5IMkrtIt9blOdrqHOnPBH+k70aWUAqPZPgopb9G5EQJFpaBx/S8zp2fC+mPW349Bziuk1o28Q==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, "node_modules/@hotwired/stimulus": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/@hotwired/stimulus/-/stimulus-3.2.2.tgz", @@ -2027,6 +2059,88 @@ "node": ">=14" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@puppeteer/browsers": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.3.tgz", + "integrity": "sha512-bJ0UBsk0ESOs6RFcLXOt99a3yTDcOKlzfjad+rhFwdaG1Lu/Wzq58GHYCDTlZ9z6mldf4g+NTb+TXEfe0PpnsQ==", + "license": "Apache-2.0", + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.4.0", + "semver": "7.6.0", + "tar-fs": "3.0.5", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@puppeteer/browsers/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@puppeteer/browsers/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@puppeteer/browsers/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@puppeteer/browsers/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -2052,6 +2166,10 @@ "@hotwired/stimulus": "^3.0" } }, + "node_modules/@symfony/ux-live-component": { + "resolved": "vendor/symfony/ux-live-component/assets", + "link": true + }, "node_modules/@symfony/webpack-encore": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/@symfony/webpack-encore/-/webpack-encore-4.6.1.tgz", @@ -2296,6 +2414,117 @@ "node": ">=8" } }, + "node_modules/@testing-library/dom": { + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.6", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@testing-library/dom/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/user-event": { + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", + "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -2305,6 +2534,12 @@ "node": ">=10.13.0" } }, + "node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -2464,6 +2699,16 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, "node_modules/@types/node-forge": { "version": "1.3.11", "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", @@ -2560,6 +2805,16 @@ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@vue/reactivity": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz", @@ -2795,6 +3050,18 @@ "node": ">=8.9" } }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2923,6 +3190,19 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -2967,6 +3247,24 @@ "webpack": ">=5.0.0" } }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, "node_modules/autoprefixer": { "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", @@ -3003,6 +3301,12 @@ "postcss": "^8.1.0" } }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "license": "Apache-2.0" + }, "node_modules/babel-loader": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", @@ -3117,6 +3421,81 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/bare-events": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.3.1.tgz", + "integrity": "sha512-sJnSOTVESURZ61XgEleqmP255T6zTYwHPwE4r6SssIh0U9/uDvfpdoJYpVUerJJZH2fueO+CdT8ZT+OC/7aZDA==", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-fs": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.1.tgz", + "integrity": "sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-path": "^2.0.0", + "bare-stream": "^2.0.0" + } + }, + "node_modules/bare-os": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.3.0.tgz", + "integrity": "sha512-oPb8oMM1xZbhRQBngTgpcQ5gXw6kjOaRsSWsIeNyRxGed2w/ARyP7ScBYpWR1qfX2E5rS3gBw6OWcSQo+s+kUg==", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-path": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", + "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-os": "^2.1.0" + } + }, + "node_modules/bare-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.0.1.tgz", + "integrity": "sha512-ubLyoDqPnUf5o0kSFp709HC0WRZuxVuh4pbte5eY95Xvx5bdvz07c2JFmXBfqqe60q+9PJ8S4X5GRvmcNSKMxg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "streamx": "^2.18.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -3207,6 +3586,24 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3259,6 +3656,39 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3403,6 +3833,20 @@ "node": ">=6.0" } }, + "node_modules/chromium-bidi": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.19.tgz", + "integrity": "sha512-UA6zL77b7RYCjJkZBsZ0wlvCTD+jTjllZ8f6wdO4buevXgTZYjV+XLB9CiEa2OuuTGGTLnI7eN9I60YxuALGQg==", + "license": "Apache-2.0", + "dependencies": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0", + "zod": "3.22.4" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -3433,6 +3877,70 @@ "webpack": ">=4.0.0 <6.0.0" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -3472,6 +3980,18 @@ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -3628,6 +4148,17 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-js-pure": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.37.1.tgz", + "integrity": "sha512-J/r5JTHSmzTxbiYYrzXg9w1VpqrYt+gexenBE9pugeyhwPZTAEJddyiReJWsLO6uNQ8xJZFbod6XC7KKwatCiA==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -4027,11 +4558,19 @@ "url": "https://opencollective.com/daisyui" } }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -4082,6 +4621,20 @@ "node": ">=8" } }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/del": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", @@ -4100,6 +4653,15 @@ "node": ">=6" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -4125,6 +4687,12 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, + "node_modules/devtools-protocol": { + "version": "0.0.1286932", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1286932.tgz", + "integrity": "sha512-wu58HMQll9voDjR4NlPyoDEw1syfzaBNHymMMZ/QOXiHRNluOnDgu9hp1yHOKYoMlxCh4lSSiugLITe6Fvu1eA==", + "license": "BSD-3-Clause" + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -4147,6 +4715,12 @@ "node": ">=6" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, "node_modules/dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -4250,6 +4824,15 @@ "node": ">= 0.8" } }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.16.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz", @@ -4271,6 +4854,15 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/envinfo": { "version": "7.13.0", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", @@ -4352,6 +4944,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -4364,6 +4986,19 @@ "node": ">=8.0.0" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -4395,7 +5030,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4503,11 +5137,52 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -4572,6 +5247,15 @@ "node": ">=0.8.0" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -4703,6 +5387,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -4733,6 +5431,20 @@ "node": ">= 0.6" } }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/fs-monkey": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", @@ -4775,6 +5487,15 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -4815,6 +5536,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -5089,6 +5825,19 @@ "node": ">=8.0.0" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/http-proxy-middleware": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", @@ -5113,6 +5862,19 @@ } } }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -5146,6 +5908,32 @@ "postcss": "^8.1.0" } }, + "node_modules/idiomorph": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/idiomorph/-/idiomorph-0.3.0.tgz", + "integrity": "sha512-UhV1Ey5xCxIwR9B+OgIjQa+1Jx99XQ1vQHUsKBU1RpQzCx1u+b+N6SOXgf5mEJDqemUI/ffccu6+71l2mJUsRA==", + "dev": true + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/immutable": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", @@ -5285,6 +6073,19 @@ "node": ">= 0.10" } }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", @@ -5639,6 +6440,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -5673,6 +6480,18 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -5778,6 +6597,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/mdn-data": { "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", @@ -5984,11 +6812,16 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -6044,6 +6877,35 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -6180,7 +7042,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -6278,6 +7139,38 @@ "node": ">=6" } }, + "node_modules/pac-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", + "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6389,6 +7282,12 @@ "node": ">=8" } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", @@ -7169,12 +8068,131 @@ "renderkid": "^3.0.0" } }, + "node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/pretty-format/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/pretty-format/node_modules/@types/yargs": { + "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pretty-format/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/pretty-format/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -7197,6 +8215,50 @@ "node": ">= 0.10" } }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -7205,6 +8267,84 @@ "node": ">=6" } }, + "node_modules/puppeteer": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.10.0.tgz", + "integrity": "sha512-ZOkZd6a6t0BdKcWb0wAYHWQqCfdlN1PPnXOmg/XNrbo6gJhYWFX4qCNb6ahSn8TpAqBqLCoD4Q010F7GwOM7mA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.2.3", + "cosmiconfig": "9.0.0", + "devtools-protocol": "0.0.1286932", + "puppeteer-core": "22.10.0" + }, + "bin": { + "puppeteer": "lib/esm/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.10.0.tgz", + "integrity": "sha512-I54J4Vy4I07UHsgB1QSmuFoF7KNQjJWcvFBPhtY+ezMdBfwgGDr8dzYrJa11aPgP9kxIUHjhktcMmmfJkOAtTw==", + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.2.3", + "chromium-bidi": "0.5.19", + "debug": "4.3.4", + "devtools-protocol": "0.0.1286932", + "ws": "8.17.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/puppeteer/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -7239,6 +8379,12 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "license": "MIT" + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -7280,6 +8426,12 @@ "node": ">= 0.8" } }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -7423,6 +8575,15 @@ "strip-ansi": "^6.0.1" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -7921,6 +9082,16 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -7932,6 +9103,34 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -7987,6 +9186,12 @@ "wbuf": "^1.7.3" } }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, "node_modules/stackframe": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", @@ -8002,6 +9207,20 @@ "node": ">= 0.8" } }, + "node_modules/streamx": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", + "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -8364,6 +9583,31 @@ "node": ">=6" } }, + "node_modules/tar-fs": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", + "integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/terser": { "version": "5.31.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz", @@ -8454,6 +9698,15 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "node_modules/text-decoder": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", + "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -8473,6 +9726,12 @@ "node": ">=0.8" } }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT" + }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -8517,11 +9776,23 @@ "node": ">=0.6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "license": "0BSD" + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -8535,6 +9806,16 @@ "node": ">= 0.6" } }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "license": "MIT", + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -8580,6 +9861,15 @@ "node": ">=4" } }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -8626,6 +9916,12 @@ "punycode": "^2.1.0" } }, + "node_modules/urlpattern-polyfill": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -8685,6 +9981,12 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, "node_modules/webpack": { "version": "5.91.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz", @@ -9045,6 +10347,16 @@ "node": ">=0.8.0" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9188,14 +10500,12 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { "version": "8.17.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", - "dev": true, "engines": { "node": ">=10.0.0" }, @@ -9212,6 +10522,15 @@ } } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -9229,15 +10548,42 @@ "node": ">= 14" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "engines": { "node": ">=12" } }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yocto-queue": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", @@ -9249,6 +10595,34 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "vendor/symfony/ux-live-component/assets": { + "name": "@symfony/ux-live-component", + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "idiomorph": "^0.3.0" + }, + "devDependencies": { + "@hotwired/stimulus": "^3.0.0", + "@testing-library/dom": "^7.31.0", + "@testing-library/user-event": "^13.1.9", + "@types/node-fetch": "^2.6.2", + "node-fetch": "^2.6.1" + }, + "peerDependencies": { + "@hotwired/stimulus": "^3.0.0" + } } } } diff --git a/package.json b/package.json index 807d8ea..7250549 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "@babel/preset-env": "^7.16.0", "@hotwired/stimulus": "^3.0.0", "@symfony/stimulus-bridge": "^3.2.0", + "@symfony/ux-live-component": "file:vendor/symfony/ux-live-component/assets", "@symfony/webpack-encore": "^4.0.0", "core-js": "^3.23.0", "daisyui": "^4.4.2", @@ -23,9 +24,12 @@ "build": "encore production --progress" }, "dependencies": { + "@fortawesome/fontawesome-free": "^6.5.2", "alpinejs": "^3.13.3", "autoprefixer": "^10.4.14", + "bootstrap": "^5.3.3", "postcss-loader": "^7.1.0", + "puppeteer": "^22.10.0", "tailwindcss": "^3.2.7" } } diff --git a/public/img/mangarr_logo.png b/public/img/mangarr_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..42a786ef7fb7112ef60a329b33db3c029307a4a2 GIT binary patch literal 105191 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%0D#45HG{o19xzp#zT3xjifv^#^&03;^`;x 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 { + try { + // Récupérer les paramètres de la ligne de commande + const [url, imageSelector, nextButtonSelector] = process.argv.slice(2); + + console.log('URL:', url); + console.log('Image Selector:', imageSelector); + console.log('Next Button Selector:', nextButtonSelector); + + const browser = await puppeteer.launch({ + headless: true, + executablePath: process.env.CHROME_BIN || null, + args: ['--no-sandbox', '--headless', '--disable-gpu', '--disable-dev-shm-usage'] + }); + + console.log('Browser launched'); + + const page = await browser.newPage(); + console.log('New page created'); + + await page.goto(url, {waitUntil: 'networkidle2'}); + console.log('Page loaded'); + + // Function to scroll to the bottom of the page + async function autoScroll(page){ + await page.evaluate(async () => { + await new Promise((resolve, reject) => { + var totalHeight = 0; + var distance = 100; + var timer = setInterval(() => { + var scrollHeight = document.body.scrollHeight; + window.scrollBy(0, distance); + totalHeight += distance; + + if(totalHeight >= scrollHeight){ + clearInterval(timer); + resolve(); + } + }, 100); + }); + }); + } + + // Attendre que le conteneur des images soit présent pour s'assurer que la page est complètement chargée + await page.waitForSelector(imageSelector); + + console.log('Image selector found'); + + const imageUrls = new Set(); // Utiliser un Set pour éviter les doublons + + // let previousImageUrl = null; + while (true) { + console.log('Fetching images'); + const pageImageUrls = await page.$$eval(imageSelector, imgs => + imgs.map(img => img.getAttribute('src') || img.getAttribute('data-src')) + ); + + console.log('Page image URLs:', pageImageUrls); + + pageImageUrls.forEach(url => { + if (!imageUrls.has(url)) { + imageUrls.add(url); + console.log('Image URL:', url); + } + }); + + // Cliquer sur le bouton suivant + const nextButton = await page.$(nextButtonSelector); + console.log('Next button'); + if (!nextButton) { + console.log(page); + break; // Sortir de la boucle si le bouton suivant n'existe pas + } + console.log('Clicking next button'); + await nextButton.click(); + // await page.waitForTimeout(1000); // Attendre 1 seconde + await page.waitForSelector(imageSelector); + } + + console.log('Image URLs:', JSON.stringify(Array.from(imageUrls))); + + await browser.close(); + } catch (error) { + console.error('Error:', error); + process.exit(1); // Exit with a failure code + } +})(); diff --git a/src/Client/MangadexClient.php b/src/Client/MangadexClient.php new file mode 100644 index 0000000..26a31da --- /dev/null +++ b/src/Client/MangadexClient.php @@ -0,0 +1,86 @@ +httpClient = $httpClient; + $this->clientId = $clientId; + $this->clientSecret = $clientSecret; + $this->username = $username; + $this->password = $password; + $this->authenticate(); + } + + public function authenticate(): void + { + $response = $this->httpClient->request('POST', self::AUTHENTICATION_URL, [ + 'form_params' => [ + 'grant_type' => 'password', + 'username' => $this->username, + 'password' => $this->password, + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + ], + ]); + + $data = json_decode($response->getBody()->getContents(), true); + $this->accessToken = $data['access_token']; + $this->refreshToken = $data['refresh_token']; + } + + public function refresh(): void + { + $response = $this->httpClient->request('POST', self::AUTHENTICATION_URL, [ + 'form_params' => [ + 'grant_type' => 'refresh_token', + 'refresh_token' => $this->refreshToken, + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + ], + ]); + + $data = json_decode($response->getBody()->getContents(), true); + $this->accessToken = $data['access_token']; + } + + private function request(string $method, string $endpoint, array $options = []): array + { + $options['headers']['Authorization'] = 'Bearer ' . $this->accessToken; + + $response = $this->httpClient->request($method, self::API_URL . $endpoint, $options); + + if ($response->getStatusCode() === 429) { + $this->refresh(); + $options['headers']['Authorization'] = 'Bearer ' . $this->accessToken; + $response = $this->httpClient->request($method, self::API_URL . $endpoint, $options); + } + + return json_decode($response->getBody()->getContents(), true); + } + + public function get(string $endpoint, array $params = []): array + { + return $this->request('GET', $endpoint, ['query' => $params]); + } + + public function post(string $endpoint, array $data): array + { + return $this->request('POST', $endpoint, ['json' => $data]); + } +} diff --git a/src/Controller/MangaController.php b/src/Controller/MangaController.php index 5205d39..9d1accd 100644 --- a/src/Controller/MangaController.php +++ b/src/Controller/MangaController.php @@ -6,8 +6,8 @@ use App\Entity\Manga; use App\Repository\MangaRepository; use App\Service\MangaExportService; use App\Service\LelScansProviderService; -use App\Service\MangaScraperService; -use App\Service\MangaUpdatesDbProvider; +use App\Service\MangaScraperServiceOld; +use App\Service\MangaUpdatesMetadataProvider; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\Request; @@ -20,11 +20,11 @@ use Symfony\Component\String\Slugger\AsciiSlugger; class MangaController extends AbstractController { public function __construct( - private readonly MangaScraperService $mangaScraperService, + private readonly MangaScraperServiceOld $mangaScraperService, private readonly MangaExportService $mangaExportService, private readonly LelScansProviderService $mangaProviderService, private readonly MangaRepository $mangaRepository, - private MangaUpdatesDbProvider $mangaUpdatesDbProvider + private MangaUpdatesMetadataProvider $mangaUpdatesDbProvider ) { } @@ -48,12 +48,17 @@ class MangaController extends AbstractController throw new NotFoundHttpException("Le manga demandé n'existe pas."); } - $availableChapters = $this->mangaProviderService->getChapterList($mangaSlug); + $chaptersByVolume = []; + foreach ($manga->getChapters() as $chapter) { + $volume = $chapter->getVolume() ?? 'Not Found'; + $chaptersByVolume[$volume][] = $chapter; + } + + $chaptersByVolume = array_map('array_reverse', array_reverse($chaptersByVolume, true)); return $this->render('manga/show_chapters.html.twig', [ - 'controller_name' => 'MangaController', + 'chapters_by_volume' => $chaptersByVolume, 'manga' => $manga, - 'availableChapters' => $availableChapters, ]); } @@ -83,19 +88,11 @@ class MangaController extends AbstractController ]); } - #[Route('/addNew', name: 'add_new_manga')] - public function addNew(): Response + #[Route('/addNew/{query}', name: 'add_new_manga')] + public function addNew(string $query = ''): Response { - $availableManga = $this->mangaProviderService->getMangaList(); - - foreach ($availableManga as $key => $manga) { - $availableManga[$key]['slug'] = $this->titleToSlug($manga['name']); - } - - $mangas = $this->mangaRepository->findAll(); return $this->render('manga/add_new.html.twig', [ - 'availableManga' => $availableManga, - 'mangas' => $mangas, + 'query' => $query, ]); } diff --git a/src/Controller/TestController.php b/src/Controller/TestController.php new file mode 100644 index 0000000..8afe679 --- /dev/null +++ b/src/Controller/TestController.php @@ -0,0 +1,30 @@ +mangaRepository->find(8); + + dd($this->mangadexProvider->getFeed($manga)); + } +} diff --git a/src/Entity/Chapter.php b/src/Entity/Chapter.php index baa7cb2..4a159cf 100644 --- a/src/Entity/Chapter.php +++ b/src/Entity/Chapter.php @@ -28,6 +28,15 @@ class Chapter #[ORM\OneToMany(mappedBy: 'chapter', targetEntity: Page::class, orphanRemoval: true)] private Collection $pagesLink; + #[ORM\Column(nullable: true)] + private ?int $volume = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $title = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $localPath = null; + public function __construct() { $this->pagesLink = new ArrayCollection(); @@ -105,16 +114,52 @@ class Chapter } public function getPageByNumber(int $number): ?Page - { - /** - * @var Page $page - */ - foreach ($this->pagesLink as $page) { - if ($page->getNumber() === $number) { - return $page; - } - } + { + /** + * @var Page $page + */ + foreach ($this->pagesLink as $page) { + if ($page->getNumber() === $number) { + return $page; + } + } + + return null; + } - return null; - } + public function getVolume(): ?int + { + return $this->volume; + } + + public function setVolume(?int $volume): static + { + $this->volume = $volume; + + return $this; + } + + public function getTitle(): ?string + { + return $this->title; + } + + public function setTitle(?string $title): static + { + $this->title = $title; + + return $this; + } + + public function getLocalPath(): ?string + { + return $this->localPath; + } + + public function setLocalPath(?string $localPath): static + { + $this->localPath = $localPath; + + return $this; + } } diff --git a/src/Entity/ContentSource.php b/src/Entity/ContentSource.php new file mode 100644 index 0000000..5f90073 --- /dev/null +++ b/src/Entity/ContentSource.php @@ -0,0 +1,100 @@ +id; + } + + public function getBaseUrl(): ?string + { + return $this->baseUrl; + } + + public function setBaseUrl(string $baseUrl): static + { + $this->baseUrl = $baseUrl; + + return $this; + } + + public function getImageSelector(): ?string + { + return $this->imageSelector; + } + + public function setImageSelector(string $imageSelector): static + { + $this->imageSelector = $imageSelector; + + return $this; + } + + public function getNextPageSelector(): ?string + { + return $this->NextPageSelector; + } + + public function setNextPageSelector(string $NextPageSelector): static + { + $this->NextPageSelector = $NextPageSelector; + + return $this; + } + + public function getChapterUrlFormat(): ?string + { + return $this->chapterUrlFormat; + } + + public function setChapterUrlFormat(string $chapterUrlFormat): static + { + $this->chapterUrlFormat = $chapterUrlFormat; + + return $this; + } + + public function getChapterUrl(string $mangaTitle, float $chapterNumber): string + { + return sprintf($this->chapterUrlFormat, $mangaTitle, $chapterNumber); + } + + public function getScrapingType(): ?string + { + return $this->scrapingType; + } + + public function setScrapingType(string $scrapingType): static + { + $this->scrapingType = $scrapingType; + + return $this; + } +} diff --git a/src/Entity/Manga.php b/src/Entity/Manga.php index 48b11e3..05c516c 100644 --- a/src/Entity/Manga.php +++ b/src/Entity/Manga.php @@ -22,7 +22,7 @@ class Manga #[ORM\OneToMany(mappedBy: 'manga', targetEntity: Chapter::class, orphanRemoval: true)] private Collection $chapters; - #[ORM\Column(length: 255)] + #[ORM\Column(length: 255, unique: true)] private ?string $slug = null; #[ORM\Column(length: 255, nullable: true)] @@ -37,9 +37,25 @@ class Manga #[ORM\Column(type: Types::ARRAY, nullable: true)] private ?array $genres = null; + #[ORM\Column] + private ?\DateTimeImmutable $createdAt = null; + + #[ORM\Column(nullable: true)] + private ?float $rating = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $author = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $externalId = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $status = null; + public function __construct() { $this->chapters = new ArrayCollection(); + $this->createdAt = new \DateTimeImmutable(); } public function getId(): ?int @@ -67,15 +83,15 @@ class Manga return $this->chapters; } - public function getChapterByNumber(float $number): ?Chapter - { - foreach ($this->chapters as $chapter) { - if ($chapter->getNumber() === $number) { - return $chapter; - } - } - return null; - } + public function getChapterByNumber(float $number): ?Chapter + { + foreach ($this->chapters as $chapter) { + if ($chapter->getNumber() === $number) { + return $chapter; + } + } + return null; + } public function addChapter(Chapter $chapter): self { @@ -158,4 +174,64 @@ class Manga return $this; } + + public function getCreatedAt(): ?\DateTimeImmutable + { + return $this->createdAt; + } + + public function setCreatedAt(\DateTimeImmutable $createdAt): static + { + $this->createdAt = $createdAt; + + return $this; + } + + public function getRating(): ?float + { + return $this->rating; + } + + public function setRating(?float $rating): static + { + $this->rating = $rating; + + return $this; + } + + public function getAuthor(): ?string + { + return $this->author; + } + + public function setAuthor(?string $author): static + { + $this->author = $author; + + return $this; + } + + public function getExternalId(): ?string + { + return $this->externalId; + } + + public function setExternalId(?string $externalId): static + { + $this->externalId = $externalId; + + return $this; + } + + public function getStatus(): ?string + { + return $this->status; + } + + public function setStatus(?string $status): static + { + $this->status = $status; + + return $this; + } } diff --git a/src/EventListener/ExceptionListener.php b/src/EventListener/ExceptionListener.php index 3830335..5bffc1d 100644 --- a/src/EventListener/ExceptionListener.php +++ b/src/EventListener/ExceptionListener.php @@ -21,24 +21,24 @@ class ExceptionListener public function onKernelException(ExceptionEvent $event): void { - $exception = $event->getThrowable(); - - $response = match(true) { - $exception instanceof FilterValidationException, - $exception instanceof BadRequestException => $this->createResponse($exception, Response::HTTP_BAD_REQUEST), - $exception instanceof NotFoundHttpException, - $exception instanceof ItemNotFoundException => $this->createResponse($exception, Response::HTTP_NOT_FOUND), - $exception instanceof AccessDeniedHttpException => $this->createResponse($exception, Response::HTTP_FORBIDDEN), - $exception instanceof ValidationException, - $exception instanceof NotNormalizableValueException => $this->createResponse($exception, Response::HTTP_UNPROCESSABLE_ENTITY), - default => null, - }; - - if ($response) { - $event->setResponse($response); - }else{ - $this->logger->error($exception->getMessage(), ['exception' => $exception]); - } +// $exception = $event->getThrowable(); +// +// $response = match(true) { +// $exception instanceof FilterValidationException, +// $exception instanceof BadRequestException => $this->createResponse($exception, Response::HTTP_BAD_REQUEST), +// $exception instanceof NotFoundHttpException, +// $exception instanceof ItemNotFoundException => $this->createResponse($exception, Response::HTTP_NOT_FOUND), +// $exception instanceof AccessDeniedHttpException => $this->createResponse($exception, Response::HTTP_FORBIDDEN), +// $exception instanceof ValidationException, +// $exception instanceof NotNormalizableValueException => $this->createResponse($exception, Response::HTTP_UNPROCESSABLE_ENTITY), +// default => null, +// }; +// +// if ($response) { +// $event->setResponse($response); +// }else{ +// $this->logger->error($exception->getMessage(), ['exception' => $exception]); +// } } private function createResponse(\Throwable $exception, int $statusCode): Response diff --git a/src/Factory/MangaFactory.php b/src/Factory/MangaFactory.php index 8e5dd87..3b0b175 100644 --- a/src/Factory/MangaFactory.php +++ b/src/Factory/MangaFactory.php @@ -52,6 +52,10 @@ final class MangaFactory extends ModelFactory return [ 'slug' => $this->slugger->slug($title)->lower(), 'title' => $title, + 'description' => self::faker()->text(), + 'genres' => self::faker()->words(rand(1, 5)), + 'publicationYear' => self::faker()->year(), + 'rating' => self::faker()->randomFloat(1, 0, 10), ]; } diff --git a/src/Factory/PageFactory.php b/src/Factory/PageFactory.php index 5192350..4e56d05 100644 --- a/src/Factory/PageFactory.php +++ b/src/Factory/PageFactory.php @@ -48,8 +48,8 @@ final class PageFactory extends ModelFactory { return [ 'chapter' => ChapterFactory::new(), - 'imageLocalUrl' => self::faker()->text(255), - 'imageUrl' => self::faker()->text(255), + 'imageLocalUrl' => 'https://placehold.co/770x1090', + 'imageUrl' => 'https://placehold.co/770x1090', 'number' => self::faker()->randomNumber(2), ]; } diff --git a/src/Interface/ClientInterface.php b/src/Interface/ClientInterface.php new file mode 100644 index 0000000..f38aa92 --- /dev/null +++ b/src/Interface/ClientInterface.php @@ -0,0 +1,9 @@ + + * + * @method ContentSource|null find($id, $lockMode = null, $lockVersion = null) + * @method ContentSource|null findOneBy(array $criteria, array $orderBy = null) + * @method ContentSource[] findAll() + * @method ContentSource[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + */ +class ContentSourceRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, ContentSource::class); + } + +// /** +// * @return ContentSource[] Returns an array of ContentSource objects +// */ +// public function findByExampleField($value): array +// { +// return $this->createQueryBuilder('c') +// ->andWhere('c.exampleField = :val') +// ->setParameter('val', $value) +// ->orderBy('c.id', 'ASC') +// ->setMaxResults(10) +// ->getQuery() +// ->getResult() +// ; +// } + +// public function findOneBySomeField($value): ?ContentSource +// { +// return $this->createQueryBuilder('c') +// ->andWhere('c.exampleField = :val') +// ->setParameter('val', $value) +// ->getQuery() +// ->getOneOrNullResult() +// ; +// } +} diff --git a/src/Repository/MangaRepository.php b/src/Repository/MangaRepository.php index 06b60da..60bb6e1 100644 --- a/src/Repository/MangaRepository.php +++ b/src/Repository/MangaRepository.php @@ -39,6 +39,15 @@ class MangaRepository extends ServiceEntityRepository } } + public function findByTitle(string $title): array + { + return $this->createQueryBuilder('m') + ->andWhere('m.title LIKE :title') + ->setParameter('title', "%$title%") + ->getQuery() + ->getResult(); + } + // /** // * @return Manga[] Returns an array of Manga objects // */ diff --git a/src/Service/LelScansProviderService.php b/src/Service/LelScansProviderService.php index b9ca605..cdeca56 100644 --- a/src/Service/LelScansProviderService.php +++ b/src/Service/LelScansProviderService.php @@ -1,10 +1,12 @@ new LelScansProviderService(), @@ -12,4 +14,4 @@ class MangaProviderFactory default => throw new \Exception("Provider {$providerName} non supporté."), }; } -} \ No newline at end of file +} diff --git a/src/Service/MangaProviderInterface.php b/src/Service/MangaProviderInterface.php deleted file mode 100644 index 8336049..0000000 --- a/src/Service/MangaProviderInterface.php +++ /dev/null @@ -1,9 +0,0 @@ -projectDir = $projectDir; - $this->eventDispatcher = $eventDispatcher; - } + public function __construct($projectDir, EventDispatcherInterface $eventDispatcher) + { + $this->projectDir = $projectDir; + $this->eventDispatcher = $eventDispatcher; + } - public function extractMangaPageData(string $html): array - { - $baseUrl = 'https://lelscans.net'; - //pour éviter à PhpStorm de gueuler... - $selector = 'img'; - $crawler = new Crawler($html); - $imgUrl = $crawler->filter($selector)->attr('src'); - $nextLink = $crawler->filter('a[title="Suivant"]'); + public function extractMangaPageData(string $html, ContentSource $mangaSource): array + { + $crawler = new Crawler($html); + $imgUrls = []; - if (!preg_match('/^https?:\/\//', $imgUrl)) { - $urlComponents = parse_url($baseUrl); - $scheme = $urlComponents['scheme']; - $host = $urlComponents['host']; + // Search for images with different extensions + foreach (['img[src$=".jpg"]', 'img[src$=".jpeg"]', 'img[src$=".png"]', 'img'] as $selector) { + $crawler->filter($selector)->each(function (Crawler $node) use (&$imgUrls) { + $src = $node->attr('src') ?? $node->attr('data-src'); + if ($src) { + $imgUrls[] = $src; + } + }); + } - // Construit l'URL absolue de l'image - $imgUrl = $scheme . '://' . $host . '/' . ltrim($imgUrl, '/'); - } + if (empty($imgUrls)) { + throw new \Exception('No valid image found on the page.'); + } - if($nextLink->count() > 0){ - $nextUrl = $nextLink->attr('href'); - }else{ - $nextUrl = null; - } + $nextLink = $crawler->filter($mangaSource->getNextPageSelector()); + $nextUrl = $nextLink->count() > 0 ? $nextLink->attr('href') : null; - return [ - 'image_url' => $imgUrl, - 'next_page_url' => $nextUrl, - ]; - } + // Convert relative URLs to absolute URLs + $baseUrl = $mangaSource->getBaseUrl(); + $imgUrls = array_map(function ($imgUrl) use ($baseUrl) { + if (!preg_match('/^https?:\/\//', $imgUrl)) { + $urlComponents = parse_url($baseUrl); + $scheme = $urlComponents['scheme']; + $host = $urlComponents['host']; + $imgUrl = $scheme . '://' . $host . '/' . ltrim($imgUrl, '/'); + } + return $imgUrl; + }, $imgUrls); + + return [ + 'image_urls' => $imgUrls, + 'next_page_url' => $nextUrl, + ]; + } /** * @throws GuzzleException */ - public function scrapeMangaChapter(string $chapterUrl, string $mangaTitle, float $chapterNumber): array|bool - { - if(!$this->isChapterAvailable($chapterUrl, $chapterNumber)){ - return false; - } + public function scrapeManga(Manga $manga, ContentSource $mangaSource): array + { + $allChaptersData = []; - $pageData = []; - $currentPageUrl = $chapterUrl; + foreach ($manga->getChapters() as $chapter) { + $chapterData = $this->scrapeChapter($manga, $chapter, $mangaSource); + if ($chapterData !== false) { + $allChaptersData[$chapter->getNumber()] = $chapterData; + } + } - $mangaDir = sprintf('%s/%s', $this->projectDir . self::IMG_BASE_DIR, $mangaTitle); - if (!is_dir($mangaDir)) { - mkdir($mangaDir, 0755, true); - } + return $allChaptersData; + } - // Créez le dossier du chapitre s'il n'existe pas - $chapterDir = sprintf('%s/%s', $mangaDir, $chapterNumber); - if (!is_dir($chapterDir)) { - mkdir($chapterDir, 0755, true); - } + private function scrapeChapter(Manga $manga, Chapter $chapter, ContentSource $mangaSource): array|bool + { + switch ($mangaSource->getScrapingType()) { + case 'html': + return $this->scrapeChapterHtml($manga, $chapter, $mangaSource); + case 'javascript': + return $this->scrapeChapterJavaScript($manga, $chapter, $mangaSource); +// case 'api': +// // Implémentez la méthode de scraping par API si nécessaire +// return $this->scrapeChapterApi($manga, $chapter, $mangaSource); + default: + throw new \Exception('Unsupported scraping type: ' . $mangaSource->getScrapingType()); + } + } - do { - $html = $this->fetchHtml($currentPageUrl); - $page = $this->extractMangaPageData($html); - $pageData[] = $page; - $currentPageUrl = $page['next_page_url']; +// private function scrapeChapterHtml(Manga $manga, Chapter $chapter, MangaSource $mangaSource): array|bool +// { +// $chapterUrl = $mangaSource->getChapterUrl($manga->getTitle(), $chapter->getChapterNumber()); +// $html = $this->fetchHtml($chapterUrl); +// $imgUrls = $this->extractMangaPageData($html); +// +// return $this->saveChapterImages($manga, $chapter, $imgUrls); +// } - // Construisez le nom de fichier de l'image - $imageName = sprintf('%03d.jpg', count($pageData)); + private function scrapeChapterJavaScript(Manga $manga, Chapter $chapter, ContentSource $mangaSource): array|bool + { + $chapterUrl = $mangaSource->getChapterUrl($manga->getTitle(), $chapter->getNumber()); + $imgUrls = $this->fetchImagesUsingPuppeteer($chapterUrl, $mangaSource->getImageSelector(), $mangaSource->getNextPageSelector()); - // Construisez le chemin du fichier de l'image - $imagePath = sprintf('%s/%s', $chapterDir, $imageName); + return $this->saveChapterImages($manga, $chapter, $imgUrls); + } - // Téléchargez et enregistrez l'image - $this->downloadAndSaveImage($page['image_url'], $imagePath); + private function fetchImagesUsingPuppeteer(string $url, string $imageSelector, string $nextButtonSelector): array + { + // Appeler le script Puppeteer avec les paramètres nécessaires + $output = []; + $command = sprintf('node puppeteer-script.js "%s" "%s" "%s" 2>&1', $url, $imageSelector, $nextButtonSelector); // Redirect stderr to stdout + dump($command); +// exec($command, $output, $return_var); - // Modifiez les données de la page pour inclure l'URL de l'image stockée localement - $pageData[count($pageData) - 1]['local_image_url'] = sprintf('/manga-images/%s/%s/%s', $mangaTitle, $chapterNumber, $imageName); - $pageData[count($pageData) - 1]['page_number'] = count($pageData); + dd($command, $output); - } while ($currentPageUrl); + // Convertir la sortie JSON en tableau PHP + return json_decode(implode("", $output), true); + } - $event = new MangaScrapedEvent($mangaTitle, $chapterNumber, $pageData); - $this->eventDispatcher->dispatch($event, MangaScrapedEvent::NAME); + /** + * @throws GuzzleException + */ + private function scrapeChapterHtml(Manga $manga, Chapter $chapter, ContentSource $mangaSource): array|bool + { + $chapterUrl = $mangaSource->getChapterUrl($manga->getSlug(), $chapter->getNumber()); - return $pageData; - } + $pageData = []; + $currentPageUrl = $chapterUrl; + $mangaTitle = $manga->getTitle(); + $chapterNumber = $chapter->getNumber(); + + $mangaDir = sprintf('%s/%s', $this->projectDir . self::IMG_BASE_DIR, $mangaTitle); + if (!is_dir($mangaDir)) { + mkdir($mangaDir, 0755, true); + } + + $chapterDir = sprintf('%s/%s', $mangaDir, $chapterNumber); + if (!is_dir($chapterDir)) { + mkdir($chapterDir, 0755, true); + } + + do { + $html = $this->fetchHtml($currentPageUrl); + $page = $this->extractMangaPageData($html, $mangaSource); + + foreach ($page['image_urls'] as $imgUrl) { + dump($imgUrl); + dump(base64_decode($imgUrl)); + // Déterminer l'extension de l'image + $imageExtension = pathinfo(parse_url($imgUrl, PHP_URL_PATH), PATHINFO_EXTENSION); + + // Construire le nom de fichier de l'image + $imageName = sprintf('%03d.%s', count($pageData) + 1, $imageExtension); + $imagePath = sprintf('%s/%s', $chapterDir, $imageName); + + $this->downloadAndSaveImage($imgUrl, $imagePath); + + $pageData[] = [ + 'image_url' => $imgUrl, + 'local_image_url' => sprintf('/manga-images/%s/%s/%s', $mangaTitle, $chapterNumber, $imageName), + 'page_number' => count($pageData) + 1, + ]; + } + + // Si plus d'une image a été trouvée, ne pas chercher la page suivante + if (count($page['image_urls']) > 1) { + break; + } + + $currentPageUrl = $page['next_page_url']; + } while ($currentPageUrl); + + $event = new MangaScrapedEvent($mangaTitle, $chapterNumber, $pageData); + $this->eventDispatcher->dispatch($event, MangaScrapedEvent::NAME); + + return $pageData; + } /** * @throws GuzzleException */ private function fetchHtml(string $url): string - { - $client = new Client(); - $response = $client->get($url); + { + $client = new Client(); + $response = $client->get($url); - return (string) $response->getBody(); - } + return (string)$response->getBody(); + } /** * @throws GuzzleException */ private function downloadAndSaveImage(string $imageUrl, string $destinationPath): void - { - $client = new Client(); - $response = $client->get($imageUrl); + { + $client = new Client(); + $response = $client->get($imageUrl); - file_put_contents($destinationPath, $response->getBody()->getContents()); - } + file_put_contents($destinationPath, $response->getBody()->getContents()); + } + + private function saveChapterImages(Manga $manga, Chapter $chapter, array $imgUrls): array + { + $mangaTitle = $manga->getTitle(); + $chapterNumber = $chapter->getNumber(); + + $mangaDir = sprintf('%s/%s', $this->projectDir . self::IMG_BASE_DIR, $mangaTitle); + if (!is_dir($mangaDir)) { + mkdir($mangaDir, 0755, true); + } + + $chapterDir = sprintf('%s/%s', $mangaDir, $chapterNumber); + if (!is_dir($chapterDir)) { + mkdir($chapterDir, 0755, true); + } + + $pageData = []; + foreach ($imgUrls as $index => $imgUrl) { + $imageName = sprintf('%03d.%s', $index + 1, pathinfo(parse_url($imgUrl, PHP_URL_PATH), PATHINFO_EXTENSION)); + $imagePath = sprintf('%s/%s', $chapterDir, $imageName); + + $this->downloadAndSaveImage($imgUrl, $imagePath); + + $pageData[] = [ + 'image_url' => $imgUrl, + 'local_image_url' => sprintf('/manga-images/%s/%s/%s', $mangaTitle, $chapterNumber, $imageName), + 'page_number' => $index + 1, + ]; + } + + $event = new MangaScrapedEvent($mangaTitle, $chapterNumber, $pageData); + $this->eventDispatcher->dispatch($event, MangaScrapedEvent::NAME); + + return $pageData; + } /** * @throws GuzzleException */ - private function isChapterAvailable(string $chapterUrl, float $chapterNumber): bool - { - $html = $this->fetchHtml($chapterUrl); - $crawler = new Crawler($html); - $nextLink = $crawler->filter('a[title="Suivant"]'); + private function isChapterAvailable(string $chapterUrl, float $chapterNumber, ContentSource $mangaSource): bool + { + $html = $this->fetchHtml($chapterUrl); + $crawler = new Crawler($html); + $nextLink = $crawler->filter($mangaSource->getNextPageSelector()); - if($nextLink->count() === 0){ - return false; - }else{ - $nextUrl = $nextLink->attr('href'); - } + if ($nextLink->count() === 0) { + return false; + } - $routeCollection = new RouteCollection(); - $routeCollection->add('manga_chapter', new Route('/scan-{manga}/{chapter}/{page}')); - $context = new RequestContext('/'); - $matcher = new UrlMatcher($routeCollection, $context); - $path = parse_url($nextUrl, PHP_URL_PATH); - $parameters = $matcher->match($path); + $nextUrl = $nextLink->attr('href'); + $routeCollection = new RouteCollection(); + $routeCollection->add('manga_chapter', new Route('/scan-{manga}/{chapter}/{page}')); + $context = new RequestContext('/'); + $matcher = new UrlMatcher($routeCollection, $context); + $path = parse_url($nextUrl, PHP_URL_PATH); + $parameters = $matcher->match($path); - if((float) $parameters['chapter'] !== $chapterNumber){ - return false; - } - - return true; - } + return (float)$parameters['chapter'] === $chapterNumber; + } } diff --git a/src/Service/MangaScraperServiceOld.php b/src/Service/MangaScraperServiceOld.php new file mode 100644 index 0000000..bd06161 --- /dev/null +++ b/src/Service/MangaScraperServiceOld.php @@ -0,0 +1,157 @@ +projectDir = $projectDir; + $this->eventDispatcher = $eventDispatcher; + } + + public function extractMangaPageData(string $html): array + { + $baseUrl = 'https://lelscans.net'; + //pour éviter à PhpStorm de gueuler... + $selector = 'img'; + $crawler = new Crawler($html); + $imgUrl = $crawler->filter($selector)->attr('src'); + $nextLink = $crawler->filter('a[title="Suivant"]'); + + if (!preg_match('/^https?:\/\//', $imgUrl)) { + $urlComponents = parse_url($baseUrl); + $scheme = $urlComponents['scheme']; + $host = $urlComponents['host']; + + // Construit l'URL absolue de l'image + $imgUrl = $scheme . '://' . $host . '/' . ltrim($imgUrl, '/'); + } + + if($nextLink->count() > 0){ + $nextUrl = $nextLink->attr('href'); + }else{ + $nextUrl = null; + } + + return [ + 'image_url' => $imgUrl, + 'next_page_url' => $nextUrl, + ]; + } + + /** + * @throws GuzzleException + */ + public function scrapeMangaChapter(string $chapterUrl, string $mangaTitle, float $chapterNumber): array|bool + { + if(!$this->isChapterAvailable($chapterUrl, $chapterNumber)){ + return false; + } + + $pageData = []; + $currentPageUrl = $chapterUrl; + + $mangaDir = sprintf('%s/%s', $this->projectDir . self::IMG_BASE_DIR, $mangaTitle); + if (!is_dir($mangaDir)) { + mkdir($mangaDir, 0755, true); + } + + // Créez le dossier du chapitre s'il n'existe pas + $chapterDir = sprintf('%s/%s', $mangaDir, $chapterNumber); + if (!is_dir($chapterDir)) { + mkdir($chapterDir, 0755, true); + } + + do { + $html = $this->fetchHtml($currentPageUrl); + $page = $this->extractMangaPageData($html); + $pageData[] = $page; + $currentPageUrl = $page['next_page_url']; + + // Construisez le nom de fichier de l'image + $imageName = sprintf('%03d.jpg', count($pageData)); + + // Construisez le chemin du fichier de l'image + $imagePath = sprintf('%s/%s', $chapterDir, $imageName); + + // Téléchargez et enregistrez l'image + $this->downloadAndSaveImage($page['image_url'], $imagePath); + + // Modifiez les données de la page pour inclure l'URL de l'image stockée localement + $pageData[count($pageData) - 1]['local_image_url'] = sprintf('/manga-images/%s/%s/%s', $mangaTitle, $chapterNumber, $imageName); + $pageData[count($pageData) - 1]['page_number'] = count($pageData); + + } while ($currentPageUrl); + + $event = new MangaScrapedEvent($mangaTitle, $chapterNumber, $pageData); + $this->eventDispatcher->dispatch($event, MangaScrapedEvent::NAME); + + return $pageData; + } + + /** + * @throws GuzzleException + */ + private function fetchHtml(string $url): string + { + $client = new Client(); + $response = $client->get($url); + + return (string) $response->getBody(); + } + + /** + * @throws GuzzleException + */ + private function downloadAndSaveImage(string $imageUrl, string $destinationPath): void + { + $client = new Client(); + $response = $client->get($imageUrl); + + file_put_contents($destinationPath, $response->getBody()->getContents()); + } + + /** + * @throws GuzzleException + */ + private function isChapterAvailable(string $chapterUrl, float $chapterNumber): bool + { + $html = $this->fetchHtml($chapterUrl); + $crawler = new Crawler($html); + $nextLink = $crawler->filter('a[title="Suivant"]'); + + if($nextLink->count() === 0){ + return false; + }else{ + $nextUrl = $nextLink->attr('href'); + } + + $routeCollection = new RouteCollection(); + $routeCollection->add('manga_chapter', new Route('/scan-{manga}/{chapter}/{page}')); + $context = new RequestContext('/'); + $matcher = new UrlMatcher($routeCollection, $context); + $path = parse_url($nextUrl, PHP_URL_PATH); + $parameters = $matcher->match($path); + + if((float) $parameters['chapter'] !== $chapterNumber){ + return false; + } + + return true; + } +} diff --git a/src/Service/MangaUpdatesDbProvider.php b/src/Service/MangaUpdatesMetadataProvider.php similarity index 72% rename from src/Service/MangaUpdatesDbProvider.php rename to src/Service/MangaUpdatesMetadataProvider.php index 9ba7965..1cfaff8 100644 --- a/src/Service/MangaUpdatesDbProvider.php +++ b/src/Service/MangaUpdatesMetadataProvider.php @@ -3,20 +3,19 @@ namespace App\Service; use App\Entity\Manga; +use App\Interface\MetadataProviderInterface; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Exception; use GuzzleHttp\Client; use GuzzleHttp\Exception\GuzzleException; -use Symfony\Component\BrowserKit\HttpBrowser; use Symfony\Component\String\Slugger\SluggerInterface; -use Symfony\Contracts\HttpClient\HttpClientInterface; -class MangaUpdatesDbProvider implements MangaDbProviderInterface +class MangaUpdatesMetadataProvider implements MetadataProviderInterface { private Client $client; - public function __construct(private SluggerInterface $slugger) + public function __construct(private readonly SluggerInterface $slugger) { $this->client = new Client(); } @@ -40,6 +39,9 @@ class MangaUpdatesDbProvider implements MangaDbProviderInterface $results = $this->client->request('POST', 'https://api.mangaupdates.com/v1/series/search', [ 'json' => [ 'search' => $title, + 'licensed' => 'yes', + 'type' => ['Manga'], + 'exclude_genre' => ['Doujinshi', 'Adult', 'Hentai', 'Ecchi', 'Yaoi', 'Yuri', 'Josei', 'Smut', 'Gender Bender'], 'orderby' => 'score', ] ])->withHeader('Authorization', 'Bearer ' . $jwt) @@ -50,13 +52,21 @@ class MangaUpdatesDbProvider implements MangaDbProviderInterface $mangas = []; foreach (json_decode($results, true)['results'] as $record) { $record = $record['record']; + + $genres = []; + foreach ($record['genres'] as $genre) { + $genres[] = $genre['genre']; + } + $mangas[] = (new Manga()) ->setTitle($record['title']) ->setSlug($this->slugger->slug($record['title'])->lower()) ->setDescription($record['description']) ->setImageUrl($record['image']['url']['original']) - ->setGenres($record['genres']) - ->setPublicationYear((int)$record['year']); + ->setGenres($genres) + ->setPublicationYear((int)$record['year']) + ->setRating((float)$record['bayesian_rating']) + ; } return new ArrayCollection($mangas); diff --git a/src/Service/MangadexProvider.php b/src/Service/MangadexProvider.php new file mode 100644 index 0000000..83db533 --- /dev/null +++ b/src/Service/MangadexProvider.php @@ -0,0 +1,123 @@ +client->get('/manga', [ + 'title' => $title, + 'contentRating' => ['safe'], + 'includes' => ['cover_art', 'author'] + ]); + + $mangas = []; + foreach ($results['data'] as $result) { + $mangas[] = (new Manga()) + ->setExternalId($result['id']) + ->setTitle($result['attributes']['title']['en']) + ->setSlug($this->slugger->slug($result['attributes']['title']['en'])->lower()) + ->setDescription($result['attributes']['description']['fr'] ?? $result['attributes']['description']['en'] ?? '') + ->setPublicationYear($result['attributes']['year']) + ; + $tags = []; + foreach($result['attributes']['tags'] as $tag){ + $tags[] = $tag['attributes']['name']['en']; + } + + $mangas[count($mangas) - 1]->setGenres($tags); + + foreach($result['relationships'] as $relationship) { + if($relationship['type'] === 'author') { + $mangas[count($mangas) - 1]->setAuthor($relationship['attributes']['name']); + } + + if($relationship['type'] === 'cover_art') { + $mangas[count($mangas) - 1]->setImageUrl('https://mangadex.org/covers/' . $result['id'] . '/' .$relationship['attributes']['fileName']); + } + } + } + + $test = array_map(fn($manga) => $manga->getExternalId(), $mangas); + + $ratings = $this->client->get('/statistics/manga', [ + 'manga' => $test + ]); + + foreach($mangas as $manga) { + $manga->setRating($ratings['statistics'][$manga->getExternalId()]['rating']['average']); + } + + return new ArrayCollection($mangas); + } + + public function getFeed(Manga $manga): Manga + { + if($manga->getExternalId() === null) { + return $manga; + } + + $chapters = []; + $page = 0; + + do { + $results = $this->getFeedWithPagination($manga->getExternalId(), $page); + if (isset($results['data'])) { + $chapters = array_merge($chapters, $results['data']); + } else { + break; + } + $page++; + } while (count($chapters) < $results['total']); + + foreach($chapters as $result) { + $chapterNumber = (float)$result['attributes']['chapter']; + + // Utilisez la méthode exists de Doctrine pour vérifier si un chapitre avec le même numéro existe déjà + $chapterExists = $manga->getChapters()->exists(function($key, $existingChapter) use ($chapterNumber) { + return $existingChapter->getNumber() === $chapterNumber; + }); + + // Si le chapitre existe déjà, on skip + if ($chapterExists) { + continue; + } + + // Créez et ajoutez le nouveau chapitre + $chapter = new Chapter(); + $chapter->setNumber($chapterNumber) + ->setTitle($result['attributes']['title']) + ->setVolume((int)$result['attributes']['volume'] ?? null); + + $manga->addChapter($chapter); + } + + return $manga; + } + + private function getFeedWithPagination(string $externalId, int $page){ + return $this->client->get('/manga/' . $externalId . '/feed', [ + 'limit' => 500, + 'translatedLanguage' =>['en'], + 'order' => ['chapter' => 'asc'], + 'offset' => $page * 500 + ]); + } +} diff --git a/src/Service/SushiScanProviderService.php b/src/Service/SushiScanProviderService.php index eade353..dccc42a 100644 --- a/src/Service/SushiScanProviderService.php +++ b/src/Service/SushiScanProviderService.php @@ -2,33 +2,72 @@ namespace App\Service; -use Goutte\Client; +use App\Entity\Manga; +use App\Interface\ContentProviderInterface; +use Symfony\Component\BrowserKit\HttpBrowser; +use Symfony\Component\BrowserKit\HttpBrowser as Client; +//use GuzzleHttp\Client; +use GuzzleHttp\Exception\GuzzleException; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\HttpClient\HttpClient; -class SushiScanProviderService implements MangaProviderInterface +class SushiScanProviderService { - const PROVIDER_URL = 'https://sushiscan.com/'; - const MANGA_SLUG = '/{manga}/{chapter}/{page}'; - private Client $client; + const PROVIDER_URL = 'https://sushiscan.net/catalogue/'; + const MANGA_SLUG = '/{manga}/{chapter}/{page}'; - public function __construct() - { - $this->client = new Client(); - } + const CONTENT_TYPE = ['volume', 'chapitre']; + private Client $client; - /** - * @return array - */ - public function getMangaList(): array - { - // TODO: Implement getMangaList() method. - } + public function __construct() + { + $httpClient = HttpClient::create(['timeout' => 60]); + $this->client = new HttpBrowser($httpClient); + } - /** - * @param string $mangaSlug - * @return array - */ - public function getChapterList(string $mangaSlug): array - { - // TODO: Implement getChapterList() method. - } -} \ No newline at end of file + public function getAvailableContent(Manga $manga) + { + $url = 'http://flaresolverr:8191/v1'; + $jsonContent = json_encode([ + 'cmd' => 'request.get', + 'url' => self::PROVIDER_URL . $manga->getSlug(), + 'maxTimeout' => 90000, + ]); + + + try{ + $crawler = $this->client->request('POST', $url, [], [], [ + 'HTTP_CONTENT_TYPE' => 'application/json', + ], $jsonContent); + + }catch (\Exception $e) { + dd($e); + } + $contentList = []; + + dd($crawler); + + $crawler->filter('#chapterList ul > li')->each(function (Crawler $node) use (&$contentList) { + dump($node); +// $contentName = $node->text(); +// $contentUrl = $node->attr('href'); +// if ($contentName && $contentUrl) { +// $contentList[] = [ +// 'name' => $contentName, +// 'url' => $contentUrl, +// ]; +// } + }); + + return $contentList; + } + + /** + * @param string $mangaSlug + * @return array + */ + public function getChapterList(string $mangaSlug): array + { + // TODO: Implement getChapterList() method. + } +} diff --git a/src/Twig/Components/AddMangaModalComponent.php b/src/Twig/Components/AddMangaModalComponent.php new file mode 100644 index 0000000..b6633f2 --- /dev/null +++ b/src/Twig/Components/AddMangaModalComponent.php @@ -0,0 +1,27 @@ +manga = $manga; + } + + public function close(): void + { + $this->manga = null; + } +} diff --git a/src/Twig/Components/BootstrapModal.php b/src/Twig/Components/BootstrapModal.php new file mode 100644 index 0000000..331c5da --- /dev/null +++ b/src/Twig/Components/BootstrapModal.php @@ -0,0 +1,11 @@ +mangaSlug; +// $chapter = $this->chapter; +// $manga = $mangaRepository->findOneBy(['slug' => $mangaSlug]); +// $chapter = $chapterRepository->findOneBy(['manga' => $manga, 'number' => $chapter]); + + + return 0; + + } +} diff --git a/src/Twig/Components/MangaSearch.php b/src/Twig/Components/MangaSearch.php new file mode 100644 index 0000000..cfd1ae1 --- /dev/null +++ b/src/Twig/Components/MangaSearch.php @@ -0,0 +1,38 @@ +query === null || $this->query === '') { + return null; + } + + return $this->mangadexProvider->search($this->query); + } +} diff --git a/src/Twig/Components/NewMangaForm.php b/src/Twig/Components/NewMangaForm.php new file mode 100644 index 0000000..d91f531 --- /dev/null +++ b/src/Twig/Components/NewMangaForm.php @@ -0,0 +1,79 @@ +manga = $manga; + $this->mangaData = [ + 'title' => $manga->getTitle(), + 'slug' => $manga->getSlug(), + 'description' => $manga->getDescription(), + 'imageUrl' => $manga->getImageUrl(), + 'status' => $manga->getStatus(), + 'genres' => $manga->getGenres(), + 'author' => $manga->getAuthor(), + 'publicationYear' => $manga->getPublicationYear(), + 'rating' => $manga->getRating(), + 'externalId' => $manga->getExternalId(), + ]; + } + + #[LiveAction] + public function saveManga(EntityManagerInterface $entityManager, MangadexProvider $mangadexProvider): Response + { + $manga = new Manga(); + $manga->setTitle($this->mangaData['title']) + ->setSlug($this->mangaData['slug']) + ->setDescription($this->mangaData['description']) + ->setImageUrl($this->mangaData['imageUrl']) + ->setStatus($this->mangaData['status']) + ->setGenres($this->mangaData['genres']) + ->setAuthor($this->mangaData['author']) + ->setPublicationYear($this->mangaData['publicationYear']) + ->setRating($this->mangaData['rating']) + ->setExternalId($this->mangaData['externalId']); + + $mangadexProvider->getFeed($manga); + try { + foreach ($manga->getChapters() as $chapter) { + $entityManager->persist($chapter); + } + + $entityManager->persist($manga); + $entityManager->flush(); + } catch (\Exception $e) { + if ($e instanceof UniqueConstraintViolationException) { + return new RedirectResponse('/manga/' . $manga->getSlug()); + } + throw $e; + } + + return new RedirectResponse('/manga/' . $manga->getSlug()); + } +} diff --git a/src/Twig/Components/Search.php b/src/Twig/Components/Search.php new file mode 100644 index 0000000..5652231 --- /dev/null +++ b/src/Twig/Components/Search.php @@ -0,0 +1,28 @@ +query ? $this->mangaRepository->findByTitle($this->query) : []; + } +} diff --git a/src/Twig/Components/ToolBarButton.php b/src/Twig/Components/ToolBarButton.php new file mode 100644 index 0000000..45f4edf --- /dev/null +++ b/src/Twig/Components/ToolBarButton.php @@ -0,0 +1,12 @@ + $limit ? substr($value, 0, $limit) . '...' : $value; + } +} diff --git a/src/Twig/Runtime/TruncateExtensionRuntime.php b/src/Twig/Runtime/TruncateExtensionRuntime.php new file mode 100644 index 0000000..20b23f0 --- /dev/null +++ b/src/Twig/Runtime/TruncateExtensionRuntime.php @@ -0,0 +1,18 @@ +⚫️"> {% block stylesheets %} {{ encore_entry_link_tags('app') }} - {{ encore_entry_link_tags('app') }} + {% endblock %} + {% block javascripts %} + {{ encore_entry_script_tags('app') }} {% endblock %} - + +
+ +
+ {% include 'menu/menu.html.twig' %} -
- - Mangarr - +
+
+ {% block toolbar %} + {% endblock %} +
+
+ {% block body %} + {% endblock %} +
+
+
-
- {% include 'menu/menu.html.twig' %} - {% block body %}{% endblock %} -
-{% block javascripts %} - {{ encore_entry_script_tags('app') }} - {{ encore_entry_script_tags('app') }} -{% endblock %} - diff --git a/templates/bundles/TwigBundle/Exception/error404.html.twig b/templates/bundles/TwigBundle/Exception/error404.html.twig new file mode 100644 index 0000000..45cf13f --- /dev/null +++ b/templates/bundles/TwigBundle/Exception/error404.html.twig @@ -0,0 +1,9 @@ +{# templates/bundles/TwigBundle/Exception/error404.html.twig #} +{% extends 'base.html.twig' %} + +{% block title %}Page non trouvée{% endblock %} + +{% block body %} +

Page non trouvée

+

La page que vous cherchez n'existe pas.

+{% endblock %} diff --git a/templates/components/AddMangaModal.html.twig b/templates/components/AddMangaModal.html.twig new file mode 100644 index 0000000..370c77b --- /dev/null +++ b/templates/components/AddMangaModal.html.twig @@ -0,0 +1,12 @@ +{# templates/components/manga_modal.html.twig #} +
+ +
diff --git a/templates/components/BootstrapModal.html.twig b/templates/components/BootstrapModal.html.twig new file mode 100644 index 0000000..e99311d --- /dev/null +++ b/templates/components/BootstrapModal.html.twig @@ -0,0 +1,33 @@ +
+ +
diff --git a/templates/components/DownloadChapter.html.twig b/templates/components/DownloadChapter.html.twig new file mode 100644 index 0000000..df74fce --- /dev/null +++ b/templates/components/DownloadChapter.html.twig @@ -0,0 +1,5 @@ + + + + +
diff --git a/templates/components/MangaSearch.html.twig b/templates/components/MangaSearch.html.twig new file mode 100644 index 0000000..7b8aeaa --- /dev/null +++ b/templates/components/MangaSearch.html.twig @@ -0,0 +1,65 @@ +{# templates/components/MangaSearch.html.twig #} + +
+
+
+
+ + + + + +
+
+
+ + {% if this.mangas %} +
+ {% for manga in this.mangas %} +
+ + {{ manga.title }} + +
+
+
+
+ {{ manga.title }} + ({{ manga.publicationYear }}) +
+ + + +
+ {% for genre in manga.genres %} + + {{ genre }} + + {% endfor %} +
+
+

{{ manga.description|truncate(250) }}

+
+
+ + + {{ manga.rating }} + +
+
+
+ {{ component('NewMangaForm', {manga: manga, index: loop.index}) }} + {% endfor %} +
+ {% endif %} +
diff --git a/templates/components/NewMangaForm.html.twig b/templates/components/NewMangaForm.html.twig new file mode 100644 index 0000000..9144294 --- /dev/null +++ b/templates/components/NewMangaForm.html.twig @@ -0,0 +1,40 @@ +
+ {% component BootstrapModal with {id: 'mangaModal' ~ index ~ '-' ~ manga.slug } %} + {% block modal_header %} +
+ + +
+ {% endblock %} + {% block modal_body %} +
+
+ {{ manga.title }} +
+

{{ manga.description }}

+

Année de publication: {{ manga.publicationYear }}

+

Genres: {{ manga.genres|join(', ') }}

+

Note: {{ manga.rating }}

+
+
+
+ {% endblock %} + + {% block modal_footer %} + + {% endblock %} + {% endcomponent %} +
diff --git a/templates/components/Search.html.twig b/templates/components/Search.html.twig new file mode 100644 index 0000000..70c1cc5 --- /dev/null +++ b/templates/components/Search.html.twig @@ -0,0 +1,37 @@ + +
+ + +
+ + {% if query %} +
+ +
+ {% endif %} + diff --git a/templates/components/ToolBarButton.html.twig b/templates/components/ToolBarButton.html.twig new file mode 100644 index 0000000..29f9f1f --- /dev/null +++ b/templates/components/ToolBarButton.html.twig @@ -0,0 +1,6 @@ + + + diff --git a/templates/manga/add_new.html.twig b/templates/manga/add_new.html.twig index a5a3daa..c73c410 100644 --- a/templates/manga/add_new.html.twig +++ b/templates/manga/add_new.html.twig @@ -1,80 +1,6 @@ {% extends 'base.html.twig' %} {% block body %} -
-
-
- -
- - - -
-
-
-
-
-
-
- - -
-
+
+ {{ component('MangaSearch', {query: query}) }}
{% endblock %} - -{% block javascripts %} - -{% endblock %} diff --git a/templates/manga/index.html.twig b/templates/manga/index.html.twig index 3a62793..1f371e1 100644 --- a/templates/manga/index.html.twig +++ b/templates/manga/index.html.twig @@ -1,16 +1,42 @@ {% extends 'base.html.twig' %} +{% block toolbar %} +
+
+
+ + +
+ + +
+ +
+
+ +
+ + + +
+
+
+{% endblock %} {% block body %} -
+
{% for manga in mangas %} -
+
- {{ manga.title }} -{# {{ manga.title }}#} + {{ manga.title }}
-

{{ manga.title }}

-

Auteur

-

Ajouter: Jun 2 2024

+
+ {{ manga.title }} + ({{ manga.publicationYear }}) +
+

Added: {{ manga.createdAt|date('M d, Y') }}

{% else %} diff --git a/templates/manga/show_chapters.html.twig b/templates/manga/show_chapters.html.twig index b388c3e..0212e93 100644 --- a/templates/manga/show_chapters.html.twig +++ b/templates/manga/show_chapters.html.twig @@ -1,64 +1,135 @@ {% extends 'base.html.twig' %} +{% block toolbar %} +
+
+
+ + +
+ + +
+ + +
+
+
+{% endblock %} {% block body %} -
-

Chapitres de {{ manga.title }}

- - - -

Scrapper un chapitre

-
- -
- - +
+
+
+
+
+ +
+
+ +

{{ manga.title }}

+
+
+ {{ manga.publicationYear }} + Chapters: {{ manga.chapters.count }} +
+
+ + /media/mangas/{{ manga.title }} ({{ manga.publicationYear }}) + {{ manga.status ?? 'Terminé' }} +
+
+ {% set genre_count = 0 %} + {% for genre in manga.genres %} + {% if genre_count < 5 %} + {{ genre }} + {% set genre_count = genre_count + 1 %} + {% endif %} + {% endfor %} + {% if genre_count == 5 and manga.genres|length > 5 %} + ... + {% endif %} +
+
+
+ + {{ manga.rating|round(2) }} +
+

{{ manga.description|truncate(500) }}

+
+
+
-
- - -
-
- - -
- - +
- {% block javascripts %} - {{ parent() }} - - {% endblock %} + + {% if chapter.pages|length > 0 %} + {{ chapter.title ?? 'No title' }} + {% else %} + {{ chapter.title ?? 'No title'}} + {% endif %} + + + {# #} + + + + {# #} + {# #} + {# #} + + + {% endfor %} + + +
+
+
+ {% endfor %} +
{% endblock %} diff --git a/templates/menu/menu.html.twig b/templates/menu/menu.html.twig index edd3268..25320c3 100644 --- a/templates/menu/menu.html.twig +++ b/templates/menu/menu.html.twig @@ -3,12 +3,15 @@