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 0000000..42a786e
Binary files /dev/null and b/public/img/mangarr_logo.png differ
diff --git a/public/puppeteer-script.js b/public/puppeteer-script.js
new file mode 100644
index 0000000..acd2874
--- /dev/null
+++ b/public/puppeteer-script.js
@@ -0,0 +1,89 @@
+const puppeteer = require('puppeteer');
+
+(async () => {
+ 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 @@
+
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 #} +{{ manga.title }}
-Auteur
-Ajouter: Jun 2 2024
+Added: {{ manga.createdAt|date('M d, Y') }}