From 306377a7bebecfd1e7851a144470b899ad51b310 Mon Sep 17 00:00:00 2001 From: Francesco Grazioso <40018163+FrancescoGrazioso@users.noreply.github.com> Date: Sat, 1 Jun 2024 11:59:11 +0200 Subject: [PATCH 01/13] Feat/app api and frontend (#136) * minor fixes * created basic django app * add django dependency * created basic search endpoint * created retrieve method for search * remove retrieve * start implementing download endpoint (only movie for now) * start implementing episode info for series * finished get_episodes_info * minor fixes * add download anime episode * start implementing download for tv series * refactor methods * finished download endpoint (will implement possibility to download single episodes of season in tv series) * new domain and black on project * start * add cors * add start gui command * add gui for search * edited .gitignore * create component for media details * better UX/UI * edited anime episode to stream response (better experience) * implemented UI for media details (TODO add download capabilities) * fix poster fetching * minor fixes * fix cors error * start implementing download * fix typing on anime movies * refactor * refactor + add download OVA * add plot for all anime types * add download for all anime episodes * add download all tv series episodes * fix crach if localStorage is undefined * moved download logic in separeted file * fix wrong index passed while downloading tv series * fix style searchbar * add loader to search button and add enter listener while searching * remove dependency from loading episodes to download all in anime series * add function to download selected episodes for anime * add sh command to kill gui * fix messages in kill_gui.sh * start implementing download select episodes for tv series (to be tested) + run black and eslint * start refactoring to version 2.0 * start implementing preview endpoint --- .gitignore | 13 +- Src/Api/Animeunity/Core/Class/EpisodeType.py | 15 + Src/Api/Animeunity/Core/Class/PreviewType.py | 13 + Src/Api/Animeunity/Core/Class/SearchType.py | 23 + .../Core/Class/EpisodeType.py | 28 + .../Core/Class/PreviewType.py | 13 + .../Core/Class/SearchType.py | 34 + api/__init__.py | 0 api/api/__init__.py | 0 api/api/asgi.py | 16 + api/api/settings.py | 140 + api/api/urls.py | 24 + api/api/wsgi.py | 16 + api/endpoints/__init__.py | 0 api/endpoints/admin.py | 3 + api/endpoints/apps.py | 6 + api/endpoints/migrations/__init__.py | 0 api/endpoints/models.py | 3 + api/endpoints/tests.py | 3 + api/endpoints/urls.py | 10 + api/endpoints/views.py | 241 ++ api/manage.py | 24 + config.json | 2 +- frontend/.eslintrc.cjs | 15 + frontend/.gitignore | 30 + frontend/.prettierrc.json | 8 + frontend/.vscode/extensions.json | 7 + frontend/README.md | 39 + frontend/env.d.ts | 1 + frontend/index.html | 13 + frontend/package-lock.json | 3225 +++++++++++++++++ frontend/package.json | 36 + frontend/public/favicon.ico | Bin 0 -> 4286 bytes frontend/src/App.vue | 36 + frontend/src/api/api.ts | 81 + frontend/src/api/interfaces.ts | 64 + frontend/src/api/utils.ts | 63 + frontend/src/assets/base.css | 86 + frontend/src/assets/logo.svg | 1 + frontend/src/assets/main.css | 35 + frontend/src/components/Card.vue | 92 + frontend/src/components/Toggle.vue | 105 + frontend/src/main.ts | 11 + frontend/src/router/index.ts | 30 + frontend/src/views/Details.vue | 335 ++ frontend/src/views/HomeView.vue | 176 + frontend/tsconfig.app.json | 14 + frontend/tsconfig.json | 11 + frontend/tsconfig.node.json | 19 + frontend/vite.config.ts | 16 + kill_gui.sh | 29 + requirements.txt | 9 +- start_gui.sh | 23 + 53 files changed, 5234 insertions(+), 3 deletions(-) create mode 100644 api/__init__.py create mode 100644 api/api/__init__.py create mode 100644 api/api/asgi.py create mode 100644 api/api/settings.py create mode 100644 api/api/urls.py create mode 100644 api/api/wsgi.py create mode 100644 api/endpoints/__init__.py create mode 100644 api/endpoints/admin.py create mode 100644 api/endpoints/apps.py create mode 100644 api/endpoints/migrations/__init__.py create mode 100644 api/endpoints/models.py create mode 100644 api/endpoints/tests.py create mode 100644 api/endpoints/urls.py create mode 100644 api/endpoints/views.py create mode 100755 api/manage.py create mode 100644 frontend/.eslintrc.cjs create mode 100644 frontend/.gitignore create mode 100644 frontend/.prettierrc.json create mode 100644 frontend/.vscode/extensions.json create mode 100644 frontend/README.md create mode 100644 frontend/env.d.ts create mode 100644 frontend/index.html create mode 100644 frontend/package-lock.json create mode 100644 frontend/package.json create mode 100644 frontend/public/favicon.ico create mode 100644 frontend/src/App.vue create mode 100644 frontend/src/api/api.ts create mode 100644 frontend/src/api/interfaces.ts create mode 100644 frontend/src/api/utils.ts create mode 100644 frontend/src/assets/base.css create mode 100644 frontend/src/assets/logo.svg create mode 100644 frontend/src/assets/main.css create mode 100644 frontend/src/components/Card.vue create mode 100644 frontend/src/components/Toggle.vue create mode 100644 frontend/src/main.ts create mode 100644 frontend/src/router/index.ts create mode 100644 frontend/src/views/Details.vue create mode 100644 frontend/src/views/HomeView.vue create mode 100644 frontend/tsconfig.app.json create mode 100644 frontend/tsconfig.json create mode 100644 frontend/tsconfig.node.json create mode 100644 frontend/vite.config.ts create mode 100755 kill_gui.sh create mode 100755 start_gui.sh diff --git a/.gitignore b/.gitignore index be44e50..69e9099 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,14 @@ local_settings.py db.sqlite3 db.sqlite3-journal + +# Vue stuff: +frontend/dist/ +frontend/node_modules/ +frontend/npm-debug.log +frontend/.vite/ +frontend/.vscode/ + # Jupyter Notebook .ipynb_checkpoints @@ -55,4 +63,7 @@ env.bak/ venv.bak/ # Other -Video \ No newline at end of file +Video +.idea/ +.vscode/ +.DS_Store diff --git a/Src/Api/Animeunity/Core/Class/EpisodeType.py b/Src/Api/Animeunity/Core/Class/EpisodeType.py index 14b9694..f583914 100644 --- a/Src/Api/Animeunity/Core/Class/EpisodeType.py +++ b/Src/Api/Animeunity/Core/Class/EpisodeType.py @@ -45,6 +45,21 @@ class Episode: def __str__(self): return f"Episode(id={self.id}, number={self.number}, name='{self.name}', plot='{self.plot}', duration={self.duration} sec)" + + def to_dict(self) -> Dict[str, Any]: + return { + "id": self.id, + "number": self.number, + "name": self.name, + "plot": self.plot, + "duration": self.duration, + "scws_id": self.scws_id, + "season_id": self.season_id, + "created_by": self.created_by, + "created_at": self.created_at, + "updated_at": self.updated_at, + "images": [image.__dict__ for image in self.images] + } class EpisodeManager: diff --git a/Src/Api/Animeunity/Core/Class/PreviewType.py b/Src/Api/Animeunity/Core/Class/PreviewType.py index 28d741e..7b80b0a 100644 --- a/Src/Api/Animeunity/Core/Class/PreviewType.py +++ b/Src/Api/Animeunity/Core/Class/PreviewType.py @@ -60,4 +60,17 @@ class PreviewManager: images_str = "\n".join(str(image) for image in self.images) return f"Title: ID={self.id}, Type={self.type}, Runtime={self.runtime}, Release Date={self.release_date}, Quality={self.quality}, Plot={self.plot}, Seasons Count={self.seasons_count}\nGenres:\n{genres_str}\nPreview:\n{self.preview}\nImages:\n{images_str}" + def to_dict(self): + return { + "id": self.id, + "type": self.type, + "runtime": self.runtime, + "release_date": self.release_date, + "quality": self.quality, + "plot": self.plot, + "seasons_count": self.seasons_count, + "genres": [genre.__dict__ for genre in self.genres], + "preview": self.preview.__dict__, + "images": [image.__dict__ for image in self.images] + } diff --git a/Src/Api/Animeunity/Core/Class/SearchType.py b/Src/Api/Animeunity/Core/Class/SearchType.py index 6c492bf..4e3c50f 100644 --- a/Src/Api/Animeunity/Core/Class/SearchType.py +++ b/Src/Api/Animeunity/Core/Class/SearchType.py @@ -37,10 +37,33 @@ class MediaItem: self.last_air_date: str = data.get('last_air_date') self.seasons_count: int = data.get('seasons_count') self.images: List[Image] = [Image(image_data) for image_data in data.get('images', [])] + self.comment: str = data.get('comment') + self.plot: str = data.get('plot') def __str__(self): return f"MediaItem(id={self.id}, slug='{self.slug}', name='{self.name}', type='{self.type}', score='{self.score}', sub_ita={self.sub_ita}, last_air_date='{self.last_air_date}', seasons_count={self.seasons_count}, images={self.images})" + @property + def to_dict(self) -> dict: + """ + Convert the MediaItem to a dictionary. + + Returns: + dict: The MediaItem as a dictionary. + """ + return { + "id": self.id, + "slug": self.slug, + "name": self.name, + "type": self.type.upper(), + "score": self.score, + "sub_ita": self.sub_ita, + "last_air_date": self.last_air_date, + "seasons_count": self.seasons_count, + "images": [image.__dict__ for image in self.images], + "comment": self.comment, + "plot": self.plot + } class MediaManager: def __init__(self): diff --git a/Src/Api/Streamingcommunity/Core/Class/EpisodeType.py b/Src/Api/Streamingcommunity/Core/Class/EpisodeType.py index 468e98b..8857726 100644 --- a/Src/Api/Streamingcommunity/Core/Class/EpisodeType.py +++ b/Src/Api/Streamingcommunity/Core/Class/EpisodeType.py @@ -27,6 +27,19 @@ class Image: def __str__(self): return f"Image(id={self.id}, filename='{self.filename}', type='{self.type}', imageable_type='{self.imageable_type}', url='{self.url}')" + + def to_dict(self) -> Dict[str, Any]: + return { + 'id': self.id, + 'filename': self.filename, + 'type': self.type, + 'imageable_type': self.imageable_type, + 'imageable_id': self.imageable_id, + 'created_at': self.created_at, + 'updated_at': self.updated_at, + 'original_url_field': self.original_url_field, + 'url': self.url + } class Episode: @@ -45,6 +58,21 @@ class Episode: def __str__(self): return f"Episode(id={self.id}, number={self.number}, name='{self.name}', plot='{self.plot}', duration={self.duration} sec)" + + def to_dict(self) -> Dict[str, Any]: + return { + 'id': self.id, + 'number': self.number, + 'name': self.name, + 'plot': self.plot, + 'duration': self.duration, + 'scws_id': self.scws_id, + 'season_id': self.season_id, + 'created_by': self.created_by, + 'created_at': self.created_at, + 'updated_at': self.updated_at, + 'images': [image.to_dict() for image in self.images] + } class EpisodeManager: diff --git a/Src/Api/Streamingcommunity/Core/Class/PreviewType.py b/Src/Api/Streamingcommunity/Core/Class/PreviewType.py index 28d741e..7b80b0a 100644 --- a/Src/Api/Streamingcommunity/Core/Class/PreviewType.py +++ b/Src/Api/Streamingcommunity/Core/Class/PreviewType.py @@ -60,4 +60,17 @@ class PreviewManager: images_str = "\n".join(str(image) for image in self.images) return f"Title: ID={self.id}, Type={self.type}, Runtime={self.runtime}, Release Date={self.release_date}, Quality={self.quality}, Plot={self.plot}, Seasons Count={self.seasons_count}\nGenres:\n{genres_str}\nPreview:\n{self.preview}\nImages:\n{images_str}" + def to_dict(self): + return { + "id": self.id, + "type": self.type, + "runtime": self.runtime, + "release_date": self.release_date, + "quality": self.quality, + "plot": self.plot, + "seasons_count": self.seasons_count, + "genres": [genre.__dict__ for genre in self.genres], + "preview": self.preview.__dict__, + "images": [image.__dict__ for image in self.images] + } diff --git a/Src/Api/Streamingcommunity/Core/Class/SearchType.py b/Src/Api/Streamingcommunity/Core/Class/SearchType.py index 115677d..4e20c1c 100644 --- a/Src/Api/Streamingcommunity/Core/Class/SearchType.py +++ b/Src/Api/Streamingcommunity/Core/Class/SearchType.py @@ -37,10 +37,44 @@ class MediaItem: self.last_air_date: str = data.get('last_air_date') self.seasons_count: int = data.get('seasons_count') self.images: List[Image] = [Image(image_data) for image_data in data.get('images', [])] + self.comment: str = data.get('comment') + self.plot: str = data.get('plot') def __str__(self): return f"MediaItem(id={self.id}, slug='{self.slug}', name='{self.name}', type='{self.type}', score='{self.score}', sub_ita={self.sub_ita}, last_air_date='{self.last_air_date}', seasons_count={self.seasons_count}, images={self.images})" + @property + def to_dict(self) -> dict: + """ + Convert the MediaItem to a dictionary. + + Returns: + dict: The MediaItem as a dictionary. + """ + return { + "id": self.id, + "slug": self.slug, + "name": self.name, + "type": self.type.upper(), + "score": self.score, + "sub_ita": self.sub_ita, + "last_air_date": self.last_air_date, + "seasons_count": self.seasons_count, + "images": [image.__dict__ for image in self.images], + "comment": self.comment, + "plot": self.plot + } + + @property + def get_site_id(self) -> str: + """ + Get the site ID of the media item. + + Returns: + int: The site ID of the media item. + """ + return f"{self.id}-{self.slug}" + class MediaManager: def __init__(self): diff --git a/api/__init__.py b/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/api/__init__.py b/api/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/api/asgi.py b/api/api/asgi.py new file mode 100644 index 0000000..57b0c31 --- /dev/null +++ b/api/api/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for api project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings") + +application = get_asgi_application() diff --git a/api/api/settings.py b/api/api/settings.py new file mode 100644 index 0000000..d64cd0f --- /dev/null +++ b/api/api/settings.py @@ -0,0 +1,140 @@ +""" +Django settings for api project. + +Generated by 'django-admin startproject' using Django 4.2.7. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure-7u!h-#6b--%h8()19so$s+t9cjh5y1+ljnqum*@gm))0(a_qka" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "corsheaders", + "endpoints", + "rest_framework", +] + +MIDDLEWARE = [ + "corsheaders.middleware.CorsMiddleware", + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "api.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "api.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = "static/" + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +CORS_ALLOWED_ORIGINS = [ + "http://localhost:5173", +] + +CORS_ALLOWED_METHODS = ( + "DELETE", + "GET", + "OPTIONS", + "PATCH", + "POST", + "PUT", +) diff --git a/api/api/urls.py b/api/api/urls.py new file mode 100644 index 0000000..30b52fe --- /dev/null +++ b/api/api/urls.py @@ -0,0 +1,24 @@ +""" +URL configuration for api project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" + +from django.contrib import admin +from django.urls import path, include + +urlpatterns = [ + path("admin/", admin.site.urls), + path("api/", include("endpoints.urls")), +] diff --git a/api/api/wsgi.py b/api/api/wsgi.py new file mode 100644 index 0000000..bfbc45a --- /dev/null +++ b/api/api/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for api project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings") + +application = get_wsgi_application() diff --git a/api/endpoints/__init__.py b/api/endpoints/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/endpoints/admin.py b/api/endpoints/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/api/endpoints/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/api/endpoints/apps.py b/api/endpoints/apps.py new file mode 100644 index 0000000..0cf6cd7 --- /dev/null +++ b/api/endpoints/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class EndpointsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "endpoints" diff --git a/api/endpoints/migrations/__init__.py b/api/endpoints/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/endpoints/models.py b/api/endpoints/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/api/endpoints/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/api/endpoints/tests.py b/api/endpoints/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/api/endpoints/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/api/endpoints/urls.py b/api/endpoints/urls.py new file mode 100644 index 0000000..184bb2f --- /dev/null +++ b/api/endpoints/urls.py @@ -0,0 +1,10 @@ +from rest_framework import routers + +from .views import SearchView#, DownloadView + +router = routers.DefaultRouter() + +router.register(r"search", SearchView, basename="search") +#router.register(r"download", DownloadView, basename="download") + +urlpatterns = router.urls diff --git a/api/endpoints/views.py b/api/endpoints/views.py new file mode 100644 index 0000000..0df7062 --- /dev/null +++ b/api/endpoints/views.py @@ -0,0 +1,241 @@ +import json +import os + +from django.http import StreamingHttpResponse + +from rest_framework import viewsets +from rest_framework.decorators import action +from rest_framework.response import Response + +from Src.Api.Animeunity import title_search as anime_search +from Src.Api.Animeunity.Core.Vix_player.player import VideoSource as anime_source +from Src.Api.Animeunity.site import media_search_manager as anime_media_manager + +from Src.Api.Streamingcommunity import title_search as sc_search, get_version_and_domain +from Src.Api.Streamingcommunity.Core.Vix_player.player import VideoSource as film_video_source +from Src.Api.Streamingcommunity.site import media_search_manager as film_media_manager + + +class SearchView(viewsets.ViewSet): + + def list(self, request): + self.search_query = request.query_params.get("search_terms") + self.type_search = request.query_params.get("type") + + media_manager = anime_media_manager if self.type_search == "anime" else film_media_manager + media_manager.media_list = [] + self.len_database = 0 + if self.type_search == "film": + _, self.domain = get_version_and_domain() + self.len_database = sc_search(self.search_query, self.domain) + elif self.type_search == "anime": + self.len_database = anime_search(self.search_query) + + media_list = media_manager.media_list + + if self.len_database != 0: + data_to_return = [] + for _, media in enumerate(media_list): + if self.type_search == "anime": + if media.type == "TV": + media.type = "TV_ANIME" + if media.type == "Movie": + media.type = "OVA" + data_to_return.append(media.to_dict) + + return Response({"media": data_to_return}) + + return Response({"error": "No media found with that search query"}) + + @action(detail=False, methods=["get"]) + def get_episodes_info(self, request): + self.media_id = request.query_params.get("media_id") + self.media_slug = request.query_params.get("media_slug") + self.type_media = request.query_params.get("type_media") + + try: + match self.type_media: + case "TV": + + def stream_episodes(): + self.version, self.domain = get_version_and_domain() + + video_source = film_video_source() + video_source.setup( + version=self.version, + domain=self.domain, + media_id=self.media_id, + series_name=self.media_slug + ) + video_source.collect_info_seasons() + seasons_count = video_source.obj_title_manager.get_length() + + episodes = {} + for i_season in range(1, seasons_count + 1): + video_source.obj_episode_manager.clear() + video_source.collect_title_season(i_season) + episodes_count = ( + video_source.obj_episode_manager.get_length() + ) + episodes[i_season] = {} + for i_episode in range(1, episodes_count + 1): + episode = video_source.obj_episode_manager.episodes[ + i_episode - 1 + ] + episodes[i_season][i_episode] = episode.to_dict() + + yield f'{json.dumps({"episodes": episodes})}\n\n' + + response = StreamingHttpResponse( + stream_episodes(), content_type="text/event-stream" + ) + return response + + case "TV_ANIME": + def stream_episodes(): + video_source = anime_source() + video_source.setup( + media_id = self.media_id, + series_name = self.media_slug + ) + episoded_count = video_source.get_count_episodes() + + for i in range(0, episoded_count): + episode_info = video_source.get_info_episode(i).to_dict() + episode_info["episode_id"] = i + episode_info["episode_total"] = episoded_count + print(f"Getting episode {i} of {episoded_count} info...") + yield f"{json.dumps(episode_info)}\n\n" + + response = StreamingHttpResponse( + stream_episodes(), content_type="text/event-stream" + ) + return response + + except Exception as e: + return Response( + { + "error": "Error while getting episodes info", + "message": str(e), + } + ) + + return Response({"error": "No media found with that search query"}) + + @action(detail=False, methods=["get"]) + def get_preview(self, request): + self.media_id = request.query_params.get("media_id") + self.media_slug = request.query_params.get("media_slug") + self.type_media = request.query_params.get("type_media") + + try: + if self.type_media in ["TV", "MOVIE"]: + version, domain = get_version_and_domain() + video_source = film_video_source() + video_source.setup(media_id=self.media_id, version=version, domain=domain, series_name=self.media_slug) + video_source.get_preview() + return Response(video_source.obj_preview.to_dict()) + if self.type_media in ["TV_ANIME", "OVA", "SPECIAL"]: + video_source = anime_source() + video_source.setup(media_id=self.media_id, series_name=self.media_slug) + video_source.get_preview() + return Response(video_source.obj_preview.to_dict()) + except Exception as e: + return Response( + { + "error": "Error while getting preview info", + "message": str(e), + } + ) + + return Response({"error": "No media found with that search query"}) + + +''' +class DownloadView(viewsets.ViewSet): + + def create(self, request): + self.media_id = request.data.get("media_id") + self.media_slug = request.data.get("media_slug") + self.type_media = request.data.get("type_media").upper() + self.download_id = request.data.get("download_id") + self.tv_series_episode_id = request.data.get("tv_series_episode_id") + + if self.type_media in ["TV", "MOVIE"]: + self.site_version, self.domain = get_version_and_domain() + + response_dict = {"error": "No media found with that search query"} + + try: + match self.type_media: + case "MOVIE": + download_film(self.media_id, self.media_slug, self.domain) + case "TV": + video_source = VideoSource() + video_source.set_url_base_name(STREAM_SITE_NAME) + video_source.set_version(self.site_version) + video_source.set_domain(self.domain) + video_source.set_series_name(self.media_slug) + video_source.set_media_id(self.media_id) + + video_source.collect_info_seasons() + video_source.obj_episode_manager.clear() + + video_source.collect_title_season(self.download_id) + episodes_count = video_source.obj_episode_manager.get_length() + for i_episode in range(1, episodes_count + 1): + episode_id = video_source.obj_episode_manager.episodes[ + i_episode - 1 + ].id + + # Define filename and path for the downloaded video + mp4_name = remove_special_characters( + f"{map_episode_title(self.media_slug,video_source.obj_episode_manager.episodes[i_episode - 1],self.download_id)}.mp4" + ) + mp4_path = remove_special_characters( + os.path.join( + ROOT_PATH, + SERIES_FOLDER, + self.media_slug, + f"S{self.download_id}", + ) + ) + os.makedirs(mp4_path, exist_ok=True) + + # Get iframe and content for the episode + video_source.get_iframe(episode_id) + video_source.get_content() + video_source.set_url_base_name(STREAM_SITE_NAME) + + # Download the episode + obj_download = Downloader( + m3u8_playlist=video_source.get_playlist(), + key=video_source.get_key(), + output_filename=os.path.join(mp4_path, mp4_name), + ) + + obj_download.download_m3u8() + + case "TV_ANIME": + episodes_downloader = EpisodeDownloader( + self.media_id, self.media_slug + ) + episodes_downloader.download_episode(self.download_id) + case "OVA" | "SPECIAL": + anime_download_film( + id_film=self.media_id, title_name=self.media_slug + ) + case _: + raise Exception("Type media not supported") + + response_dict = { + "message": "Download done, it is saved in Video folder inside project root" + } + except Exception as e: + response_dict = { + "error": "Error while downloading the media", + "message": str(e), + } + + return Response(response_dict) +''' diff --git a/api/manage.py b/api/manage.py new file mode 100755 index 0000000..3b72e09 --- /dev/null +++ b/api/manage.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/config.json b/config.json index 2603713..c2bc0e2 100644 --- a/config.json +++ b/config.json @@ -45,4 +45,4 @@ "animeunity": "to", "altadefinizione": "food" } -} +} \ No newline at end of file diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs new file mode 100644 index 0000000..6f40582 --- /dev/null +++ b/frontend/.eslintrc.cjs @@ -0,0 +1,15 @@ +/* eslint-env node */ +require('@rushstack/eslint-patch/modern-module-resolution') + +module.exports = { + root: true, + 'extends': [ + 'plugin:vue/vue3-essential', + 'eslint:recommended', + '@vue/eslint-config-typescript', + '@vue/eslint-config-prettier/skip-formatting' + ], + parserOptions: { + ecmaVersion: 'latest' + } +} diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/frontend/.prettierrc.json b/frontend/.prettierrc.json new file mode 100644 index 0000000..66e2335 --- /dev/null +++ b/frontend/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "tabWidth": 2, + "singleQuote": true, + "printWidth": 100, + "trailingComma": "none" +} \ No newline at end of file diff --git a/frontend/.vscode/extensions.json b/frontend/.vscode/extensions.json new file mode 100644 index 0000000..93ea3e7 --- /dev/null +++ b/frontend/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] +} diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..9b4c74c --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,39 @@ +# frontend + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/frontend/env.d.ts b/frontend/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/frontend/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..dd00361 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,3225 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "axios": "^1.6.8", + "vue": "^3.4.21", + "vue-router": "^4.3.0" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.8.0", + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.12.5", + "@vitejs/plugin-vue": "^5.0.4", + "@vue/eslint-config-prettier": "^9.0.0", + "@vue/eslint-config-typescript": "^13.0.0", + "@vue/tsconfig": "^0.5.1", + "eslint": "^8.57.0", + "eslint-plugin-vue": "^9.23.0", + "npm-run-all2": "^6.1.2", + "prettier": "^3.2.5", + "typescript": "~5.4.0", + "vite": "^5.2.8", + "vue-tsc": "^2.0.11" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.0.tgz", + "integrity": "sha512-nNvLvC2fjC+3+bHYN9uaGF3gcyy7RHGZhtl8TB/kINj9hiOQza8kWJGZh47GRPMrqeseO8U+Z8ElDMCZlWBdHA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.0.tgz", + "integrity": "sha512-+kjt6dvxnyTIAo7oHeYseYhDyZ7xRKTNl/FoQI96PHkJVxoChldJnne/LzYqpqidoK1/0kX0/q+5rrYqjpth6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.0.tgz", + "integrity": "sha512-Oj6Tp0unMpGTBjvNwbSRv3DopMNLu+mjBzhKTt2zLbDJ/45fB1pltr/rqrO4bE95LzuYwhYn127pop+x/pzf5w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.0.tgz", + "integrity": "sha512-3nJx0T+yptxMd+v93rBRxSPTAVCv8szu/fGZDJiKX7kvRe9sENj2ggXjCH/KK1xZEmJOhaNo0c9sGMgGdfkvEw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.0.tgz", + "integrity": "sha512-Vb2e8p9b2lxxgqyOlBHmp6hJMu/HSU6g//6Tbr7x5V1DlPCHWLOm37nSIVK314f+IHzORyAQSqL7+9tELxX3zQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.0.tgz", + "integrity": "sha512-Md60KsmC5ZIaRq/bYYDloklgU+XLEZwS2EXXVcSpiUw+13/ZASvSWQ/P92rQ9YDCL6EIoXxuQ829JkReqdYbGg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.0.tgz", + "integrity": "sha512-zL5rBFtJ+2EGnMRm2TqKjdjgFqlotSU+ZJEN37nV+fiD3I6Gy0dUh3jBWN0wSlcXVDEJYW7YBe+/2j0N9unb2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.0.tgz", + "integrity": "sha512-s2xAyNkJqUdtRVgNK4NK4P9QttS538JuX/kfVQOdZDI5FIKVAUVdLW7qhGfmaySJ1EvN/Bnj9oPm5go9u8navg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.0.tgz", + "integrity": "sha512-7F99yzVT67B7IUNMjLD9QCFDCyHkyCJMS1dywZrGgVFJao4VJ9szrIEgH67cR+bXQgEaY01ur/WSL6B0jtcLyA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.0.tgz", + "integrity": "sha512-leFtyiXisfa3Sg9pgZJwRKITWnrQfhtqDjCamnZhkZuIsk1FXmYwKoTkp6lsCgimIcneFFkHKp/yGLxDesga4g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.0.tgz", + "integrity": "sha512-FtOgui6qMJ4jbSXTxElsy/60LEe/3U0rXkkz2G5CJ9rbHPAvjMvI+3qF0A0fwLQ5hW+/ZC6PbnS2KfRW9JkgDQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.0.tgz", + "integrity": "sha512-v6eiam/1w3HUfU/ZjzIDodencqgrSqzlNuNtiwH7PFJHYSo1ezL0/UIzmS2lpSJF1ORNaplXeKHYmmdt81vV2g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.0.tgz", + "integrity": "sha512-OUhkSdpM5ofVlVU2k4CwVubYwiwu1a4jYWPpubzN7Vzao73GoPBowHcCfaRSFRz1SszJ3HIsk3dZYk4kzbqjgw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.0.tgz", + "integrity": "sha512-uL7UYO/MNJPGL/yflybI+HI+n6+4vlfZmQZOCb4I+z/zy1wisHT3exh7oNQsnL6Eso0EUTEfgQ/PaGzzXf6XyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.0.tgz", + "integrity": "sha512-4WnSgaUiUmXILwFqREdOcqvSj6GD/7FrvSjhaDjmwakX9w4Z2F8JwiSP1AZZbuRkPqzi444UI5FPv33VKOWYFQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.0.tgz", + "integrity": "sha512-ve+D8t1prRSRnF2S3pyDtTXDlvW1Pngbz76tjgYFQW1jxVSysmQCZfPoDAo4WP+Ano8zeYp85LsArZBI12HfwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz", + "integrity": "sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==", + "dev": true + }, + "node_modules/@tsconfig/node20": { + "version": "20.1.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.4.tgz", + "integrity": "sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", + "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/type-utils": "7.7.1", + "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz", + "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", + "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", + "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/utils": "7.7.1", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", + "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", + "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", + "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", + "semver": "^7.6.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", + "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.7.1", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz", + "integrity": "sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.2.0-alpha.10", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.2.0-alpha.10.tgz", + "integrity": "sha512-njVJLtpu0zMvDaEk7K5q4BRpOgbyEUljU++un9TfJoJNhxG0z/hWwpwgTRImO42EKvwIxF3XUzeMk+qatAFy7Q==", + "dev": true, + "dependencies": { + "@volar/source-map": "2.2.0-alpha.10" + } + }, + "node_modules/@volar/source-map": { + "version": "2.2.0-alpha.10", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.2.0-alpha.10.tgz", + "integrity": "sha512-nrdWApVkP5cksAnDEyy1JD9rKdwOJsEq1B+seWO4vNXmZNcxQQCx4DULLBvKt7AzRUAQiAuw5aQkb9RBaSqdVA==", + "dev": true, + "dependencies": { + "muggle-string": "^0.4.0" + } + }, + "node_modules/@volar/typescript": { + "version": "2.2.0-alpha.10", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.2.0-alpha.10.tgz", + "integrity": "sha512-GCa0vTVVdA9ULUsu2Rx7jwsIuyZQPvPVT9o3NrANTbYv+523Ao1gv3glC5vzNSDPM6bUl37r94HbCj7KINQr+g==", + "dev": true, + "dependencies": { + "@volar/language-core": "2.2.0-alpha.10", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.25.tgz", + "integrity": "sha512-Y2pLLopaElgWnMNolgG8w3C5nNUVev80L7hdQ5iIKPtMJvhVpG0zhnBG/g3UajJmZdvW0fktyZTotEHD1Srhbg==", + "dependencies": { + "@babel/parser": "^7.24.4", + "@vue/shared": "3.4.25", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.25.tgz", + "integrity": "sha512-Ugz5DusW57+HjllAugLci19NsDK+VyjGvmbB2TXaTcSlQxwL++2PETHx/+Qv6qFwNLzSt7HKepPe4DcTE3pBWg==", + "dependencies": { + "@vue/compiler-core": "3.4.25", + "@vue/shared": "3.4.25" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.25.tgz", + "integrity": "sha512-m7rryuqzIoQpOBZ18wKyq05IwL6qEpZxFZfRxlNYuIPDqywrXQxgUwLXIvoU72gs6cRdY6wHD0WVZIFE4OEaAQ==", + "dependencies": { + "@babel/parser": "^7.24.4", + "@vue/compiler-core": "3.4.25", + "@vue/compiler-dom": "3.4.25", + "@vue/compiler-ssr": "3.4.25", + "@vue/shared": "3.4.25", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.10", + "postcss": "^8.4.38", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.25.tgz", + "integrity": "sha512-H2ohvM/Pf6LelGxDBnfbbXFPyM4NE3hrw0e/EpwuSiYu8c819wx+SVGdJ65p/sFrYDd6OnSDxN1MB2mN07hRSQ==", + "dependencies": { + "@vue/compiler-dom": "3.4.25", + "@vue/shared": "3.4.25" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.1.tgz", + "integrity": "sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==" + }, + "node_modules/@vue/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-z1ZIAAUS9pKzo/ANEfd2sO+v2IUalz7cM/cTLOZ7vRFOPk5/xuRKQteOu1DErFLAh/lYGXMVZ0IfYKlyInuDVg==", + "dev": true, + "dependencies": { + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0" + }, + "peerDependencies": { + "eslint": ">= 8.0.0", + "prettier": ">= 3.0.0" + } + }, + "node_modules/@vue/eslint-config-typescript": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-13.0.0.tgz", + "integrity": "sha512-MHh9SncG/sfqjVqjcuFLOLD6Ed4dRAis4HNt0dXASeAuLqIAx4YMB1/m2o4pUKK1vCt8fUvYG8KKX2Ot3BVZTg==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^7.1.1", + "@typescript-eslint/parser": "^7.1.1", + "vue-eslint-parser": "^9.3.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "peerDependencies": { + "eslint": "^8.56.0", + "eslint-plugin-vue": "^9.0.0", + "typescript": ">=4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.14.tgz", + "integrity": "sha512-3q8mHSNcGTR7sfp2X6jZdcb4yt8AjBXAfKk0qkZIh7GAJxOnoZ10h5HToZglw4ToFvAnq+xu/Z2FFbglh9Icag==", + "dev": true, + "dependencies": { + "@volar/language-core": "2.2.0-alpha.10", + "@vue/compiler-dom": "^3.4.0", + "@vue/shared": "^3.4.0", + "computeds": "^0.0.1", + "minimatch": "^9.0.3", + "path-browserify": "^1.0.1", + "vue-template-compiler": "^2.7.14" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.25.tgz", + "integrity": "sha512-mKbEtKr1iTxZkAG3vm3BtKHAOhuI4zzsVcN0epDldU/THsrvfXRKzq+lZnjczZGnTdh3ojd86/WrP+u9M51pWQ==", + "dependencies": { + "@vue/shared": "3.4.25" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.25.tgz", + "integrity": "sha512-3qhsTqbEh8BMH3pXf009epCI5E7bKu28fJLi9O6W+ZGt/6xgSfMuGPqa5HRbUxLoehTNp5uWvzCr60KuiRIL0Q==", + "dependencies": { + "@vue/reactivity": "3.4.25", + "@vue/shared": "3.4.25" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.25.tgz", + "integrity": "sha512-ode0sj77kuwXwSc+2Yhk8JMHZh1sZp9F/51wdBiz3KGaWltbKtdihlJFhQG4H6AY+A06zzeMLkq6qu8uDSsaoA==", + "dependencies": { + "@vue/runtime-core": "3.4.25", + "@vue/shared": "3.4.25", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.25.tgz", + "integrity": "sha512-8VTwq0Zcu3K4dWV0jOwIVINESE/gha3ifYCOKEhxOj6MEl5K5y8J8clQncTcDhKF+9U765nRw4UdUEXvrGhyVQ==", + "dependencies": { + "@vue/compiler-ssr": "3.4.25", + "@vue/shared": "3.4.25" + }, + "peerDependencies": { + "vue": "3.4.25" + } + }, + "node_modules/@vue/shared": { + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.25.tgz", + "integrity": "sha512-k0yappJ77g2+KNrIaF0FFnzwLvUBLUYr8VOwz+/6vLsmItFp51AcxLL7Ey3iPd7BIRyWPOcqUjMnm7OkahXllA==" + }, + "node_modules/@vue/tsconfig": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.5.1.tgz", + "integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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/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/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/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/computeds": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", + "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.25.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.25.0.tgz", + "integrity": "sha512-tDWlx14bVe6Bs+Nnh3IGrD+hb11kf2nukfm6jLsmJIhmiRQ1SUaksvwY9U5MvPB0pcrg0QK0xapQkfITs3RKOA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.0", + "vue-eslint-parser": "^9.4.2", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/esutils": { + "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" + } + }, + "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==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "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==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "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/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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 + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-run-all2": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.1.2.tgz", + "integrity": "sha512-WwwnS8Ft+RpXve6T2EIEVpFLSqN+ORHRvgNk3H9N62SZXjmzKoRhMFg3I17TK3oMaAEr+XFbRirWS2Fn3BCPSg==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.3", + "memorystream": "^0.3.1", + "minimatch": "^9.0.0", + "pidtree": "^0.6.0", + "read-package-json-fast": "^3.0.2", + "shell-quote": "^1.7.3" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0", + "npm": ">= 8" + } + }, + "node_modules/npm-run-all2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/once": { + "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" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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==" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.0.tgz", + "integrity": "sha512-wZJSn0WMtWrxhYKQRt5Z6GIXlziOoMDFmbHmRfL3v+sBTAshx2DBq1AfMArB7eIjF63r4ocn2ZTAyUptg/7kmQ==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.17.0", + "@rollup/rollup-android-arm64": "4.17.0", + "@rollup/rollup-darwin-arm64": "4.17.0", + "@rollup/rollup-darwin-x64": "4.17.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.17.0", + "@rollup/rollup-linux-arm-musleabihf": "4.17.0", + "@rollup/rollup-linux-arm64-gnu": "4.17.0", + "@rollup/rollup-linux-arm64-musl": "4.17.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.17.0", + "@rollup/rollup-linux-riscv64-gnu": "4.17.0", + "@rollup/rollup-linux-s390x-gnu": "4.17.0", + "@rollup/rollup-linux-x64-gnu": "4.17.0", + "@rollup/rollup-linux-x64-musl": "4.17.0", + "@rollup/rollup-win32-arm64-msvc": "4.17.0", + "@rollup/rollup-win32-ia32-msvc": "4.17.0", + "@rollup/rollup-win32-x64-msvc": "4.17.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "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==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/vite": { + "version": "5.2.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz", + "integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==", + "dev": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.4.25", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.25.tgz", + "integrity": "sha512-HWyDqoBHMgav/OKiYA2ZQg+kjfMgLt/T0vg4cbIF7JbXAjDexRf5JRg+PWAfrAkSmTd2I8aPSXtooBFWHB98cg==", + "dependencies": { + "@vue/compiler-dom": "3.4.25", + "@vue/compiler-sfc": "3.4.25", + "@vue/runtime-dom": "3.4.25", + "@vue/server-renderer": "3.4.25", + "@vue/shared": "3.4.25" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.2.tgz", + "integrity": "sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-router": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.2.tgz", + "integrity": "sha512-hKQJ1vDAZ5LVkKEnHhmm1f9pMiWIBNGF5AwU67PdH7TyXCj/a4hTccuUuYCAMgJK6rO/NVYtQIEN3yL8CECa7Q==", + "dependencies": { + "@vue/devtools-api": "^6.5.1" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/vue-template-compiler": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", + "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", + "dev": true, + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/vue-tsc": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.14.tgz", + "integrity": "sha512-DgAO3U1cnCHOUO7yB35LENbkapeRsBZ7Ugq5hGz/QOHny0+1VQN8eSwSBjYbjLVPfvfw6EY7sNPjbuHHUhckcg==", + "dev": true, + "dependencies": { + "@volar/typescript": "2.2.0-alpha.10", + "@vue/language-core": "2.0.14", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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 + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..10a021d --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,36 @@ +{ + "name": "frontend", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", + "format": "prettier --write src/" + }, + "dependencies": { + "axios": "^1.6.8", + "vue": "^3.4.21", + "vue-router": "^4.3.0" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.8.0", + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.12.5", + "@vitejs/plugin-vue": "^5.0.4", + "@vue/eslint-config-prettier": "^9.0.0", + "@vue/eslint-config-typescript": "^13.0.0", + "@vue/tsconfig": "^0.5.1", + "eslint": "^8.57.0", + "eslint-plugin-vue": "^9.23.0", + "npm-run-all2": "^6.1.2", + "prettier": "^3.2.5", + "typescript": "~5.4.0", + "vite": "^5.2.8", + "vue-tsc": "^2.0.11" + } +} diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/frontend/src/App.vue b/frontend/src/App.vue new file mode 100644 index 0000000..ad56b70 --- /dev/null +++ b/frontend/src/App.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/frontend/src/api/api.ts b/frontend/src/api/api.ts new file mode 100644 index 0000000..7ec0039 --- /dev/null +++ b/frontend/src/api/api.ts @@ -0,0 +1,81 @@ +import axios from "axios"; +import type { AxiosResponse } from "axios"; +import type { DownloadResponse, MediaItemResponse } from "@/api/interfaces"; + +const BASE_URL = "http://localhost:8000/api"; + +const api = axios.create({ + baseURL: BASE_URL, +}); + +async function get(url: string): Promise> { + return api.get(url); +} + +async function post(url: string, data: any): Promise> { + return api.post(url, data); +} + +export default function search( + query: string, + type: string +): Promise> { + return get(`/search?search_terms=${query}&type=${type}`); +} + +export async function getEpisodesInfo( + mediaId: number, + mediaSlug: string, + mediaType: string +): Promise { + const url = `/search/get_episodes_info?media_id=${mediaId}&media_slug=${mediaSlug}&type_media=${mediaType}`; + return fetch(`${BASE_URL}${url}`, { + method: "GET", + headers: { + "Content-Type": "text/event-stream", + }, + }); +} + +export async function getPreview( + mediaId: number, + mediaSlug: string, + mediaType: string +): Promise> { + const url = `/search/get_preview?media_id=${mediaId}&media_slug=${mediaSlug}&type_media=${mediaType}`; + return get(url); +} + +async function downloadMedia( + mediaId: number, + mediaSlug: string, + mediaType: string, + downloadId?: number, + tvSeriesEpisodeId?: number +): Promise> { + const url = `/download/`; + const data = { + media_id: mediaId, + media_slug: mediaSlug, + type_media: mediaType, + download_id: downloadId, + tv_series_episode_id: tvSeriesEpisodeId, + }; + return post(url, data); +} + +export const downloadFilm = (mediaId: number, mediaSlug: string) => + downloadMedia(mediaId, mediaSlug, "MOVIE"); +export const downloadTvSeries = ( + mediaId: number, + mediaSlug: string, + downloadId: number, + tvSeriesEpisodeId?: number +) => downloadMedia(mediaId, mediaSlug, "TV", downloadId, tvSeriesEpisodeId); +export const downloadAnimeFilm = (mediaId: number, mediaSlug: string) => + downloadMedia(mediaId, mediaSlug, "OVA"); +export const downloadAnimeSeries = ( + mediaId: number, + mediaSlug: string, + downloadId: number +) => downloadMedia(mediaId, mediaSlug, "TV_ANIME", downloadId); diff --git a/frontend/src/api/interfaces.ts b/frontend/src/api/interfaces.ts new file mode 100644 index 0000000..d33f703 --- /dev/null +++ b/frontend/src/api/interfaces.ts @@ -0,0 +1,64 @@ +interface Image { + imageable_id: number; + imageable_type: string; + filename: string; + type: string; + original_url_field: string; +} + +export interface MediaItem { + id: number; + slug: string; + name: string; + type: string; + score: string; + sub_ita: number; + last_air_date: string; + seasons_count: number; + images: Image[]; + comment: string; + plot: string; +} + +export interface MediaItemResponse { + media: MediaItem[]; +} + +export interface Episode { + id: number; + anime_id: number; + user_id: number | null; + number: string; + created_at: string; + link: string; + visite: number; + hidden: number; + public: number; + scws_id: number; + file_name: string; + tg_post: number; + episode_id: number; + episode_total: number; + name: string; // TV Show exclusive + plot: string; // TV Show exclusive + duration: number; // TV Show exclusive + season_id: number; // TV Show exclusive + created_by: any; // TV Show exclusive + updated_at: string; // TV Show exclusive + season_index: number; // TV Show exclusive +} + +export interface Season { + [key: string]: { + [key: string]: Episode; + }; +} + +export interface SeasonResponse { + episodes: Season; +} + +export interface DownloadResponse { + error: string; + message: string; +} \ No newline at end of file diff --git a/frontend/src/api/utils.ts b/frontend/src/api/utils.ts new file mode 100644 index 0000000..4432fdd --- /dev/null +++ b/frontend/src/api/utils.ts @@ -0,0 +1,63 @@ +import {downloadAnimeFilm, downloadAnimeSeries, downloadFilm, downloadTvSeries} from "@/api/api"; +import type {DownloadResponse, Episode, MediaItem, Season} from "@/api/interfaces"; + +export const handleTVDownload = async (tvShowEpisodes: any[], item: MediaItem) => { + alertDownload(); + for (const season of tvShowEpisodes) { + const i = tvShowEpisodes.indexOf(season); + const res = (await downloadTvSeries(item.id, item.slug, i + 1)).data; + handleDownloadError(res); + } +}; + +export const handleTVEpisodesDownload = async (episodes: Episode[], item: MediaItem) => { + alertDownload(); + for (const episode of episodes) { + const i = episodes.indexOf(episode); + const res = (await downloadTvSeries(item.id, item.slug, episode.season_index + 1, i)).data; + handleDownloadError(res); + } +} + +export const handleMovieDownload = async (item: MediaItem) => { + alertDownload(); + const res = (await downloadFilm(item.id, item.slug)).data; + handleDownloadError(res); +}; + +export const handleTVAnimeDownload = async (episodeCount: number, item: MediaItem) => { + alertDownload(); + for (let i = 0; i < episodeCount; i++) { + const res = (await downloadAnimeSeries(item.id, item.slug, i)).data; + handleDownloadError(res); + } +}; + +export const handleTvAnimeEpisodesDownload = async (episodes: Episode[], item: MediaItem) => { + alertDownload(); + for (const episode of episodes) { + const res = (await downloadAnimeSeries(item.id, item.slug, episode.episode_id)).data; + handleDownloadError(res); + } + +} + +export const handleOVADownload = async (item: MediaItem) => { + alertDownload(); + const res = (await downloadAnimeFilm(item.id, item.slug)).data; + handleDownloadError(res); +}; + +const handleDownloadError = (res: DownloadResponse) => { + if (res.error) { + throw new Error(`${res.error} - ${res.message}`); + } +}; + +export const alertDownload = (message?: any) => { + if (message) { + alert(message) + return; + } + alert('Il downlaod è iniziato, il file sarà disponibile tra qualche minuto nella cartella \'Video\' del progetto...') +} \ No newline at end of file diff --git a/frontend/src/assets/base.css b/frontend/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/frontend/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/frontend/src/assets/logo.svg b/frontend/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/frontend/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/frontend/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/frontend/src/components/Card.vue b/frontend/src/components/Card.vue new file mode 100644 index 0000000..9817f43 --- /dev/null +++ b/frontend/src/components/Card.vue @@ -0,0 +1,92 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/components/Toggle.vue b/frontend/src/components/Toggle.vue new file mode 100644 index 0000000..1f31799 --- /dev/null +++ b/frontend/src/components/Toggle.vue @@ -0,0 +1,105 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/main.ts b/frontend/src/main.ts new file mode 100644 index 0000000..5a5dbdb --- /dev/null +++ b/frontend/src/main.ts @@ -0,0 +1,11 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' +import router from './router' + +const app = createApp(App) + +app.use(router) + +app.mount('#app') diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts new file mode 100644 index 0000000..fbbbafb --- /dev/null +++ b/frontend/src/router/index.ts @@ -0,0 +1,30 @@ +import { createRouter, createWebHistory } from 'vue-router' +import HomeView from '../views/HomeView.vue' +import Details from "../views/Details.vue"; + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'home', + component: HomeView + }, + { + path: '/details:item:imageUrl', + name: 'details', + component: Details, + props: route => { + let item; + try { + item = JSON.parse(route.params.item); + } catch (error) { + item = {}; // default value + } + return { item: item, imageUrl: route.params.imageUrl }; + }, + } + ] +}) + +export default router diff --git a/frontend/src/views/Details.vue b/frontend/src/views/Details.vue new file mode 100644 index 0000000..5880730 --- /dev/null +++ b/frontend/src/views/Details.vue @@ -0,0 +1,335 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue new file mode 100644 index 0000000..5919c7e --- /dev/null +++ b/frontend/src/views/HomeView.vue @@ -0,0 +1,176 @@ + + + + + \ No newline at end of file diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/frontend/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/frontend/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000..5c45e1d --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/kill_gui.sh b/kill_gui.sh new file mode 100755 index 0000000..c7fac45 --- /dev/null +++ b/kill_gui.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Trova i processi che utilizzano la porta 8000 +PROCESSES=$(lsof -i :8000 | awk 'NR!=1 {print $2}') + +# Termina i processi trovati +if [ -n "$PROCESSES" ]; then + echo "Terminating processes using port 8000:" + for PID in $PROCESSES; do + echo "Killing process with PID: $PID" + kill -9 $PID + done +else + echo "No processes found using port 8000" +fi + +# Trova i processi che utilizzano la porta 5173 +PROCESSES=$(lsof -i :5173 | awk 'NR!=1 {print $2}') + +# Termina i processi trovati +if [ -n "$PROCESSES" ]; then + echo "Terminating processes using port 5173:" + for PID in $PROCESSES; do + echo "Killing process with PID: $PID" + kill -9 $PID + done +else + echo "No processes found using port 5173" +fi \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 21218f8..d471fcb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,11 @@ bs4 tqdm rich -unidecode \ No newline at end of file +unidecode +ffmpeg-python +pycryptodome +m3u8 +lxml +django==4.2.11 +djangorestframework==3.15.1 +django-cors-headers==4.3.1 \ No newline at end of file diff --git a/start_gui.sh b/start_gui.sh new file mode 100755 index 0000000..e339262 --- /dev/null +++ b/start_gui.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Installa i pacchetti Python +echo "Installazione dei pacchetti Python..." +pip install -r requirements.txt + +# Installa i pacchetti npm +echo "Installazione dei pacchetti npm..." +cd frontend +npm install +cd .. + +# Avvia il backend Django +echo "Avvio del backend Django..." +python3.11 api/manage.py runserver & + +# Avvia il frontend Vue.js con Vite +echo "Avvio del frontend Vue.js con Vite..." +cd frontend +npm run dev & + +# Attendi l'esecuzione dei processi +wait \ No newline at end of file From 2abfe82815bdba05591f3f5b1aefc9aef581911e Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Sat, 1 Jun 2024 12:07:36 +0200 Subject: [PATCH 02/13] Restore ... --- .gitignore | 13 +- Src/Api/Animeunity/Core/Class/EpisodeType.py | 15 - Src/Api/Animeunity/Core/Class/PreviewType.py | 13 - Src/Api/Animeunity/Core/Class/SearchType.py | 23 - .../Core/Class/EpisodeType.py | 28 - .../Core/Class/PreviewType.py | 13 - .../Core/Class/SearchType.py | 34 - api/__init__.py | 0 api/api/__init__.py | 0 api/api/asgi.py | 16 - api/api/settings.py | 140 - api/api/urls.py | 24 - api/api/wsgi.py | 16 - api/endpoints/__init__.py | 0 api/endpoints/admin.py | 3 - api/endpoints/apps.py | 6 - api/endpoints/migrations/__init__.py | 0 api/endpoints/models.py | 3 - api/endpoints/tests.py | 3 - api/endpoints/urls.py | 10 - api/endpoints/views.py | 241 -- api/manage.py | 24 - config.json | 2 +- frontend/.eslintrc.cjs | 15 - frontend/.gitignore | 30 - frontend/.prettierrc.json | 8 - frontend/.vscode/extensions.json | 7 - frontend/README.md | 39 - frontend/env.d.ts | 1 - frontend/index.html | 13 - frontend/package-lock.json | 3225 ----------------- frontend/package.json | 36 - frontend/public/favicon.ico | Bin 4286 -> 0 bytes frontend/src/App.vue | 36 - frontend/src/api/api.ts | 81 - frontend/src/api/interfaces.ts | 64 - frontend/src/api/utils.ts | 63 - frontend/src/assets/base.css | 86 - frontend/src/assets/logo.svg | 1 - frontend/src/assets/main.css | 35 - frontend/src/components/Card.vue | 92 - frontend/src/components/Toggle.vue | 105 - frontend/src/main.ts | 11 - frontend/src/router/index.ts | 30 - frontend/src/views/Details.vue | 335 -- frontend/src/views/HomeView.vue | 176 - frontend/tsconfig.app.json | 14 - frontend/tsconfig.json | 11 - frontend/tsconfig.node.json | 19 - frontend/vite.config.ts | 16 - kill_gui.sh | 29 - requirements.txt | 9 +- start_gui.sh | 23 - 53 files changed, 3 insertions(+), 5234 deletions(-) delete mode 100644 api/__init__.py delete mode 100644 api/api/__init__.py delete mode 100644 api/api/asgi.py delete mode 100644 api/api/settings.py delete mode 100644 api/api/urls.py delete mode 100644 api/api/wsgi.py delete mode 100644 api/endpoints/__init__.py delete mode 100644 api/endpoints/admin.py delete mode 100644 api/endpoints/apps.py delete mode 100644 api/endpoints/migrations/__init__.py delete mode 100644 api/endpoints/models.py delete mode 100644 api/endpoints/tests.py delete mode 100644 api/endpoints/urls.py delete mode 100644 api/endpoints/views.py delete mode 100755 api/manage.py delete mode 100644 frontend/.eslintrc.cjs delete mode 100644 frontend/.gitignore delete mode 100644 frontend/.prettierrc.json delete mode 100644 frontend/.vscode/extensions.json delete mode 100644 frontend/README.md delete mode 100644 frontend/env.d.ts delete mode 100644 frontend/index.html delete mode 100644 frontend/package-lock.json delete mode 100644 frontend/package.json delete mode 100644 frontend/public/favicon.ico delete mode 100644 frontend/src/App.vue delete mode 100644 frontend/src/api/api.ts delete mode 100644 frontend/src/api/interfaces.ts delete mode 100644 frontend/src/api/utils.ts delete mode 100644 frontend/src/assets/base.css delete mode 100644 frontend/src/assets/logo.svg delete mode 100644 frontend/src/assets/main.css delete mode 100644 frontend/src/components/Card.vue delete mode 100644 frontend/src/components/Toggle.vue delete mode 100644 frontend/src/main.ts delete mode 100644 frontend/src/router/index.ts delete mode 100644 frontend/src/views/Details.vue delete mode 100644 frontend/src/views/HomeView.vue delete mode 100644 frontend/tsconfig.app.json delete mode 100644 frontend/tsconfig.json delete mode 100644 frontend/tsconfig.node.json delete mode 100644 frontend/vite.config.ts delete mode 100755 kill_gui.sh delete mode 100755 start_gui.sh diff --git a/.gitignore b/.gitignore index 69e9099..be44e50 100644 --- a/.gitignore +++ b/.gitignore @@ -42,14 +42,6 @@ local_settings.py db.sqlite3 db.sqlite3-journal - -# Vue stuff: -frontend/dist/ -frontend/node_modules/ -frontend/npm-debug.log -frontend/.vite/ -frontend/.vscode/ - # Jupyter Notebook .ipynb_checkpoints @@ -63,7 +55,4 @@ env.bak/ venv.bak/ # Other -Video -.idea/ -.vscode/ -.DS_Store +Video \ No newline at end of file diff --git a/Src/Api/Animeunity/Core/Class/EpisodeType.py b/Src/Api/Animeunity/Core/Class/EpisodeType.py index f583914..14b9694 100644 --- a/Src/Api/Animeunity/Core/Class/EpisodeType.py +++ b/Src/Api/Animeunity/Core/Class/EpisodeType.py @@ -45,21 +45,6 @@ class Episode: def __str__(self): return f"Episode(id={self.id}, number={self.number}, name='{self.name}', plot='{self.plot}', duration={self.duration} sec)" - - def to_dict(self) -> Dict[str, Any]: - return { - "id": self.id, - "number": self.number, - "name": self.name, - "plot": self.plot, - "duration": self.duration, - "scws_id": self.scws_id, - "season_id": self.season_id, - "created_by": self.created_by, - "created_at": self.created_at, - "updated_at": self.updated_at, - "images": [image.__dict__ for image in self.images] - } class EpisodeManager: diff --git a/Src/Api/Animeunity/Core/Class/PreviewType.py b/Src/Api/Animeunity/Core/Class/PreviewType.py index 7b80b0a..28d741e 100644 --- a/Src/Api/Animeunity/Core/Class/PreviewType.py +++ b/Src/Api/Animeunity/Core/Class/PreviewType.py @@ -60,17 +60,4 @@ class PreviewManager: images_str = "\n".join(str(image) for image in self.images) return f"Title: ID={self.id}, Type={self.type}, Runtime={self.runtime}, Release Date={self.release_date}, Quality={self.quality}, Plot={self.plot}, Seasons Count={self.seasons_count}\nGenres:\n{genres_str}\nPreview:\n{self.preview}\nImages:\n{images_str}" - def to_dict(self): - return { - "id": self.id, - "type": self.type, - "runtime": self.runtime, - "release_date": self.release_date, - "quality": self.quality, - "plot": self.plot, - "seasons_count": self.seasons_count, - "genres": [genre.__dict__ for genre in self.genres], - "preview": self.preview.__dict__, - "images": [image.__dict__ for image in self.images] - } diff --git a/Src/Api/Animeunity/Core/Class/SearchType.py b/Src/Api/Animeunity/Core/Class/SearchType.py index 4e3c50f..6c492bf 100644 --- a/Src/Api/Animeunity/Core/Class/SearchType.py +++ b/Src/Api/Animeunity/Core/Class/SearchType.py @@ -37,33 +37,10 @@ class MediaItem: self.last_air_date: str = data.get('last_air_date') self.seasons_count: int = data.get('seasons_count') self.images: List[Image] = [Image(image_data) for image_data in data.get('images', [])] - self.comment: str = data.get('comment') - self.plot: str = data.get('plot') def __str__(self): return f"MediaItem(id={self.id}, slug='{self.slug}', name='{self.name}', type='{self.type}', score='{self.score}', sub_ita={self.sub_ita}, last_air_date='{self.last_air_date}', seasons_count={self.seasons_count}, images={self.images})" - @property - def to_dict(self) -> dict: - """ - Convert the MediaItem to a dictionary. - - Returns: - dict: The MediaItem as a dictionary. - """ - return { - "id": self.id, - "slug": self.slug, - "name": self.name, - "type": self.type.upper(), - "score": self.score, - "sub_ita": self.sub_ita, - "last_air_date": self.last_air_date, - "seasons_count": self.seasons_count, - "images": [image.__dict__ for image in self.images], - "comment": self.comment, - "plot": self.plot - } class MediaManager: def __init__(self): diff --git a/Src/Api/Streamingcommunity/Core/Class/EpisodeType.py b/Src/Api/Streamingcommunity/Core/Class/EpisodeType.py index 8857726..468e98b 100644 --- a/Src/Api/Streamingcommunity/Core/Class/EpisodeType.py +++ b/Src/Api/Streamingcommunity/Core/Class/EpisodeType.py @@ -27,19 +27,6 @@ class Image: def __str__(self): return f"Image(id={self.id}, filename='{self.filename}', type='{self.type}', imageable_type='{self.imageable_type}', url='{self.url}')" - - def to_dict(self) -> Dict[str, Any]: - return { - 'id': self.id, - 'filename': self.filename, - 'type': self.type, - 'imageable_type': self.imageable_type, - 'imageable_id': self.imageable_id, - 'created_at': self.created_at, - 'updated_at': self.updated_at, - 'original_url_field': self.original_url_field, - 'url': self.url - } class Episode: @@ -58,21 +45,6 @@ class Episode: def __str__(self): return f"Episode(id={self.id}, number={self.number}, name='{self.name}', plot='{self.plot}', duration={self.duration} sec)" - - def to_dict(self) -> Dict[str, Any]: - return { - 'id': self.id, - 'number': self.number, - 'name': self.name, - 'plot': self.plot, - 'duration': self.duration, - 'scws_id': self.scws_id, - 'season_id': self.season_id, - 'created_by': self.created_by, - 'created_at': self.created_at, - 'updated_at': self.updated_at, - 'images': [image.to_dict() for image in self.images] - } class EpisodeManager: diff --git a/Src/Api/Streamingcommunity/Core/Class/PreviewType.py b/Src/Api/Streamingcommunity/Core/Class/PreviewType.py index 7b80b0a..28d741e 100644 --- a/Src/Api/Streamingcommunity/Core/Class/PreviewType.py +++ b/Src/Api/Streamingcommunity/Core/Class/PreviewType.py @@ -60,17 +60,4 @@ class PreviewManager: images_str = "\n".join(str(image) for image in self.images) return f"Title: ID={self.id}, Type={self.type}, Runtime={self.runtime}, Release Date={self.release_date}, Quality={self.quality}, Plot={self.plot}, Seasons Count={self.seasons_count}\nGenres:\n{genres_str}\nPreview:\n{self.preview}\nImages:\n{images_str}" - def to_dict(self): - return { - "id": self.id, - "type": self.type, - "runtime": self.runtime, - "release_date": self.release_date, - "quality": self.quality, - "plot": self.plot, - "seasons_count": self.seasons_count, - "genres": [genre.__dict__ for genre in self.genres], - "preview": self.preview.__dict__, - "images": [image.__dict__ for image in self.images] - } diff --git a/Src/Api/Streamingcommunity/Core/Class/SearchType.py b/Src/Api/Streamingcommunity/Core/Class/SearchType.py index 4e20c1c..115677d 100644 --- a/Src/Api/Streamingcommunity/Core/Class/SearchType.py +++ b/Src/Api/Streamingcommunity/Core/Class/SearchType.py @@ -37,44 +37,10 @@ class MediaItem: self.last_air_date: str = data.get('last_air_date') self.seasons_count: int = data.get('seasons_count') self.images: List[Image] = [Image(image_data) for image_data in data.get('images', [])] - self.comment: str = data.get('comment') - self.plot: str = data.get('plot') def __str__(self): return f"MediaItem(id={self.id}, slug='{self.slug}', name='{self.name}', type='{self.type}', score='{self.score}', sub_ita={self.sub_ita}, last_air_date='{self.last_air_date}', seasons_count={self.seasons_count}, images={self.images})" - @property - def to_dict(self) -> dict: - """ - Convert the MediaItem to a dictionary. - - Returns: - dict: The MediaItem as a dictionary. - """ - return { - "id": self.id, - "slug": self.slug, - "name": self.name, - "type": self.type.upper(), - "score": self.score, - "sub_ita": self.sub_ita, - "last_air_date": self.last_air_date, - "seasons_count": self.seasons_count, - "images": [image.__dict__ for image in self.images], - "comment": self.comment, - "plot": self.plot - } - - @property - def get_site_id(self) -> str: - """ - Get the site ID of the media item. - - Returns: - int: The site ID of the media item. - """ - return f"{self.id}-{self.slug}" - class MediaManager: def __init__(self): diff --git a/api/__init__.py b/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/api/api/__init__.py b/api/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/api/api/asgi.py b/api/api/asgi.py deleted file mode 100644 index 57b0c31..0000000 --- a/api/api/asgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -ASGI config for api project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ -""" - -import os - -from django.core.asgi import get_asgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings") - -application = get_asgi_application() diff --git a/api/api/settings.py b/api/api/settings.py deleted file mode 100644 index d64cd0f..0000000 --- a/api/api/settings.py +++ /dev/null @@ -1,140 +0,0 @@ -""" -Django settings for api project. - -Generated by 'django-admin startproject' using Django 4.2.7. - -For more information on this file, see -https://docs.djangoproject.com/en/4.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/4.2/ref/settings/ -""" - -from pathlib import Path - -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "django-insecure-7u!h-#6b--%h8()19so$s+t9cjh5y1+ljnqum*@gm))0(a_qka" - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - "django.contrib.admin", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.staticfiles", - "corsheaders", - "endpoints", - "rest_framework", -] - -MIDDLEWARE = [ - "corsheaders.middleware.CorsMiddleware", - "django.middleware.security.SecurityMiddleware", - "django.contrib.sessions.middleware.SessionMiddleware", - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - "django.contrib.auth.middleware.AuthenticationMiddleware", - "django.contrib.messages.middleware.MessageMiddleware", - "django.middleware.clickjacking.XFrameOptionsMiddleware", -] - -ROOT_URLCONF = "api.urls" - -TEMPLATES = [ - { - "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [], - "APP_DIRS": True, - "OPTIONS": { - "context_processors": [ - "django.template.context_processors.debug", - "django.template.context_processors.request", - "django.contrib.auth.context_processors.auth", - "django.contrib.messages.context_processors.messages", - ], - }, - }, -] - -WSGI_APPLICATION = "api.wsgi.application" - - -# Database -# https://docs.djangoproject.com/en/4.2/ref/settings/#databases - -DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": BASE_DIR / "db.sqlite3", - } -} - - -# Password validation -# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", - }, - { - "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/4.2/topics/i18n/ - -LANGUAGE_CODE = "en-us" - -TIME_ZONE = "UTC" - -USE_I18N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/4.2/howto/static-files/ - -STATIC_URL = "static/" - -# Default primary key field type -# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field - -DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" - -CORS_ALLOWED_ORIGINS = [ - "http://localhost:5173", -] - -CORS_ALLOWED_METHODS = ( - "DELETE", - "GET", - "OPTIONS", - "PATCH", - "POST", - "PUT", -) diff --git a/api/api/urls.py b/api/api/urls.py deleted file mode 100644 index 30b52fe..0000000 --- a/api/api/urls.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -URL configuration for api project. - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/4.2/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" - -from django.contrib import admin -from django.urls import path, include - -urlpatterns = [ - path("admin/", admin.site.urls), - path("api/", include("endpoints.urls")), -] diff --git a/api/api/wsgi.py b/api/api/wsgi.py deleted file mode 100644 index bfbc45a..0000000 --- a/api/api/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -WSGI config for api project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings") - -application = get_wsgi_application() diff --git a/api/endpoints/__init__.py b/api/endpoints/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/api/endpoints/admin.py b/api/endpoints/admin.py deleted file mode 100644 index 8c38f3f..0000000 --- a/api/endpoints/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/api/endpoints/apps.py b/api/endpoints/apps.py deleted file mode 100644 index 0cf6cd7..0000000 --- a/api/endpoints/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class EndpointsConfig(AppConfig): - default_auto_field = "django.db.models.BigAutoField" - name = "endpoints" diff --git a/api/endpoints/migrations/__init__.py b/api/endpoints/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/api/endpoints/models.py b/api/endpoints/models.py deleted file mode 100644 index 71a8362..0000000 --- a/api/endpoints/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/api/endpoints/tests.py b/api/endpoints/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/api/endpoints/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/api/endpoints/urls.py b/api/endpoints/urls.py deleted file mode 100644 index 184bb2f..0000000 --- a/api/endpoints/urls.py +++ /dev/null @@ -1,10 +0,0 @@ -from rest_framework import routers - -from .views import SearchView#, DownloadView - -router = routers.DefaultRouter() - -router.register(r"search", SearchView, basename="search") -#router.register(r"download", DownloadView, basename="download") - -urlpatterns = router.urls diff --git a/api/endpoints/views.py b/api/endpoints/views.py deleted file mode 100644 index 0df7062..0000000 --- a/api/endpoints/views.py +++ /dev/null @@ -1,241 +0,0 @@ -import json -import os - -from django.http import StreamingHttpResponse - -from rest_framework import viewsets -from rest_framework.decorators import action -from rest_framework.response import Response - -from Src.Api.Animeunity import title_search as anime_search -from Src.Api.Animeunity.Core.Vix_player.player import VideoSource as anime_source -from Src.Api.Animeunity.site import media_search_manager as anime_media_manager - -from Src.Api.Streamingcommunity import title_search as sc_search, get_version_and_domain -from Src.Api.Streamingcommunity.Core.Vix_player.player import VideoSource as film_video_source -from Src.Api.Streamingcommunity.site import media_search_manager as film_media_manager - - -class SearchView(viewsets.ViewSet): - - def list(self, request): - self.search_query = request.query_params.get("search_terms") - self.type_search = request.query_params.get("type") - - media_manager = anime_media_manager if self.type_search == "anime" else film_media_manager - media_manager.media_list = [] - self.len_database = 0 - if self.type_search == "film": - _, self.domain = get_version_and_domain() - self.len_database = sc_search(self.search_query, self.domain) - elif self.type_search == "anime": - self.len_database = anime_search(self.search_query) - - media_list = media_manager.media_list - - if self.len_database != 0: - data_to_return = [] - for _, media in enumerate(media_list): - if self.type_search == "anime": - if media.type == "TV": - media.type = "TV_ANIME" - if media.type == "Movie": - media.type = "OVA" - data_to_return.append(media.to_dict) - - return Response({"media": data_to_return}) - - return Response({"error": "No media found with that search query"}) - - @action(detail=False, methods=["get"]) - def get_episodes_info(self, request): - self.media_id = request.query_params.get("media_id") - self.media_slug = request.query_params.get("media_slug") - self.type_media = request.query_params.get("type_media") - - try: - match self.type_media: - case "TV": - - def stream_episodes(): - self.version, self.domain = get_version_and_domain() - - video_source = film_video_source() - video_source.setup( - version=self.version, - domain=self.domain, - media_id=self.media_id, - series_name=self.media_slug - ) - video_source.collect_info_seasons() - seasons_count = video_source.obj_title_manager.get_length() - - episodes = {} - for i_season in range(1, seasons_count + 1): - video_source.obj_episode_manager.clear() - video_source.collect_title_season(i_season) - episodes_count = ( - video_source.obj_episode_manager.get_length() - ) - episodes[i_season] = {} - for i_episode in range(1, episodes_count + 1): - episode = video_source.obj_episode_manager.episodes[ - i_episode - 1 - ] - episodes[i_season][i_episode] = episode.to_dict() - - yield f'{json.dumps({"episodes": episodes})}\n\n' - - response = StreamingHttpResponse( - stream_episodes(), content_type="text/event-stream" - ) - return response - - case "TV_ANIME": - def stream_episodes(): - video_source = anime_source() - video_source.setup( - media_id = self.media_id, - series_name = self.media_slug - ) - episoded_count = video_source.get_count_episodes() - - for i in range(0, episoded_count): - episode_info = video_source.get_info_episode(i).to_dict() - episode_info["episode_id"] = i - episode_info["episode_total"] = episoded_count - print(f"Getting episode {i} of {episoded_count} info...") - yield f"{json.dumps(episode_info)}\n\n" - - response = StreamingHttpResponse( - stream_episodes(), content_type="text/event-stream" - ) - return response - - except Exception as e: - return Response( - { - "error": "Error while getting episodes info", - "message": str(e), - } - ) - - return Response({"error": "No media found with that search query"}) - - @action(detail=False, methods=["get"]) - def get_preview(self, request): - self.media_id = request.query_params.get("media_id") - self.media_slug = request.query_params.get("media_slug") - self.type_media = request.query_params.get("type_media") - - try: - if self.type_media in ["TV", "MOVIE"]: - version, domain = get_version_and_domain() - video_source = film_video_source() - video_source.setup(media_id=self.media_id, version=version, domain=domain, series_name=self.media_slug) - video_source.get_preview() - return Response(video_source.obj_preview.to_dict()) - if self.type_media in ["TV_ANIME", "OVA", "SPECIAL"]: - video_source = anime_source() - video_source.setup(media_id=self.media_id, series_name=self.media_slug) - video_source.get_preview() - return Response(video_source.obj_preview.to_dict()) - except Exception as e: - return Response( - { - "error": "Error while getting preview info", - "message": str(e), - } - ) - - return Response({"error": "No media found with that search query"}) - - -''' -class DownloadView(viewsets.ViewSet): - - def create(self, request): - self.media_id = request.data.get("media_id") - self.media_slug = request.data.get("media_slug") - self.type_media = request.data.get("type_media").upper() - self.download_id = request.data.get("download_id") - self.tv_series_episode_id = request.data.get("tv_series_episode_id") - - if self.type_media in ["TV", "MOVIE"]: - self.site_version, self.domain = get_version_and_domain() - - response_dict = {"error": "No media found with that search query"} - - try: - match self.type_media: - case "MOVIE": - download_film(self.media_id, self.media_slug, self.domain) - case "TV": - video_source = VideoSource() - video_source.set_url_base_name(STREAM_SITE_NAME) - video_source.set_version(self.site_version) - video_source.set_domain(self.domain) - video_source.set_series_name(self.media_slug) - video_source.set_media_id(self.media_id) - - video_source.collect_info_seasons() - video_source.obj_episode_manager.clear() - - video_source.collect_title_season(self.download_id) - episodes_count = video_source.obj_episode_manager.get_length() - for i_episode in range(1, episodes_count + 1): - episode_id = video_source.obj_episode_manager.episodes[ - i_episode - 1 - ].id - - # Define filename and path for the downloaded video - mp4_name = remove_special_characters( - f"{map_episode_title(self.media_slug,video_source.obj_episode_manager.episodes[i_episode - 1],self.download_id)}.mp4" - ) - mp4_path = remove_special_characters( - os.path.join( - ROOT_PATH, - SERIES_FOLDER, - self.media_slug, - f"S{self.download_id}", - ) - ) - os.makedirs(mp4_path, exist_ok=True) - - # Get iframe and content for the episode - video_source.get_iframe(episode_id) - video_source.get_content() - video_source.set_url_base_name(STREAM_SITE_NAME) - - # Download the episode - obj_download = Downloader( - m3u8_playlist=video_source.get_playlist(), - key=video_source.get_key(), - output_filename=os.path.join(mp4_path, mp4_name), - ) - - obj_download.download_m3u8() - - case "TV_ANIME": - episodes_downloader = EpisodeDownloader( - self.media_id, self.media_slug - ) - episodes_downloader.download_episode(self.download_id) - case "OVA" | "SPECIAL": - anime_download_film( - id_film=self.media_id, title_name=self.media_slug - ) - case _: - raise Exception("Type media not supported") - - response_dict = { - "message": "Download done, it is saved in Video folder inside project root" - } - except Exception as e: - response_dict = { - "error": "Error while downloading the media", - "message": str(e), - } - - return Response(response_dict) -''' diff --git a/api/manage.py b/api/manage.py deleted file mode 100755 index 3b72e09..0000000 --- a/api/manage.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python -"""Django's command-line utility for administrative tasks.""" -import os -import sys - -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) - - -def main(): - """Run administrative tasks.""" - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings") - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) - - -if __name__ == "__main__": - main() diff --git a/config.json b/config.json index c2bc0e2..2603713 100644 --- a/config.json +++ b/config.json @@ -45,4 +45,4 @@ "animeunity": "to", "altadefinizione": "food" } -} \ No newline at end of file +} diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs deleted file mode 100644 index 6f40582..0000000 --- a/frontend/.eslintrc.cjs +++ /dev/null @@ -1,15 +0,0 @@ -/* eslint-env node */ -require('@rushstack/eslint-patch/modern-module-resolution') - -module.exports = { - root: true, - 'extends': [ - 'plugin:vue/vue3-essential', - 'eslint:recommended', - '@vue/eslint-config-typescript', - '@vue/eslint-config-prettier/skip-formatting' - ], - parserOptions: { - ecmaVersion: 'latest' - } -} diff --git a/frontend/.gitignore b/frontend/.gitignore deleted file mode 100644 index 8ee54e8..0000000 --- a/frontend/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -.DS_Store -dist -dist-ssr -coverage -*.local - -/cypress/videos/ -/cypress/screenshots/ - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? - -*.tsbuildinfo diff --git a/frontend/.prettierrc.json b/frontend/.prettierrc.json deleted file mode 100644 index 66e2335..0000000 --- a/frontend/.prettierrc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/prettierrc", - "semi": false, - "tabWidth": 2, - "singleQuote": true, - "printWidth": 100, - "trailingComma": "none" -} \ No newline at end of file diff --git a/frontend/.vscode/extensions.json b/frontend/.vscode/extensions.json deleted file mode 100644 index 93ea3e7..0000000 --- a/frontend/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "recommendations": [ - "Vue.volar", - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode" - ] -} diff --git a/frontend/README.md b/frontend/README.md deleted file mode 100644 index 9b4c74c..0000000 --- a/frontend/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# frontend - -This template should help get you started developing with Vue 3 in Vite. - -## Recommended IDE Setup - -[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). - -## Type Support for `.vue` Imports in TS - -TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. - -## Customize configuration - -See [Vite Configuration Reference](https://vitejs.dev/config/). - -## Project Setup - -```sh -npm install -``` - -### Compile and Hot-Reload for Development - -```sh -npm run dev -``` - -### Type-Check, Compile and Minify for Production - -```sh -npm run build -``` - -### Lint with [ESLint](https://eslint.org/) - -```sh -npm run lint -``` diff --git a/frontend/env.d.ts b/frontend/env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/frontend/env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/frontend/index.html b/frontend/index.html deleted file mode 100644 index a888544..0000000 --- a/frontend/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite App - - -
- - - diff --git a/frontend/package-lock.json b/frontend/package-lock.json deleted file mode 100644 index dd00361..0000000 --- a/frontend/package-lock.json +++ /dev/null @@ -1,3225 +0,0 @@ -{ - "name": "frontend", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "frontend", - "version": "0.0.0", - "dependencies": { - "axios": "^1.6.8", - "vue": "^3.4.21", - "vue-router": "^4.3.0" - }, - "devDependencies": { - "@rushstack/eslint-patch": "^1.8.0", - "@tsconfig/node20": "^20.1.4", - "@types/node": "^20.12.5", - "@vitejs/plugin-vue": "^5.0.4", - "@vue/eslint-config-prettier": "^9.0.0", - "@vue/eslint-config-typescript": "^13.0.0", - "@vue/tsconfig": "^0.5.1", - "eslint": "^8.57.0", - "eslint-plugin-vue": "^9.23.0", - "npm-run-all2": "^6.1.2", - "prettier": "^3.2.5", - "typescript": "~5.4.0", - "vite": "^5.2.8", - "vue-tsc": "^2.0.11" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "dev": true - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.0.tgz", - "integrity": "sha512-nNvLvC2fjC+3+bHYN9uaGF3gcyy7RHGZhtl8TB/kINj9hiOQza8kWJGZh47GRPMrqeseO8U+Z8ElDMCZlWBdHA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.0.tgz", - "integrity": "sha512-+kjt6dvxnyTIAo7oHeYseYhDyZ7xRKTNl/FoQI96PHkJVxoChldJnne/LzYqpqidoK1/0kX0/q+5rrYqjpth6w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.0.tgz", - "integrity": "sha512-Oj6Tp0unMpGTBjvNwbSRv3DopMNLu+mjBzhKTt2zLbDJ/45fB1pltr/rqrO4bE95LzuYwhYn127pop+x/pzf5w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.0.tgz", - "integrity": "sha512-3nJx0T+yptxMd+v93rBRxSPTAVCv8szu/fGZDJiKX7kvRe9sENj2ggXjCH/KK1xZEmJOhaNo0c9sGMgGdfkvEw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.0.tgz", - "integrity": "sha512-Vb2e8p9b2lxxgqyOlBHmp6hJMu/HSU6g//6Tbr7x5V1DlPCHWLOm37nSIVK314f+IHzORyAQSqL7+9tELxX3zQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.0.tgz", - "integrity": "sha512-Md60KsmC5ZIaRq/bYYDloklgU+XLEZwS2EXXVcSpiUw+13/ZASvSWQ/P92rQ9YDCL6EIoXxuQ829JkReqdYbGg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.0.tgz", - "integrity": "sha512-zL5rBFtJ+2EGnMRm2TqKjdjgFqlotSU+ZJEN37nV+fiD3I6Gy0dUh3jBWN0wSlcXVDEJYW7YBe+/2j0N9unb2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.0.tgz", - "integrity": "sha512-s2xAyNkJqUdtRVgNK4NK4P9QttS538JuX/kfVQOdZDI5FIKVAUVdLW7qhGfmaySJ1EvN/Bnj9oPm5go9u8navg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.0.tgz", - "integrity": "sha512-7F99yzVT67B7IUNMjLD9QCFDCyHkyCJMS1dywZrGgVFJao4VJ9szrIEgH67cR+bXQgEaY01ur/WSL6B0jtcLyA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.0.tgz", - "integrity": "sha512-leFtyiXisfa3Sg9pgZJwRKITWnrQfhtqDjCamnZhkZuIsk1FXmYwKoTkp6lsCgimIcneFFkHKp/yGLxDesga4g==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.0.tgz", - "integrity": "sha512-FtOgui6qMJ4jbSXTxElsy/60LEe/3U0rXkkz2G5CJ9rbHPAvjMvI+3qF0A0fwLQ5hW+/ZC6PbnS2KfRW9JkgDQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.0.tgz", - "integrity": "sha512-v6eiam/1w3HUfU/ZjzIDodencqgrSqzlNuNtiwH7PFJHYSo1ezL0/UIzmS2lpSJF1ORNaplXeKHYmmdt81vV2g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.0.tgz", - "integrity": "sha512-OUhkSdpM5ofVlVU2k4CwVubYwiwu1a4jYWPpubzN7Vzao73GoPBowHcCfaRSFRz1SszJ3HIsk3dZYk4kzbqjgw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.0.tgz", - "integrity": "sha512-uL7UYO/MNJPGL/yflybI+HI+n6+4vlfZmQZOCb4I+z/zy1wisHT3exh7oNQsnL6Eso0EUTEfgQ/PaGzzXf6XyQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.0.tgz", - "integrity": "sha512-4WnSgaUiUmXILwFqREdOcqvSj6GD/7FrvSjhaDjmwakX9w4Z2F8JwiSP1AZZbuRkPqzi444UI5FPv33VKOWYFQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.0.tgz", - "integrity": "sha512-ve+D8t1prRSRnF2S3pyDtTXDlvW1Pngbz76tjgYFQW1jxVSysmQCZfPoDAo4WP+Ano8zeYp85LsArZBI12HfwQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz", - "integrity": "sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==", - "dev": true - }, - "node_modules/@tsconfig/node20": { - "version": "20.1.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.4.tgz", - "integrity": "sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==", - "dev": true - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", - "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/type-utils": "7.7.1", - "@typescript-eslint/utils": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz", - "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", - "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", - "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/utils": "7.7.1", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", - "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", - "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", - "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", - "semver": "^7.6.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", - "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.7.1", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/@vitejs/plugin-vue": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz", - "integrity": "sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==", - "dev": true, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "vite": "^5.0.0", - "vue": "^3.2.25" - } - }, - "node_modules/@volar/language-core": { - "version": "2.2.0-alpha.10", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.2.0-alpha.10.tgz", - "integrity": "sha512-njVJLtpu0zMvDaEk7K5q4BRpOgbyEUljU++un9TfJoJNhxG0z/hWwpwgTRImO42EKvwIxF3XUzeMk+qatAFy7Q==", - "dev": true, - "dependencies": { - "@volar/source-map": "2.2.0-alpha.10" - } - }, - "node_modules/@volar/source-map": { - "version": "2.2.0-alpha.10", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.2.0-alpha.10.tgz", - "integrity": "sha512-nrdWApVkP5cksAnDEyy1JD9rKdwOJsEq1B+seWO4vNXmZNcxQQCx4DULLBvKt7AzRUAQiAuw5aQkb9RBaSqdVA==", - "dev": true, - "dependencies": { - "muggle-string": "^0.4.0" - } - }, - "node_modules/@volar/typescript": { - "version": "2.2.0-alpha.10", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.2.0-alpha.10.tgz", - "integrity": "sha512-GCa0vTVVdA9ULUsu2Rx7jwsIuyZQPvPVT9o3NrANTbYv+523Ao1gv3glC5vzNSDPM6bUl37r94HbCj7KINQr+g==", - "dev": true, - "dependencies": { - "@volar/language-core": "2.2.0-alpha.10", - "path-browserify": "^1.0.1" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.25.tgz", - "integrity": "sha512-Y2pLLopaElgWnMNolgG8w3C5nNUVev80L7hdQ5iIKPtMJvhVpG0zhnBG/g3UajJmZdvW0fktyZTotEHD1Srhbg==", - "dependencies": { - "@babel/parser": "^7.24.4", - "@vue/shared": "3.4.25", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.0" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.25.tgz", - "integrity": "sha512-Ugz5DusW57+HjllAugLci19NsDK+VyjGvmbB2TXaTcSlQxwL++2PETHx/+Qv6qFwNLzSt7HKepPe4DcTE3pBWg==", - "dependencies": { - "@vue/compiler-core": "3.4.25", - "@vue/shared": "3.4.25" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.25.tgz", - "integrity": "sha512-m7rryuqzIoQpOBZ18wKyq05IwL6qEpZxFZfRxlNYuIPDqywrXQxgUwLXIvoU72gs6cRdY6wHD0WVZIFE4OEaAQ==", - "dependencies": { - "@babel/parser": "^7.24.4", - "@vue/compiler-core": "3.4.25", - "@vue/compiler-dom": "3.4.25", - "@vue/compiler-ssr": "3.4.25", - "@vue/shared": "3.4.25", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.10", - "postcss": "^8.4.38", - "source-map-js": "^1.2.0" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.25.tgz", - "integrity": "sha512-H2ohvM/Pf6LelGxDBnfbbXFPyM4NE3hrw0e/EpwuSiYu8c819wx+SVGdJ65p/sFrYDd6OnSDxN1MB2mN07hRSQ==", - "dependencies": { - "@vue/compiler-dom": "3.4.25", - "@vue/shared": "3.4.25" - } - }, - "node_modules/@vue/devtools-api": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.1.tgz", - "integrity": "sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==" - }, - "node_modules/@vue/eslint-config-prettier": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@vue/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", - "integrity": "sha512-z1ZIAAUS9pKzo/ANEfd2sO+v2IUalz7cM/cTLOZ7vRFOPk5/xuRKQteOu1DErFLAh/lYGXMVZ0IfYKlyInuDVg==", - "dev": true, - "dependencies": { - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-prettier": "^5.0.0" - }, - "peerDependencies": { - "eslint": ">= 8.0.0", - "prettier": ">= 3.0.0" - } - }, - "node_modules/@vue/eslint-config-typescript": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-13.0.0.tgz", - "integrity": "sha512-MHh9SncG/sfqjVqjcuFLOLD6Ed4dRAis4HNt0dXASeAuLqIAx4YMB1/m2o4pUKK1vCt8fUvYG8KKX2Ot3BVZTg==", - "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "^7.1.1", - "@typescript-eslint/parser": "^7.1.1", - "vue-eslint-parser": "^9.3.1" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "peerDependencies": { - "eslint": "^8.56.0", - "eslint-plugin-vue": "^9.0.0", - "typescript": ">=4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@vue/language-core": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.14.tgz", - "integrity": "sha512-3q8mHSNcGTR7sfp2X6jZdcb4yt8AjBXAfKk0qkZIh7GAJxOnoZ10h5HToZglw4ToFvAnq+xu/Z2FFbglh9Icag==", - "dev": true, - "dependencies": { - "@volar/language-core": "2.2.0-alpha.10", - "@vue/compiler-dom": "^3.4.0", - "@vue/shared": "^3.4.0", - "computeds": "^0.0.1", - "minimatch": "^9.0.3", - "path-browserify": "^1.0.1", - "vue-template-compiler": "^2.7.14" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@vue/reactivity": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.25.tgz", - "integrity": "sha512-mKbEtKr1iTxZkAG3vm3BtKHAOhuI4zzsVcN0epDldU/THsrvfXRKzq+lZnjczZGnTdh3ojd86/WrP+u9M51pWQ==", - "dependencies": { - "@vue/shared": "3.4.25" - } - }, - "node_modules/@vue/runtime-core": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.25.tgz", - "integrity": "sha512-3qhsTqbEh8BMH3pXf009epCI5E7bKu28fJLi9O6W+ZGt/6xgSfMuGPqa5HRbUxLoehTNp5uWvzCr60KuiRIL0Q==", - "dependencies": { - "@vue/reactivity": "3.4.25", - "@vue/shared": "3.4.25" - } - }, - "node_modules/@vue/runtime-dom": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.25.tgz", - "integrity": "sha512-ode0sj77kuwXwSc+2Yhk8JMHZh1sZp9F/51wdBiz3KGaWltbKtdihlJFhQG4H6AY+A06zzeMLkq6qu8uDSsaoA==", - "dependencies": { - "@vue/runtime-core": "3.4.25", - "@vue/shared": "3.4.25", - "csstype": "^3.1.3" - } - }, - "node_modules/@vue/server-renderer": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.25.tgz", - "integrity": "sha512-8VTwq0Zcu3K4dWV0jOwIVINESE/gha3ifYCOKEhxOj6MEl5K5y8J8clQncTcDhKF+9U765nRw4UdUEXvrGhyVQ==", - "dependencies": { - "@vue/compiler-ssr": "3.4.25", - "@vue/shared": "3.4.25" - }, - "peerDependencies": { - "vue": "3.4.25" - } - }, - "node_modules/@vue/shared": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.25.tgz", - "integrity": "sha512-k0yappJ77g2+KNrIaF0FFnzwLvUBLUYr8VOwz+/6vLsmItFp51AcxLL7Ey3iPd7BIRyWPOcqUjMnm7OkahXllA==" - }, - "node_modules/@vue/tsconfig": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.5.1.tgz", - "integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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/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/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/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/computeds": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", - "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" - }, - "node_modules/de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-vue": { - "version": "9.25.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.25.0.tgz", - "integrity": "sha512-tDWlx14bVe6Bs+Nnh3IGrD+hb11kf2nukfm6jLsmJIhmiRQ1SUaksvwY9U5MvPB0pcrg0QK0xapQkfITs3RKOA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "globals": "^13.24.0", - "natural-compare": "^1.4.0", - "nth-check": "^2.1.1", - "postcss-selector-parser": "^6.0.15", - "semver": "^7.6.0", - "vue-eslint-parser": "^9.4.2", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": "^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" - }, - "node_modules/esutils": { - "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" - } - }, - "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==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "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==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "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/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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 - }, - "node_modules/muggle-string": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", - "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-run-all2": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.1.2.tgz", - "integrity": "sha512-WwwnS8Ft+RpXve6T2EIEVpFLSqN+ORHRvgNk3H9N62SZXjmzKoRhMFg3I17TK3oMaAEr+XFbRirWS2Fn3BCPSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.2.1", - "cross-spawn": "^7.0.3", - "memorystream": "^0.3.1", - "minimatch": "^9.0.0", - "pidtree": "^0.6.0", - "read-package-json-fast": "^3.0.2", - "shell-quote": "^1.7.3" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "npm-run-all2": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0", - "npm": ">= 8" - } - }, - "node_modules/npm-run-all2/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/once": { - "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" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "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==" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/read-package-json-fast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", - "dev": true, - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.0.tgz", - "integrity": "sha512-wZJSn0WMtWrxhYKQRt5Z6GIXlziOoMDFmbHmRfL3v+sBTAshx2DBq1AfMArB7eIjF63r4ocn2ZTAyUptg/7kmQ==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.17.0", - "@rollup/rollup-android-arm64": "4.17.0", - "@rollup/rollup-darwin-arm64": "4.17.0", - "@rollup/rollup-darwin-x64": "4.17.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.17.0", - "@rollup/rollup-linux-arm-musleabihf": "4.17.0", - "@rollup/rollup-linux-arm64-gnu": "4.17.0", - "@rollup/rollup-linux-arm64-musl": "4.17.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.17.0", - "@rollup/rollup-linux-riscv64-gnu": "4.17.0", - "@rollup/rollup-linux-s390x-gnu": "4.17.0", - "@rollup/rollup-linux-x64-gnu": "4.17.0", - "@rollup/rollup-linux-x64-musl": "4.17.0", - "@rollup/rollup-win32-arm64-msvc": "4.17.0", - "@rollup/rollup-win32-ia32-msvc": "4.17.0", - "@rollup/rollup-win32-x64-msvc": "4.17.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "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==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "devOptional": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/vite": { - "version": "5.2.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz", - "integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==", - "dev": true, - "dependencies": { - "esbuild": "^0.20.1", - "postcss": "^8.4.38", - "rollup": "^4.13.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vue": { - "version": "3.4.25", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.25.tgz", - "integrity": "sha512-HWyDqoBHMgav/OKiYA2ZQg+kjfMgLt/T0vg4cbIF7JbXAjDexRf5JRg+PWAfrAkSmTd2I8aPSXtooBFWHB98cg==", - "dependencies": { - "@vue/compiler-dom": "3.4.25", - "@vue/compiler-sfc": "3.4.25", - "@vue/runtime-dom": "3.4.25", - "@vue/server-renderer": "3.4.25", - "@vue/shared": "3.4.25" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/vue-eslint-parser": { - "version": "9.4.2", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.2.tgz", - "integrity": "sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", - "lodash": "^4.17.21", - "semver": "^7.3.6" - }, - "engines": { - "node": "^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=6.0.0" - } - }, - "node_modules/vue-router": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.2.tgz", - "integrity": "sha512-hKQJ1vDAZ5LVkKEnHhmm1f9pMiWIBNGF5AwU67PdH7TyXCj/a4hTccuUuYCAMgJK6rO/NVYtQIEN3yL8CECa7Q==", - "dependencies": { - "@vue/devtools-api": "^6.5.1" - }, - "funding": { - "url": "https://github.com/sponsors/posva" - }, - "peerDependencies": { - "vue": "^3.2.0" - } - }, - "node_modules/vue-template-compiler": { - "version": "2.7.16", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", - "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", - "dev": true, - "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" - } - }, - "node_modules/vue-tsc": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.14.tgz", - "integrity": "sha512-DgAO3U1cnCHOUO7yB35LENbkapeRsBZ7Ugq5hGz/QOHny0+1VQN8eSwSBjYbjLVPfvfw6EY7sNPjbuHHUhckcg==", - "dev": true, - "dependencies": { - "@volar/typescript": "2.2.0-alpha.10", - "@vue/language-core": "2.0.14", - "semver": "^7.5.4" - }, - "bin": { - "vue-tsc": "bin/vue-tsc.js" - }, - "peerDependencies": { - "typescript": "*" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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 - }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/frontend/package.json b/frontend/package.json deleted file mode 100644 index 10a021d..0000000 --- a/frontend/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "frontend", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "dev": "vite", - "build": "run-p type-check \"build-only {@}\" --", - "preview": "vite preview", - "build-only": "vite build", - "type-check": "vue-tsc --build --force", - "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", - "format": "prettier --write src/" - }, - "dependencies": { - "axios": "^1.6.8", - "vue": "^3.4.21", - "vue-router": "^4.3.0" - }, - "devDependencies": { - "@rushstack/eslint-patch": "^1.8.0", - "@tsconfig/node20": "^20.1.4", - "@types/node": "^20.12.5", - "@vitejs/plugin-vue": "^5.0.4", - "@vue/eslint-config-prettier": "^9.0.0", - "@vue/eslint-config-typescript": "^13.0.0", - "@vue/tsconfig": "^0.5.1", - "eslint": "^8.57.0", - "eslint-plugin-vue": "^9.23.0", - "npm-run-all2": "^6.1.2", - "prettier": "^3.2.5", - "typescript": "~5.4.0", - "vite": "^5.2.8", - "vue-tsc": "^2.0.11" - } -} diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico deleted file mode 100644 index df36fcfb72584e00488330b560ebcf34a41c64c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S diff --git a/frontend/src/App.vue b/frontend/src/App.vue deleted file mode 100644 index ad56b70..0000000 --- a/frontend/src/App.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - - - diff --git a/frontend/src/api/api.ts b/frontend/src/api/api.ts deleted file mode 100644 index 7ec0039..0000000 --- a/frontend/src/api/api.ts +++ /dev/null @@ -1,81 +0,0 @@ -import axios from "axios"; -import type { AxiosResponse } from "axios"; -import type { DownloadResponse, MediaItemResponse } from "@/api/interfaces"; - -const BASE_URL = "http://localhost:8000/api"; - -const api = axios.create({ - baseURL: BASE_URL, -}); - -async function get(url: string): Promise> { - return api.get(url); -} - -async function post(url: string, data: any): Promise> { - return api.post(url, data); -} - -export default function search( - query: string, - type: string -): Promise> { - return get(`/search?search_terms=${query}&type=${type}`); -} - -export async function getEpisodesInfo( - mediaId: number, - mediaSlug: string, - mediaType: string -): Promise { - const url = `/search/get_episodes_info?media_id=${mediaId}&media_slug=${mediaSlug}&type_media=${mediaType}`; - return fetch(`${BASE_URL}${url}`, { - method: "GET", - headers: { - "Content-Type": "text/event-stream", - }, - }); -} - -export async function getPreview( - mediaId: number, - mediaSlug: string, - mediaType: string -): Promise> { - const url = `/search/get_preview?media_id=${mediaId}&media_slug=${mediaSlug}&type_media=${mediaType}`; - return get(url); -} - -async function downloadMedia( - mediaId: number, - mediaSlug: string, - mediaType: string, - downloadId?: number, - tvSeriesEpisodeId?: number -): Promise> { - const url = `/download/`; - const data = { - media_id: mediaId, - media_slug: mediaSlug, - type_media: mediaType, - download_id: downloadId, - tv_series_episode_id: tvSeriesEpisodeId, - }; - return post(url, data); -} - -export const downloadFilm = (mediaId: number, mediaSlug: string) => - downloadMedia(mediaId, mediaSlug, "MOVIE"); -export const downloadTvSeries = ( - mediaId: number, - mediaSlug: string, - downloadId: number, - tvSeriesEpisodeId?: number -) => downloadMedia(mediaId, mediaSlug, "TV", downloadId, tvSeriesEpisodeId); -export const downloadAnimeFilm = (mediaId: number, mediaSlug: string) => - downloadMedia(mediaId, mediaSlug, "OVA"); -export const downloadAnimeSeries = ( - mediaId: number, - mediaSlug: string, - downloadId: number -) => downloadMedia(mediaId, mediaSlug, "TV_ANIME", downloadId); diff --git a/frontend/src/api/interfaces.ts b/frontend/src/api/interfaces.ts deleted file mode 100644 index d33f703..0000000 --- a/frontend/src/api/interfaces.ts +++ /dev/null @@ -1,64 +0,0 @@ -interface Image { - imageable_id: number; - imageable_type: string; - filename: string; - type: string; - original_url_field: string; -} - -export interface MediaItem { - id: number; - slug: string; - name: string; - type: string; - score: string; - sub_ita: number; - last_air_date: string; - seasons_count: number; - images: Image[]; - comment: string; - plot: string; -} - -export interface MediaItemResponse { - media: MediaItem[]; -} - -export interface Episode { - id: number; - anime_id: number; - user_id: number | null; - number: string; - created_at: string; - link: string; - visite: number; - hidden: number; - public: number; - scws_id: number; - file_name: string; - tg_post: number; - episode_id: number; - episode_total: number; - name: string; // TV Show exclusive - plot: string; // TV Show exclusive - duration: number; // TV Show exclusive - season_id: number; // TV Show exclusive - created_by: any; // TV Show exclusive - updated_at: string; // TV Show exclusive - season_index: number; // TV Show exclusive -} - -export interface Season { - [key: string]: { - [key: string]: Episode; - }; -} - -export interface SeasonResponse { - episodes: Season; -} - -export interface DownloadResponse { - error: string; - message: string; -} \ No newline at end of file diff --git a/frontend/src/api/utils.ts b/frontend/src/api/utils.ts deleted file mode 100644 index 4432fdd..0000000 --- a/frontend/src/api/utils.ts +++ /dev/null @@ -1,63 +0,0 @@ -import {downloadAnimeFilm, downloadAnimeSeries, downloadFilm, downloadTvSeries} from "@/api/api"; -import type {DownloadResponse, Episode, MediaItem, Season} from "@/api/interfaces"; - -export const handleTVDownload = async (tvShowEpisodes: any[], item: MediaItem) => { - alertDownload(); - for (const season of tvShowEpisodes) { - const i = tvShowEpisodes.indexOf(season); - const res = (await downloadTvSeries(item.id, item.slug, i + 1)).data; - handleDownloadError(res); - } -}; - -export const handleTVEpisodesDownload = async (episodes: Episode[], item: MediaItem) => { - alertDownload(); - for (const episode of episodes) { - const i = episodes.indexOf(episode); - const res = (await downloadTvSeries(item.id, item.slug, episode.season_index + 1, i)).data; - handleDownloadError(res); - } -} - -export const handleMovieDownload = async (item: MediaItem) => { - alertDownload(); - const res = (await downloadFilm(item.id, item.slug)).data; - handleDownloadError(res); -}; - -export const handleTVAnimeDownload = async (episodeCount: number, item: MediaItem) => { - alertDownload(); - for (let i = 0; i < episodeCount; i++) { - const res = (await downloadAnimeSeries(item.id, item.slug, i)).data; - handleDownloadError(res); - } -}; - -export const handleTvAnimeEpisodesDownload = async (episodes: Episode[], item: MediaItem) => { - alertDownload(); - for (const episode of episodes) { - const res = (await downloadAnimeSeries(item.id, item.slug, episode.episode_id)).data; - handleDownloadError(res); - } - -} - -export const handleOVADownload = async (item: MediaItem) => { - alertDownload(); - const res = (await downloadAnimeFilm(item.id, item.slug)).data; - handleDownloadError(res); -}; - -const handleDownloadError = (res: DownloadResponse) => { - if (res.error) { - throw new Error(`${res.error} - ${res.message}`); - } -}; - -export const alertDownload = (message?: any) => { - if (message) { - alert(message) - return; - } - alert('Il downlaod è iniziato, il file sarà disponibile tra qualche minuto nella cartella \'Video\' del progetto...') -} \ No newline at end of file diff --git a/frontend/src/assets/base.css b/frontend/src/assets/base.css deleted file mode 100644 index 8816868..0000000 --- a/frontend/src/assets/base.css +++ /dev/null @@ -1,86 +0,0 @@ -/* color palette from */ -:root { - --vt-c-white: #ffffff; - --vt-c-white-soft: #f8f8f8; - --vt-c-white-mute: #f2f2f2; - - --vt-c-black: #181818; - --vt-c-black-soft: #222222; - --vt-c-black-mute: #282828; - - --vt-c-indigo: #2c3e50; - - --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); - --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); - --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); - --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); - - --vt-c-text-light-1: var(--vt-c-indigo); - --vt-c-text-light-2: rgba(60, 60, 60, 0.66); - --vt-c-text-dark-1: var(--vt-c-white); - --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); -} - -/* semantic color variables for this project */ -:root { - --color-background: var(--vt-c-white); - --color-background-soft: var(--vt-c-white-soft); - --color-background-mute: var(--vt-c-white-mute); - - --color-border: var(--vt-c-divider-light-2); - --color-border-hover: var(--vt-c-divider-light-1); - - --color-heading: var(--vt-c-text-light-1); - --color-text: var(--vt-c-text-light-1); - - --section-gap: 160px; -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background: var(--vt-c-black); - --color-background-soft: var(--vt-c-black-soft); - --color-background-mute: var(--vt-c-black-mute); - - --color-border: var(--vt-c-divider-dark-2); - --color-border-hover: var(--vt-c-divider-dark-1); - - --color-heading: var(--vt-c-text-dark-1); - --color-text: var(--vt-c-text-dark-2); - } -} - -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - font-weight: normal; -} - -body { - min-height: 100vh; - color: var(--color-text); - background: var(--color-background); - transition: - color 0.5s, - background-color 0.5s; - line-height: 1.6; - font-family: - Inter, - -apple-system, - BlinkMacSystemFont, - 'Segoe UI', - Roboto, - Oxygen, - Ubuntu, - Cantarell, - 'Fira Sans', - 'Droid Sans', - 'Helvetica Neue', - sans-serif; - font-size: 15px; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} diff --git a/frontend/src/assets/logo.svg b/frontend/src/assets/logo.svg deleted file mode 100644 index 7565660..0000000 --- a/frontend/src/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css deleted file mode 100644 index 36fb845..0000000 --- a/frontend/src/assets/main.css +++ /dev/null @@ -1,35 +0,0 @@ -@import './base.css'; - -#app { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - font-weight: normal; -} - -a, -.green { - text-decoration: none; - color: hsla(160, 100%, 37%, 1); - transition: 0.4s; - padding: 3px; -} - -@media (hover: hover) { - a:hover { - background-color: hsla(160, 100%, 37%, 0.2); - } -} - -@media (min-width: 1024px) { - body { - display: flex; - place-items: center; - } - - #app { - display: grid; - grid-template-columns: 1fr 1fr; - padding: 0 2rem; - } -} diff --git a/frontend/src/components/Card.vue b/frontend/src/components/Card.vue deleted file mode 100644 index 9817f43..0000000 --- a/frontend/src/components/Card.vue +++ /dev/null @@ -1,92 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/components/Toggle.vue b/frontend/src/components/Toggle.vue deleted file mode 100644 index 1f31799..0000000 --- a/frontend/src/components/Toggle.vue +++ /dev/null @@ -1,105 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/main.ts b/frontend/src/main.ts deleted file mode 100644 index 5a5dbdb..0000000 --- a/frontend/src/main.ts +++ /dev/null @@ -1,11 +0,0 @@ -import './assets/main.css' - -import { createApp } from 'vue' -import App from './App.vue' -import router from './router' - -const app = createApp(App) - -app.use(router) - -app.mount('#app') diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts deleted file mode 100644 index fbbbafb..0000000 --- a/frontend/src/router/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { createRouter, createWebHistory } from 'vue-router' -import HomeView from '../views/HomeView.vue' -import Details from "../views/Details.vue"; - -const router = createRouter({ - history: createWebHistory(import.meta.env.BASE_URL), - routes: [ - { - path: '/', - name: 'home', - component: HomeView - }, - { - path: '/details:item:imageUrl', - name: 'details', - component: Details, - props: route => { - let item; - try { - item = JSON.parse(route.params.item); - } catch (error) { - item = {}; // default value - } - return { item: item, imageUrl: route.params.imageUrl }; - }, - } - ] -}) - -export default router diff --git a/frontend/src/views/Details.vue b/frontend/src/views/Details.vue deleted file mode 100644 index 5880730..0000000 --- a/frontend/src/views/Details.vue +++ /dev/null @@ -1,335 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue deleted file mode 100644 index 5919c7e..0000000 --- a/frontend/src/views/HomeView.vue +++ /dev/null @@ -1,176 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json deleted file mode 100644 index e14c754..0000000 --- a/frontend/tsconfig.app.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], - "exclude": ["src/**/__tests__/*"], - "compilerOptions": { - "composite": true, - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - } -} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json deleted file mode 100644 index 66b5e57..0000000 --- a/frontend/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "files": [], - "references": [ - { - "path": "./tsconfig.node.json" - }, - { - "path": "./tsconfig.app.json" - } - ] -} diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json deleted file mode 100644 index f094063..0000000 --- a/frontend/tsconfig.node.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "@tsconfig/node20/tsconfig.json", - "include": [ - "vite.config.*", - "vitest.config.*", - "cypress.config.*", - "nightwatch.conf.*", - "playwright.config.*" - ], - "compilerOptions": { - "composite": true, - "noEmit": true, - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - - "module": "ESNext", - "moduleResolution": "Bundler", - "types": ["node"] - } -} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts deleted file mode 100644 index 5c45e1d..0000000 --- a/frontend/vite.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { fileURLToPath, URL } from 'node:url' - -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [ - vue(), - ], - resolve: { - alias: { - '@': fileURLToPath(new URL('./src', import.meta.url)) - } - } -}) diff --git a/kill_gui.sh b/kill_gui.sh deleted file mode 100755 index c7fac45..0000000 --- a/kill_gui.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -# Trova i processi che utilizzano la porta 8000 -PROCESSES=$(lsof -i :8000 | awk 'NR!=1 {print $2}') - -# Termina i processi trovati -if [ -n "$PROCESSES" ]; then - echo "Terminating processes using port 8000:" - for PID in $PROCESSES; do - echo "Killing process with PID: $PID" - kill -9 $PID - done -else - echo "No processes found using port 8000" -fi - -# Trova i processi che utilizzano la porta 5173 -PROCESSES=$(lsof -i :5173 | awk 'NR!=1 {print $2}') - -# Termina i processi trovati -if [ -n "$PROCESSES" ]; then - echo "Terminating processes using port 5173:" - for PID in $PROCESSES; do - echo "Killing process with PID: $PID" - kill -9 $PID - done -else - echo "No processes found using port 5173" -fi \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index d471fcb..21218f8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,4 @@ bs4 tqdm rich -unidecode -ffmpeg-python -pycryptodome -m3u8 -lxml -django==4.2.11 -djangorestframework==3.15.1 -django-cors-headers==4.3.1 \ No newline at end of file +unidecode \ No newline at end of file diff --git a/start_gui.sh b/start_gui.sh deleted file mode 100755 index e339262..0000000 --- a/start_gui.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# Installa i pacchetti Python -echo "Installazione dei pacchetti Python..." -pip install -r requirements.txt - -# Installa i pacchetti npm -echo "Installazione dei pacchetti npm..." -cd frontend -npm install -cd .. - -# Avvia il backend Django -echo "Avvio del backend Django..." -python3.11 api/manage.py runserver & - -# Avvia il frontend Vue.js con Vite -echo "Avvio del frontend Vue.js con Vite..." -cd frontend -npm run dev & - -# Attendi l'esecuzione dei processi -wait \ No newline at end of file From 2960b810cd9089978fa72a6cf0c9069f14fac784 Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Sat, 1 Jun 2024 14:20:50 +0200 Subject: [PATCH 03/13] Fix shorter video and small bar, remove ctrl+c. --- Src/Api/Animeunity/Core/Vix_player/player.py | 4 +- .../Core/Vix_player/player.py | 3 +- Src/Api/Streamingcommunity/costant.py | 5 +- Src/Lib/FFmpeg/capture.py | 4 + Src/Lib/FFmpeg/command.py | 94 ++++++++++++++----- Src/Lib/FFmpeg/util.py | 28 +++++- Src/Lib/Hls/downloader.py | 37 +++++--- Src/Lib/Hls/segments.py | 34 ++----- Src/Lib/M3U8/parser.py | 48 ++++++---- Src/Lib/Request/my_requests.py | 6 +- Src/Util/os.py | 17 +++- config.json | 5 +- run.py | 64 ++++++------- 13 files changed, 222 insertions(+), 127 deletions(-) diff --git a/Src/Api/Animeunity/Core/Vix_player/player.py b/Src/Api/Animeunity/Core/Vix_player/player.py index 9fad807..bcac59a 100644 --- a/Src/Api/Animeunity/Core/Vix_player/player.py +++ b/Src/Api/Animeunity/Core/Vix_player/player.py @@ -1,5 +1,6 @@ # 01.03.24 +import sys import logging from urllib.parse import urljoin, urlparse, parse_qs, urlencode, urlunparse @@ -11,6 +12,7 @@ from bs4 import BeautifulSoup # Internal utilities from Src.Util.headers import get_headers +from Src.Util.console import console from Src.Util._jsonConfig import config_manager @@ -204,4 +206,4 @@ class VideoSource: new_url = m._replace(query=new_query) # Replace the old query string with the new one final_url = urlunparse(new_url) # Construct the final URL from the modified parts - return final_url \ No newline at end of file + return final_url diff --git a/Src/Api/Streamingcommunity/Core/Vix_player/player.py b/Src/Api/Streamingcommunity/Core/Vix_player/player.py index 831e216..e72e7e0 100644 --- a/Src/Api/Streamingcommunity/Core/Vix_player/player.py +++ b/Src/Api/Streamingcommunity/Core/Vix_player/player.py @@ -202,7 +202,6 @@ class VideoSource: logging.error(f"Error getting content: {e}") raise - def get_playlist(self) -> str: """ Get playlist. @@ -240,4 +239,4 @@ class VideoSource: new_url = m._replace(query=new_query) # Replace the old query string with the new one final_url = urlunparse(new_url) # Construct the final URL from the modified parts - return final_url \ No newline at end of file + return final_url diff --git a/Src/Api/Streamingcommunity/costant.py b/Src/Api/Streamingcommunity/costant.py index e1e8653..8ac2f97 100644 --- a/Src/Api/Streamingcommunity/costant.py +++ b/Src/Api/Streamingcommunity/costant.py @@ -4,4 +4,7 @@ STREAMING_FOLDER = "streamingcommunity" MOVIE_FOLDER = "Movie" SERIES_FOLDER = "Serie" -SERVER_IP = ['162.19.231.20', '162.19.255.224', '162.19.254.232', '162.19.254.230', '51.195.107.230', '162.19.255.36', '162.19.228.128', '51.195.107.7', '162.19.253.242', '141.95.0.248', '57.129.4.77', '57.129.7.85'] \ No newline at end of file +SERVER_IP = ['162.19.255.224', '162.19.255.223', '162.19.254.244', '162.19.254.232', '162.19.254.230', + '162.19.253.242', '162.19.249.48', '162.19.245.142', '162.19.231.20', '162.19.229.177', + '162.19.228.128', '162.19.228.127', '162.19.228.105', '141.95.1.32', '141.95.1.196', + '141.95.1.102', '141.95.0.50', '141.95.0.248', '135.125.237.84', '135.125.233.236'] \ No newline at end of file diff --git a/Src/Lib/FFmpeg/capture.py b/Src/Lib/FFmpeg/capture.py index fe4ddbd..561820e 100644 --- a/Src/Lib/FFmpeg/capture.py +++ b/Src/Lib/FFmpeg/capture.py @@ -40,6 +40,10 @@ def capture_output(process: subprocess.Popen, description: str) -> None: logging.info(f"FFMPEG line: {line}") + # Capture only error + if "rror" in str(line): + console.log(f"[red]FFMPEG: {str(line).strip()}") + # Check if termination is requested if terminate_flag.is_set(): break diff --git a/Src/Lib/FFmpeg/command.py b/Src/Lib/FFmpeg/command.py index af2f57b..f3b85c1 100644 --- a/Src/Lib/FFmpeg/command.py +++ b/Src/Lib/FFmpeg/command.py @@ -19,14 +19,18 @@ except: pass from Src.Util._jsonConfig import config_manager from Src.Util.os import check_file_existence, suppress_output from Src.Util.console import console -from .util import has_audio_stream, need_to_force_to_ts, check_ffmpeg_input +from .util import has_audio_stream, need_to_force_to_ts, check_ffmpeg_input, check_duration_v_a from .capture import capture_ffmpeg_real_time +from ..M3U8.parser import M3U8_Codec # Config DEBUG_MODE = config_manager.get_bool("DEFAULT", "debug") DEBUG_FFMPEG = "debug" if DEBUG_MODE else "error" -USE_CODECS = config_manager.get_bool("M3U8_CONVERSION", "use_codec") +USE_CODEC = config_manager.get_bool("M3U8_CONVERSION", "use_codec") +USE_VCODEC = config_manager.get_bool("M3U8_CONVERSION", "use_vcodec") +USE_ACODEC = config_manager.get_bool("M3U8_CONVERSION", "use_acodec") +USE_BITRATE = config_manager.get_bool("M3U8_CONVERSION", "use_bitrate") USE_GPU = config_manager.get_bool("M3U8_CONVERSION", "use_gpu") FFMPEG_DEFAULT_PRESET = config_manager.get("M3U8_CONVERSION", "default_preset") CHECK_OUTPUT_CONVERSION = config_manager.get_bool("M3U8_CONVERSION", "check_output_after_ffmpeg") @@ -263,7 +267,7 @@ def __transcode_with_subtitles(video: str, subtitles_list: List[Dict[str, str]], # --> v 1.1 (new) -def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str = None, bitrate: str = None): +def join_video(video_path: str, out_path: str, codec: M3U8_Codec = None): """ Joins single ts video file to mp4 @@ -281,12 +285,12 @@ def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str = logging.error("Missing input video for ffmpeg conversion.") sys.exit(0) - # Start command ffmpeg_cmd = ['ffmpeg'] # Enabled the use of gpu - ffmpeg_cmd.extend(['-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda']) + if USE_GPU: + ffmpeg_cmd.extend(['-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda']) # Add mpegts to force to detect input file as ts file if need_to_force_to_ts(video_path): @@ -294,15 +298,30 @@ def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str = ffmpeg_cmd.extend(['-f', 'mpegts']) vcodec = "libx264" - # Insert input video path ffmpeg_cmd.extend(['-i', video_path]) # Add output args - if USE_CODECS: - if vcodec: ffmpeg_cmd.extend(['-c:v', vcodec]) - if acodec: ffmpeg_cmd.extend(['-c:a', acodec]) - if bitrate: ffmpeg_cmd.extend(['-b:a', str(bitrate)]) + if USE_CODEC: + if USE_VCODEC: + if codec.video_codec_name: + if not USE_GPU: + ffmpeg_cmd.extend(['-c:v', codec.video_codec_name]) + else: + ffmpeg_cmd.extend(['-c:v', 'h264_nvenc']) + else: + console.log("[red]Cant find vcodec for 'join_audios'") + + if USE_ACODEC: + if codec.audio_codec_name: + ffmpeg_cmd.extend(['-c:a', codec.audio_codec_name]) + else: + console.log("[red]Cant find acodec for 'join_audios'") + + if USE_BITRATE: + ffmpeg_cmd.extend(['-b:v', f'{codec.video_bitrate // 1000}k']) + ffmpeg_cmd.extend(['-b:a', f'{codec.audio_bitrate // 1000}k']) + else: ffmpeg_cmd.extend(['-c', 'copy']) @@ -312,12 +331,10 @@ def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str = else: ffmpeg_cmd.extend(['-preset', 'fast']) - # Overwrite ffmpeg_cmd += [out_path, "-y"] logging.info(f"FFmpeg command: {ffmpeg_cmd}") - # Run join if DEBUG_MODE: subprocess.run(ffmpeg_cmd, check=True) @@ -333,8 +350,6 @@ def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str = capture_ffmpeg_real_time(ffmpeg_cmd, "[cyan]Join video") print() - - # Check file output if CHECK_OUTPUT_CONVERSION: console.log("[red]Check output ffmpeg") @@ -347,7 +362,7 @@ def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str = sys.exit(0) -def join_audios(video_path: str, audio_tracks: List[Dict[str, str]], out_path: str): +def join_audios(video_path: str, audio_tracks: List[Dict[str, str]], out_path: str, codec: M3U8_Codec = None): """ Joins audio tracks with a video file using FFmpeg. @@ -362,9 +377,17 @@ def join_audios(video_path: str, audio_tracks: List[Dict[str, str]], out_path: s logging.error("Missing input video for ffmpeg conversion.") sys.exit(0) + video_audio_same_duration = check_duration_v_a(video_path, audio_tracks[0].get('path')) # Start command - ffmpeg_cmd = ['ffmpeg', '-i', video_path] + ffmpeg_cmd = ['ffmpeg'] + + # Enabled the use of gpu + if USE_GPU: + ffmpeg_cmd.extend(['-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda']) + + # Insert input video path + ffmpeg_cmd.extend(['-i', video_path]) # Add audio tracks as input for i, audio_track in enumerate(audio_tracks): @@ -373,7 +396,6 @@ def join_audios(video_path: str, audio_tracks: List[Dict[str, str]], out_path: s else: logging.error(f"Skip audio join: {audio_track.get('path')} dont exist") - # Map the video and audio streams ffmpeg_cmd.append('-map') ffmpeg_cmd.append('0:v') # Map video stream from the first input (video_path) @@ -382,18 +404,45 @@ def join_audios(video_path: str, audio_tracks: List[Dict[str, str]], out_path: s ffmpeg_cmd.append('-map') ffmpeg_cmd.append(f'{i}:a') # Map audio streams from subsequent inputs - # Add output args - if USE_CODECS: - ffmpeg_cmd.extend(['-c:v', 'copy', '-c:a', 'copy']) + if USE_CODEC: + if USE_VCODEC: + if codec.video_codec_name: + if not USE_GPU: + ffmpeg_cmd.extend(['-c:v', codec.video_codec_name]) + else: + ffmpeg_cmd.extend(['-c:v', 'h264_nvenc']) + else: + console.log("[red]Cant find vcodec for 'join_audios'") + + if USE_ACODEC: + if codec.audio_codec_name: + ffmpeg_cmd.extend(['-c:a', codec.audio_codec_name]) + else: + console.log("[red]Cant find acodec for 'join_audios'") + + if USE_BITRATE: + ffmpeg_cmd.extend(['-b:v', f'{codec.video_bitrate // 1000}k']) + ffmpeg_cmd.extend(['-b:a', f'{codec.audio_bitrate // 1000}k']) + else: ffmpeg_cmd.extend(['-c', 'copy']) + # Ultrafast preset always or fast for gpu + if not USE_GPU: + ffmpeg_cmd.extend(['-preset', FFMPEG_DEFAULT_PRESET]) + else: + ffmpeg_cmd.extend(['-preset', 'fast']) + + # Use shortest input path for video and audios + if not video_audio_same_duration: + console.log("[red]Use shortest input.") + ffmpeg_cmd.extend(['-shortest', '-strict', 'experimental']) + # Overwrite ffmpeg_cmd += [out_path, "-y"] logging.info(f"FFmpeg command: {ffmpeg_cmd}") - # Run join if DEBUG_MODE: subprocess.run(ffmpeg_cmd, check=True) @@ -409,7 +458,6 @@ def join_audios(video_path: str, audio_tracks: List[Dict[str, str]], out_path: s capture_ffmpeg_real_time(ffmpeg_cmd, "[cyan]Join audio") print() - # Check file output if CHECK_OUTPUT_CONVERSION: console.log("[red]Check output ffmpeg") @@ -456,7 +504,7 @@ def join_subtitle(video_path: str, subtitles_list: List[Dict[str, str]], out_pat ffmpeg_cmd += ["-metadata:s:s:{}".format(idx), "title={}".format(subtitle['name'])] # Add output args - if USE_CODECS: + if USE_CODEC: ffmpeg_cmd.extend(['-c:v', 'copy', '-c:a', 'copy', '-c:s', 'mov_text']) else: ffmpeg_cmd.extend(['-c', 'copy', '-c:s', 'mov_text']) diff --git a/Src/Lib/FFmpeg/util.py b/Src/Lib/FFmpeg/util.py index 4e03244..10ef22c 100644 --- a/Src/Lib/FFmpeg/util.py +++ b/Src/Lib/FFmpeg/util.py @@ -92,7 +92,7 @@ def format_duration(seconds: float) -> Tuple[int, int, int]: return int(hours), int(minutes), int(seconds) -def print_duration_table(file_path: str) -> None: +def print_duration_table(file_path: str, show = True) -> None: """ Print duration of a video file in hours, minutes, and seconds. @@ -104,7 +104,10 @@ def print_duration_table(file_path: str) -> None: if video_duration is not None: hours, minutes, seconds = format_duration(video_duration) - console.log(f"[cyan]Duration for [white]([green]{os.path.basename(file_path)}[white]): [yellow]{int(hours)}[red]h [yellow]{int(minutes)}[red]m [yellow]{int(seconds)}[red]s") + if show: + console.print(f"[cyan]Duration for [white]([green]{os.path.basename(file_path)}[white]): [yellow]{int(hours)}[red]h [yellow]{int(minutes)}[red]m [yellow]{int(seconds)}[red]s") + else: + return f"[yellow]{int(hours)}[red]h [yellow]{int(minutes)}[red]m [yellow]{int(seconds)}[red]s" def get_ffprobe_info(file_path): @@ -210,3 +213,24 @@ def check_ffmpeg_input(input_file): except Exception as e: logging.error(f"An unexpected error occurred: {e}") return False + +def check_duration_v_a(video_path, audio_path): + """ + Check if the duration of the video and audio matches. + + Args: + - video_path (str): Path to the video file. + - audio_path (str): Path to the audio file. + + Returns: + - bool: True if the duration of the video and audio matches, False otherwise. + """ + + # Ottieni la durata del video + video_duration = get_video_duration(video_path) + + # Ottieni la durata dell'audio + audio_duration = get_video_duration(audio_path) + + # Verifica se le durate corrispondono + return video_duration == audio_duration \ No newline at end of file diff --git a/Src/Lib/Hls/downloader.py b/Src/Lib/Hls/downloader.py index a3fea2c..9ef3ff3 100644 --- a/Src/Lib/Hls/downloader.py +++ b/Src/Lib/Hls/downloader.py @@ -178,7 +178,7 @@ class Downloader(): # Check if there is some audios, else disable download if self.list_available_audio != None: - console.log(f"[cyan]Find audios [white]=> [red]{[obj_audio.get('language') for obj_audio in self.list_available_audio]}") + console.print(f"[cyan]Find audios [white]=> [red]{[obj_audio.get('language') for obj_audio in self.list_available_audio]}") else: console.log("[red]Cant find a list of audios") @@ -191,7 +191,7 @@ class Downloader(): # Check if there is some subtitles, else disable download if self.list_available_subtitles != None: - console.log(f"[cyan]Find subtitles [white]=> [red]{[obj_sub.get('language') for obj_sub in self.list_available_subtitles]}") + console.print(f"[cyan]Find subtitles [white]=> [red]{[obj_sub.get('language') for obj_sub in self.list_available_subtitles]}") else: console.log("[red]Cant find a list of audios") @@ -208,7 +208,7 @@ class Downloader(): logging.info(f"M3U8 index select: {self.m3u8_index}, with resolution: {video_res}") # Get URI of the best quality and codecs parameters - console.log(f"[cyan]Find resolution [white]=> [red]{sorted(list_available_resolution, reverse=True)}") + console.print(f"[cyan]Find resolution [white]=> [red]{sorted(list_available_resolution, reverse=True)}") # Fix URL if it is not complete with http:\\site_name.domain\... if "http" not in self.m3u8_index: @@ -219,7 +219,7 @@ class Downloader(): # Check if a valid HTTPS URL is obtained if self.m3u8_index is not None and "https" in self.m3u8_index: - console.log(f"[cyan]Found m3u8 index [white]=> [red]{self.m3u8_index}") + console.print(f"[cyan]Found m3u8 index [white]=> [red]{self.m3u8_index}") else: logging.error("[download_m3u8] Can't find a valid m3u8 index") raise @@ -229,7 +229,8 @@ class Downloader(): logging.info(f"Find codec: {self.codec}") if self.codec is not None: - console.log(f"[cyan]Find codec [white]=> ([green]'v'[white]: [yellow]{self.codec.video_codec_name}[white], [green]'a'[white]: [yellow]{self.codec.audio_codec_name}[white], [green]'b'[white]: [yellow]{self.codec.bandwidth})") + console.print(f"[cyan]Find codec [white]=> ([green]'v'[white]: [yellow]{self.codec.video_codec_name}[white] ([green]b[white]: [yellow]{self.codec.video_bitrate // 1000}k[white]), [green]'a'[white]: [yellow]{self.codec.audio_codec_name}[white] ([green]b[white]: [yellow]{self.codec.audio_bitrate // 1000}k[white]))") + def __donwload_video__(self, server_ip: list = None): """ @@ -263,6 +264,9 @@ class Downloader(): # Download the video segments video_m3u8.download_streams(f"{Colors.MAGENTA}video") + # Get time of output file + print_duration_table(os.path.join(full_path_video, "0.ts")) + else: console.log("[cyan]Video [red]already exists.") @@ -309,6 +313,9 @@ class Downloader(): # Download the audio segments audio_m3u8.download_streams(f"{Colors.MAGENTA}audio {Colors.RED}{obj_audio.get('language')}") + # Get time of output file + print_duration_table(os.path.join(full_path_audio, "0.ts")) + else: console.log(f"[cyan]Audio [white]([green]{obj_audio.get('language')}[white]) [red]already exists.") @@ -373,14 +380,14 @@ class Downloader(): ) # Initiate the download of the subtitle content - console.log(f"[cyan]Downloading subtitle: [red]{sub_language.lower()}") + console.print(f"[cyan]Downloading subtitle: [red]{sub_language.lower()}") futures.append(executor.submit(self.__save_subtitle_content, m3u8_sub_parser.subtitle[-1], sub_full_path)) # Wait for all downloads to finish for future in futures: future.result() - def __join_video__(self, vcodec = 'copy') -> str: + def __join_video__(self) -> str: """ Join downloaded video segments into a single video file. @@ -397,10 +404,9 @@ class Downloader(): join_video( video_path = self.downloaded_video[0].get('path'), out_path = path_join_video, - vcodec = vcodec + codec = self.codec ) - print_duration_table(path_join_video) return path_join_video def __join_video_audio__(self) -> str: @@ -420,10 +426,10 @@ class Downloader(): join_audios( video_path = self.downloaded_video[0].get('path'), audio_tracks = self.downloaded_audio, - out_path = path_join_video_audio + out_path = path_join_video_audio, + codec = self.codec ) - print_duration_table(path_join_video_audio) return path_join_video_audio def __join_video_subtitles__(self, input_path: str) -> str: @@ -449,7 +455,6 @@ class Downloader(): path_join_video_subtitle ) - print_duration_table(path_join_video_subtitle) return path_join_video_subtitle def __clean__(self, out_path: str) -> None: @@ -473,7 +478,11 @@ class Downloader(): os.rename(out_path, self.output_filename) # Print size of the file - console.print(Panel(f"[bold green]Download completed![/bold green]\nFile size: [bold red]{format_size(os.path.getsize(self.output_filename))}[/bold red]", title=f"{os.path.basename(self.output_filename.replace('.mp4', ''))}", border_style="green")) + console.print(Panel( + f"[bold green]Download completed![/bold green]\n" + f"File size: [bold red]{format_size(os.path.getsize(self.output_filename))}[/bold red]\n" + f"Duration: [bold]{print_duration_table(self.output_filename, show=False)}[/bold]", + title=f"{os.path.basename(self.output_filename.replace('.mp4', ''))}", border_style="green")) # Delete all files except the output file delete_files_except_one(self.base_path, os.path.basename(self.output_filename)) @@ -535,7 +544,7 @@ class Downloader(): there_is_video: bool = (len(self.downloaded_video) > 0) there_is_audio: bool = (len(self.downloaded_audio) > 0) there_is_subtitle: bool = (len(self.downloaded_subtitle) > 0) - console.log(f"[cyan]Conversion [white]=> ([green]Audio: [yellow]{there_is_audio}[white], [green]Subtitle: [yellow]{there_is_subtitle}[white])") + console.print(f"[cyan]Conversion [white]=> ([green]Audio: [yellow]{there_is_audio}[white], [green]Subtitle: [yellow]{there_is_subtitle}[white])") # Join audio and video diff --git a/Src/Lib/Hls/segments.py b/Src/Lib/Hls/segments.py index beeb831..c52d82d 100644 --- a/Src/Lib/Hls/segments.py +++ b/Src/Lib/Hls/segments.py @@ -31,7 +31,6 @@ from ..M3U8 import ( M3U8_UrlFix ) - # Config TQDM_MAX_WORKER = config_manager.get_int('M3U8_DOWNLOAD', 'tdqm_workers') TQDM_USE_LARGE_BAR = config_manager.get_int('M3U8_DOWNLOAD', 'tqdm_use_large_bar') @@ -122,7 +121,7 @@ class M3U8_Segments: m3u8_parser = M3U8_Parser() m3u8_parser.parse_data(uri=self.url, raw_content=m3u8_content) # Parse the content of the M3U8 playlist - console.log(f"[cyan]There is key: [yellow]{m3u8_parser.keys is not None}") + console.print(f"[red]There is key: [yellow]{m3u8_parser.keys is not None}") # Check if there is an encryption key in the playlis if m3u8_parser.keys is not None: @@ -166,6 +165,7 @@ class M3U8_Segments: # Update segments for estimator self.class_ts_estimator.total_segments = len(self.segments) + logging.info(f"fSegmnets to donwload: [{len(self.segments)}]") def get_info(self) -> None: """ @@ -220,12 +220,13 @@ class M3U8_Segments: # Generate new user agent headers_segments['user-agent'] = get_headers() + logging.info(f"Make request to get segmenet: [{index} - {len(self.segments)}]") try: # Make request and calculate time duration start_time = time.time() - response = requests.get(ts_url, headers=headers_segments, verify_ssl=REQUEST_VERIFY_SSL) + response = requests.get(ts_url, headers=headers_segments, verify=REQUEST_VERIFY_SSL, timeout=30) duration = time.time() - start_time if response.ok: @@ -267,7 +268,7 @@ class M3U8_Segments: while not stop_event.is_set() or not self.segment_queue.empty(): with self.condition: while self.segment_queue.empty() and not stop_event.is_set(): - self.condition.wait(timeout=1) # Wait until a new segment is available or stop_event is set + self.condition.wait() # Wait until a new segment is available or stop_event is set if stop_event.is_set(): break @@ -311,16 +312,6 @@ class M3U8_Segments: mininterval=0.01 ) - def signal_handler(sig, frame): - self.ctrl_c_detected = True # Set global variable to indicate Ctrl+C detection - - stop_event.set() - with self.condition: - self.condition.notify_all() # Wake up the writer thread if it's waiting - - # Register the signal handler for Ctrl+C - signal.signal(signal.SIGINT, signal_handler) - with ThreadPoolExecutor(max_workers=TQDM_MAX_WORKER) as executor: # Start a separate thread to write segments to the file @@ -330,24 +321,13 @@ class M3U8_Segments: # Delay the start of each worker for index, segment_url in enumerate(self.segments): - # Check for Ctrl+C before starting each download task - time.sleep(0.03) - - if self.ctrl_c_detected: - console.log("[red]Ctrl+C detected. Stopping further downloads.") - - stop_event.set() - with self.condition: - self.condition.notify_all() # Wake up the writer thread if it's waiting - - break - # Submit the download task to the executor executor.submit(self.make_requests_stream, segment_url, index, stop_event, progress_bar) # Wait for all segments to be downloaded - executor.shutdown(wait=True) + executor.shutdown() stop_event.set() # Set the stop event to halt the writer thread with self.condition: self.condition.notify_all() # Wake up the writer thread if it's waiting writer_thread.join() # Wait for the writer thread to finish + diff --git a/Src/Lib/M3U8/parser.py b/Src/Lib/M3U8/parser.py index 2e3b647..9514dae 100644 --- a/Src/Lib/M3U8/parser.py +++ b/Src/Lib/M3U8/parser.py @@ -48,10 +48,6 @@ RESOLUTIONS = [ class M3U8_Codec: - """ - Represents codec information for an M3U8 playlist. - """ - def __init__(self, bandwidth, codecs): """ Initializes the M3U8Codec object with the provided parameters. @@ -64,20 +60,23 @@ class M3U8_Codec: self.codecs = codecs self.audio_codec = None self.video_codec = None + self.video_codec_name = None + self.audio_codec_name = None self.extract_codecs() self.parse_codecs() + self.calculate_bitrates() def extract_codecs(self): """ Parses the codecs information to extract audio and video codecs. Extracted codecs are set as attributes: audio_codec and video_codec. """ - - # Split the codecs string by comma try: + # Split the codecs string by comma codecs_list = self.codecs.split(',') except Exception as e: - logging.error(f"Cant split codec list: {self.codecs} with error {e}") + logging.error(f"Can't split codec list: {self.codecs} with error {e}") + return # Separate audio and video codecs for codec in codecs_list: @@ -87,7 +86,6 @@ class M3U8_Codec: self.audio_codec = codec def convert_video_codec(self, video_codec_identifier) -> str: - """ Convert video codec identifier to codec name. @@ -97,6 +95,9 @@ class M3U8_Codec: Returns: str: Codec name corresponding to the identifier. """ + if not video_codec_identifier: + logging.warning("No video codec identifier provided. Using default codec libx264.") + return "libx264" # Default # Extract codec type from the identifier codec_type = video_codec_identifier.split('.')[0] @@ -107,13 +108,11 @@ class M3U8_Codec: if codec_name: return codec_name - else: logging.warning(f"No corresponding video codec found for {video_codec_identifier}. Using default codec libx264.") - return "libx264" # Default - - def convert_audio_codec(self, audio_codec_identifier) -> str: + return "libx264" # Default + def convert_audio_codec(self, audio_codec_identifier) -> str: """ Convert audio codec identifier to codec name. @@ -123,6 +122,9 @@ class M3U8_Codec: Returns: str: Codec name corresponding to the identifier. """ + if not audio_codec_identifier: + logging.warning("No audio codec identifier provided. Using default codec aac.") + return "aac" # Default # Extract codec type from the identifier codec_type = audio_codec_identifier.split('.')[0] @@ -133,25 +135,33 @@ class M3U8_Codec: if codec_name: return codec_name - else: logging.warning(f"No corresponding audio codec found for {audio_codec_identifier}. Using default codec aac.") - return "aac" # Default - + return "aac" # Default + def parse_codecs(self): """ Parse video and audio codecs. This method updates `video_codec_name` and `audio_codec_name` attributes. """ - self.video_codec_name = self.convert_video_codec(self.video_codec) self.audio_codec_name = self.convert_audio_codec(self.audio_codec) - def __str__(self): + def calculate_bitrates(self): """ - Returns a string representation of the M3U8Codec object. + Calculate video and audio bitrates based on the available bandwidth. """ - return f"BANDWIDTH={self.bandwidth},RESOLUTION={self.resolution},CODECS=\"{self.codecs}\"" + if self.bandwidth: + + # Define the video and audio bitrates + video_bitrate = int(self.bandwidth * 0.8) # Using 80% of bandwidth for video + audio_bitrate = self.bandwidth - video_bitrate + + self.video_bitrate = video_bitrate + self.audio_bitrate = audio_bitrate + else: + logging.warning("No bandwidth provided. Bitrates cannot be calculated.") + class M3U8_Video: diff --git a/Src/Lib/Request/my_requests.py b/Src/Lib/Request/my_requests.py index 5c8c06c..45e774c 100644 --- a/Src/Lib/Request/my_requests.py +++ b/Src/Lib/Request/my_requests.py @@ -189,7 +189,7 @@ class ManageRequests: timeout: float = HTTP_TIMEOUT, retries: int = HTTP_RETRIES, params: Optional[Dict[str, str]] = None, - verify_ssl: bool = True, + verify: bool = True, auth: Optional[tuple] = None, proxy: Optional[str] = None, cookies: Optional[Dict[str, str]] = None, @@ -206,7 +206,7 @@ class ManageRequests: - timeout (float, optional): The request timeout. Defaults to HTTP_TIMEOUT. - retries (int, optional): The number of retries in case of request failure. Defaults to HTTP_RETRIES. - params (Optional[Dict[str, str]], optional): The query parameters for the request. Defaults to None. - - verify_ssl (bool, optional): Indicates whether SSL certificate verification should be performed. Defaults to True. + - verify (bool, optional): Indicates whether SSL certificate verification should be performed. Defaults to True. - auth (Optional[tuple], optional): Tuple containing the username and password for basic authentication. Defaults to None. - proxy (Optional[str], optional): The proxy URL. Defaults to None. - cookies (Optional[Dict[str, str]], optional): The cookies to be included in the request. Defaults to None. @@ -218,7 +218,7 @@ class ManageRequests: self.timeout = timeout self.retries = retries self.params = params - self.verify_ssl = verify_ssl + self.verify_ssl = verify self.auth = auth self.proxy = proxy self.cookies = cookies diff --git a/Src/Util/os.py b/Src/Util/os.py index f2ab1de..a9617f5 100644 --- a/Src/Util/os.py +++ b/Src/Util/os.py @@ -16,6 +16,7 @@ import platform import importlib import subprocess import contextlib +import urllib.request import importlib.metadata from typing import List @@ -403,6 +404,19 @@ def convert_to_hex(bytes_data: bytes) -> str: # --> OS GET SUMMARY +def check_internet(): + while True: + try: + # Attempt to open a connection to a website to check for internet connection + urllib.request.urlopen("http://www.google.com", timeout=1) + console.log("[bold green]Internet is available![/bold green]") + break + + except urllib.error.URLError: + console.log("[bold red]Internet is not available. Waiting...[/bold red]") + time.sleep(5) + print() + def get_executable_version(command): try: version_output = subprocess.check_output(command, stderr=subprocess.STDOUT).decode().split('\n')[0] @@ -419,7 +433,8 @@ def get_library_version(lib_name): return f"{lib_name}-not installed" def get_system_summary(): - + + check_internet() console.print("[bold blue]System Summary[/bold blue][white]:") # Python version and platform diff --git a/config.json b/config.json index 2603713..d769c1b 100644 --- a/config.json +++ b/config.json @@ -32,7 +32,10 @@ }, "M3U8_CONVERSION": { "use_codec": false, - "use_gpu": false, + "use_vcodec": true, + "use_acodec": true, + "use_bitrate": true, + "use_gpu": true, "default_preset": "ultrafast", "check_output_after_ffmpeg": false }, diff --git a/run.py b/run.py index 762982a..e99a551 100644 --- a/run.py +++ b/run.py @@ -27,34 +27,6 @@ from Src.Api.Altadefinizione import main_film as altadefinizione_film CLOSE_CONSOLE = config_manager.get_bool('DEFAULT', 'not_close') -def initialize(): - """ - Initialize the application. - Checks Python version, removes temporary folder, and displays start message. - """ - - # Set terminal size for win 7 - if platform.system() == "Windows" and "7" in platform.version(): - os.system('mode 120, 40') - - - # Check python version - if sys.version_info < (3, 7): - console.log("[red]Install python version > 3.7.16") - sys.exit(0) - - - # Removing temporary folder - start_message() - - - # Attempting GitHub update - """try: - git_update() - except Exception as e: - console.print(f"[blue]Req github [white]=> [red]Failed: {e}")""" - - def run_function(func: Callable[..., None], close_console: bool = False) -> None: """ Run a given function indefinitely or once, depending on the value of close_console. @@ -63,9 +35,6 @@ def run_function(func: Callable[..., None], close_console: bool = False) -> None func (Callable[..., None]): The function to run. close_console (bool, optional): Whether to close the console after running the function once. Defaults to False. """ - - initialize() - if close_console: while 1: func() @@ -73,11 +42,40 @@ def run_function(func: Callable[..., None], close_console: bool = False) -> None func() -def main(): - +def initialize(): + """ + Initialize the application. + Checks Python version, removes temporary folder, and displays start message. + """ + + start_message() + + # Create logger log_not = Logger() + + # Get system info get_system_summary() + # Set terminal size for win 7 + if platform.system() == "Windows" and "7" in platform.version(): + os.system('mode 120, 40') + + # Check python version + if sys.version_info < (3, 7): + console.log("[red]Install python version > 3.7.16") + sys.exit(0) + + # Attempting GitHub update + try: + git_update() + except Exception as e: + console.print(f"[blue]Req github [white]=> [red]Failed: {e}") + + +def main(): + + initialize() + # Parse command line arguments parser = argparse.ArgumentParser(description='Script to download film and series from the internet.') parser.add_argument('-sa', '--streaming_anime', action='store_true', help='Check into anime category') From 8538a17b9767f27dce2598e919937fe4a1d28848 Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Sat, 1 Jun 2024 17:43:50 +0200 Subject: [PATCH 04/13] Add function get server ip. --- Src/Lib/Hls/segments.py | 2 +- Test/t_get_server_ip_sc.py | 85 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 Test/t_get_server_ip_sc.py diff --git a/Src/Lib/Hls/segments.py b/Src/Lib/Hls/segments.py index c52d82d..e7f2179 100644 --- a/Src/Lib/Hls/segments.py +++ b/Src/Lib/Hls/segments.py @@ -220,7 +220,6 @@ class M3U8_Segments: # Generate new user agent headers_segments['user-agent'] = get_headers() - logging.info(f"Make request to get segmenet: [{index} - {len(self.segments)}]") try: @@ -228,6 +227,7 @@ class M3U8_Segments: start_time = time.time() response = requests.get(ts_url, headers=headers_segments, verify=REQUEST_VERIFY_SSL, timeout=30) duration = time.time() - start_time + logging.info(f"Make request to get segmenet: [{index} - {len(self.segments)}] in: {duration}, len data: {len(response.content)}") if response.ok: diff --git a/Test/t_get_server_ip_sc.py b/Test/t_get_server_ip_sc.py new file mode 100644 index 0000000..02bebe8 --- /dev/null +++ b/Test/t_get_server_ip_sc.py @@ -0,0 +1,85 @@ +# 13.05.24 + +import socket +import logging +import urllib3 +from urllib.parse import urlparse, urlunparse + + +import warnings +warnings.filterwarnings("ignore", category=urllib3.exceptions.InsecureRequestWarning) + + +# Variable +url_test = "https://sc-b1-18.scws-content.net/hls/170/3/25/32503b5b-4646-4376-ad47-7766c65be7e2/audio/ita/0004-0100.ts" + + +def get_ip_from_url(url): + """ + Extracts the IP address from a given URL. + + Args: + url (str): The URL from which to extract the IP address. + + Returns: + str or None: The extracted IP address if successful, otherwise None. + """ + try: + parsed_url = urlparse(url) + if not parsed_url.hostname: + logging.error(f"Invalid URL: {url}") + return None + + ip_address = socket.gethostbyname(parsed_url.hostname) + return ip_address + + except Exception as e: + logging.error(f"Error: {e}") + return None + +def replace_random_number(url, random_number): + """ + Replaces a random number in the URL. + + Args: + url (str): The URL in which to replace the random number. + random_number (int): The random number to replace in the URL. + + Returns: + str: The modified URL with the random number replaced. + """ + parsed_url = urlparse(url) + parts = parsed_url.netloc.split('.') + prefix = None + + for i, part in enumerate(parts): + if '-' in part and part.startswith("sc-"): + prefix = part.split('-')[0] + '-' + part.split('-')[1] + '-' + new_part = prefix + f"{random_number:02d}" + parts[i] = new_part + break + + new_netloc = '.'.join(parts) + return urlunparse((parsed_url.scheme, new_netloc, parsed_url.path, parsed_url.params, parsed_url.query, parsed_url.fragment)) + +def main(): + """ + Main function to test the URL manipulation. + """ + valid_ip = [] + + for i in range(1, 36): + try: + ip = get_ip_from_url(replace_random_number(url_test, i)) + + if ip: + valid_ip.append(ip) + + except Exception as e: + logging.error(f"Error: {e}") + pass + + print(f"Valid IP addresses: {sorted(valid_ip, reverse=True)}") + +if __name__ == '__main__': + main() From 32b876a08cb9f4642932cdd2a68272c53b1c20a4 Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Sun, 2 Jun 2024 08:21:34 +0200 Subject: [PATCH 05/13] Add force 1080p. --- Src/Api/Animeunity/Core/Vix_player/player.py | 45 ++++++++++++++++++- .../Core/Vix_player/player.py | 45 ++++++++++++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/Src/Api/Animeunity/Core/Vix_player/player.py b/Src/Api/Animeunity/Core/Vix_player/player.py index bcac59a..30b30d0 100644 --- a/Src/Api/Animeunity/Core/Vix_player/player.py +++ b/Src/Api/Animeunity/Core/Vix_player/player.py @@ -206,4 +206,47 @@ class VideoSource: new_url = m._replace(query=new_query) # Replace the old query string with the new one final_url = urlunparse(new_url) # Construct the final URL from the modified parts - return final_url + if "canPlayFHD" in current_params and self.window_video.quality == "1080": + return final_url + else: + console.log("[red]Rebuild master playlist.") + return self.re_build_master() + + def re_build_master(self) -> str: + """ + Rebuild the master playlist. + + Returns: + str: The rebuilt master playlist text, or an empty string if there's an error. + """ + try: + index_resolution = None + master_url = f'https://vixcloud.co/playlist/{self.window_video.id}' + index_url = f'https://vixcloud.co/playlist/{self.window_video.id}?type=video&rendition={self.window_video.quality}p' + + try: + # Fetch the master playlist text + master_text = requests.get(master_url).text + except requests.RequestException as e: + logging.error(f"Error fetching master playlist from URL: {master_url}, error: {e}") + return "" + + # Find the resolution in the index URL + for resolution in [(7680, 4320), (3840, 2160), (2560, 1440), (1920, 1080), (1280, 720), (640, 480)]: + if str(resolution[1]) in index_url: + index_resolution = resolution + break + + # Add resolution and index URL to the master playlist text + if index_resolution: + master_text += f'\n#EXT-X-STREAM-INF:BANDWIDTH=2150000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION={index_resolution[0]}x{index_resolution[1]},SUBTITLES="subs"\n' + master_text += index_url + + else: + logging.warning(f"No matching resolution found in index URL: {index_url}") + + return master_text + + except Exception as e: + logging.error(f"Unexpected error in re_build_master: {e}") + sys.exit(0) diff --git a/Src/Api/Streamingcommunity/Core/Vix_player/player.py b/Src/Api/Streamingcommunity/Core/Vix_player/player.py index e72e7e0..545944c 100644 --- a/Src/Api/Streamingcommunity/Core/Vix_player/player.py +++ b/Src/Api/Streamingcommunity/Core/Vix_player/player.py @@ -239,4 +239,47 @@ class VideoSource: new_url = m._replace(query=new_query) # Replace the old query string with the new one final_url = urlunparse(new_url) # Construct the final URL from the modified parts - return final_url + if "canPlayFHD" in current_params and self.window_video.quality == "1080": + return final_url + else: + console.log("[red]Rebuild master playlist.") + return self.re_build_master() + + def re_build_master(self) -> str: + """ + Rebuild the master playlist. + + Returns: + str: The rebuilt master playlist text, or an empty string if there's an error. + """ + try: + index_resolution = None + master_url = f'https://vixcloud.co/playlist/{self.window_video.id}' + index_url = f'https://vixcloud.co/playlist/{self.window_video.id}?type=video&rendition={self.window_video.quality}p' + + try: + # Fetch the master playlist text + master_text = requests.get(master_url).text + except requests.RequestException as e: + logging.error(f"Error fetching master playlist from URL: {master_url}, error: {e}") + return "" + + # Find the resolution in the index URL + for resolution in [(7680, 4320), (3840, 2160), (2560, 1440), (1920, 1080), (1280, 720), (640, 480)]: + if str(resolution[1]) in index_url: + index_resolution = resolution + break + + # Add resolution and index URL to the master playlist text + if index_resolution: + master_text += f'\n#EXT-X-STREAM-INF:BANDWIDTH=2150000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION={index_resolution[0]}x{index_resolution[1]},SUBTITLES="subs"\n' + master_text += index_url + + else: + logging.warning(f"No matching resolution found in index URL: {index_url}") + + return master_text + + except Exception as e: + logging.error(f"Unexpected error in re_build_master: {e}") + sys.exit(0) From 640fb87e91eb0491b2012feb3e5c9aa233646ddd Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Sun, 2 Jun 2024 09:35:36 +0200 Subject: [PATCH 06/13] Fix double logger. --- Src/Lib/Hls/segments.py | 2 +- Src/Util/logger.py | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Src/Lib/Hls/segments.py b/Src/Lib/Hls/segments.py index e7f2179..dc73d70 100644 --- a/Src/Lib/Hls/segments.py +++ b/Src/Lib/Hls/segments.py @@ -165,7 +165,7 @@ class M3U8_Segments: # Update segments for estimator self.class_ts_estimator.total_segments = len(self.segments) - logging.info(f"fSegmnets to donwload: [{len(self.segments)}]") + logging.info(f"Segmnets to donwload: [{len(self.segments)}]") def get_info(self) -> None: """ diff --git a/Src/Util/logger.py b/Src/Util/logger.py index 216c314..0aac96b 100644 --- a/Src/Util/logger.py +++ b/Src/Util/logger.py @@ -53,7 +53,3 @@ class Logger: formatter = logging.Formatter('[%(filename)s:%(lineno)s - %(funcName)20s() ] %(asctime)s - %(levelname)s - %(message)s') file_handler.setFormatter(formatter) logging.getLogger('').addHandler(file_handler) - - -# Output -logger = Logger() \ No newline at end of file From 4677deea148b8a369e0ac5b2cd1a3d48651d2b31 Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Sun, 2 Jun 2024 10:36:56 +0200 Subject: [PATCH 07/13] Finalmente fix per file con duratta errata. --- Src/Api/Streamingcommunity/costant.py | 8 +- Src/Lib/Hls/segments.py | 26 +- Src/Lib/M3U8/decryption.py | 13 +- Src/Lib/M3U8/parser.py | 23 + Src/Lib/Request/my_requests.py | 4 +- Src/Upload/update.py | 1 - Src/Util/os.py | 2 +- Test/data/TLD/creation.py | 4 +- Test/data/m3u8/index_audio.m3u8 | 663 +++++++++++++++++++++++++- Test/data/m3u8/index_video.m3u8 | 663 +++++++++++++++++++++++++- Test/data/m3u8/playlist.m3u8 | 17 +- Test/data/playlist_info.json | 10 - Test/t_m3u8_parser.py | 22 +- config.json | 1 - requirements.txt | 1 + 15 files changed, 1383 insertions(+), 75 deletions(-) delete mode 100644 Test/data/playlist_info.json diff --git a/Src/Api/Streamingcommunity/costant.py b/Src/Api/Streamingcommunity/costant.py index 8ac2f97..2ebb247 100644 --- a/Src/Api/Streamingcommunity/costant.py +++ b/Src/Api/Streamingcommunity/costant.py @@ -4,7 +4,7 @@ STREAMING_FOLDER = "streamingcommunity" MOVIE_FOLDER = "Movie" SERIES_FOLDER = "Serie" -SERVER_IP = ['162.19.255.224', '162.19.255.223', '162.19.254.244', '162.19.254.232', '162.19.254.230', - '162.19.253.242', '162.19.249.48', '162.19.245.142', '162.19.231.20', '162.19.229.177', - '162.19.228.128', '162.19.228.127', '162.19.228.105', '141.95.1.32', '141.95.1.196', - '141.95.1.102', '141.95.0.50', '141.95.0.248', '135.125.237.84', '135.125.233.236'] \ No newline at end of file +SERVER_IP = ['57.129.7.85', '57.129.7.188', '57.129.7.174', '57.129.4.77', '57.129.16.196', '57.129.16.156', '57.129.16.139', '57.129.16.135', '57.129.13.175', + '57.129.13.157', '51.38.112.237', '51.195.107.7', '51.195.107.230', '162.19.255.78', '162.19.255.36', '162.19.255.224', '162.19.255.223', '162.19.254.244', + '162.19.254.232', '162.19.254.230', '162.19.253.242', '162.19.249.48', '162.19.245.142', '162.19.231.20', '162.19.229.177', '162.19.228.128', '162.19.228.127', + '162.19.228.105', '141.95.1.32', '141.95.1.196', '141.95.1.102', '141.95.0.50', '141.95.0.248', '135.125.237.84', '135.125.233.236'] \ No newline at end of file diff --git a/Src/Lib/Hls/segments.py b/Src/Lib/Hls/segments.py index dc73d70..b03db71 100644 --- a/Src/Lib/Hls/segments.py +++ b/Src/Lib/Hls/segments.py @@ -35,7 +35,6 @@ from ..M3U8 import ( TQDM_MAX_WORKER = config_manager.get_int('M3U8_DOWNLOAD', 'tdqm_workers') TQDM_USE_LARGE_BAR = config_manager.get_int('M3U8_DOWNLOAD', 'tqdm_use_large_bar') REQUEST_VERIFY_SSL = config_manager.get_bool('REQUESTS', 'verify_ssl') -REQUEST_DISABLE_ERROR = config_manager.get_bool('REQUESTS', 'disable_error') # Variable @@ -96,8 +95,6 @@ class M3U8_Segments: logging.info(f"Uri key: {key_uri}") try: - - # Send HTTP GET request to fetch the key response = requests.get(key_uri, headers=headers_index) response.raise_for_status() @@ -119,9 +116,10 @@ class M3U8_Segments: - m3u8_content (str): The content of the M3U8 file. """ m3u8_parser = M3U8_Parser() - m3u8_parser.parse_data(uri=self.url, raw_content=m3u8_content) # Parse the content of the M3U8 playlist + m3u8_parser.parse_data(uri=self.url, raw_content=m3u8_content) - console.print(f"[red]There is key: [yellow]{m3u8_parser.keys is not None}") + console.log(f"[red]Expected duration after download: {m3u8_parser.get_duration()}") + console.log(f"[red]There is key: [yellow]{m3u8_parser.keys is not None}") # Check if there is an encryption key in the playlis if m3u8_parser.keys is not None: @@ -246,12 +244,10 @@ class M3U8_Segments: self.condition.notify() # Notify the writer thread that a new segment is available else: - if not REQUEST_DISABLE_ERROR: - logging.error(f"Failed to download segment: {ts_url}") + logging.error(f"Failed to download segment: {ts_url}") except Exception as e: - if not REQUEST_DISABLE_ERROR: - logging.error(f"Exception while downloading segment: {e}") + logging.error(f"Exception while downloading segment: {e}") # Update bar progress_bar.update(1) @@ -265,16 +261,15 @@ class M3U8_Segments: """ with open(self.tmp_file_path, 'ab') as f: - while not stop_event.is_set() or not self.segment_queue.empty(): + while not (stop_event.is_set() and self.segment_queue.empty()): # Wait until both stop_event is set and queue is empty with self.condition: while self.segment_queue.empty() and not stop_event.is_set(): - self.condition.wait() # Wait until a new segment is available or stop_event is set + self.condition.wait() # Wait until a new segment is available or stop_event is set - if stop_event.is_set(): + if stop_event.is_set() and self.segment_queue.empty(): # Exit loop if both conditions are met break if not self.segment_queue.empty(): - # Get the segment from the queue index, segment_content = self.segment_queue.get() @@ -283,10 +278,9 @@ class M3U8_Segments: f.write(segment_content) self.current_index += 1 self.segment_queue.task_done() - else: self.segment_queue.put((index, segment_content)) # Requeue the segment if it is not the next to be written - self.condition.notify() # Notify that a segment has been requeued + self.condition.notify() def download_streams(self, add_desc): """ @@ -298,7 +292,7 @@ class M3U8_Segments: stop_event = threading.Event() # Event to signal stopping if TQDM_USE_LARGE_BAR: - bar_format=f"{Colors.YELLOW}Downloading {Colors.WHITE}({add_desc}{Colors.WHITE}): {Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]" + bar_format=f"{Colors.YELLOW}Downloading {Colors.WHITE}({add_desc}{Colors.WHITE}): {Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.WHITE}| {Colors.YELLOW}{{n_fmt}}{Colors.WHITE} / {Colors.RED}{{total_fmt}} {Colors.WHITE}| {Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]" else: bar_format=f"{Colors.YELLOW}Proc{Colors.WHITE}: {Colors.RED}{{percentage:.2f}}% {Colors.WHITE}| {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]" diff --git a/Src/Lib/M3U8/decryption.py b/Src/Lib/M3U8/decryption.py index b02946c..48aef02 100644 --- a/Src/Lib/M3U8/decryption.py +++ b/Src/Lib/M3U8/decryption.py @@ -111,17 +111,16 @@ else: """ if self.method == "AES": openssl_cmd = f'openssl enc -d -aes-256-ecb -K {self.key.hex()} -nosalt' - decrypted_data = subprocess.check_output(openssl_cmd.split(), input=ciphertext) - elif self.method == "AES-128": openssl_cmd = f'openssl enc -d -aes-128-cbc -K {self.key[:16].hex()} -iv {self.iv.hex()}' - decrypted_data = subprocess.check_output(openssl_cmd.split(), input=ciphertext) - elif self.method == "AES-128-CTR": openssl_cmd = f'openssl enc -d -aes-128-ctr -K {self.key[:16].hex()} -iv {self.iv.hex()}' - decrypted_data = subprocess.check_output(openssl_cmd.split(), input=ciphertext) - else: raise ValueError("Invalid or unsupported method") - return decrypted_data + try: + decrypted_data = subprocess.check_output(openssl_cmd.split(), input=ciphertext, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + raise ValueError(f"Decryption failed: {e.output.decode()}") + + return decrypted_data \ No newline at end of file diff --git a/Src/Lib/M3U8/parser.py b/Src/Lib/M3U8/parser.py index 9514dae..a29a82f 100644 --- a/Src/Lib/M3U8/parser.py +++ b/Src/Lib/M3U8/parser.py @@ -404,6 +404,7 @@ class M3U8_Parser: self._video: M3U8_Video = None self._audio: M3U8_Audio = None self._subtitle: M3U8_Subtitle = None + self.duration: float = 0 self.__create_variable__() @@ -557,6 +558,10 @@ class M3U8_Parser: try: for segment in m3u8_obj.segments: + + # Collect all index duration + self.duration += segment.duration + if "vtt" not in segment.uri: self.segments.append(segment.uri) else: @@ -573,3 +578,21 @@ class M3U8_Parser: self._video = M3U8_Video(self.video_playlist) self._audio = M3U8_Audio(self.audio_playlist) self._subtitle = M3U8_Subtitle(self.subtitle_playlist) + + def get_duration(self): + """ + Convert duration from seconds to hours, minutes, and remaining seconds. + + Parameters: + - seconds (float): Duration in seconds. + + Returns: + - formatted_duration (str): Formatted duration string with hours, minutes, and seconds. + """ + # Calculate hours, minutes, and remaining seconds + hours = int(self.duration / 3600) + minutes = int((self.duration % 3600) / 60) + remaining_seconds = int(self.duration % 60) + + # Format the duration string with colors + return f"[yellow]{int(hours)}[red]h [yellow]{int(minutes)}[red]m [yellow]{int(remaining_seconds)}[red]s" diff --git a/Src/Lib/Request/my_requests.py b/Src/Lib/Request/my_requests.py index 45e774c..405d892 100644 --- a/Src/Lib/Request/my_requests.py +++ b/Src/Lib/Request/my_requests.py @@ -39,7 +39,6 @@ from Src.Util._jsonConfig import config_manager HTTP_TIMEOUT = config_manager.get_int('REQUESTS', 'timeout') HTTP_RETRIES = config_manager.get_int('REQUESTS', 'max_retry') HTTP_DELAY = 1 -HTTP_DISABLE_ERROR = config_manager.get_bool('REQUESTS', 'disable_error') @@ -379,8 +378,7 @@ class ManageRequests: """ Handle request error. """ - if not HTTP_DISABLE_ERROR: - logging.error(f"Request failed for URL '{self.url}': {parse_http_error(str(e))}") + logging.error(f"Request failed for URL '{self.url}': {parse_http_error(str(e))}") if self.attempt < self.retries: logging.error(f"Retry request for URL '{self.url}' (attempt {self.attempt}/{self.retries})") diff --git a/Src/Upload/update.py b/Src/Upload/update.py index 82d7402..7c6e4fa 100644 --- a/Src/Upload/update.py +++ b/Src/Upload/update.py @@ -62,5 +62,4 @@ def update(): console.print(f"[red]{repo_name} has been downloaded [yellow]{total_download_count} [red]times, but only [yellow]{percentual_stars}% [red]of users have starred it.\n\ [cyan]Help the repository grow today by leaving a [yellow]star [cyan]and [yellow]sharing [cyan]it with others online!") - time.sleep(1) console.print("\n") diff --git a/Src/Util/os.py b/Src/Util/os.py index a9617f5..bc905a2 100644 --- a/Src/Util/os.py +++ b/Src/Util/os.py @@ -457,7 +457,7 @@ def get_system_summary(): logging.info(f"Exe versions: ffmpeg {ffmpeg_version}, ffprobe {ffprobe_version}") # Optional libraries versions - optional_libraries = ['bs4', 'certifi', 'tqdm', 'rich', 'unidecode'] + optional_libraries = [line.strip() for line in open('requirements.txt', 'r', encoding='utf-8-sig')] optional_libs_versions = [get_library_version(lib) for lib in optional_libraries] console.print(f"[cyan]Libraries[white]: [bold red]{', '.join(optional_libs_versions)}[/bold red]\n") diff --git a/Test/data/TLD/creation.py b/Test/data/TLD/creation.py index 2116efa..d60341f 100644 --- a/Test/data/TLD/creation.py +++ b/Test/data/TLD/creation.py @@ -5,9 +5,6 @@ import json from bs4 import BeautifulSoup -# https://onshopify.com/domains/ - - # URL of the webpage containing the table url = 'https://icannwiki.org/New_gTLD_Generic_Applications' @@ -84,5 +81,6 @@ def main(): with open('data.json', 'w') as json_file: json.dump(data, json_file) + if __name__ == '__main__': main() \ No newline at end of file diff --git a/Test/data/m3u8/index_audio.m3u8 b/Test/data/m3u8/index_audio.m3u8 index 0928d49..d59ac13 100644 --- a/Test/data/m3u8/index_audio.m3u8 +++ b/Test/data/m3u8/index_audio.m3u8 @@ -4,10 +4,667 @@ #EXT-X-PLAYLIST-TYPE:VOD #EXT-X-KEY:METHOD=AES-128,URI="/storage/enc.key",IV=0x43A6D967D5C17290D98322F5C8F6660B #EXTINF:4.010667, -https://sc-u10-01.scws-content.net/hls/40/6/58/6585b748-cef6-4048-a9ab-c01b9366c3b9/audio/ita/0000-0100.ts +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0000-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 #EXTINF:3.989333, -https://sc-u10-01.scws-content.net/hls/40/6/58/6585b748-cef6-4048-a9ab-c01b9366c3b9/audio/ita/0001-0100.ts +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0001-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 #EXTINF:4.010667, -https://sc-u10-01.scws-content.net/hls/40/6/58/6585b748-cef6-4048-a9ab-c01b9366c3b9/audio/ita/0002-0075.ts +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0002-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 #EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0003-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0004-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0005-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0006-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0007-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0008-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0009-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0010-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0011-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0012-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0013-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0014-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0015-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0016-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0017-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0018-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0019-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0020-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0021-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0022-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0023-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0024-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0025-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0026-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0027-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0028-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0029-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0030-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0031-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0032-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0033-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0034-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0035-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0036-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0037-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0038-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0039-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0040-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0041-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0042-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0043-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0044-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0045-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0046-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0047-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0048-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0049-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0050-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0051-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0052-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0053-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0054-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0055-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0056-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0057-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0058-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0059-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0060-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0061-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0062-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0063-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0064-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0065-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0066-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0067-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0068-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0069-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0070-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0071-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0072-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0073-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0074-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0075-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0076-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0077-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0078-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0079-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0080-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0081-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0082-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0083-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0084-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0085-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0086-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0087-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0088-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0089-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0090-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0091-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0092-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0093-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0094-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0095-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0096-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0097-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0098-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0099-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0100-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0101-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0102-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0103-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0104-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0105-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0106-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0107-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0108-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0109-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0110-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0111-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0112-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0113-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0114-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0115-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0116-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0117-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0118-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0119-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0120-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0121-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0122-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0123-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0124-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0125-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0126-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0127-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0128-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0129-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0130-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0131-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0132-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0133-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0134-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0135-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0136-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0137-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0138-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0139-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0140-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0141-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0142-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0143-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0144-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0145-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0146-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0147-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0148-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0149-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0150-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0151-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0152-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0153-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0154-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0155-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0156-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0157-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0158-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0159-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0160-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0161-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0162-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0163-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0164-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0165-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0166-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0167-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0168-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0169-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0170-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0171-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0172-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0173-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0174-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0175-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0176-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0177-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0178-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0179-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0180-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0181-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0182-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0183-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0184-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0185-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0186-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0187-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0188-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0189-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0190-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0191-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0192-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0193-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0194-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0195-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0196-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0197-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0198-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0199-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0200-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0201-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0202-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0203-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0204-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0205-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0206-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0207-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0208-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0209-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0210-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0211-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0212-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0213-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0214-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0215-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0216-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0217-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0218-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0219-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0220-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0221-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0222-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0223-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0224-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0225-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0226-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0227-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0228-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0229-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0230-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0231-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0232-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0233-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0234-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0235-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0236-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0237-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0238-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0239-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0240-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0241-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0242-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0243-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0244-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0245-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0246-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0247-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0248-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0249-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0250-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0251-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0252-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0253-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0254-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0255-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0256-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0257-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0258-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0259-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0260-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0261-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0262-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0263-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0264-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0265-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0266-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0267-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0268-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0269-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0270-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0271-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0272-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0273-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0274-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0275-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0276-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0277-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0278-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0279-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0280-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0281-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0282-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0283-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0284-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0285-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0286-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0287-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0288-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0289-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0290-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0291-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0292-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0293-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0294-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0295-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0296-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0297-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0298-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0299-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0300-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0301-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0302-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0303-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0304-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0305-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0306-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0307-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0308-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0309-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0310-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0311-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0312-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0313-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0314-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0315-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0316-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0317-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0318-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0319-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0320-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0321-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0322-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0323-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0324-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0325-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0326-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0327-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0328-0100.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:3.989333, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0329-0075.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:4.010667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0330-0025.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 +#EXTINF:0.266667, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/audio/ita/0331-0025.ts?token=r1bvf1Wwun-McFrLkW1jyQ&expires=1722499729 #EXT-X-ENDLIST \ No newline at end of file diff --git a/Test/data/m3u8/index_video.m3u8 b/Test/data/m3u8/index_video.m3u8 index 49b39ec..4274422 100644 --- a/Test/data/m3u8/index_video.m3u8 +++ b/Test/data/m3u8/index_video.m3u8 @@ -4,10 +4,667 @@ #EXT-X-PLAYLIST-TYPE:VOD #EXT-X-KEY:METHOD=AES-128,URI="/storage/enc.key",IV=0x43A6D967D5C17290D98322F5C8F6660B #EXTINF:4, -https://sc-u10-01.scws-content.net/hls/40/6/58/6585b748-cef6-4048-a9ab-c01b9366c3b9/video/720p/0000-0250.ts +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0000-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 #EXTINF:4, -https://sc-u10-01.scws-content.net/hls/40/6/58/6585b748-cef6-4048-a9ab-c01b9366c3b9/video/720p/0001-0250.ts +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0001-0250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 #EXTINF:4, -https://sc-u10-01.scws-content.net/hls/40/6/58/6585b748-cef6-4048-a9ab-c01b9366c3b9/video/720p/0002-0075.ts +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0002-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 #EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0003-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0004-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0005-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0006-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0007-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0008-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0009-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0010-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0011-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0012-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0013-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0014-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0015-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0016-1750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0017-2000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0018-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0019-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0020-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0021-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0022-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0023-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0024-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0025-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0026-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0027-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0028-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0029-2000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0030-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0031-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0032-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0033-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0034-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0035-3000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0036-2000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0037-2000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0038-2000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0039-2000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0040-2500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0041-1750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0042-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0043-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0044-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0045-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0046-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0047-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0048-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0049-1750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0050-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0051-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0052-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0053-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0054-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0055-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0056-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0057-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0058-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0059-0250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0060-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0061-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0062-2500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0063-2000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0064-2500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0065-2000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0066-1750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0067-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0068-1750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0069-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0070-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0071-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0072-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0073-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0074-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0075-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0076-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0077-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0078-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0079-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0080-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0081-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0082-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0083-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0084-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0085-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0086-1750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0087-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0088-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0089-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0090-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0091-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0092-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0093-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0094-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0095-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0096-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0097-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0098-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0099-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0100-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0101-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0102-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0103-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0104-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0105-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0106-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0107-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0108-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0109-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0110-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0111-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0112-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0113-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0114-2000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0115-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0116-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0117-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0118-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0119-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0120-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0121-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0122-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0123-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0124-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0125-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0126-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0127-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0128-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0129-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0130-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0131-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0132-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0133-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0134-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0135-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0136-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0137-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0138-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0139-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0140-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0141-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0142-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0143-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0144-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0145-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0146-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0147-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0148-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0149-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0150-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0151-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0152-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0153-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0154-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0155-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0156-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0157-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0158-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0159-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0160-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0161-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0162-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0163-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0164-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0165-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0166-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0167-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0168-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0169-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0170-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0171-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0172-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0173-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0174-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0175-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0176-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0177-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0178-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0179-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0180-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0181-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0182-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0183-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0184-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0185-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0186-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0187-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0188-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0189-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0190-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0191-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0192-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0193-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0194-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0195-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0196-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0197-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0198-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0199-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0200-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0201-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0202-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0203-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0204-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0205-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0206-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0207-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0208-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0209-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0210-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0211-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0212-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0213-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0214-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0215-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0216-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0217-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0218-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0219-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0220-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0221-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0222-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0223-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0224-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0225-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0226-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0227-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0228-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0229-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0230-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0231-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0232-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0233-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0234-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0235-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0236-1750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0237-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0238-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0239-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0240-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0241-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0242-1750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0243-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0244-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0245-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0246-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0247-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0248-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0249-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0250-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0251-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0252-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0253-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0254-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0255-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0256-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0257-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0258-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0259-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0260-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0261-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0262-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0263-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0264-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0265-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0266-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0267-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0268-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0269-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0270-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0271-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0272-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0273-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0274-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0275-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0276-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0277-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0278-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0279-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0280-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0281-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0282-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0283-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0284-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0285-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0286-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0287-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0288-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0289-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0290-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0291-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0292-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0293-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0294-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0295-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0296-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0297-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0298-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0299-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0300-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0301-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0302-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0303-1750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0304-1500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0305-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0306-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0307-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0308-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0309-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0310-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0311-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0312-1750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0313-0750.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0314-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0315-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0316-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0317-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0318-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0319-1000.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0320-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0321-1250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0322-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0323-0075.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0324-0125.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0325-0250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0326-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0327-0500.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0328-0250.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0329-0100.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:4, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0330-0100.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 +#EXTINF:0.25, +https://sc-u2-01.scws-content.net/hls/190/4/13/4130abf2-c2e7-4b66-8907-f11b4ee38a27/video/1080p/0331-0050.ts?token=Yce8pl2-m8bk6uQvq7W0fg&expires=1722499729 #EXT-X-ENDLIST \ No newline at end of file diff --git a/Test/data/m3u8/playlist.m3u8 b/Test/data/m3u8/playlist.m3u8 index f047f01..5fd46ff 100644 --- a/Test/data/m3u8/playlist.m3u8 +++ b/Test/data/m3u8/playlist.m3u8 @@ -1,11 +1,12 @@ #EXTM3U -#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="Italian",DEFAULT=YES,AUTOSELECT=YES,FORCED=NO,LANGUAGE="ita",URI="https://vixcloud.co/playlist/213349?type=audio&rendition=ita&token=J0FBqnixXmTN24xdMdxAVg&expires=1720013276" - -#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English [CC]",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE="eng",URI="https://vixcloud.co/playlist/213349?type=subtitle&rendition=3-eng&token=J0FBqnixXmTN24xdMdxAVg&expires=1720013276" -#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Czech",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE="cze",URI="https://vixcloud.co/playlist/213349?type=subtitle&rendition=4-cze&token=J0FBqnixXmTN24xdMdxAVg&expires=1720013276" - +#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="Italian",DEFAULT=YES,AUTOSELECT=YES,FORCED=NO,LANGUAGE="ita",URI="https://vixcloud.co/playlist/175761?type=audio&rendition=ita&token=AfHdAGc26qqpBDVFAdKJCQ&expires=1722501194&edge=sc-u2-01" +#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="English",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE="eng",URI="https://vixcloud.co/playlist/175761?type=audio&rendition=eng&token=AfHdAGc26qqpBDVFAdKJCQ&expires=1722501194&edge=sc-u2-01" +#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE="eng",URI="https://vixcloud.co/playlist/175761?type=subtitle&rendition=eng&token=AfHdAGc26qqpBDVFAdKJCQ&expires=1722501194&edge=sc-u2-01" +#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Italian [Forced]",DEFAULT=YES,AUTOSELECT=YES,FORCED=NO,LANGUAGE="forced-ita",URI="https://vixcloud.co/playlist/175761?type=subtitle&rendition=forced-ita&token=AfHdAGc26qqpBDVFAdKJCQ&expires=1722501194&edge=sc-u2-01" +#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Italian",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE="ita",URI="https://vixcloud.co/playlist/175761?type=subtitle&rendition=ita&token=AfHdAGc26qqpBDVFAdKJCQ&expires=1722501194&edge=sc-u2-01" #EXT-X-STREAM-INF:BANDWIDTH=1200000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=854x480,AUDIO="audio",SUBTITLES="subs" -https://vixcloud.co/playlist/213349?type=video&rendition=480p&token=WcQHF0VYTJnnWXRVzGyI4A&expires=1720013276 - +https://vixcloud.co/playlist/175761?type=video&rendition=480p&token=VQk6xhvJbSGMsktylrOqLg&expires=1722501194&edge=sc-u2-01 #EXT-X-STREAM-INF:BANDWIDTH=2150000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1280x720,AUDIO="audio",SUBTITLES="subs" -https://vixcloud.co/playlist/213349?type=video&rendition=720p&token=pYMwBEGivMnsWlzTJodYQw&expires=1720013276 \ No newline at end of file +https://vixcloud.co/playlist/175761?type=video&rendition=720p&token=ecGWDJYeeYgEJTP_fjDQKQ&expires=1722501194&edge=sc-u2-01 +#EXT-X-STREAM-INF:BANDWIDTH=4500000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1920x1080,AUDIO="audio",SUBTITLES="subs" +https://vixcloud.co/playlist/175761?type=video&rendition=1080p&token=AhO8JTM1VfOMfrZFpEfjUw&expires=1722501194&edge=sc-u2-01 \ No newline at end of file diff --git a/Test/data/playlist_info.json b/Test/data/playlist_info.json deleted file mode 100644 index 26d3f2b..0000000 --- a/Test/data/playlist_info.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "2024-5": { - "token": "csVhbgxqG_z_tjvJiy1IiA", - "token360p": "", - "token480p": "S7MTy30iN4BcxC-sXt0fOw", - "token720p": "fW_SEvaLezh5bD_iKDxcpw", - "token1080p": "HSuRzJwwFYR55KhtOAC85Q", - "expires": "1720963565" - } -} \ No newline at end of file diff --git a/Test/t_m3u8_parser.py b/Test/t_m3u8_parser.py index 88bb31f..c6468e5 100644 --- a/Test/t_m3u8_parser.py +++ b/Test/t_m3u8_parser.py @@ -23,23 +23,15 @@ from Src.Lib.M3U8 import M3U8_Parser # Test data obj_m3u8_parser = M3U8_Parser() base_path_file = os.path.join('Test', 'data', 'm3u8') + + +# Collect all index +index_video = read_file(os.path.join(base_path_file, "index_video.m3u8")) index_audio = read_file(os.path.join(base_path_file, "index_audio.m3u8")) index_subtitle = read_file(os.path.join(base_path_file,"index_subtitle.m3u8")) -index_video = read_file(os.path.join(base_path_file, "index_video.m3u8")) playlist = read_file(os.path.join(base_path_file, "playlist.m3u8")) -print("AUDIO: ") -print(M3U8(index_audio).data) -print() - -print("SUBTITLE: ") -print(M3U8(index_subtitle).data) -print() - -print("INDEX: ") -print(M3U8(index_video).data) -print() - -print("PLAYLIST: ") -print(M3U8(playlist).data) +# Test class +obj_m3u8_parser.parse_data("http", index_audio) +print(f"Duration : {obj_m3u8_parser.get_duration()}") diff --git a/config.json b/config.json index d769c1b..b07741d 100644 --- a/config.json +++ b/config.json @@ -10,7 +10,6 @@ "not_close": false }, "REQUESTS": { - "disable_error": false, "timeout": 10, "max_retry": 3, "verify_ssl": false, diff --git a/requirements.txt b/requirements.txt index 21218f8..3f1f64e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ bs4 +certifi tqdm rich unidecode \ No newline at end of file From d2a9165f7d2fab7af030f9d3cdb677b3b974fb10 Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Sun, 2 Jun 2024 16:02:47 +0200 Subject: [PATCH 08/13] Remove stop_event --- Src/Lib/FFmpeg/util.py | 4 +-- Src/Lib/Hls/segments.py | 65 ++++++++++++++++------------------------- 2 files changed, 27 insertions(+), 42 deletions(-) diff --git a/Src/Lib/FFmpeg/util.py b/Src/Lib/FFmpeg/util.py index 10ef22c..1f46cf4 100644 --- a/Src/Lib/FFmpeg/util.py +++ b/Src/Lib/FFmpeg/util.py @@ -71,8 +71,8 @@ def get_video_duration(file_path: str) -> float: return float(probe_result['format']['duration']) except Exception as e: - logging.error(f"Error: {e}") - return None + logging.error(f"Error get video duration: {e}") + sys.exit(0) def format_duration(seconds: float) -> Tuple[int, int, int]: diff --git a/Src/Lib/Hls/segments.py b/Src/Lib/Hls/segments.py index b03db71..9a5e428 100644 --- a/Src/Lib/Hls/segments.py +++ b/Src/Lib/Hls/segments.py @@ -5,7 +5,6 @@ import sys import time import queue import threading -import signal import logging import binascii from concurrent.futures import ThreadPoolExecutor @@ -53,18 +52,20 @@ class M3U8_Segments: - tmp_folder (str): The temporary folder to store downloaded segments. """ self.url = url + self.fake_proxy = False self.tmp_folder = tmp_folder - self.decryption: M3U8_Decryption = None # Initialize decryption as None - self.segment_queue = queue.PriorityQueue() # Priority queue to maintain the order of segments - self.current_index = 0 # Index of the current segment to be written - self.tmp_file_path = os.path.join(self.tmp_folder, "0.ts") # Path to the temporary file - self.condition = threading.Condition() # Condition variable for thread synchronization - self.ctrl_c_detected = False # Global variable to track Ctrl+C detection + self.tmp_file_path = os.path.join(self.tmp_folder, "0.ts") + os.makedirs(self.tmp_folder, exist_ok=True) - os.makedirs(self.tmp_folder, exist_ok=True) # Create the temporary folder if it does not exist + # Util class + self.decryption: M3U8_Decryption = None self.class_ts_estimator = M3U8_Ts_Estimator(0) self.class_url_fixer = M3U8_UrlFix(url) - self.fake_proxy = False + + # Sync + self.current_index = 0 # Index of the current segment to be written + self.segment_queue = queue.PriorityQueue() # Priority queue to maintain the order of segments + self.condition = threading.Condition() # Condition variable for thread synchronization def add_server_ip(self, list_ip): """ @@ -201,21 +202,16 @@ class M3U8_Segments: return urlunparse(parsed_url) - def make_requests_stream(self, ts_url: str, index: int, stop_event: threading.Event, progress_bar: tqdm) -> None: + def make_requests_stream(self, ts_url: str, index: int, progress_bar: tqdm) -> None: """ Downloads a TS segment and adds it to the segment queue. Args: - ts_url (str): The URL of the TS segment. - index (int): The index of the segment. - - stop_event (threading.Event): Event to signal the stop of downloading. - progress_bar (tqdm): Progress counter for tracking download progress. - - add_desc (str): Additional description for the progress bar. """ - if stop_event.is_set(): - return # Exit if the stop event is set - # Generate new user agent headers_segments['user-agent'] = get_headers() @@ -225,8 +221,8 @@ class M3U8_Segments: start_time = time.time() response = requests.get(ts_url, headers=headers_segments, verify=REQUEST_VERIFY_SSL, timeout=30) duration = time.time() - start_time - logging.info(f"Make request to get segmenet: [{index} - {len(self.segments)}] in: {duration}, len data: {len(response.content)}") - + logging.info(f"Make request to get segment: [{index} - {len(self.segments)}] in: {duration}, len data: {len(response.content)}") + if response.ok: # Get the content of the segment @@ -242,7 +238,6 @@ class M3U8_Segments: with self.condition: self.segment_queue.put((index, segment_content)) # Add the segment to the queue self.condition.notify() # Notify the writer thread that a new segment is available - else: logging.error(f"Failed to download segment: {ts_url}") @@ -252,22 +247,18 @@ class M3U8_Segments: # Update bar progress_bar.update(1) - def write_segments_to_file(self, stop_event: threading.Event): + def write_segments_to_file(self): """ Writes downloaded segments to a file in the correct order. - - Args: - - stop_event (threading.Event): Event to signal the stop of writing. """ - with open(self.tmp_file_path, 'ab') as f: - while not (stop_event.is_set() and self.segment_queue.empty()): # Wait until both stop_event is set and queue is empty + while True: with self.condition: - while self.segment_queue.empty() and not stop_event.is_set(): - self.condition.wait() # Wait until a new segment is available or stop_event is set + while self.segment_queue.empty() and self.current_index < len(self.segments): + self.condition.wait() # Wait until a new segment is available or all segments are downloaded - if stop_event.is_set() and self.segment_queue.empty(): # Exit loop if both conditions are met - break + if self.segment_queue.empty() and self.current_index >= len(self.segments): + break # Exit loop if all segments have been processed if not self.segment_queue.empty(): # Get the segment from the queue @@ -279,7 +270,7 @@ class M3U8_Segments: self.current_index += 1 self.segment_queue.task_done() else: - self.segment_queue.put((index, segment_content)) # Requeue the segment if it is not the next to be written + self.segment_queue.put((index, segment_content)) # Requeue the segment if it is not the next to be written self.condition.notify() def download_streams(self, add_desc): @@ -289,8 +280,6 @@ class M3U8_Segments: Args: - add_desc (str): Additional description for the progress bar. """ - stop_event = threading.Event() # Event to signal stopping - if TQDM_USE_LARGE_BAR: bar_format=f"{Colors.YELLOW}Downloading {Colors.WHITE}({add_desc}{Colors.WHITE}): {Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.WHITE}| {Colors.YELLOW}{{n_fmt}}{Colors.WHITE} / {Colors.RED}{{total_fmt}} {Colors.WHITE}| {Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]" else: @@ -300,28 +289,24 @@ class M3U8_Segments: total=len(self.segments), unit='s', ascii='░▒█', - bar_format=bar_format, - dynamic_ncols=True, - ncols=80, - mininterval=0.01 + bar_format=bar_format ) with ThreadPoolExecutor(max_workers=TQDM_MAX_WORKER) as executor: # Start a separate thread to write segments to the file - writer_thread = threading.Thread(target=self.write_segments_to_file, args=(stop_event,)) + writer_thread = threading.Thread(target=self.write_segments_to_file) writer_thread.start() - # Delay the start of each worker + # Start all workers for index, segment_url in enumerate(self.segments): # Submit the download task to the executor - executor.submit(self.make_requests_stream, segment_url, index, stop_event, progress_bar) + executor.submit(self.make_requests_stream, segment_url, index, progress_bar) # Wait for all segments to be downloaded executor.shutdown() - stop_event.set() # Set the stop event to halt the writer thread + with self.condition: self.condition.notify_all() # Wake up the writer thread if it's waiting writer_thread.join() # Wait for the writer thread to finish - From a030a2ef3b5cfe4248e204b98b8be005a5f4d4a7 Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Sun, 2 Jun 2024 16:08:08 +0200 Subject: [PATCH 09/13] Rename repo. --- Src/Upload/version.py | 4 ++-- Src/Util/message.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Src/Upload/version.py b/Src/Upload/version.py index bb50b0f..c69e058 100644 --- a/Src/Upload/version.py +++ b/Src/Upload/version.py @@ -1,5 +1,5 @@ -__title__ = 'Streaming_community' +__title__ = 'StreamingCommunity' __version__ = 'v1.1.0' -__author__ = 'Ghost6446' +__author__ = 'Lovi-0' __description__ = 'A command-line program to download film' __copyright__ = 'Copyright 2024' diff --git a/Src/Util/message.py b/Src/Util/message.py index 4a5706c..b20000d 100644 --- a/Src/Util/message.py +++ b/Src/Util/message.py @@ -41,7 +41,7 @@ def start_message(): if SHOW: console.print(f"[bold yellow]{msg}") - console.print(f"[magenta]Created by: Ghost6446\n") + console.print(f"[magenta]Created by: Lovi\n") row = "-" * console.width console.print(f"[yellow]{row} \n") \ No newline at end of file From 37e75370b0815299334461260643dff75317e657 Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Tue, 4 Jun 2024 22:06:46 +0200 Subject: [PATCH 10/13] Only 4 workers. --- Src/Api/Animeunity/Core/Vix_player/player.py | 45 +------------------ .../Core/Vix_player/player.py | 45 +------------------ Src/Api/Streamingcommunity/costant.py | 5 --- Src/Api/Streamingcommunity/film.py | 4 +- Src/Api/Streamingcommunity/series.py | 4 +- Src/Lib/Hls/segments.py | 31 +++++++++++++ config.json | 2 +- 7 files changed, 38 insertions(+), 98 deletions(-) diff --git a/Src/Api/Animeunity/Core/Vix_player/player.py b/Src/Api/Animeunity/Core/Vix_player/player.py index 30b30d0..bcac59a 100644 --- a/Src/Api/Animeunity/Core/Vix_player/player.py +++ b/Src/Api/Animeunity/Core/Vix_player/player.py @@ -206,47 +206,4 @@ class VideoSource: new_url = m._replace(query=new_query) # Replace the old query string with the new one final_url = urlunparse(new_url) # Construct the final URL from the modified parts - if "canPlayFHD" in current_params and self.window_video.quality == "1080": - return final_url - else: - console.log("[red]Rebuild master playlist.") - return self.re_build_master() - - def re_build_master(self) -> str: - """ - Rebuild the master playlist. - - Returns: - str: The rebuilt master playlist text, or an empty string if there's an error. - """ - try: - index_resolution = None - master_url = f'https://vixcloud.co/playlist/{self.window_video.id}' - index_url = f'https://vixcloud.co/playlist/{self.window_video.id}?type=video&rendition={self.window_video.quality}p' - - try: - # Fetch the master playlist text - master_text = requests.get(master_url).text - except requests.RequestException as e: - logging.error(f"Error fetching master playlist from URL: {master_url}, error: {e}") - return "" - - # Find the resolution in the index URL - for resolution in [(7680, 4320), (3840, 2160), (2560, 1440), (1920, 1080), (1280, 720), (640, 480)]: - if str(resolution[1]) in index_url: - index_resolution = resolution - break - - # Add resolution and index URL to the master playlist text - if index_resolution: - master_text += f'\n#EXT-X-STREAM-INF:BANDWIDTH=2150000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION={index_resolution[0]}x{index_resolution[1]},SUBTITLES="subs"\n' - master_text += index_url - - else: - logging.warning(f"No matching resolution found in index URL: {index_url}") - - return master_text - - except Exception as e: - logging.error(f"Unexpected error in re_build_master: {e}") - sys.exit(0) + return final_url diff --git a/Src/Api/Streamingcommunity/Core/Vix_player/player.py b/Src/Api/Streamingcommunity/Core/Vix_player/player.py index 545944c..e72e7e0 100644 --- a/Src/Api/Streamingcommunity/Core/Vix_player/player.py +++ b/Src/Api/Streamingcommunity/Core/Vix_player/player.py @@ -239,47 +239,4 @@ class VideoSource: new_url = m._replace(query=new_query) # Replace the old query string with the new one final_url = urlunparse(new_url) # Construct the final URL from the modified parts - if "canPlayFHD" in current_params and self.window_video.quality == "1080": - return final_url - else: - console.log("[red]Rebuild master playlist.") - return self.re_build_master() - - def re_build_master(self) -> str: - """ - Rebuild the master playlist. - - Returns: - str: The rebuilt master playlist text, or an empty string if there's an error. - """ - try: - index_resolution = None - master_url = f'https://vixcloud.co/playlist/{self.window_video.id}' - index_url = f'https://vixcloud.co/playlist/{self.window_video.id}?type=video&rendition={self.window_video.quality}p' - - try: - # Fetch the master playlist text - master_text = requests.get(master_url).text - except requests.RequestException as e: - logging.error(f"Error fetching master playlist from URL: {master_url}, error: {e}") - return "" - - # Find the resolution in the index URL - for resolution in [(7680, 4320), (3840, 2160), (2560, 1440), (1920, 1080), (1280, 720), (640, 480)]: - if str(resolution[1]) in index_url: - index_resolution = resolution - break - - # Add resolution and index URL to the master playlist text - if index_resolution: - master_text += f'\n#EXT-X-STREAM-INF:BANDWIDTH=2150000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION={index_resolution[0]}x{index_resolution[1]},SUBTITLES="subs"\n' - master_text += index_url - - else: - logging.warning(f"No matching resolution found in index URL: {index_url}") - - return master_text - - except Exception as e: - logging.error(f"Unexpected error in re_build_master: {e}") - sys.exit(0) + return final_url diff --git a/Src/Api/Streamingcommunity/costant.py b/Src/Api/Streamingcommunity/costant.py index 2ebb247..6038c67 100644 --- a/Src/Api/Streamingcommunity/costant.py +++ b/Src/Api/Streamingcommunity/costant.py @@ -3,8 +3,3 @@ STREAMING_FOLDER = "streamingcommunity" MOVIE_FOLDER = "Movie" SERIES_FOLDER = "Serie" - -SERVER_IP = ['57.129.7.85', '57.129.7.188', '57.129.7.174', '57.129.4.77', '57.129.16.196', '57.129.16.156', '57.129.16.139', '57.129.16.135', '57.129.13.175', - '57.129.13.157', '51.38.112.237', '51.195.107.7', '51.195.107.230', '162.19.255.78', '162.19.255.36', '162.19.255.224', '162.19.255.223', '162.19.254.244', - '162.19.254.232', '162.19.254.230', '162.19.253.242', '162.19.249.48', '162.19.245.142', '162.19.231.20', '162.19.229.177', '162.19.228.128', '162.19.228.127', - '162.19.228.105', '141.95.1.32', '141.95.1.196', '141.95.1.102', '141.95.0.50', '141.95.0.248', '135.125.237.84', '135.125.233.236'] \ No newline at end of file diff --git a/Src/Api/Streamingcommunity/film.py b/Src/Api/Streamingcommunity/film.py index 47b0e90..2b9d7bf 100644 --- a/Src/Api/Streamingcommunity/film.py +++ b/Src/Api/Streamingcommunity/film.py @@ -18,7 +18,7 @@ from .Core.Vix_player.player import VideoSource # Config ROOT_PATH = config_manager.get('DEFAULT', 'root_path') -from .costant import STREAMING_FOLDER, MOVIE_FOLDER, SERVER_IP +from .costant import STREAMING_FOLDER, MOVIE_FOLDER # Variable @@ -59,4 +59,4 @@ def download_film(id_film: str, title_name: str, domain: str): Downloader( m3u8_playlist = master_playlist, output_filename = os.path.join(mp4_path, mp4_format) - ).start(SERVER_IP) \ No newline at end of file + ).start() \ No newline at end of file diff --git a/Src/Api/Streamingcommunity/series.py b/Src/Api/Streamingcommunity/series.py index f10be43..9b2ecc0 100644 --- a/Src/Api/Streamingcommunity/series.py +++ b/Src/Api/Streamingcommunity/series.py @@ -20,7 +20,7 @@ from .Core.Util import manage_selection, map_episode_title # Config ROOT_PATH = config_manager.get('DEFAULT', 'root_path') -from .costant import STREAMING_FOLDER, SERIES_FOLDER, SERVER_IP +from .costant import STREAMING_FOLDER, SERIES_FOLDER # Variable @@ -96,7 +96,7 @@ def donwload_video(tv_name: str, index_season_selected: int, index_episode_selec Downloader( m3u8_playlist = master_playlist, output_filename = os.path.join(mp4_path, mp4_name) - ).start(SERVER_IP) + ).start() def donwload_episode(tv_name: str, index_season_selected: int, donwload_all: bool = False) -> None: diff --git a/Src/Lib/Hls/segments.py b/Src/Lib/Hls/segments.py index 9a5e428..fe2a131 100644 --- a/Src/Lib/Hls/segments.py +++ b/Src/Lib/Hls/segments.py @@ -109,6 +109,34 @@ class M3U8_Segments: logging.info(f"Key: ('hex': {hex_content}, 'byte': {byte_content})") return byte_content + def __test_ip(self): + """ + Tests each proxy IP by sending a request to a corresponding segment URL. + """ + + failed_ips = [] + + for i in range(len(self.fake_proxy_ip)): + url_to_test = self.segments[i] + + try: + + # Attempt to send a GET request to the URL + requests.get(url_to_test, verify=self.verify_ssl) + except: + + # Log the error and add the IP to the list of failed IPs + logging.error(f"Failed to make request using IP in this request: {url_to_test}") + failed_ips.append(i) + + # Remove the failed IPs from the fake_proxy_ip list + self.fake_proxy_ip = [ip for j, ip in enumerate(self.fake_proxy_ip) if j not in failed_ips] + + # Exit the program if 50% requests failed + if len(failed_ips) / 2 > len(self.fake_proxy_ip): + logging.error("All requests with ip failed. Exiting the program.") + sys.exit(0) + def parse_data(self, m3u8_content: str) -> None: """ Parses the M3U8 content to extract segment information. @@ -156,6 +184,9 @@ class M3U8_Segments: self.segments[i] = self.__gen_proxy__(segment_url, self.segments.index(segment_url)) + # Test new url with ip + self.__test_ip() + # Save new playlist of segment path_m3u8_file = os.path.join(self.tmp_folder, "playlist_fix.m3u8") with open(path_m3u8_file, "w") as file: diff --git a/config.json b/config.json index b07741d..4cfd9e6 100644 --- a/config.json +++ b/config.json @@ -17,7 +17,7 @@ "segments": { "user-agent": ""} }, "M3U8_DOWNLOAD": { - "tdqm_workers": 30, + "tdqm_workers": 4, "tqdm_use_large_bar": true, "download_video": true, "download_audio": true, From 4553cf9f45e95facdd17444bcd2786cc1bcaf2d4 Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Tue, 4 Jun 2024 23:18:16 +0200 Subject: [PATCH 11/13] Auto switch proxy. --- Src/Api/Animeunity/anime.py | 4 +- Src/Api/Animeunity/costant.py | 4 +- .../Core/Vix_player/player.py | 2 +- Src/Api/Streamingcommunity/costant.py | 2 + Src/Api/Streamingcommunity/film.py | 4 +- Src/Api/Streamingcommunity/series.py | 4 +- Src/Lib/Hls/segments.py | 43 +++++++++++++------ 7 files changed, 41 insertions(+), 22 deletions(-) diff --git a/Src/Api/Animeunity/anime.py b/Src/Api/Animeunity/anime.py index 26a6357..79a2355 100644 --- a/Src/Api/Animeunity/anime.py +++ b/Src/Api/Animeunity/anime.py @@ -18,7 +18,7 @@ from .Core.Util import manage_selection # Config ROOT_PATH = config_manager.get('DEFAULT', 'root_path') -from .costant import ANIME_FOLDER, SERIES_FOLDER, MOVIE_FOLDER +from .costant import ANIME_FOLDER, SERIES_FOLDER, MOVIE_FOLDER, STATIC_IP_SERVER # Variable @@ -61,7 +61,7 @@ def download_episode(index_select: int): ) # Start downloading - obj_download.start() + obj_download.start(STATIC_IP_SERVER) def donwload_series(tv_id: int, tv_name: str): diff --git a/Src/Api/Animeunity/costant.py b/Src/Api/Animeunity/costant.py index 68ec402..28f0252 100644 --- a/Src/Api/Animeunity/costant.py +++ b/Src/Api/Animeunity/costant.py @@ -2,4 +2,6 @@ ANIME_FOLDER = "animeunity" SERIES_FOLDER= "Serie" -MOVIE_FOLDER = "Movie" \ No newline at end of file +MOVIE_FOLDER = "Movie" + +STATIC_IP_SERVER = ['57.129.7.85', '57.129.7.188', '57.129.7.174', '57.129.4.77', '57.129.16.196', '57.129.16.156', '57.129.16.139', '57.129.16.135', '57.129.13.175', '57.129.13.157', '51.38.112.237', '51.195.107.7', '51.195.107.230', '162.19.255.78', '162.19.255.36', '162.19.255.224', '162.19.255.223', '162.19.254.244', '162.19.254.232', '162.19.254.230', '162.19.253.242', '162.19.249.48', '162.19.245.142', '162.19.231.20', '162.19.229.177', '162.19.228.128', '162.19.228.127', '162.19.228.105', '141.95.1.32', '141.95.1.196', '141.95.1.102', '141.95.0.50', '141.95.0.248', '135.125.237.84', '135.125.233.236'] \ No newline at end of file diff --git a/Src/Api/Streamingcommunity/Core/Vix_player/player.py b/Src/Api/Streamingcommunity/Core/Vix_player/player.py index e72e7e0..bd72041 100644 --- a/Src/Api/Streamingcommunity/Core/Vix_player/player.py +++ b/Src/Api/Streamingcommunity/Core/Vix_player/player.py @@ -238,5 +238,5 @@ class VideoSource: new_query = urlencode(final_params) # Encode final_params into a query string new_url = m._replace(query=new_query) # Replace the old query string with the new one final_url = urlunparse(new_url) # Construct the final URL from the modified parts - + return final_url diff --git a/Src/Api/Streamingcommunity/costant.py b/Src/Api/Streamingcommunity/costant.py index 6038c67..de48a7f 100644 --- a/Src/Api/Streamingcommunity/costant.py +++ b/Src/Api/Streamingcommunity/costant.py @@ -3,3 +3,5 @@ STREAMING_FOLDER = "streamingcommunity" MOVIE_FOLDER = "Movie" SERIES_FOLDER = "Serie" + +STATIC_IP_SERVER = ['57.129.7.85', '57.129.7.188', '57.129.7.174', '57.129.4.77', '57.129.16.196', '57.129.16.156', '57.129.16.139', '57.129.16.135', '57.129.13.175', '57.129.13.157', '51.38.112.237', '51.195.107.7', '51.195.107.230', '162.19.255.78', '162.19.255.36', '162.19.255.224', '162.19.255.223', '162.19.254.244', '162.19.254.232', '162.19.254.230', '162.19.253.242', '162.19.249.48', '162.19.245.142', '162.19.231.20', '162.19.229.177', '162.19.228.128', '162.19.228.127', '162.19.228.105', '141.95.1.32', '141.95.1.196', '141.95.1.102', '141.95.0.50', '141.95.0.248', '135.125.237.84', '135.125.233.236'] \ No newline at end of file diff --git a/Src/Api/Streamingcommunity/film.py b/Src/Api/Streamingcommunity/film.py index 2b9d7bf..765a5cf 100644 --- a/Src/Api/Streamingcommunity/film.py +++ b/Src/Api/Streamingcommunity/film.py @@ -18,7 +18,7 @@ from .Core.Vix_player.player import VideoSource # Config ROOT_PATH = config_manager.get('DEFAULT', 'root_path') -from .costant import STREAMING_FOLDER, MOVIE_FOLDER +from .costant import STREAMING_FOLDER, MOVIE_FOLDER, STATIC_IP_SERVER # Variable @@ -59,4 +59,4 @@ def download_film(id_film: str, title_name: str, domain: str): Downloader( m3u8_playlist = master_playlist, output_filename = os.path.join(mp4_path, mp4_format) - ).start() \ No newline at end of file + ).start(STATIC_IP_SERVER) \ No newline at end of file diff --git a/Src/Api/Streamingcommunity/series.py b/Src/Api/Streamingcommunity/series.py index 9b2ecc0..1d0458b 100644 --- a/Src/Api/Streamingcommunity/series.py +++ b/Src/Api/Streamingcommunity/series.py @@ -20,7 +20,7 @@ from .Core.Util import manage_selection, map_episode_title # Config ROOT_PATH = config_manager.get('DEFAULT', 'root_path') -from .costant import STREAMING_FOLDER, SERIES_FOLDER +from .costant import STREAMING_FOLDER, SERIES_FOLDER, STATIC_IP_SERVER # Variable @@ -96,7 +96,7 @@ def donwload_video(tv_name: str, index_season_selected: int, index_episode_selec Downloader( m3u8_playlist = master_playlist, output_filename = os.path.join(mp4_path, mp4_name) - ).start() + ).start(STATIC_IP_SERVER) def donwload_episode(tv_name: str, index_season_selected: int, donwload_all: bool = False) -> None: diff --git a/Src/Lib/Hls/segments.py b/Src/Lib/Hls/segments.py index fe2a131..8dfbf05 100644 --- a/Src/Lib/Hls/segments.py +++ b/Src/Lib/Hls/segments.py @@ -109,7 +109,7 @@ class M3U8_Segments: logging.info(f"Key: ('hex': {hex_content}, 'byte': {byte_content})") return byte_content - def __test_ip(self): + def __test_ip(self, url_to_test: str): """ Tests each proxy IP by sending a request to a corresponding segment URL. """ @@ -117,16 +117,18 @@ class M3U8_Segments: failed_ips = [] for i in range(len(self.fake_proxy_ip)): - url_to_test = self.segments[i] try: + response = requests.get(url_to_test, verify=False, retries=0) + + if response == None: + logging.error(f"[Work] to make request using: {url_to_test}") + failed_ips.append(i) - # Attempt to send a GET request to the URL - requests.get(url_to_test, verify=self.verify_ssl) except: # Log the error and add the IP to the list of failed IPs - logging.error(f"Failed to make request using IP in this request: {url_to_test}") + logging.error(f"[Fail] to make request using IP in this request: {url_to_test}") failed_ips.append(i) # Remove the failed IPs from the fake_proxy_ip list @@ -134,8 +136,13 @@ class M3U8_Segments: # Exit the program if 50% requests failed if len(failed_ips) / 2 > len(self.fake_proxy_ip): - logging.error("All requests with ip failed. Exiting the program.") - sys.exit(0) + logging.error("All requests with ip failed.") + + # Set to not use proxy + self.fake_proxy_ip = None + self.fake_proxy = False + + return False def parse_data(self, m3u8_content: str) -> None: """ @@ -182,10 +189,13 @@ class M3U8_Segments: for i in range(len(self.segments)): segment_url = self.segments[i] - self.segments[i] = self.__gen_proxy__(segment_url, self.segments.index(segment_url)) + # Set to not use proxy if 50% failed + if not self.__test_ip(segment_url): + console.log("[red]Cant use proxy switch to normal url.") + self.fake_proxy = False + break - # Test new url with ip - self.__test_ip() + self.segments[i] = self.__gen_proxy__(segment_url, self.segments.index(segment_url)) # Save new playlist of segment path_m3u8_file = os.path.join(self.tmp_folder, "playlist_fix.m3u8") @@ -226,12 +236,17 @@ class M3U8_Segments: Returns: str: The modified URL with the new IP address. """ - new_ip_address = self.fake_proxy_ip[url_index % len(self.fake_proxy_ip)] + if self.fake_proxy: - # Parse the original URL and replace the hostname with the new IP address - parsed_url = urlparse(url)._replace(netloc=new_ip_address) + new_ip_address = self.fake_proxy_ip[url_index % len(self.fake_proxy_ip)] - return urlunparse(parsed_url) + # Parse the original URL and replace the hostname with the new IP address + parsed_url = urlparse(url)._replace(netloc=new_ip_address) + + return urlunparse(parsed_url) + + else: + return url def make_requests_stream(self, ts_url: str, index: int, progress_bar: tqdm) -> None: """ From febc16b6de4e70d157e337a58791ef2cf8d51807 Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Tue, 4 Jun 2024 23:20:55 +0200 Subject: [PATCH 12/13] Duplicate ip --- Src/Api/Animeunity/anime.py | 4 ++-- Src/Api/Animeunity/costant.py | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Src/Api/Animeunity/anime.py b/Src/Api/Animeunity/anime.py index 79a2355..26a6357 100644 --- a/Src/Api/Animeunity/anime.py +++ b/Src/Api/Animeunity/anime.py @@ -18,7 +18,7 @@ from .Core.Util import manage_selection # Config ROOT_PATH = config_manager.get('DEFAULT', 'root_path') -from .costant import ANIME_FOLDER, SERIES_FOLDER, MOVIE_FOLDER, STATIC_IP_SERVER +from .costant import ANIME_FOLDER, SERIES_FOLDER, MOVIE_FOLDER # Variable @@ -61,7 +61,7 @@ def download_episode(index_select: int): ) # Start downloading - obj_download.start(STATIC_IP_SERVER) + obj_download.start() def donwload_series(tv_id: int, tv_name: str): diff --git a/Src/Api/Animeunity/costant.py b/Src/Api/Animeunity/costant.py index 28f0252..7e75bc2 100644 --- a/Src/Api/Animeunity/costant.py +++ b/Src/Api/Animeunity/costant.py @@ -3,5 +3,3 @@ ANIME_FOLDER = "animeunity" SERIES_FOLDER= "Serie" MOVIE_FOLDER = "Movie" - -STATIC_IP_SERVER = ['57.129.7.85', '57.129.7.188', '57.129.7.174', '57.129.4.77', '57.129.16.196', '57.129.16.156', '57.129.16.139', '57.129.16.135', '57.129.13.175', '57.129.13.157', '51.38.112.237', '51.195.107.7', '51.195.107.230', '162.19.255.78', '162.19.255.36', '162.19.255.224', '162.19.255.223', '162.19.254.244', '162.19.254.232', '162.19.254.230', '162.19.253.242', '162.19.249.48', '162.19.245.142', '162.19.231.20', '162.19.229.177', '162.19.228.128', '162.19.228.127', '162.19.228.105', '141.95.1.32', '141.95.1.196', '141.95.1.102', '141.95.0.50', '141.95.0.248', '135.125.237.84', '135.125.233.236'] \ No newline at end of file From ae12d86d711274198680fe44ac690d960924fad9 Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Wed, 5 Jun 2024 23:29:35 +0200 Subject: [PATCH 13/13] Update library and remove my request and user agent. --- .../Altadefinizione/Core/Player/supervideo.py | 5 +- Src/Api/Altadefinizione/site.py | 2 +- Src/Api/Animeunity/Core/Util/get_domain.py | 4 +- Src/Api/Animeunity/Core/Vix_player/player.py | 2 +- Src/Api/Animeunity/site.py | 2 +- .../Core/Util/get_domain.py | 5 +- .../Core/Vix_player/player.py | 2 +- Src/Api/Streamingcommunity/site.py | 2 +- Src/Lib/Google/page.py | 2 +- Src/Lib/Hls/downloader.py | 2 +- Src/Lib/Hls/segments.py | 12 +- Src/Lib/M3U8/estimator.py | 9 +- Src/Lib/M3U8/parser.py | 2 +- Src/Lib/Request/__init__.py | 3 - Src/Lib/Request/my_requests.py | 541 ------------------ Src/Lib/UserAgent/__init__.py | 3 - Src/Lib/UserAgent/user_agent.py | 112 ---- Src/Upload/update.py | 2 +- Src/Util/headers.py | 15 +- Test/t_get_server_ip_sc.py | 3 +- requirements.txt | 6 +- 21 files changed, 43 insertions(+), 693 deletions(-) delete mode 100644 Src/Lib/Request/__init__.py delete mode 100644 Src/Lib/Request/my_requests.py delete mode 100644 Src/Lib/UserAgent/__init__.py delete mode 100644 Src/Lib/UserAgent/user_agent.py diff --git a/Src/Api/Altadefinizione/Core/Player/supervideo.py b/Src/Api/Altadefinizione/Core/Player/supervideo.py index 9be0249..48e8155 100644 --- a/Src/Api/Altadefinizione/Core/Player/supervideo.py +++ b/Src/Api/Altadefinizione/Core/Player/supervideo.py @@ -1,15 +1,12 @@ # 26.05.24 import re -import os import sys -import time import logging -import subprocess # External libraries -from Src.Lib.Request import requests +import requests from bs4 import BeautifulSoup diff --git a/Src/Api/Altadefinizione/site.py b/Src/Api/Altadefinizione/site.py index 958cc8d..1a53609 100644 --- a/Src/Api/Altadefinizione/site.py +++ b/Src/Api/Altadefinizione/site.py @@ -6,7 +6,7 @@ import logging # External libraries -from Src.Lib.Request import requests +import requests from bs4 import BeautifulSoup from unidecode import unidecode diff --git a/Src/Api/Animeunity/Core/Util/get_domain.py b/Src/Api/Animeunity/Core/Util/get_domain.py index 36e02cd..6730179 100644 --- a/Src/Api/Animeunity/Core/Util/get_domain.py +++ b/Src/Api/Animeunity/Core/Util/get_domain.py @@ -5,8 +5,8 @@ import threading import logging -# Internal libraries -from Src.Lib.Request import requests +# External libraries +import requests # Internal utilities diff --git a/Src/Api/Animeunity/Core/Vix_player/player.py b/Src/Api/Animeunity/Core/Vix_player/player.py index bcac59a..c977888 100644 --- a/Src/Api/Animeunity/Core/Vix_player/player.py +++ b/Src/Api/Animeunity/Core/Vix_player/player.py @@ -6,7 +6,7 @@ from urllib.parse import urljoin, urlparse, parse_qs, urlencode, urlunparse # External libraries -from Src.Lib.Request import requests +import requests from bs4 import BeautifulSoup diff --git a/Src/Api/Animeunity/site.py b/Src/Api/Animeunity/site.py index 28ee558..b885afd 100644 --- a/Src/Api/Animeunity/site.py +++ b/Src/Api/Animeunity/site.py @@ -5,7 +5,7 @@ import logging # External libraries -from Src.Lib.Request import requests +import requests from bs4 import BeautifulSoup from unidecode import unidecode diff --git a/Src/Api/Streamingcommunity/Core/Util/get_domain.py b/Src/Api/Streamingcommunity/Core/Util/get_domain.py index 0faada4..4017c43 100644 --- a/Src/Api/Streamingcommunity/Core/Util/get_domain.py +++ b/Src/Api/Streamingcommunity/Core/Util/get_domain.py @@ -5,8 +5,11 @@ import threading import logging +# External library +import requests + + # Internal utilities -from Src.Lib.Request import requests from Src.Lib.Google import search as google_search diff --git a/Src/Api/Streamingcommunity/Core/Vix_player/player.py b/Src/Api/Streamingcommunity/Core/Vix_player/player.py index bd72041..cb26be4 100644 --- a/Src/Api/Streamingcommunity/Core/Vix_player/player.py +++ b/Src/Api/Streamingcommunity/Core/Vix_player/player.py @@ -6,7 +6,7 @@ from urllib.parse import urljoin, urlparse, parse_qs, urlencode, urlunparse # External libraries -from Src.Lib.Request import requests +import requests from bs4 import BeautifulSoup diff --git a/Src/Api/Streamingcommunity/site.py b/Src/Api/Streamingcommunity/site.py index 606e77c..bdd5ec9 100644 --- a/Src/Api/Streamingcommunity/site.py +++ b/Src/Api/Streamingcommunity/site.py @@ -8,12 +8,12 @@ from typing import Tuple # External libraries +import requests from bs4 import BeautifulSoup from unidecode import unidecode # Internal utilities -from Src.Lib.Request import requests from Src.Util.headers import get_headers from Src.Util._jsonConfig import config_manager from Src.Util.console import console diff --git a/Src/Lib/Google/page.py b/Src/Lib/Google/page.py index 2185ad7..54e976f 100644 --- a/Src/Lib/Google/page.py +++ b/Src/Lib/Google/page.py @@ -8,7 +8,7 @@ from typing import Generator, Optional # External libraries -from Src.Lib.Request import requests +import requests from bs4 import BeautifulSoup diff --git a/Src/Lib/Hls/downloader.py b/Src/Lib/Hls/downloader.py index 9ef3ff3..26bd443 100644 --- a/Src/Lib/Hls/downloader.py +++ b/Src/Lib/Hls/downloader.py @@ -8,7 +8,7 @@ from concurrent.futures import ThreadPoolExecutor # External libraries -from Src.Lib.Request import requests +import requests from unidecode import unidecode diff --git a/Src/Lib/Hls/segments.py b/Src/Lib/Hls/segments.py index 8dfbf05..050706e 100644 --- a/Src/Lib/Hls/segments.py +++ b/Src/Lib/Hls/segments.py @@ -12,7 +12,7 @@ from urllib.parse import urljoin, urlparse, urlunparse # External libraries -from Src.Lib.Request import requests +import requests from tqdm import tqdm @@ -22,6 +22,7 @@ from Src.Util.headers import get_headers from Src.Util.color import Colors from Src.Util._jsonConfig import config_manager + # Logic class from ..M3U8 import ( M3U8_Decryption, @@ -30,6 +31,11 @@ from ..M3U8 import ( M3U8_UrlFix ) + +# Warning +import urllib3 +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + # Config TQDM_MAX_WORKER = config_manager.get_int('M3U8_DOWNLOAD', 'tdqm_workers') TQDM_USE_LARGE_BAR = config_manager.get_int('M3U8_DOWNLOAD', 'tqdm_use_large_bar') @@ -265,7 +271,7 @@ class M3U8_Segments: # Make request and calculate time duration start_time = time.time() - response = requests.get(ts_url, headers=headers_segments, verify=REQUEST_VERIFY_SSL, timeout=30) + response = requests.get(ts_url, headers=headers_segments, verify=REQUEST_VERIFY_SSL, timeout=15) duration = time.time() - start_time logging.info(f"Make request to get segment: [{index} - {len(self.segments)}] in: {duration}, len data: {len(response.content)}") @@ -275,7 +281,7 @@ class M3U8_Segments: segment_content = response.content # Update bar - self.class_ts_estimator.update_progress_bar(segment_content, duration, progress_bar) + self.class_ts_estimator.update_progress_bar(int(response.headers.get('Content-Length', 0)), duration, progress_bar) # Decrypt the segment content if decryption is needed if self.decryption is not None: diff --git a/Src/Lib/M3U8/estimator.py b/Src/Lib/M3U8/estimator.py index e0e6596..e762a40 100644 --- a/Src/Lib/M3U8/estimator.py +++ b/Src/Lib/M3U8/estimator.py @@ -31,7 +31,7 @@ class M3U8_Ts_Estimator: """ self.ts_file_sizes = [] self.now_downloaded_size = 0 - self.average_over = 6 + self.average_over = 3 self.list_speeds = deque(maxlen=self.average_over) self.smoothed_speeds = [] self.total_segments = total_segments @@ -52,7 +52,7 @@ class M3U8_Ts_Estimator: # Calculate speed outside of the lock try: - speed_mbps = (size_download * 16) / (duration * 1_000_000) + speed_mbps = (size_download * 8) / (duration * 1_000_000) except ZeroDivisionError as e: logging.error("Division by zero error while calculating speed: %s", e) return @@ -114,16 +114,15 @@ class M3U8_Ts_Estimator: """ return format_size(self.now_downloaded_size) - def update_progress_bar(self, segment_content: bytes, duration: float, progress_counter: tqdm) -> None: + def update_progress_bar(self, total_downloaded: int, duration: float, progress_counter: tqdm) -> None: """ Updates the progress bar with information about the TS segment download. Args: - segment_content (bytes): The content of the downloaded TS segment. + total_downloaded (int): The len of the content of the downloaded TS segment. duration (float): The duration of the segment download in seconds. progress_counter (tqdm): The tqdm object representing the progress bar. """ - total_downloaded = len(segment_content) # Add the size of the downloaded segment to the estimator self.add_ts_file(total_downloaded * self.total_segments, total_downloaded, duration) diff --git a/Src/Lib/M3U8/parser.py b/Src/Lib/M3U8/parser.py index a29a82f..bf364eb 100644 --- a/Src/Lib/M3U8/parser.py +++ b/Src/Lib/M3U8/parser.py @@ -8,7 +8,7 @@ from .lib_parser import load # External libraries -from Src.Lib.Request import requests +import requests # Costant diff --git a/Src/Lib/Request/__init__.py b/Src/Lib/Request/__init__.py deleted file mode 100644 index f6af28d..0000000 --- a/Src/Lib/Request/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# 04.4.24 - -from .my_requests import requests \ No newline at end of file diff --git a/Src/Lib/Request/my_requests.py b/Src/Lib/Request/my_requests.py deleted file mode 100644 index 405d892..0000000 --- a/Src/Lib/Request/my_requests.py +++ /dev/null @@ -1,541 +0,0 @@ -# 04.4.24 - -import os -import sys -import base64 -import json -import logging -import ssl -import time -import re -import subprocess -import urllib.parse -import urllib.request -import urllib.error - -from typing import Dict, Optional, Union, Any - - -try: - from typing import Unpack, TypedDict -except ImportError: - # (Python <= 3.10), - try: - from typing_extensions import Unpack, TypedDict # type: ignore - except ImportError: - raise ImportError("Unable to import Unpack from typing or typing_extensions. " - "Please make sure you have the necessary libraries installed.") - - -# External library -from bs4 import BeautifulSoup - - -# Internal utilities -from Src.Util._jsonConfig import config_manager - - -# Default settings -HTTP_TIMEOUT = config_manager.get_int('REQUESTS', 'timeout') -HTTP_RETRIES = config_manager.get_int('REQUESTS', 'max_retry') -HTTP_DELAY = 1 - - - -class RequestError(Exception): - """Custom exception class for request errors.""" - - def __init__(self, message: str, original_exception: Optional[Exception] = None) -> None: - """ - Initialize a RequestError instance. - - Args: - - message (str): The error message. - - original_exception (Optional[Exception], optional): The original exception that occurred. Defaults to None. - """ - super().__init__(message) - self.original_exception = original_exception - - def __str__(self) -> str: - """Return a string representation of the exception.""" - if self.original_exception: - return f"{super().__str__()} Original Exception: {type(self.original_exception).__name__}: {str(self.original_exception)}" - else: - return super().__str__() - - -def parse_http_error(error_string: str): - """ - Parse the HTTP error string to extract the error code and message. - - Args: - - error_string (str): The error string from an HTTP response. - - Returns: - dict: A dictionary with 'error_code' and 'message' if the string is parsed successfully, or None if parsing fails. - """ - - # Regular expression to match the error pattern - error_pattern = re.compile(r"HTTP Error (\d{3}): (.+)") - match = error_pattern.search(error_string) - - if match: - error_code = match.group(1) - message = match.group(2) - return {'error_code': error_code, 'message': message} - - else: - logging.error(f"Error string does not match expected format: {error_string}") - return None - - -class Response: - """ - Class representing an HTTP response. - """ - def __init__( - self, - status: int, - text: str, - is_json: bool = False, - content: bytes = b"", - headers: Optional[Dict[str, str]] = None, - cookies: Optional[Dict[str, str]] = None, - redirect_url: Optional[str] = None, - response_time: Optional[float] = None, - timeout: Optional[float] = None, - ): - """ - Initialize a Response object. - - Args: - - status (int): The HTTP status code of the response. - - text (str): The response content as text. - - is_json (bool, optional): Indicates if the response content is JSON. Defaults to False. - - content (bytes, optional): The response content as bytes. Defaults to b"". - - headers (Optional[Dict[str, str]], optional): The response headers. Defaults to None. - - cookies (Optional[Dict[str, str]], optional): The cookies set in the response. Defaults to None. - - redirect_url (Optional[str], optional): The URL if a redirection occurred. Defaults to None. - - response_time (Optional[float], optional): The time taken to receive the response. Defaults to None. - - timeout (Optional[float], optional): The request timeout. Defaults to None. - """ - self.status_code = status - self.text = text - self.is_json = is_json - self.content = content - self.headers = headers or {} - self.cookies = cookies or {} - self.redirect_url = redirect_url - self.response_time = response_time - self.timeout = timeout - self.ok = 200 <= status < 300 - - def raise_for_status(self): - """ - Raise an error if the response status code is not in the 2xx range. - """ - if not self.ok: - raise RequestError(f"Request failed with status code {self.status_code}") - - def json(self): - """ - Return the response content as JSON if it is JSON. - - Returns: - dict or list or None: A Python dictionary or list parsed from JSON if the response content is JSON, otherwise None. - """ - if self.is_json: - return json.loads(self.text) - else: - return None - - def get_redirects(self): - """ - Extracts unique site URLs from HTML elements within the section. - - Returns: - list or None: A list of unique site URLs if found, otherwise None. - """ - - site_find = [] - - if self.text: - soup = BeautifulSoup(self.text, "html.parser") - - for links in soup.find("head").find_all('link'): - if links is not None: - parsed_url = urllib.parse.urlparse(links.get('href')) - site = parsed_url.scheme + "://" + parsed_url.netloc - - if site not in site_find: - site_find.append(site) - - if site_find: - return site_find - else: - return None - - -class ManageRequests: - """ - Class for managing HTTP requests. - """ - def __init__( - self, - url: str, - method: str = 'GET', - headers: Optional[Dict[str, str]] = None, - timeout: float = HTTP_TIMEOUT, - retries: int = HTTP_RETRIES, - params: Optional[Dict[str, str]] = None, - verify: bool = True, - auth: Optional[tuple] = None, - proxy: Optional[str] = None, - cookies: Optional[Dict[str, str]] = None, - json_data: Optional[Dict[str, Any]] = None, - redirection_handling: bool = True, - ): - """ - Initialize a ManageRequests object. - - Args: - - url (str): The URL to which the request will be sent. - - method (str, optional): The HTTP method to be used for the request. Defaults to 'GET'. - - headers (Optional[Dict[str, str]], optional): The request headers. Defaults to None. - - timeout (float, optional): The request timeout. Defaults to HTTP_TIMEOUT. - - retries (int, optional): The number of retries in case of request failure. Defaults to HTTP_RETRIES. - - params (Optional[Dict[str, str]], optional): The query parameters for the request. Defaults to None. - - verify (bool, optional): Indicates whether SSL certificate verification should be performed. Defaults to True. - - auth (Optional[tuple], optional): Tuple containing the username and password for basic authentication. Defaults to None. - - proxy (Optional[str], optional): The proxy URL. Defaults to None. - - cookies (Optional[Dict[str, str]], optional): The cookies to be included in the request. Defaults to None. - - redirection_handling (bool, optional): Indicates whether redirections should be followed. Defaults to True. - """ - self.url = url - self.method = method - self.headers = headers or {} - self.timeout = timeout - self.retries = retries - self.params = params - self.verify_ssl = verify - self.auth = auth - self.proxy = proxy - self.cookies = cookies - self.json_data = json_data - self.redirection_handling = redirection_handling - - def add_header(self, key: str, value: str) -> None: - """ - Add a header to the request. - """ - self.headers[key] = value - - def send(self) -> Response: - """ - Send the HTTP request. - """ - - start_time = time.time() - self.attempt = 0 - redirect_url = None - - while self.attempt < self.retries: - try: - req = self._build_request() - response = self._perform_request(req) - - return self._process_response(response, start_time, redirect_url) - - except (urllib.error.URLError, urllib.error.HTTPError) as e: - self._handle_error(e) - self.attempt += 1 - - def log_request(self): - """ - Constructs a log message based on the request parameters and logs it. - """ - log_message = "Request: (" - - if self.url: - log_message += f"'url': {self.url}, " - if self.headers: - log_message += f"'headers': {self.headers}, " - if self.cookies: - log_message += f"'cookies': {self.cookies}, " - if self.json_data: - log_message += f"'body': {json.dumps(self.json_data).encode('utf-8')}, " - - # Remove the trailing comma and add parentheses - log_message = log_message.rstrip(", ") + ")" - logging.info(log_message) - - def _build_request(self) -> urllib.request.Request: - """ - Build the urllib Request object. - """ - - # Make a copy of headers to avoid modifying the original dictionary - headers = self.headers.copy() - - # Construct the URL with query parameters if present - if self.params: - url = self.url + '?' + urllib.parse.urlencode(self.params) - else: - url = self.url - - # Create the initial Request object - req = urllib.request.Request(url, headers=headers, method=self.method) - - # Add JSON data if provided - if self.json_data: - req.add_header('Content-Type', 'application/json') - req.data = json.dumps(self.json_data).encode('utf-8') - - # Add authorization header if provided - if self.auth: - req.add_header('Authorization', 'Basic ' + base64.b64encode(f"{self.auth[0]}:{self.auth[1]}".encode()).decode()) - - # Add cookies if provided - if self.cookies: - cookie_str = '; '.join([f"{name}={value}" for name, value in self.cookies.items()]) - req.add_header('Cookie', cookie_str) - - # Add default user agent if not already present - if 'user-agent' not in headers: - default_user_agent = 'Mozilla/5.0' - req.add_header('user-agent', default_user_agent) - - - self.log_request() - return req - - def _perform_request(self, req: urllib.request.Request) -> urllib.response.addinfourl: - """ - Perform the HTTP request. - """ - if self.proxy: - proxy_handler = urllib.request.ProxyHandler({'http': self.proxy, 'https': self.proxy}) - opener = urllib.request.build_opener(proxy_handler) - urllib.request.install_opener(opener) - - if not self.verify_ssl: - - # Create SSL context - ssl_context = ssl.create_default_context() - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - - # Build the request with SSL context - response = urllib.request.urlopen(req, timeout=self.timeout, context=ssl_context) - - else: - response = urllib.request.urlopen(req, timeout=self.timeout, context=ssl.create_default_context()) - - return response - - def _process_response(self, response: urllib.response.addinfourl, start_time: float, redirect_url: Optional[str]) -> Response: - """ - Process the HTTP response. - """ - response_data = response.read() - content_type = response.headers.get('Content-Type', '').lower() - - if self.redirection_handling and response.status in (301, 302, 303, 307, 308): - location = response.headers.get('Location') - logging.info(f"Redirecting to: {location}") - redirect_url = location - self.url = location - return self.send() - - return self._build_response(response, response_data, start_time, redirect_url, content_type) - - def _build_response(self, response: urllib.response.addinfourl, response_data: bytes, start_time: float, redirect_url: Optional[str], content_type: str) -> Response: - """ - Build the Response object. - """ - response_time = time.time() - start_time - response_headers = dict(response.headers) - response_cookies = {} - - for cookie in response.headers.get_all('Set-Cookie', []): - cookie_parts = cookie.split(';') - cookie_name, cookie_value = cookie_parts[0].split('=', 1) # Only the first - response_cookies[cookie_name.strip()] = cookie_value.strip() - - return Response( - status=response.status, - text=response_data.decode('latin-1'), - is_json=("json" in content_type), - content=response_data, - headers=response_headers, - cookies=response_cookies, - redirect_url=redirect_url, - response_time=response_time, - timeout=self.timeout, - ) - - def _handle_error(self, e: Union[urllib.error.URLError, urllib.error.HTTPError]) -> None: - """ - Handle request error. - """ - logging.error(f"Request failed for URL '{self.url}': {parse_http_error(str(e))}") - - if self.attempt < self.retries: - logging.error(f"Retry request for URL '{self.url}' (attempt {self.attempt}/{self.retries})") - time.sleep(HTTP_DELAY) - - else: - logging.error(f"Maximum retries reached for URL '{self.url}'") - raise RequestError(str(e)) - - -class ValidateRequest: - """ - Class for validating request inputs. - """ - @staticmethod - def validate_url(url: str) -> bool: - """Validate URL format.""" - - url_regex = re.compile( - r'^(?:http|ftp)s?://' # http:// or https:// - r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' # domain... - r'localhost|' # localhost... - r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', re.IGNORECASE) - return re.match(url_regex, url) is not None - - @staticmethod - def validate_headers(headers: Dict[str, str]) -> bool: - """Validate header values.""" - - for key, value in headers.items(): - if not isinstance(key, str) or not isinstance(value, str): - return False - return True - - -class ValidateResponse: - """ - Class for validating response data. - """ - @staticmethod - def is_valid_json(data: str) -> bool: - """Check if response data is a valid JSON.""" - - try: - json.loads(data) - return True - except ValueError: - return False - - -class SSLHandler: - """Class for handling SSL certificates.""" - @staticmethod - def load_certificate(custom_cert_path: str) -> None: - """Load custom SSL certificate.""" - ssl_context = ssl.create_default_context(cafile=custom_cert_path) - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - - -class KwargsRequest(TypedDict, total = False): - url: str - headers: Optional[Dict[str, str]] = None - timeout: float = HTTP_TIMEOUT - retries: int = HTTP_RETRIES - params: Optional[Dict[str, str]] = None - cookies: Optional[Dict[str, str]] = None - verify_ssl: bool = True - json_data: Optional[Dict[str, Any]] = None - - -class Request: - """ - Class for making HTTP requests. - """ - def __init__(self) -> None: - - # Ensure SSL certificate is set up - self.__setup_ssl_certificate__() - - def __setup_ssl_certificate__(self): - """ - Set up SSL certificate environment variables. - """ - try: - # Determine the Python executable - python_executable = sys.executable - logging.info("Python path: ", python_executable) - - # Check if certifi package is installed, install it if not - if subprocess.run([python_executable, "-c", "import certifi"], capture_output=True).returncode != 0: - subprocess.run(["pip", "install", "certifi"], check=True) - logging.info("Installed certifi package.") - - # Get path to SSL certificate - cert_path = subprocess.run([python_executable, "-c", "import certifi; print(certifi.where())"], capture_output=True, text=True, check=True).stdout.strip() - logging.info("Path cert: ", cert_path) - - if not cert_path: - raise ValueError("Unable to determine the path to the SSL certificate.") - - # Set SSL certificate environment variables - os.environ['SSL_CERT_FILE'] = cert_path - os.environ['REQUESTS_CA_BUNDLE'] = cert_path - - except subprocess.CalledProcessError as e: - raise ValueError(f"Error executing subprocess: {e}") from e - - def get(self, url: str, **kwargs: Unpack[KwargsRequest])-> 'Response': - """ - Send a GET request. - - Args: - - url (str): The URL to which the request will be sent. - **kwargs: Additional keyword arguments for the request. - - Returns: - Response: The response object. - """ - return self._send_request(url, 'GET', **kwargs) - - def post(self, url: str, **kwargs: Unpack[KwargsRequest]) -> 'Response': - """ - Send a POST request. - - Args: - - url (str): The URL to which the request will be sent. - **kwargs: Additional keyword arguments for the request. - - Returns: - Response: The response object. - """ - return self._send_request(url, 'POST', **kwargs) - - def head(self, url: str, **kwargs: Unpack[KwargsRequest]) -> 'Response': - """ - Send a HEAD request. - - Args: - - url (str): The URL to which the request will be sent. - **kwargs: Additional keyword arguments for the request. - - Returns: - Response: The response object. - """ - return self._send_request(url, 'HEAD', **kwargs) - - def _send_request(self, url: str, method: str, **kwargs: Unpack[KwargsRequest]) -> 'Response': - """Send an HTTP request.""" - if not ValidateRequest.validate_url(url): - raise ValueError("Invalid URL format") - - if 'headers' in kwargs and not ValidateRequest.validate_headers(kwargs['headers']): - raise ValueError("Invalid header values") - - return ManageRequests(url, method, **kwargs).send() - - -# Output -requests: Request = Request() \ No newline at end of file diff --git a/Src/Lib/UserAgent/__init__.py b/Src/Lib/UserAgent/__init__.py deleted file mode 100644 index b90fa6e..0000000 --- a/Src/Lib/UserAgent/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# 04.4.24 - -from .user_agent import ua \ No newline at end of file diff --git a/Src/Lib/UserAgent/user_agent.py b/Src/Lib/UserAgent/user_agent.py deleted file mode 100644 index b7c5b74..0000000 --- a/Src/Lib/UserAgent/user_agent.py +++ /dev/null @@ -1,112 +0,0 @@ -# 04.4.24 - -import logging -import re -import os -import random -import threading -import json -import tempfile - -from typing import Dict, List - - -# Internal libraries -from Src.Lib.Request import requests - - - -def get_browser_user_agents_online(browser: str) -> List[str]: - """ - Retrieve browser user agent strings from a website. - - Args: - - browser (str): The name of the browser (e.g., 'chrome', 'firefox', 'safari'). - - Returns: - List[str]: List of user agent strings for the specified browser. - """ - url = f"https://useragentstring.com/pages/{browser}/" - - try: - - # Make request and find all user agents - html = requests.get(url).text - browser_user_agents = re.findall(r"(.+?)", html, re.UNICODE) - return [ua for ua in browser_user_agents if "more" not in ua.lower()] - - except Exception as e: - logging.error(f"Failed to fetch user agents for '{browser}': {str(e)}") - return [] - - -def update_user_agents(browser_name: str, browser_user_agents: Dict[str, List[str]]) -> None: - """ - Update browser user agents dictionary with new requests. - - Args: - - browser_name (str): Name of the browser. - - browser_user_agents (Dict[str, List[str]]): Dictionary to store browser user agents. - """ - browser_user_agents[browser_name] = get_browser_user_agents_online(browser_name) - - -def create_or_update_user_agent_file() -> None: - """ - Create or update the user agent file with browser user agents. - """ - user_agent_file = os.path.join(tempfile.gettempdir(), 'fake_user_agent.json') - logging.info(f"Upload file: {user_agent_file}") - - if not os.path.exists(user_agent_file): - browser_user_agents: Dict[str, List[str]] = {} - threads = [] - - for browser_name in ['chrome', 'firefox', 'safari']: - t = threading.Thread(target=update_user_agents, args=(browser_name, browser_user_agents)) - threads.append(t) - t.start() - - for t in threads: - t.join() - - with open(user_agent_file, 'w') as f: - json.dump(browser_user_agents, f, indent=4) - logging.info(f"User agent file created at: {user_agent_file}") - - else: - logging.info("User agent file already exists.") - - -class UserAgentManager: - """ - Manager class to access browser user agents from a file. - """ - def __init__(self): - - # Get path to temp file where save all user agents - self.user_agent_file = os.path.join(tempfile.gettempdir(), 'fake_user_agent.json') - logging.info(f"Check file: {self.user_agent_file}") - - # If file dont exist, creaet it - if not os.path.exists(self.user_agent_file): - create_or_update_user_agent_file() - logging.info(f"Create file: {self.user_agent_file}") - - def get_random_user_agent(self, browser: str) -> str: - """ - Get a random user agent for the specified browser. - - Args: - browser (str): The name of the browser ('chrome', 'firefox', 'safari'). - - Returns: - Optional[str]: Random user agent string for the specified browser. - """ - with open(self.user_agent_file, 'r') as f: - browser_user_agents = json.load(f) - return random.choice(browser_user_agents.get(browser.lower(), [])) - - -# Output -ua: UserAgentManager = UserAgentManager() \ No newline at end of file diff --git a/Src/Upload/update.py b/Src/Upload/update.py index 7c6e4fa..6e3e543 100644 --- a/Src/Upload/update.py +++ b/Src/Upload/update.py @@ -10,7 +10,7 @@ from Src.Util.console import console # External library -from Src.Lib.Request import requests +import requests # Variable diff --git a/Src/Util/headers.py b/Src/Util/headers.py index ca76388..b84f4e9 100644 --- a/Src/Util/headers.py +++ b/Src/Util/headers.py @@ -3,8 +3,12 @@ import logging -# Internal utilities -from Src.Lib.UserAgent import ua +# External library +import fake_useragent + + +# Variable +useragent = fake_useragent.UserAgent() def get_headers() -> str: @@ -12,11 +16,8 @@ def get_headers() -> str: Generate a random user agent to use in HTTP requests. Returns: - str: A random user agent string. + - str: A random user agent string. """ # Get a random user agent string from the user agent rotator - random_headers = ua.get_random_user_agent("firefox") - - #logging.info(f"Use headers: {random_headers}") - return random_headers \ No newline at end of file + return useragent.firefox \ No newline at end of file diff --git a/Test/t_get_server_ip_sc.py b/Test/t_get_server_ip_sc.py index 02bebe8..d89ebac 100644 --- a/Test/t_get_server_ip_sc.py +++ b/Test/t_get_server_ip_sc.py @@ -11,7 +11,7 @@ warnings.filterwarnings("ignore", category=urllib3.exceptions.InsecureRequestWar # Variable -url_test = "https://sc-b1-18.scws-content.net/hls/170/3/25/32503b5b-4646-4376-ad47-7766c65be7e2/audio/ita/0004-0100.ts" +url_test = "https://sc-b1-18.scws-content.net/hls/100/b/d3/bd3a430d-0a13-4bec-8fcc-ea41af183555/audio/ita/0010-0100.ts?token=CiEPTIyvEoTkGk3szgDu9g&expires=1722801022" def get_ip_from_url(url): @@ -81,5 +81,6 @@ def main(): print(f"Valid IP addresses: {sorted(valid_ip, reverse=True)}") + if __name__ == '__main__': main() diff --git a/requirements.txt b/requirements.txt index 3f1f64e..d9a07e1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ -bs4 +requests +bs4 certifi tqdm rich -unidecode \ No newline at end of file +unidecode +fake-useragent \ No newline at end of file