diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index ea06d6d43..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: "[Bug Report] Short Form Subject (50 Chars or less)" -labels: bug report -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem please ensure that your screenshots are SFW or at least appropriately censored. - -**Stash Version: (from Settings -> About):** - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..0dc6d10a8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,64 @@ +name: Bug Report +description: Create a report to help us fix the bug +labels: ["bug report"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: textarea + id: description + attributes: + label: Describe the bug + description: Provide a clear and concise description of what the bug is. + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Steps to reproduce + description: Detail the steps that would replicate this issue. + placeholder: | + 1. Go to '...' + 2. Click on '....' + 3. Scroll down to '....' + 4. See error + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected behaviour + description: Provide clear and concise description of what you expected to happen. + validations: + required: true + - type: textarea + id: context + attributes: + label: Screenshots or additional context + description: Provide any additional context and SFW screenshots here to help us solve this issue. + validations: + required: false + - type: input + id: stashversion + attributes: + label: Stash version + description: This can be found in Settings > About. + placeholder: (e.g. v0.28.1) + validations: + required: true + - type: input + id: devicedetails + attributes: + label: Device details + description: | + If this is an issue that occurs when using the Stash interface, please provide details of the device/browser used which presents the reported issue. + placeholder: (e.g. Firefox 97 (64-bit) on Windows 11) + validations: + required: false + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output from Settings > Logs. This will be automatically formatted into code, so no need for backticks. + render: shell \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..028fdf8ac --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: Community forum + url: https://discourse.stashapp.cc + about: Start a discussion on the community forum. + - name: Community Discord + url: https://discord.gg/Y8MNsvQBvZ + about: Chat with the community on Discord. + - name: Documentation + url: https://docs.stashapp.cc + about: Check out documentation for help and information. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/discussion---request-for-commentary--rfc-.md b/.github/ISSUE_TEMPLATE/discussion---request-for-commentary--rfc-.md deleted file mode 100644 index b79564f83..000000000 --- a/.github/ISSUE_TEMPLATE/discussion---request-for-commentary--rfc-.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -name: Discussion / Request for Commentary [RFC] -about: This is for issues that will be discussed and won't necessarily result directly - in commits or pull requests. -title: "[RFC] Short Form Title" -labels: help wanted -assignees: '' - ---- - - - -## Long Form - - -## Examples - - -## Reference Reading - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index db5df9d8b..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: "[Feature] Short Form Title (50 chars or less.)" -labels: feature request -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..f139433c5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,44 @@ +name: Feature Request +description: Request a new feature or idea to be added to Stash +labels: ["feature request"] +body: + - type: textarea + id: description + attributes: + label: Describe the feature you'd like + description: Provide a clear description of the feature you'd like implemented + validations: + required: true + - type: textarea + id: benefits + attributes: + label: Describe the benefits this would bring to existing users + description: | + Explain the measurable benefits this feature would achieve for existing users. + The benefits should be described in terms of outcomes for users, not specific implementations. + validations: + required: true + - type: textarea + id: already_possible + attributes: + label: Is there an existing way to achieve this goal? + description: | + Yes/No. If Yes, describe how your proposed feature differs from or improves upon the current method + validations: + required: true + - type: checkboxes + id: confirm-search + attributes: + label: Have you searched for an existing open/closed issue? + description: | + To help us keep these issues under control, please ensure you have first [searched our issue list](https://github.com/stashapp/stash/issues?q=is%3Aissue) for any existing issues that cover the core request or benefit of your proposal. + options: + - label: I have searched for existing issues and none cover the core request of my proposal + required: true + - type: textarea + id: context + attributes: + label: Additional context + description: Add any other context or screenshots about the feature request here. + validations: + required: false \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 92c98effc..1e46ecd69 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,10 @@ name: Build on: push: - branches: [ develop, master ] + branches: + - develop + - master + - 'releases/**' pull_request: release: types: [ published ] @@ -12,7 +15,7 @@ concurrency: cancel-in-progress: true env: - COMPILER_IMAGE: stashapp/compiler:11 + COMPILER_IMAGE: stashapp/compiler:12 jobs: build: @@ -37,7 +40,7 @@ jobs: cache-name: cache-node_modules with: path: ui/v2.5/node_modules - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('ui/v2.5/yarn.lock') }} + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('ui/v2.5/pnpm-lock.yaml') }} - name: Cache UI build uses: actions/cache@v3 @@ -46,7 +49,7 @@ jobs: cache-name: cache-ui with: path: ui/v2.5/build - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('ui/v2.5/yarn.lock', 'ui/v2.5/public/**', 'ui/v2.5/src/**', 'graphql/**/*.graphql') }} + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('ui/v2.5/pnpm-lock.yaml', 'ui/v2.5/public/**', 'ui/v2.5/src/**', 'graphql/**/*.graphql') }} - name: Cache go build uses: actions/cache@v3 @@ -65,7 +68,7 @@ jobs: docker run -d --name build --mount type=bind,source="$(pwd)",target=/stash,consistency=delegated --mount type=bind,source="$(pwd)/.go-cache",target=/root/.cache/go-build,consistency=delegated --env OFFICIAL_BUILD=${{ env.official-build }} -w /stash $COMPILER_IMAGE tail -f /dev/null - name: Pre-install - run: docker exec -t build /bin/bash -c "make pre-ui" + run: docker exec -t build /bin/bash -c "make CI=1 pre-ui" - name: Generate run: docker exec -t build /bin/bash -c "make generate" diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 1b7838b62..71c743ced 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -6,10 +6,11 @@ on: branches: - master - develop + - 'releases/**' pull_request: env: - COMPILER_IMAGE: stashapp/compiler:11 + COMPILER_IMAGE: stashapp/compiler:12 jobs: golangci: diff --git a/.idea/go.iml b/.idea/go.iml index eddfcc6c3..86461b085 100644 --- a/.idea/go.iml +++ b/.idea/go.iml @@ -1,5 +1,6 @@ + @@ -10,4 +11,4 @@ - + \ No newline at end of file diff --git a/Makefile b/Makefile index b6d0a9e28..7e19063a3 100644 --- a/Makefile +++ b/Makefile @@ -275,7 +275,7 @@ generate: generate-backend generate-ui .PHONY: generate-ui generate-ui: - cd ui/v2.5 && yarn run gqlgen + cd ui/v2.5 && npm run gqlgen .PHONY: generate-backend generate-backend: touch-ui @@ -338,9 +338,19 @@ server-clean: # installs UI dependencies. Run when first cloning repository, or if UI # dependencies have changed +# If CI is set, configures pnpm to use a local store to avoid +# putting .pnpm-store in /stash +# NOTE: to run in the docker build container, using the existing +# node_modules folder, rename the .modules.yaml to .modules.yaml.bak +# and a new one will be generated. This will need to be reversed after +# building. .PHONY: pre-ui pre-ui: - cd ui/v2.5 && yarn install --frozen-lockfile +ifdef CI + cd ui/v2.5 && pnpm config set store-dir ~/.pnpm-store && pnpm install --frozen-lockfile +else + cd ui/v2.5 && pnpm install --frozen-lockfile +endif .PHONY: ui-env ui-env: build-info @@ -359,7 +369,7 @@ ui: ui-only generate-login-locale .PHONY: ui-only ui-only: ui-env - cd ui/v2.5 && yarn build + cd ui/v2.5 && npm run build .PHONY: zip-ui zip-ui: @@ -368,20 +378,24 @@ zip-ui: .PHONY: ui-start ui-start: ui-env - cd ui/v2.5 && yarn start --host + cd ui/v2.5 && npm run start -- --host .PHONY: fmt-ui fmt-ui: - cd ui/v2.5 && yarn format + cd ui/v2.5 && npm run format # runs all of the frontend PR-acceptance steps .PHONY: validate-ui validate-ui: - cd ui/v2.5 && yarn run validate + cd ui/v2.5 && npm run validate # these targets run the same steps as fmt-ui and validate-ui, but only on files that have changed fmt-ui-quick: - cd ui/v2.5 && yarn run prettier --write $$(git diff --name-only --relative --diff-filter d . ../../graphql) + cd ui/v2.5 && \ + files=$$(git diff --name-only --relative --diff-filter d . ../../graphql); \ + if [ -n "$$files" ]; then \ + npm run prettier -- --write $$files; \ + fi # does not run tsc checks, as they are slow validate-ui-quick: @@ -389,9 +403,9 @@ validate-ui-quick: tsfiles=$$(git diff --name-only --relative --diff-filter d src | grep -e "\.tsx\?\$$"); \ scssfiles=$$(git diff --name-only --relative --diff-filter d src | grep "\.scss"); \ prettyfiles=$$(git diff --name-only --relative --diff-filter d . ../../graphql); \ - if [ -n "$$tsfiles" ]; then yarn run eslint $$tsfiles; fi && \ - if [ -n "$$scssfiles" ]; then yarn run stylelint $$scssfiles; fi && \ - if [ -n "$$prettyfiles" ]; then yarn run prettier --check $$prettyfiles; fi + if [ -n "$$tsfiles" ]; then npm run eslint -- $$tsfiles; fi && \ + if [ -n "$$scssfiles" ]; then npm run stylelint -- $$scssfiles; fi && \ + if [ -n "$$prettyfiles" ]; then npm run prettier -- --check $$prettyfiles; fi # runs all of the backend PR-acceptance steps .PHONY: validate-backend diff --git a/README.md b/README.md index c54d94528..e47363395 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![GitHub release (latest by date)](https://img.shields.io/github/v/release/stashapp/stash?logo=github)](https://github.com/stashapp/stash/releases/latest) [![GitHub issues by-label](https://img.shields.io/github/issues-raw/stashapp/stash/bounty)](https://github.com/stashapp/stash/labels/bounty) -### **Stash is a self-hosted webapp written in Go which organizes and serves your porn.** +### **Stash is a self-hosted webapp written in Go which organizes and serves your diverse content collection, catering to both your SFW and NSFW needs.** ![demo image](docs/readme_assets/demo_image.png) * Stash gathers information about videos in your collection from the internet, and is extensible through the use of community-built plugins for a large number of content producers and sites. diff --git a/cmd/stash/main.go b/cmd/stash/main.go index 86edd6276..e3a54f020 100644 --- a/cmd/stash/main.go +++ b/cmd/stash/main.go @@ -110,7 +110,7 @@ func main() { // Logs only error level message to stderr. func initLogTemp() *log.Logger { l := log.NewLogger() - l.Init("", true, "Error") + l.Init("", true, "Error", 0) logger.Logger = l return l @@ -118,7 +118,7 @@ func initLogTemp() *log.Logger { func initLog(cfg *config.Config) *log.Logger { l := log.NewLogger() - l.Init(cfg.GetLogFile(), cfg.GetLogOut(), cfg.GetLogLevel()) + l.Init(cfg.GetLogFile(), cfg.GetLogOut(), cfg.GetLogLevel(), cfg.GetLogFileMaxSize()) logger.Logger = l return l diff --git a/docker/build/x86_64/Dockerfile b/docker/build/x86_64/Dockerfile index 4d153e8bc..163bd64b2 100644 --- a/docker/build/x86_64/Dockerfile +++ b/docker/build/x86_64/Dockerfile @@ -1,14 +1,16 @@ # This dockerfile should be built with `make docker-build` from the stash root. # Build Frontend -FROM node:20-alpine AS frontend +FROM node:24-alpine AS frontend RUN apk add --no-cache make git ## cache node_modules separately -COPY ./ui/v2.5/package.json ./ui/v2.5/yarn.lock /stash/ui/v2.5/ +COPY ./ui/v2.5/package.json ./ui/v2.5/pnpm-lock.yaml /stash/ui/v2.5/ WORKDIR /stash COPY Makefile /stash/ COPY ./graphql /stash/graphql/ COPY ./ui /stash/ui/ +# pnpm install with npm +RUN npm install -g pnpm RUN make pre-ui RUN make generate-ui ARG GITHASH diff --git a/docker/build/x86_64/Dockerfile-CUDA b/docker/build/x86_64/Dockerfile-CUDA index 4cab3f6c1..8a0b02e10 100644 --- a/docker/build/x86_64/Dockerfile-CUDA +++ b/docker/build/x86_64/Dockerfile-CUDA @@ -5,11 +5,13 @@ ARG CUDA_VERSION=12.8.0 FROM node:20-alpine AS frontend RUN apk add --no-cache make git ## cache node_modules separately -COPY ./ui/v2.5/package.json ./ui/v2.5/yarn.lock /stash/ui/v2.5/ +COPY ./ui/v2.5/package.json ./ui/v2.5/pnpm-lock.yaml /stash/ui/v2.5/ WORKDIR /stash COPY Makefile /stash/ COPY ./graphql /stash/graphql/ COPY ./ui /stash/ui/ +# pnpm install with npm +RUN npm install -g pnpm RUN make pre-ui RUN make generate-ui ARG GITHASH diff --git a/docker/ci/x86_64/Dockerfile b/docker/ci/x86_64/Dockerfile index f0f1e242b..6a9c6b76d 100644 --- a/docker/ci/x86_64/Dockerfile +++ b/docker/ci/x86_64/Dockerfile @@ -12,9 +12,8 @@ RUN if [ "$TARGETPLATFORM" = "linux/arm/v6" ]; then BIN=stash-linux-arm32v6; \ FROM --platform=$TARGETPLATFORM alpine:latest AS app COPY --from=binary /stash /usr/bin/ -RUN apk add --no-cache ca-certificates python3 py3-requests py3-requests-toolbelt py3-lxml py3-pip ffmpeg ruby tzdata vips vips-tools \ - && pip install --user --break-system-packages mechanicalsoup cloudscraper stashapp-tools \ - && gem install faraday +RUN apk add --no-cache ca-certificates python3 py3-requests py3-requests-toolbelt py3-lxml py3-pip ffmpeg tzdata vips vips-tools \ + && pip install --break-system-packages mechanicalsoup cloudscraper stashapp-tools ENV STASH_CONFIG_FILE=/root/.stash/config.yml # Basic build-time metadata as defined at https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys diff --git a/docker/compiler/Dockerfile b/docker/compiler/Dockerfile index 40b92c180..0154d7e61 100644 --- a/docker/compiler/Dockerfile +++ b/docker/compiler/Dockerfile @@ -8,15 +8,11 @@ RUN mkdir -p /etc/apt/keyrings ADD https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key nodesource.gpg.key RUN cat nodesource.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && rm nodesource.gpg.key -RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list - -ADD https://dl.yarnpkg.com/debian/pubkey.gpg yarn.gpg -RUN cat yarn.gpg | gpg --dearmor -o /etc/apt/keyrings/yarn.gpg && rm yarn.gpg -RUN echo "deb [signed-by=/etc/apt/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list +RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_24.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list RUN apt-get update && \ apt-get install -y --no-install-recommends \ - git make tar bash nodejs yarn zip \ + git make tar bash nodejs zip \ clang llvm-dev cmake patch libxml2-dev uuid-dev libssl-dev xz-utils \ bzip2 gzip sed cpio libbz2-dev zlib1g-dev \ gcc-mingw-w64 \ @@ -24,6 +20,9 @@ RUN apt-get update && \ gcc-aarch64-linux-gnu libc-dev-arm64-cross && \ rm -rf /var/lib/apt/lists/*; +# pnpm install with npm +RUN npm install -g pnpm + # FreeBSD cross-compilation setup # https://github.com/smartmontools/docker-build/blob/6b8c92560d17d325310ba02d9f5a4b250cb0764a/Dockerfile#L66 ENV FREEBSD_VERSION 13.4 diff --git a/docker/compiler/Makefile b/docker/compiler/Makefile index 275466640..ed6a9a285 100644 --- a/docker/compiler/Makefile +++ b/docker/compiler/Makefile @@ -1,6 +1,6 @@ user=stashapp repo=compiler -version=11 +version=12 latest: docker build -t ${user}/${repo}:latest . diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 4a1cf30df..85c2f6f23 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -5,7 +5,8 @@ * [Go](https://golang.org/dl/) * [GolangCI](https://golangci-lint.run/) - A meta-linter which runs several linters in parallel * To install, follow the [local installation instructions](https://golangci-lint.run/welcome/install/#local-installation) -* [Yarn](https://yarnpkg.com/en/docs/install) - Yarn package manager +* [nodejs](https://nodejs.org/en/download) - nodejs runtime + * corepack/[pnpm](https://pnpm.io/installation) - nodejs package manager (included with nodejs) ## Environment @@ -22,32 +23,22 @@ NOTE: The `make` command in Windows will be `mingw32-make` with MinGW. For examp ### macOS 1. If you don't have it already, install the [Homebrew package manager](https://brew.sh). -2. Install dependencies: `brew install go git yarn gcc make node ffmpeg` +2. Install dependencies: `brew install go git gcc make node ffmpeg` ### Linux #### Arch Linux -1. Install dependencies: `sudo pacman -S go git yarn gcc make nodejs ffmpeg --needed` +1. Install dependencies: `sudo pacman -S go git gcc make nodejs ffmpeg --needed` #### Ubuntu -1. Install dependencies: `sudo apt-get install golang git yarnpkg gcc nodejs ffmpeg -y` +1. Install dependencies: `sudo apt-get install golang git gcc nodejs ffmpeg -y` ### OpenBSD -1. Install dependencies `doas pkg_add gmake go git yarn node cmake` -2. Compile a custom ffmpeg from ports. The default ffmpeg in OpenBSD's packages is not compiled with WebP support, which is required by Stash. - - If you've already installed ffmpeg, uninstall it: `doas pkg_delete ffmpeg` - - If you haven't already, [fetch the ports tree and verify](https://www.openbsd.org/faq/ports/ports.html#PortsFetch). - - Find the ffmpeg port in `/usr/ports/graphics/ffmpeg`, and patch the Makefile to include libwebp - - Add `webp` to `WANTLIB` - - Add `graphics/libwebp` to the list in `LIB_DEPENDS` - - Add `-lwebp -lwebpdecoder -lwebpdemux -lwebpmux` to `LIBavcodec_EXTRALIBS` - - Add `--enable-libweb` to the list in `CONFIGURE_ARGS` - - If you've already built ffmpeg from ports before, you may need to also increment `REVISION` - - Run `doas make install` - - Follow the instructions below to build a release, but replace the final step `make build-release` with `gmake flags-release stash`, to [avoid the PIE buildmode](https://github.com/golang/go/issues/59866). +1. Install dependencies `doas pkg_add gmake go git node cmake ffmpeg` +2. Follow the instructions below to build a release, but replace the final step `make build-release` with `gmake flags-release stash`, to [avoid the PIE buildmode](https://github.com/golang/go/issues/59866). NOTE: The `make` command in OpenBSD will be `gmake`. For example, `make pre-ui` will be `gmake pre-ui`. diff --git a/go.mod b/go.mod index 268276841..4d6b78dc6 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/disintegration/imaging v1.6.2 github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d github.com/doug-martin/goqu/v9 v9.18.0 - github.com/go-chi/chi/v5 v5.0.12 + github.com/go-chi/chi/v5 v5.2.2 github.com/go-chi/cors v1.2.1 github.com/go-chi/httplog v0.3.1 github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 @@ -32,7 +32,11 @@ require ( github.com/json-iterator/go v1.1.12 github.com/kermieisinthehouse/gosx-notifier v0.1.2 github.com/kermieisinthehouse/systray v1.2.4 - github.com/knadh/koanf v1.5.0 + github.com/knadh/koanf/parsers/yaml v1.1.0 + github.com/knadh/koanf/providers/env v1.1.0 + github.com/knadh/koanf/providers/file v1.2.0 + github.com/knadh/koanf/providers/posflag v1.0.1 + github.com/knadh/koanf/v2 v2.2.1 github.com/lucasb-eyer/go-colorful v1.2.0 github.com/mattn/go-sqlite3 v1.14.22 github.com/mitchellh/mapstructure v1.5.0 @@ -42,7 +46,7 @@ require ( github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd github.com/sirupsen/logrus v1.9.3 github.com/spf13/cast v1.6.0 - github.com/spf13/pflag v1.0.5 + github.com/spf13/pflag v1.0.6 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.16.0 github.com/vearutop/statigz v1.4.0 @@ -59,6 +63,7 @@ require ( golang.org/x/text v0.25.0 golang.org/x/time v0.10.0 gopkg.in/guregu/null.v4 v4.0.0 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -72,9 +77,9 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect - github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/ws v1.3.0 // indirect @@ -86,6 +91,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/knadh/koanf/maps v0.1.2 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.14 // indirect @@ -114,6 +120,7 @@ require ( github.com/urfave/cli/v2 v2.27.6 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect go.uber.org/atomic v1.11.0 // indirect + go.yaml.in/yaml/v3 v3.0.3 // indirect golang.org/x/mod v0.24.0 // indirect golang.org/x/sync v0.14.0 // indirect golang.org/x/tools v0.33.0 // indirect diff --git a/go.sum b/go.sum index bbb38befb..bc84b1f23 100644 --- a/go.sum +++ b/go.sum @@ -72,7 +72,6 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/anacrolix/dms v1.2.2 h1:0mk2/DXNqa5KDDbaLgFPf3oMV6VCGdFNh3d/gt4oafM= github.com/anacrolix/dms v1.2.2/go.mod h1:msPKAoppoNRfrYplJqx63FZ+VipDZ4Xsj3KzIQxyU7k= github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= @@ -104,16 +103,6 @@ github.com/asticode/go-astisub v0.25.1 h1:RZMGfZPp7CXOkI6g+zCU7DRLuciGPGup921uKZ github.com/asticode/go-astisub v0.25.1/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2zLRVFf6bIFQK8= github.com/asticode/go-astits v1.8.0 h1:rf6aiiGn/QhlFjNON1n5plqF3Fs025XLUwiQ0NB6oZg= github.com/asticode/go-astits v1.8.0/go.mod h1:DkOWmBNQpnr9mv24KfZjq4JawCFX1FCqjLVGvO0DygQ= -github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= -github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw= -github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.6.0/go.mod h1:gqlclDEZp4aqJOancXK6TN24aKhT0W0Ae9MHk3wzTMM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.2.4/go.mod h1:ZcBrrI3zBKlhGFNYWvju0I3TR93I7YIgAfy82Fh4lcQ= -github.com/aws/aws-sdk-go-v2/service/appconfig v1.4.2/go.mod h1:FZ3HkCe+b10uFZZkFdvf98LHW21k49W8o8J366lqVKY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72HRZDLMtmVQiLG2tLfQcaWLCssELvGl+Zf2WVxMmR8= -github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk= -github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g= -github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -185,7 +174,6 @@ github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8 github.com/doug-martin/goqu/v9 v9.18.0 h1:/6bcuEtAe6nsSMVK/M+fOiXUNfyFF3yYtE07DBPFMYY= github.com/doug-martin/goqu/v9 v9.18.0/go.mod h1:nf0Wc2/hV3gYK9LiyqIrzBEVGlI8qW3GuDCEobC4wBQ= github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -200,19 +188,17 @@ github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= -github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618= +github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/httplog v0.3.1 h1:uC3IUWCZagtbCinb3ypFh36SEcgd6StWw2Bu0XSXRtg= @@ -222,22 +208,18 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE= github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4/go.mod h1:kW3HQ4UdaAyrUCSSDR4xUzBKW6O2iA4uHhk7AtyYp10= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= @@ -288,7 +270,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -305,7 +286,6 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -346,11 +326,9 @@ github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7Fsg github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -358,8 +336,6 @@ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= -github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -369,17 +345,12 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -394,14 +365,8 @@ github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q= -github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= -github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hasura/go-graphql-client v0.13.1 h1:kKbjhxhpwz58usVl+Xvgah/TDha5K2akNTRQdsEHN6U= github.com/hasura/go-graphql-client v0.13.1/go.mod h1:k7FF7h53C+hSNFRG3++DdVZWIuHdCaTbI7siTJ//zGQ= -github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs= -github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -412,18 +377,12 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= -github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -431,17 +390,25 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kermieisinthehouse/gosx-notifier v0.1.2 h1:KV0KBeKK2B24kIHY7iK0jgS64Q05f4oB+hUZmsPodxQ= github.com/kermieisinthehouse/gosx-notifier v0.1.2/go.mod h1:xyWT07azFtUOcHl96qMVvKhvKzsMcS7rKTHQyv8WTho= github.com/kermieisinthehouse/systray v1.2.4 h1:pdH5vnl+KKjRrVCRU4g/2W1/0HVzuuJ6WXHlPPHYY6s= github.com/kermieisinthehouse/systray v1.2.4/go.mod h1:axh6C/jNuSyC0QGtidZJURc9h+h41HNoMySoLVrhVR4= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs= -github.com/knadh/koanf v1.5.0/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs= +github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= +github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= +github.com/knadh/koanf/parsers/yaml v1.1.0 h1:3ltfm9ljprAHt4jxgeYLlFPmUaunuCgu1yILuTXRdM4= +github.com/knadh/koanf/parsers/yaml v1.1.0/go.mod h1:HHmcHXUrp9cOPcuC+2wrr44GTUB0EC+PyfN3HZD9tFg= +github.com/knadh/koanf/providers/env v1.1.0 h1:U2VXPY0f+CsNDkvdsG8GcsnK4ah85WwWyJgef9oQMSc= +github.com/knadh/koanf/providers/env v1.1.0/go.mod h1:QhHHHZ87h9JxJAn2czdEl6pdkNnDh/JS1Vtsyt65hTY= +github.com/knadh/koanf/providers/file v1.2.0 h1:hrUJ6Y9YOA49aNu/RSYzOTFlqzXSCpmYIDXI7OJU6+U= +github.com/knadh/koanf/providers/file v1.2.0/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA= +github.com/knadh/koanf/providers/posflag v1.0.1 h1:EnMxHSrPkYCFnKgBUl5KBgrjed8gVFrcXDzaW4l/C6Y= +github.com/knadh/koanf/providers/posflag v1.0.1/go.mod h1:3Wn3+YG3f4ljzRyCUgIwH7G0sZ1pMjCOsNBovrbKmAk= +github.com/knadh/koanf/v2 v2.2.1 h1:jaleChtw85y3UdBnI0wCqcg1sj1gPoz6D3caGNHtrNE= +github.com/knadh/koanf/v2 v2.2.1/go.mod h1:PSFru3ufQgTsI7IF+95rf9s8XA1+aHxKuO/W+dPoHEY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -492,22 +459,17 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -519,26 +481,20 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007 h1:Ohgj9L0EYOgXxkDp+bczlMBiulwmqYzQpvQNUdtt3oc= github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007/go.mod h1:wKCOWMb6iNlvKiOToY2cNuaovSXvIiv1zDi9QDR7aGQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -555,24 +511,17 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= -github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -590,8 +539,6 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= @@ -600,7 +547,6 @@ github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -621,8 +567,9 @@ github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= @@ -683,11 +630,8 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t github.com/zencoder/go-dash/v3 v3.0.2 h1:oP1+dOh+Gp57PkvdCyMfbHtrHaxfl3w4kR3KBBbuqQE= github.com/zencoder/go-dash/v3 v3.0.2/go.mod h1:30R5bKy1aUYY45yesjtZ9l8trNc2TwNqbS17WVQmCzk= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= -go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -701,6 +645,8 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= +go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -850,11 +796,9 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190415145633-3fd5a3612ccd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -866,12 +810,10 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -886,8 +828,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -895,7 +835,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -908,7 +847,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -931,7 +869,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -945,7 +882,6 @@ golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1068,7 +1004,6 @@ google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1132,11 +1067,9 @@ google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -1177,7 +1110,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1190,14 +1122,14 @@ gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -1214,4 +1146,3 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/gqlgen.yml b/gqlgen.yml index d3b8fc67f..b949d44dc 100644 --- a/gqlgen.yml +++ b/gqlgen.yml @@ -35,6 +35,8 @@ models: model: github.com/stashapp/stash/internal/api.BoolMap PluginConfigMap: model: github.com/stashapp/stash/internal/api.PluginConfigMap + File: + model: github.com/stashapp/stash/internal/api.File VideoFile: fields: # override float fields - #1572 diff --git a/graphql/schema/schema.graphql b/graphql/schema/schema.graphql index 51718aee3..2a9d067ae 100644 --- a/graphql/schema/schema.graphql +++ b/graphql/schema/schema.graphql @@ -6,6 +6,26 @@ type Query { findDefaultFilter(mode: FilterMode!): SavedFilter @deprecated(reason: "default filter now stored in UI config") + "Find a file by its id or path" + findFile(id: ID, path: String): BaseFile! + + "Queries for Files" + findFiles( + file_filter: FileFilterType + filter: FindFilterType + ids: [ID!] + ): FindFilesResultType! + + "Find a file by its id or path" + findFolder(id: ID, path: String): Folder! + + "Queries for Files" + findFolders( + folder_filter: FolderFilterType + filter: FindFilterType + ids: [ID!] + ): FindFoldersResultType! + "Find a scene by ID or Checksum" findScene(id: ID, checksum: String): Scene findSceneByHash(input: SceneHashInput!): Scene @@ -308,6 +328,7 @@ type Mutation { sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker + bulkSceneMarkerUpdate(input: BulkSceneMarkerUpdateInput!): [SceneMarker!] sceneMarkerDestroy(id: ID!): Boolean! sceneMarkersDestroy(ids: [ID!]!): Boolean! @@ -351,6 +372,7 @@ type Mutation { studioUpdate(input: StudioUpdateInput!): Studio studioDestroy(input: StudioDestroyInput!): Boolean! studiosDestroy(ids: [ID!]!): Boolean! + bulkStudioUpdate(input: BulkStudioUpdateInput!): [Studio!] movieCreate(input: MovieCreateInput!): Movie @deprecated(reason: "Use groupCreate instead") diff --git a/graphql/schema/types/config.graphql b/graphql/schema/types/config.graphql index 4d6d2080b..732296572 100644 --- a/graphql/schema/types/config.graphql +++ b/graphql/schema/types/config.graphql @@ -2,6 +2,8 @@ input SetupInput { "Empty to indicate $HOME/.stash/config.yml default" configLocation: String! stashes: [StashConfigInput!]! + "True if SFW content mode is enabled" + sfwContentMode: Boolean "Empty to indicate default" databaseFile: String! "Empty to indicate default" @@ -67,6 +69,8 @@ input ConfigGeneralInput { databasePath: String "Path to backup directory" backupDirectoryPath: String + "Path to trash directory - if set, deleted files will be moved here instead of being permanently deleted" + deleteTrashPath: String "Path to generated files" generatedPath: String "Path to import/export files" @@ -153,6 +157,8 @@ input ConfigGeneralInput { logLevel: String "Whether to log http access" logAccess: Boolean + "Maximum log size" + logFileMaxSize: Int "True if galleries should be created from folders with images" createGalleriesFromFolders: Boolean "Regex used to identify images as gallery covers" @@ -187,6 +193,8 @@ type ConfigGeneralResult { databasePath: String! "Path to backup directory" backupDirectoryPath: String! + "Path to trash directory - if set, deleted files will be moved here instead of being permanently deleted" + deleteTrashPath: String! "Path to generated files" generatedPath: String! "Path to import/export files" @@ -277,6 +285,8 @@ type ConfigGeneralResult { logLevel: String! "Whether to log http access" logAccess: Boolean! + "Maximum log size" + logFileMaxSize: Int! "Array of video file extensions" videoExtensions: [String!]! "Array of image file extensions" @@ -341,6 +351,9 @@ type ConfigImageLightboxResult { } input ConfigInterfaceInput { + "True if SFW content mode is enabled" + sfwContentMode: Boolean + "Ordered list of items that should be shown in the menu" menuItems: [String!] @@ -407,6 +420,9 @@ type ConfigDisableDropdownCreate { } type ConfigInterfaceResult { + "True if SFW content mode is enabled" + sfwContentMode: Boolean! + "Ordered list of items that should be shown in the menu" menuItems: [String!] diff --git a/graphql/schema/types/file.graphql b/graphql/schema/types/file.graphql index 8dea777bd..835479fad 100644 --- a/graphql/schema/types/file.graphql +++ b/graphql/schema/types/file.graphql @@ -7,8 +7,11 @@ type Folder { id: ID! path: String! - parent_folder_id: ID - zip_file_id: ID + parent_folder_id: ID @deprecated(reason: "Use parent_folder instead") + zip_file_id: ID @deprecated(reason: "Use zip_file instead") + + parent_folder: Folder + zip_file: BasicFile mod_time: Time! @@ -21,8 +24,32 @@ interface BaseFile { path: String! basename: String! - parent_folder_id: ID! - zip_file_id: ID + parent_folder_id: ID! @deprecated(reason: "Use parent_folder instead") + zip_file_id: ID @deprecated(reason: "Use zip_file instead") + + parent_folder: Folder! + zip_file: BasicFile + + mod_time: Time! + size: Int64! + + fingerprint(type: String!): String + fingerprints: [Fingerprint!]! + + created_at: Time! + updated_at: Time! +} + +type BasicFile implements BaseFile { + id: ID! + path: String! + basename: String! + + parent_folder_id: ID! @deprecated(reason: "Use parent_folder instead") + zip_file_id: ID @deprecated(reason: "Use zip_file instead") + + parent_folder: Folder! + zip_file: BasicFile mod_time: Time! size: Int64! @@ -39,8 +66,11 @@ type VideoFile implements BaseFile { path: String! basename: String! - parent_folder_id: ID! - zip_file_id: ID + parent_folder_id: ID! @deprecated(reason: "Use parent_folder instead") + zip_file_id: ID @deprecated(reason: "Use zip_file instead") + + parent_folder: Folder! + zip_file: BasicFile mod_time: Time! size: Int64! @@ -66,8 +96,11 @@ type ImageFile implements BaseFile { path: String! basename: String! - parent_folder_id: ID! - zip_file_id: ID + parent_folder_id: ID! @deprecated(reason: "Use parent_folder instead") + zip_file_id: ID @deprecated(reason: "Use zip_file instead") + + parent_folder: Folder! + zip_file: BasicFile mod_time: Time! size: Int64! @@ -75,6 +108,7 @@ type ImageFile implements BaseFile { fingerprint(type: String!): String fingerprints: [Fingerprint!]! + format: String! width: Int! height: Int! @@ -89,8 +123,11 @@ type GalleryFile implements BaseFile { path: String! basename: String! - parent_folder_id: ID! - zip_file_id: ID + parent_folder_id: ID! @deprecated(reason: "Use parent_folder instead") + zip_file_id: ID @deprecated(reason: "Use zip_file instead") + + parent_folder: Folder! + zip_file: BasicFile mod_time: Time! size: Int64! @@ -125,3 +162,22 @@ input FileSetFingerprintsInput { "only supplied fingerprint types will be modified" fingerprints: [SetFingerprintsInput!]! } + +type FindFilesResultType { + count: Int! + + "Total megapixels of any image files" + megapixels: Float! + "Total duration in seconds of any video files" + duration: Float! + + "Total file size in bytes" + size: Int! + + files: [BaseFile!]! +} + +type FindFoldersResultType { + count: Int! + folders: [Folder!]! +} diff --git a/graphql/schema/types/filters.graphql b/graphql/schema/types/filters.graphql index 14bb8680b..4eb91aa77 100644 --- a/graphql/schema/types/filters.graphql +++ b/graphql/schema/types/filters.graphql @@ -330,6 +330,8 @@ input SceneFilterType { groups_filter: GroupFilterType "Filter by related markers that meet this criteria" markers_filter: SceneMarkerFilterType + "Filter by related files that meet this criteria" + files_filter: FileFilterType } input MovieFilterType { @@ -401,6 +403,8 @@ input GroupFilterType { created_at: TimestampCriterionInput "Filter by last update time" updated_at: TimestampCriterionInput + "Filter by o-counter" + o_counter: IntCriterionInput "Filter by containing groups" containing_groups: HierarchicalMultiCriterionInput @@ -534,6 +538,10 @@ input GalleryFilterType { studios_filter: StudioFilterType "Filter by related tags that meet this criteria" tags_filter: TagFilterType + "Filter by related files that meet this criteria" + files_filter: FileFilterType + "Filter by related folders that meet this criteria" + folders_filter: FolderFilterType } input TagFilterType { @@ -679,6 +687,106 @@ input ImageFilterType { studios_filter: StudioFilterType "Filter by related tags that meet this criteria" tags_filter: TagFilterType + "Filter by related files that meet this criteria" + files_filter: FileFilterType +} + +input FileFilterType { + AND: FileFilterType + OR: FileFilterType + NOT: FileFilterType + + path: StringCriterionInput + basename: StringCriterionInput + dir: StringCriterionInput + + parent_folder: HierarchicalMultiCriterionInput + zip_file: MultiCriterionInput + + "Filter by modification time" + mod_time: TimestampCriterionInput + + "Filter files that have an exact match available" + duplicated: PHashDuplicationCriterionInput + + "find files based on hash" + hashes: [FingerprintFilterInput!] + + video_file_filter: VideoFileFilterInput + image_file_filter: ImageFileFilterInput + + scene_count: IntCriterionInput + image_count: IntCriterionInput + gallery_count: IntCriterionInput + + "Filter by related scenes that meet this criteria" + scenes_filter: SceneFilterType + "Filter by related images that meet this criteria" + images_filter: ImageFilterType + "Filter by related galleries that meet this criteria" + galleries_filter: GalleryFilterType + + "Filter by creation time" + created_at: TimestampCriterionInput + "Filter by last update time" + updated_at: TimestampCriterionInput +} + +input FolderFilterType { + AND: FolderFilterType + OR: FolderFilterType + NOT: FolderFilterType + + path: StringCriterionInput + + parent_folder: HierarchicalMultiCriterionInput + zip_file: MultiCriterionInput + + "Filter by modification time" + mod_time: TimestampCriterionInput + + gallery_count: IntCriterionInput + + "Filter by files that meet this criteria" + files_filter: FileFilterType + "Filter by related galleries that meet this criteria" + galleries_filter: GalleryFilterType + + "Filter by creation time" + created_at: TimestampCriterionInput + "Filter by last update time" + updated_at: TimestampCriterionInput +} + +input VideoFileFilterInput { + resolution: ResolutionCriterionInput + orientation: OrientationCriterionInput + framerate: IntCriterionInput + bitrate: IntCriterionInput + format: StringCriterionInput + video_codec: StringCriterionInput + audio_codec: StringCriterionInput + + "in seconds" + duration: IntCriterionInput + + captions: StringCriterionInput + + interactive: Boolean + interactive_speed: IntCriterionInput +} + +input ImageFileFilterInput { + format: StringCriterionInput + resolution: ResolutionCriterionInput + orientation: OrientationCriterionInput +} + +input FingerprintFilterInput { + type: String! + value: String! + "Hamming distance - defaults to 0" + distance: Int } enum CriterionModifier { diff --git a/graphql/schema/types/group.graphql b/graphql/schema/types/group.graphql index 35fc17a68..a46932054 100644 --- a/graphql/schema/types/group.graphql +++ b/graphql/schema/types/group.graphql @@ -30,6 +30,7 @@ type Group { performer_count(depth: Int): Int! # Resolver sub_group_count(depth: Int): Int! # Resolver scenes: [Scene!]! + o_counter: Int # Resolver } input GroupDescriptionInput { diff --git a/graphql/schema/types/scene-marker.graphql b/graphql/schema/types/scene-marker.graphql index 6d1441213..9312c5aa3 100644 --- a/graphql/schema/types/scene-marker.graphql +++ b/graphql/schema/types/scene-marker.graphql @@ -42,6 +42,13 @@ input SceneMarkerUpdateInput { tag_ids: [ID!] } +input BulkSceneMarkerUpdateInput { + ids: [ID!] + title: String + primary_tag_id: ID + tag_ids: BulkUpdateIds +} + type FindSceneMarkersResultType { count: Int! scene_markers: [SceneMarker!]! diff --git a/graphql/schema/types/scraper.graphql b/graphql/schema/types/scraper.graphql index 8d430be5f..2c13872f3 100644 --- a/graphql/schema/types/scraper.graphql +++ b/graphql/schema/types/scraper.graphql @@ -55,9 +55,14 @@ type ScrapedStudio { "Set if studio matched" stored_id: ID name: String! - url: String + url: String @deprecated(reason: "use urls") + urls: [String!] parent: ScrapedStudio image: String + details: String + "Aliases must be comma-delimited to be parsed correctly" + aliases: String + tags: [ScrapedTag!] remote_site_id: String } @@ -66,6 +71,8 @@ type ScrapedTag { "Set if tag matched" stored_id: ID name: String! + "Remote site ID, if applicable" + remote_site_id: String } type ScrapedScene { diff --git a/graphql/schema/types/studio.graphql b/graphql/schema/types/studio.graphql index 7823bf0c4..4c5778c5b 100644 --- a/graphql/schema/types/studio.graphql +++ b/graphql/schema/types/studio.graphql @@ -1,7 +1,8 @@ type Studio { id: ID! name: String! - url: String + url: String @deprecated(reason: "Use urls") + urls: [String!]! parent_studio: Studio child_studios: [Studio!]! aliases: [String!]! @@ -24,11 +25,13 @@ type Studio { updated_at: Time! groups: [Group!]! movies: [Movie!]! @deprecated(reason: "use groups instead") + o_counter: Int } input StudioCreateInput { name: String! - url: String + url: String @deprecated(reason: "Use urls") + urls: [String!] parent_id: ID "This should be a URL or a base64 encoded data URL" image: String @@ -45,7 +48,8 @@ input StudioCreateInput { input StudioUpdateInput { id: ID! name: String - url: String + url: String @deprecated(reason: "Use urls") + urls: [String!] parent_id: ID "This should be a URL or a base64 encoded data URL" image: String @@ -59,6 +63,19 @@ input StudioUpdateInput { ignore_auto_tag: Boolean } +input BulkStudioUpdateInput { + ids: [ID!]! + url: String @deprecated(reason: "Use urls") + urls: BulkUpdateStrings + parent_id: ID + # rating expressed as 1-100 + rating100: Int + favorite: Boolean + details: String + tag_ids: BulkUpdateIds + ignore_auto_tag: Boolean +} + input StudioDestroyInput { id: ID! } diff --git a/graphql/schema/types/tag.graphql b/graphql/schema/types/tag.graphql index 504f23e3d..8424ab92a 100644 --- a/graphql/schema/types/tag.graphql +++ b/graphql/schema/types/tag.graphql @@ -9,6 +9,7 @@ type Tag { created_at: Time! updated_at: Time! favorite: Boolean! + stash_ids: [StashID!]! image_path: String # Resolver scene_count(depth: Int): Int! # Resolver scene_marker_count(depth: Int): Int! # Resolver @@ -35,6 +36,7 @@ input TagCreateInput { favorite: Boolean "This should be a URL or a base64 encoded data URL" image: String + stash_ids: [StashIDInput!] parent_ids: [ID!] child_ids: [ID!] @@ -51,6 +53,7 @@ input TagUpdateInput { favorite: Boolean "This should be a URL or a base64 encoded data URL" image: String + stash_ids: [StashIDInput!] parent_ids: [ID!] child_ids: [ID!] diff --git a/graphql/stash-box/query.graphql b/graphql/stash-box/query.graphql index f7528e728..4fa023070 100644 --- a/graphql/stash-box/query.graphql +++ b/graphql/stash-box/query.graphql @@ -13,6 +13,7 @@ fragment ImageFragment on Image { fragment StudioFragment on Studio { name id + aliases urls { ...URLFragment } diff --git a/internal/api/check_version.go b/internal/api/check_version.go index 6279997d7..f4c2950f1 100644 --- a/internal/api/check_version.go +++ b/internal/api/check_version.go @@ -7,8 +7,10 @@ import ( "fmt" "io" "net/http" + "os" "regexp" "runtime" + "strings" "time" "golang.org/x/sys/cpu" @@ -36,6 +38,24 @@ var stashReleases = func() map[string]string { } } +// isMacOSBundle checks if the application is running from within a macOS .app bundle +func isMacOSBundle() bool { + exec, err := os.Executable() + return err == nil && strings.Contains(exec, "Stash.app/") +} + +// getWantedRelease determines which release variant to download based on platform and bundle type +func getWantedRelease(platform string) string { + release := stashReleases()[platform] + + // On macOS, check if running from .app bundle + if runtime.GOOS == "darwin" && isMacOSBundle() { + return "Stash.app.zip" + } + + return release +} + type githubReleasesResponse struct { Url string Assets_url string @@ -168,7 +188,7 @@ func GetLatestRelease(ctx context.Context) (*LatestRelease, error) { } platform := fmt.Sprintf("%s/%s", runtime.GOOS, arch) - wantedRelease := stashReleases()[platform] + wantedRelease := getWantedRelease(platform) url := apiReleases if build.IsDevelop() { diff --git a/internal/api/fields.go b/internal/api/fields.go new file mode 100644 index 000000000..5f47ed06f --- /dev/null +++ b/internal/api/fields.go @@ -0,0 +1,23 @@ +package api + +import ( + "context" + + "github.com/99designs/gqlgen/graphql" +) + +type queryFields []string + +func collectQueryFields(ctx context.Context) queryFields { + fields := graphql.CollectAllFields(ctx) + return queryFields(fields) +} + +func (f queryFields) Has(field string) bool { + for _, v := range f { + if v == field { + return true + } + } + return false +} diff --git a/internal/api/images.go b/internal/api/images.go index 89a8e87b0..9e16fc0df 100644 --- a/internal/api/images.go +++ b/internal/api/images.go @@ -101,7 +101,7 @@ func initCustomPerformerImages(customPath string) { } } -func getDefaultPerformerImage(name string, gender *models.GenderEnum) []byte { +func getDefaultPerformerImage(name string, gender *models.GenderEnum, sfwMode bool) []byte { // try the custom box first if we have one if performerBoxCustom != nil { ret, err := performerBoxCustom.GetRandomImageByName(name) @@ -111,6 +111,10 @@ func getDefaultPerformerImage(name string, gender *models.GenderEnum) []byte { logger.Warnf("error loading custom default performer image: %v", err) } + if sfwMode { + return static.ReadAll(static.DefaultSFWPerformerImage) + } + var g models.GenderEnum if gender != nil { g = *gender diff --git a/internal/api/loaders/dataloaders.go b/internal/api/loaders/dataloaders.go index 493c353d7..38f72b0a1 100644 --- a/internal/api/loaders/dataloaders.go +++ b/internal/api/loaders/dataloaders.go @@ -10,6 +10,7 @@ //go:generate go run github.com/vektah/dataloaden TagLoader int *github.com/stashapp/stash/pkg/models.Tag //go:generate go run github.com/vektah/dataloaden GroupLoader int *github.com/stashapp/stash/pkg/models.Group //go:generate go run github.com/vektah/dataloaden FileLoader github.com/stashapp/stash/pkg/models.FileID github.com/stashapp/stash/pkg/models.File +//go:generate go run github.com/vektah/dataloaden FolderLoader github.com/stashapp/stash/pkg/models.FolderID *github.com/stashapp/stash/pkg/models.Folder //go:generate go run github.com/vektah/dataloaden SceneFileIDsLoader int []github.com/stashapp/stash/pkg/models.FileID //go:generate go run github.com/vektah/dataloaden ImageFileIDsLoader int []github.com/stashapp/stash/pkg/models.FileID //go:generate go run github.com/vektah/dataloaden GalleryFileIDsLoader int []github.com/stashapp/stash/pkg/models.FileID @@ -62,6 +63,7 @@ type Loaders struct { TagByID *TagLoader GroupByID *GroupLoader FileByID *FileLoader + FolderByID *FolderLoader } type Middleware struct { @@ -117,6 +119,11 @@ func (m Middleware) Middleware(next http.Handler) http.Handler { maxBatch: maxBatch, fetch: m.fetchFiles(ctx), }, + FolderByID: &FolderLoader{ + wait: wait, + maxBatch: maxBatch, + fetch: m.fetchFolders(ctx), + }, SceneFiles: &SceneFileIDsLoader{ wait: wait, maxBatch: maxBatch, @@ -279,6 +286,17 @@ func (m Middleware) fetchFiles(ctx context.Context) func(keys []models.FileID) ( } } +func (m Middleware) fetchFolders(ctx context.Context) func(keys []models.FolderID) ([]*models.Folder, []error) { + return func(keys []models.FolderID) (ret []*models.Folder, errs []error) { + err := m.Repository.WithDB(ctx, func(ctx context.Context) error { + var err error + ret, err = m.Repository.Folder.FindMany(ctx, keys) + return err + }) + return ret, toErrorSlice(err) + } +} + func (m Middleware) fetchScenesFileIDs(ctx context.Context) func(keys []int) ([][]models.FileID, []error) { return func(keys []int) (ret [][]models.FileID, errs []error) { err := m.Repository.WithDB(ctx, func(ctx context.Context) error { diff --git a/internal/api/loaders/folderloader_gen.go b/internal/api/loaders/folderloader_gen.go new file mode 100644 index 000000000..ca2518b82 --- /dev/null +++ b/internal/api/loaders/folderloader_gen.go @@ -0,0 +1,224 @@ +// Code generated by github.com/vektah/dataloaden, DO NOT EDIT. + +package loaders + +import ( + "sync" + "time" + + "github.com/stashapp/stash/pkg/models" +) + +// FolderLoaderConfig captures the config to create a new FolderLoader +type FolderLoaderConfig struct { + // Fetch is a method that provides the data for the loader + Fetch func(keys []models.FolderID) ([]*models.Folder, []error) + + // Wait is how long wait before sending a batch + Wait time.Duration + + // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit + MaxBatch int +} + +// NewFolderLoader creates a new FolderLoader given a fetch, wait, and maxBatch +func NewFolderLoader(config FolderLoaderConfig) *FolderLoader { + return &FolderLoader{ + fetch: config.Fetch, + wait: config.Wait, + maxBatch: config.MaxBatch, + } +} + +// FolderLoader batches and caches requests +type FolderLoader struct { + // this method provides the data for the loader + fetch func(keys []models.FolderID) ([]*models.Folder, []error) + + // how long to done before sending a batch + wait time.Duration + + // this will limit the maximum number of keys to send in one batch, 0 = no limit + maxBatch int + + // INTERNAL + + // lazily created cache + cache map[models.FolderID]*models.Folder + + // the current batch. keys will continue to be collected until timeout is hit, + // then everything will be sent to the fetch method and out to the listeners + batch *folderLoaderBatch + + // mutex to prevent races + mu sync.Mutex +} + +type folderLoaderBatch struct { + keys []models.FolderID + data []*models.Folder + error []error + closing bool + done chan struct{} +} + +// Load a Folder by key, batching and caching will be applied automatically +func (l *FolderLoader) Load(key models.FolderID) (*models.Folder, error) { + return l.LoadThunk(key)() +} + +// LoadThunk returns a function that when called will block waiting for a Folder. +// This method should be used if you want one goroutine to make requests to many +// different data loaders without blocking until the thunk is called. +func (l *FolderLoader) LoadThunk(key models.FolderID) func() (*models.Folder, error) { + l.mu.Lock() + if it, ok := l.cache[key]; ok { + l.mu.Unlock() + return func() (*models.Folder, error) { + return it, nil + } + } + if l.batch == nil { + l.batch = &folderLoaderBatch{done: make(chan struct{})} + } + batch := l.batch + pos := batch.keyIndex(l, key) + l.mu.Unlock() + + return func() (*models.Folder, error) { + <-batch.done + + var data *models.Folder + if pos < len(batch.data) { + data = batch.data[pos] + } + + var err error + // its convenient to be able to return a single error for everything + if len(batch.error) == 1 { + err = batch.error[0] + } else if batch.error != nil { + err = batch.error[pos] + } + + if err == nil { + l.mu.Lock() + l.unsafeSet(key, data) + l.mu.Unlock() + } + + return data, err + } +} + +// LoadAll fetches many keys at once. It will be broken into appropriate sized +// sub batches depending on how the loader is configured +func (l *FolderLoader) LoadAll(keys []models.FolderID) ([]*models.Folder, []error) { + results := make([]func() (*models.Folder, error), len(keys)) + + for i, key := range keys { + results[i] = l.LoadThunk(key) + } + + folders := make([]*models.Folder, len(keys)) + errors := make([]error, len(keys)) + for i, thunk := range results { + folders[i], errors[i] = thunk() + } + return folders, errors +} + +// LoadAllThunk returns a function that when called will block waiting for a Folders. +// This method should be used if you want one goroutine to make requests to many +// different data loaders without blocking until the thunk is called. +func (l *FolderLoader) LoadAllThunk(keys []models.FolderID) func() ([]*models.Folder, []error) { + results := make([]func() (*models.Folder, error), len(keys)) + for i, key := range keys { + results[i] = l.LoadThunk(key) + } + return func() ([]*models.Folder, []error) { + folders := make([]*models.Folder, len(keys)) + errors := make([]error, len(keys)) + for i, thunk := range results { + folders[i], errors[i] = thunk() + } + return folders, errors + } +} + +// Prime the cache with the provided key and value. If the key already exists, no change is made +// and false is returned. +// (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) +func (l *FolderLoader) Prime(key models.FolderID, value *models.Folder) bool { + l.mu.Lock() + var found bool + if _, found = l.cache[key]; !found { + // make a copy when writing to the cache, its easy to pass a pointer in from a loop var + // and end up with the whole cache pointing to the same value. + cpy := *value + l.unsafeSet(key, &cpy) + } + l.mu.Unlock() + return !found +} + +// Clear the value at key from the cache, if it exists +func (l *FolderLoader) Clear(key models.FolderID) { + l.mu.Lock() + delete(l.cache, key) + l.mu.Unlock() +} + +func (l *FolderLoader) unsafeSet(key models.FolderID, value *models.Folder) { + if l.cache == nil { + l.cache = map[models.FolderID]*models.Folder{} + } + l.cache[key] = value +} + +// keyIndex will return the location of the key in the batch, if its not found +// it will add the key to the batch +func (b *folderLoaderBatch) keyIndex(l *FolderLoader, key models.FolderID) int { + for i, existingKey := range b.keys { + if key == existingKey { + return i + } + } + + pos := len(b.keys) + b.keys = append(b.keys, key) + if pos == 0 { + go b.startTimer(l) + } + + if l.maxBatch != 0 && pos >= l.maxBatch-1 { + if !b.closing { + b.closing = true + l.batch = nil + go b.end(l) + } + } + + return pos +} + +func (b *folderLoaderBatch) startTimer(l *FolderLoader) { + time.Sleep(l.wait) + l.mu.Lock() + + // we must have hit a batch limit and are already finalizing this batch + if b.closing { + l.mu.Unlock() + return + } + + l.batch = nil + l.mu.Unlock() + + b.end(l) +} + +func (b *folderLoaderBatch) end(l *FolderLoader) { + b.data, b.error = l.fetch(b.keys) + close(b.done) +} diff --git a/internal/api/models.go b/internal/api/models.go index d8f4dc63c..1c7346697 100644 --- a/internal/api/models.go +++ b/internal/api/models.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/sliceutil" ) type BaseFile interface { @@ -27,6 +28,29 @@ func convertVisualFile(f models.File) (VisualFile, error) { } } +func convertBaseFile(f models.File) BaseFile { + if f == nil { + return nil + } + + switch f := f.(type) { + case BaseFile: + return f + case *models.VideoFile: + return &VideoFile{VideoFile: f} + case *models.ImageFile: + return &ImageFile{ImageFile: f} + case *models.BaseFile: + return &BasicFile{BaseFile: f} + default: + panic("unknown file type") + } +} + +func convertBaseFiles(files []models.File) []BaseFile { + return sliceutil.Map(files, convertBaseFile) +} + type GalleryFile struct { *models.BaseFile } @@ -62,3 +86,15 @@ func (ImageFile) IsVisualFile() {} func (f *ImageFile) Fingerprints() []models.Fingerprint { return f.ImageFile.Fingerprints } + +type BasicFile struct { + *models.BaseFile +} + +func (BasicFile) IsBaseFile() {} + +func (BasicFile) IsVisualFile() {} + +func (f *BasicFile) Fingerprints() []models.Fingerprint { + return f.BaseFile.Fingerprints +} diff --git a/internal/api/resolver.go b/internal/api/resolver.go index f3097969d..061d0e1a9 100644 --- a/internal/api/resolver.go +++ b/internal/api/resolver.go @@ -95,6 +95,12 @@ func (r *Resolver) VideoFile() VideoFileResolver { func (r *Resolver) ImageFile() ImageFileResolver { return &imageFileResolver{r} } +func (r *Resolver) BasicFile() BasicFileResolver { + return &basicFileResolver{r} +} +func (r *Resolver) Folder() FolderResolver { + return &folderResolver{r} +} func (r *Resolver) SavedFilter() SavedFilterResolver { return &savedFilterResolver{r} } @@ -125,6 +131,8 @@ type tagResolver struct{ *Resolver } type galleryFileResolver struct{ *Resolver } type videoFileResolver struct{ *Resolver } type imageFileResolver struct{ *Resolver } +type basicFileResolver struct{ *Resolver } +type folderResolver struct{ *Resolver } type savedFilterResolver struct{ *Resolver } type pluginResolver struct{ *Resolver } type configResultResolver struct{ *Resolver } diff --git a/internal/api/resolver_model_file.go b/internal/api/resolver_model_file.go index 35013cfbd..4b9995311 100644 --- a/internal/api/resolver_model_file.go +++ b/internal/api/resolver_model_file.go @@ -1,30 +1,80 @@ package api -import "context" +import ( + "context" -func (r *galleryFileResolver) Fingerprint(ctx context.Context, obj *GalleryFile, type_ string) (*string, error) { - fp := obj.BaseFile.Fingerprints.For(type_) - if fp != nil { - v := fp.Value() - return &v, nil + "github.com/stashapp/stash/internal/api/loaders" + "github.com/stashapp/stash/pkg/models" +) + +func fingerprintResolver(fp models.Fingerprints, type_ string) (*string, error) { + fingerprint := fp.For(type_) + if fingerprint != nil { + value := fingerprint.Value() + return &value, nil } return nil, nil } +func (r *galleryFileResolver) Fingerprint(ctx context.Context, obj *GalleryFile, type_ string) (*string, error) { + return fingerprintResolver(obj.BaseFile.Fingerprints, type_) +} + func (r *imageFileResolver) Fingerprint(ctx context.Context, obj *ImageFile, type_ string) (*string, error) { - fp := obj.ImageFile.Fingerprints.For(type_) - if fp != nil { - v := fp.Value() - return &v, nil - } - return nil, nil + return fingerprintResolver(obj.ImageFile.Fingerprints, type_) } func (r *videoFileResolver) Fingerprint(ctx context.Context, obj *VideoFile, type_ string) (*string, error) { - fp := obj.VideoFile.Fingerprints.For(type_) - if fp != nil { - v := fp.Value() - return &v, nil - } - return nil, nil + return fingerprintResolver(obj.VideoFile.Fingerprints, type_) +} + +func (r *basicFileResolver) Fingerprint(ctx context.Context, obj *BasicFile, type_ string) (*string, error) { + return fingerprintResolver(obj.BaseFile.Fingerprints, type_) +} + +func (r *galleryFileResolver) ParentFolder(ctx context.Context, obj *GalleryFile) (*models.Folder, error) { + return loaders.From(ctx).FolderByID.Load(obj.ParentFolderID) +} + +func (r *imageFileResolver) ParentFolder(ctx context.Context, obj *ImageFile) (*models.Folder, error) { + return loaders.From(ctx).FolderByID.Load(obj.ParentFolderID) +} + +func (r *videoFileResolver) ParentFolder(ctx context.Context, obj *VideoFile) (*models.Folder, error) { + return loaders.From(ctx).FolderByID.Load(obj.ParentFolderID) +} + +func (r *basicFileResolver) ParentFolder(ctx context.Context, obj *BasicFile) (*models.Folder, error) { + return loaders.From(ctx).FolderByID.Load(obj.ParentFolderID) +} + +func zipFileResolver(ctx context.Context, zipFileID *models.FileID) (*BasicFile, error) { + if zipFileID == nil { + return nil, nil + } + + f, err := loaders.From(ctx).FileByID.Load(*zipFileID) + if err != nil { + return nil, err + } + + return &BasicFile{ + BaseFile: f.Base(), + }, nil +} + +func (r *galleryFileResolver) ZipFile(ctx context.Context, obj *GalleryFile) (*BasicFile, error) { + return zipFileResolver(ctx, obj.ZipFileID) +} + +func (r *imageFileResolver) ZipFile(ctx context.Context, obj *ImageFile) (*BasicFile, error) { + return zipFileResolver(ctx, obj.ZipFileID) +} + +func (r *videoFileResolver) ZipFile(ctx context.Context, obj *VideoFile) (*BasicFile, error) { + return zipFileResolver(ctx, obj.ZipFileID) +} + +func (r *basicFileResolver) ZipFile(ctx context.Context, obj *BasicFile) (*BasicFile, error) { + return zipFileResolver(ctx, obj.ZipFileID) } diff --git a/internal/api/resolver_model_folder.go b/internal/api/resolver_model_folder.go new file mode 100644 index 000000000..ee6bbfd05 --- /dev/null +++ b/internal/api/resolver_model_folder.go @@ -0,0 +1,20 @@ +package api + +import ( + "context" + + "github.com/stashapp/stash/internal/api/loaders" + "github.com/stashapp/stash/pkg/models" +) + +func (r *folderResolver) ParentFolder(ctx context.Context, obj *models.Folder) (*models.Folder, error) { + if obj.ParentFolderID == nil { + return nil, nil + } + + return loaders.From(ctx).FolderByID.Load(*obj.ParentFolderID) +} + +func (r *folderResolver) ZipFile(ctx context.Context, obj *models.Folder) (*BasicFile, error) { + return zipFileResolver(ctx, obj.ZipFileID) +} diff --git a/internal/api/resolver_model_movie.go b/internal/api/resolver_model_movie.go index e3fba57c0..317123c6e 100644 --- a/internal/api/resolver_model_movie.go +++ b/internal/api/resolver_model_movie.go @@ -204,3 +204,14 @@ func (r *groupResolver) Scenes(ctx context.Context, obj *models.Group) (ret []*m return ret, nil } + +func (r *groupResolver) OCounter(ctx context.Context, obj *models.Group) (ret *int, err error) { + var count int + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + count, err = r.repository.Scene.OCountByGroupID(ctx, obj.ID) + return err + }); err != nil { + return nil, err + } + return &count, nil +} diff --git a/internal/api/resolver_model_studio.go b/internal/api/resolver_model_studio.go index 2111039c8..fabcf38bd 100644 --- a/internal/api/resolver_model_studio.go +++ b/internal/api/resolver_model_studio.go @@ -40,6 +40,35 @@ func (r *studioResolver) Aliases(ctx context.Context, obj *models.Studio) ([]str return obj.Aliases.List(), nil } +func (r *studioResolver) URL(ctx context.Context, obj *models.Studio) (*string, error) { + if !obj.URLs.Loaded() { + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + return obj.LoadURLs(ctx, r.repository.Studio) + }); err != nil { + return nil, err + } + } + + urls := obj.URLs.List() + if len(urls) == 0 { + return nil, nil + } + + return &urls[0], nil +} + +func (r *studioResolver) Urls(ctx context.Context, obj *models.Studio) ([]string, error) { + if !obj.URLs.Loaded() { + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + return obj.LoadURLs(ctx, r.repository.Studio) + }); err != nil { + return nil, err + } + } + + return obj.URLs.List(), nil +} + func (r *studioResolver) Tags(ctx context.Context, obj *models.Studio) (ret []*models.Tag, err error) { if !obj.TagIDs.Loaded() { if err := r.withReadTxn(ctx, func(ctx context.Context) error { @@ -114,6 +143,24 @@ func (r *studioResolver) MovieCount(ctx context.Context, obj *models.Studio, dep return r.GroupCount(ctx, obj, depth) } +func (r *studioResolver) OCounter(ctx context.Context, obj *models.Studio) (ret *int, err error) { + var res_scene int + var res_image int + var res int + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + res_scene, err = r.repository.Scene.OCountByStudioID(ctx, obj.ID) + if err != nil { + return err + } + res_image, err = r.repository.Image.OCountByStudioID(ctx, obj.ID) + return err + }); err != nil { + return nil, err + } + res = res_scene + res_image + return &res, nil +} + func (r *studioResolver) ParentStudio(ctx context.Context, obj *models.Studio) (ret *models.Studio, err error) { if obj.ParentID == nil { return nil, nil diff --git a/internal/api/resolver_model_tag.go b/internal/api/resolver_model_tag.go index 14237d2fe..deae41f21 100644 --- a/internal/api/resolver_model_tag.go +++ b/internal/api/resolver_model_tag.go @@ -54,6 +54,16 @@ func (r *tagResolver) Aliases(ctx context.Context, obj *models.Tag) (ret []strin return obj.Aliases.List(), nil } +func (r *tagResolver) StashIds(ctx context.Context, obj *models.Tag) ([]*models.StashID, error) { + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + return obj.LoadStashIDs(ctx, r.repository.Tag) + }); err != nil { + return nil, err + } + + return stashIDsSliceToPtrSlice(obj.StashIDs.List()), nil +} + func (r *tagResolver) SceneCount(ctx context.Context, obj *models.Tag, depth *int) (ret int, err error) { if err := r.withReadTxn(ctx, func(ctx context.Context) error { ret, err = scene.CountByTagID(ctx, r.repository.Scene, obj.ID, depth) diff --git a/internal/api/resolver_mutation_configure.go b/internal/api/resolver_mutation_configure.go index d9c71b09f..d49105916 100644 --- a/internal/api/resolver_mutation_configure.go +++ b/internal/api/resolver_mutation_configure.go @@ -150,6 +150,15 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input ConfigGen c.SetString(config.BackupDirectoryPath, *input.BackupDirectoryPath) } + existingDeleteTrashPath := c.GetDeleteTrashPath() + if input.DeleteTrashPath != nil && existingDeleteTrashPath != *input.DeleteTrashPath { + if err := validateDir(config.DeleteTrashPath, *input.DeleteTrashPath, true); err != nil { + return makeConfigGeneralResult(), err + } + + c.SetString(config.DeleteTrashPath, *input.DeleteTrashPath) + } + existingGeneratedPath := c.GetGeneratedPath() if input.GeneratedPath != nil && existingGeneratedPath != *input.GeneratedPath { if err := validateDir(config.Generated, *input.GeneratedPath, false); err != nil { @@ -334,6 +343,10 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input ConfigGen logger.SetLogLevel(*input.LogLevel) } + if input.LogFileMaxSize != nil && *input.LogFileMaxSize != c.GetLogFileMaxSize() { + c.SetInt(config.LogFileMaxSize, *input.LogFileMaxSize) + } + if input.Excludes != nil { for _, r := range input.Excludes { _, err := regexp.Compile(r) @@ -445,6 +458,8 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input ConfigGen func (r *mutationResolver) ConfigureInterface(ctx context.Context, input ConfigInterfaceInput) (*ConfigInterfaceResult, error) { c := config.GetInstance() + r.setConfigBool(config.SFWContentMode, input.SfwContentMode) + if input.MenuItems != nil { c.SetInterface(config.MenuItems, input.MenuItems) } diff --git a/internal/api/resolver_mutation_file.go b/internal/api/resolver_mutation_file.go index c303446e1..c5e5e3530 100644 --- a/internal/api/resolver_mutation_file.go +++ b/internal/api/resolver_mutation_file.go @@ -149,7 +149,9 @@ func (r *mutationResolver) DeleteFiles(ctx context.Context, ids []string) (ret b return false, fmt.Errorf("converting ids: %w", err) } - fileDeleter := file.NewDeleter() + trashPath := manager.GetInstance().Config.GetDeleteTrashPath() + + fileDeleter := file.NewDeleterWithTrash(trashPath) destroyer := &file.ZipDestroyer{ FileDestroyer: r.repository.File, FolderDestroyer: r.repository.Folder, diff --git a/internal/api/resolver_mutation_gallery.go b/internal/api/resolver_mutation_gallery.go index 5d5cd4b37..db6862274 100644 --- a/internal/api/resolver_mutation_gallery.go +++ b/internal/api/resolver_mutation_gallery.go @@ -333,10 +333,12 @@ func (r *mutationResolver) GalleryDestroy(ctx context.Context, input models.Gall return false, fmt.Errorf("converting ids: %w", err) } + trashPath := manager.GetInstance().Config.GetDeleteTrashPath() + var galleries []*models.Gallery var imgsDestroyed []*models.Image fileDeleter := &image.FileDeleter{ - Deleter: file.NewDeleter(), + Deleter: file.NewDeleterWithTrash(trashPath), Paths: manager.GetInstance().Paths, } diff --git a/internal/api/resolver_mutation_image.go b/internal/api/resolver_mutation_image.go index 721598634..82d9be4cd 100644 --- a/internal/api/resolver_mutation_image.go +++ b/internal/api/resolver_mutation_image.go @@ -308,9 +308,11 @@ func (r *mutationResolver) ImageDestroy(ctx context.Context, input models.ImageD return false, fmt.Errorf("converting id: %w", err) } + trashPath := manager.GetInstance().Config.GetDeleteTrashPath() + var i *models.Image fileDeleter := &image.FileDeleter{ - Deleter: file.NewDeleter(), + Deleter: file.NewDeleterWithTrash(trashPath), Paths: manager.GetInstance().Paths, } if err := r.withTxn(ctx, func(ctx context.Context) error { @@ -348,9 +350,11 @@ func (r *mutationResolver) ImagesDestroy(ctx context.Context, input models.Image return false, fmt.Errorf("converting ids: %w", err) } + trashPath := manager.GetInstance().Config.GetDeleteTrashPath() + var images []*models.Image fileDeleter := &image.FileDeleter{ - Deleter: file.NewDeleter(), + Deleter: file.NewDeleterWithTrash(trashPath), Paths: manager.GetInstance().Paths, } if err := r.withTxn(ctx, func(ctx context.Context) error { diff --git a/internal/api/resolver_mutation_scene.go b/internal/api/resolver_mutation_scene.go index b740955d0..ae5903112 100644 --- a/internal/api/resolver_mutation_scene.go +++ b/internal/api/resolver_mutation_scene.go @@ -428,10 +428,11 @@ func (r *mutationResolver) SceneDestroy(ctx context.Context, input models.SceneD } fileNamingAlgo := manager.GetInstance().Config.GetVideoFileNamingAlgorithm() + trashPath := manager.GetInstance().Config.GetDeleteTrashPath() var s *models.Scene fileDeleter := &scene.FileDeleter{ - Deleter: file.NewDeleter(), + Deleter: file.NewDeleterWithTrash(trashPath), FileNamingAlgo: fileNamingAlgo, Paths: manager.GetInstance().Paths, } @@ -482,9 +483,10 @@ func (r *mutationResolver) ScenesDestroy(ctx context.Context, input models.Scene var scenes []*models.Scene fileNamingAlgo := manager.GetInstance().Config.GetVideoFileNamingAlgorithm() + trashPath := manager.GetInstance().Config.GetDeleteTrashPath() fileDeleter := &scene.FileDeleter{ - Deleter: file.NewDeleter(), + Deleter: file.NewDeleterWithTrash(trashPath), FileNamingAlgo: fileNamingAlgo, Paths: manager.GetInstance().Paths, } @@ -593,8 +595,9 @@ func (r *mutationResolver) SceneMerge(ctx context.Context, input SceneMergeInput } mgr := manager.GetInstance() + trashPath := mgr.Config.GetDeleteTrashPath() fileDeleter := &scene.FileDeleter{ - Deleter: file.NewDeleter(), + Deleter: file.NewDeleterWithTrash(trashPath), FileNamingAlgo: mgr.Config.GetVideoFileNamingAlgorithm(), Paths: mgr.Paths, } @@ -736,9 +739,10 @@ func (r *mutationResolver) SceneMarkerUpdate(ctx context.Context, input SceneMar } mgr := manager.GetInstance() + trashPath := mgr.Config.GetDeleteTrashPath() fileDeleter := &scene.FileDeleter{ - Deleter: file.NewDeleter(), + Deleter: file.NewDeleterWithTrash(trashPath), FileNamingAlgo: mgr.Config.GetVideoFileNamingAlgorithm(), Paths: mgr.Paths, } @@ -820,6 +824,123 @@ func (r *mutationResolver) SceneMarkerUpdate(ctx context.Context, input SceneMar return r.getSceneMarker(ctx, markerID) } +func (r *mutationResolver) BulkSceneMarkerUpdate(ctx context.Context, input BulkSceneMarkerUpdateInput) ([]*models.SceneMarker, error) { + ids, err := stringslice.StringSliceToIntSlice(input.Ids) + if err != nil { + return nil, fmt.Errorf("converting ids: %w", err) + } + + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), + } + + // Populate performer from the input + partial := models.NewSceneMarkerPartial() + + partial.Title = translator.optionalString(input.Title, "title") + + partial.PrimaryTagID, err = translator.optionalIntFromString(input.PrimaryTagID, "primary_tag_id") + if err != nil { + return nil, fmt.Errorf("converting primary tag id: %w", err) + } + + partial.TagIDs, err = translator.updateIdsBulk(input.TagIds, "tag_ids") + if err != nil { + return nil, fmt.Errorf("converting tag ids: %w", err) + } + + ret := []*models.SceneMarker{} + + // Start the transaction and save the performers + if err := r.withTxn(ctx, func(ctx context.Context) error { + qb := r.repository.SceneMarker + + for _, id := range ids { + l := partial + + if err := adjustMarkerPartialForTagExclusion(ctx, r.repository.SceneMarker, id, &l); err != nil { + return err + } + + updated, err := qb.UpdatePartial(ctx, id, l) + if err != nil { + return err + } + + ret = append(ret, updated) + } + + return nil + }); err != nil { + return nil, err + } + + // execute post hooks outside of txn + var newRet []*models.SceneMarker + for _, m := range ret { + r.hookExecutor.ExecutePostHooks(ctx, m.ID, hook.SceneMarkerUpdatePost, input, translator.getFields()) + + m, err = r.getSceneMarker(ctx, m.ID) + if err != nil { + return nil, err + } + + newRet = append(newRet, m) + } + + return newRet, nil +} + +// adjustMarkerPartialForTagExclusion adjusts the SceneMarkerPartial to exclude the primary tag from tag updates. +func adjustMarkerPartialForTagExclusion(ctx context.Context, r models.SceneMarkerReader, id int, partial *models.SceneMarkerPartial) error { + if partial.TagIDs == nil && !partial.PrimaryTagID.Set { + return nil + } + + // exclude primary tag from tag updates + var primaryTagID int + if partial.PrimaryTagID.Set { + primaryTagID = partial.PrimaryTagID.Value + } else { + existing, err := r.Find(ctx, id) + if err != nil { + return fmt.Errorf("finding existing primary tag id: %w", err) + } + + primaryTagID = existing.PrimaryTagID + } + + existingTagIDs, err := r.GetTagIDs(ctx, id) + if err != nil { + return fmt.Errorf("getting existing tag ids: %w", err) + } + + tagIDAttr := partial.TagIDs + + if tagIDAttr == nil { + tagIDAttr = &models.UpdateIDs{ + IDs: existingTagIDs, + Mode: models.RelationshipUpdateModeSet, + } + } + + newTagIDs := tagIDAttr.Apply(existingTagIDs) + // Remove primary tag from newTagIDs if present + newTagIDs = sliceutil.Exclude(newTagIDs, []int{primaryTagID}) + + if len(existingTagIDs) != len(newTagIDs) { + partial.TagIDs = &models.UpdateIDs{ + IDs: newTagIDs, + Mode: models.RelationshipUpdateModeSet, + } + } else { + // no change to tags required + partial.TagIDs = nil + } + + return nil +} + func (r *mutationResolver) SceneMarkerDestroy(ctx context.Context, id string) (bool, error) { return r.SceneMarkersDestroy(ctx, []string{id}) } @@ -832,9 +953,10 @@ func (r *mutationResolver) SceneMarkersDestroy(ctx context.Context, markerIDs [] var markers []*models.SceneMarker fileNamingAlgo := manager.GetInstance().Config.GetVideoFileNamingAlgorithm() + trashPath := manager.GetInstance().Config.GetDeleteTrashPath() fileDeleter := &scene.FileDeleter{ - Deleter: file.NewDeleter(), + Deleter: file.NewDeleterWithTrash(trashPath), FileNamingAlgo: fileNamingAlgo, Paths: manager.GetInstance().Paths, } diff --git a/internal/api/resolver_mutation_stash_box.go b/internal/api/resolver_mutation_stash_box.go index bbfe8b854..4026667eb 100644 --- a/internal/api/resolver_mutation_stash_box.go +++ b/internal/api/resolver_mutation_stash_box.go @@ -153,6 +153,14 @@ func (r *mutationResolver) makeSceneDraft(ctx context.Context, s *models.Scene, return nil, err } + // Load StashIDs for tags + tqb := r.repository.Tag + for _, t := range draft.Tags { + if err := t.LoadStashIDs(ctx, tqb); err != nil { + return nil, err + } + } + draft.Cover = cover return draft, nil diff --git a/internal/api/resolver_mutation_studio.go b/internal/api/resolver_mutation_studio.go index 727951755..03c13d85f 100644 --- a/internal/api/resolver_mutation_studio.go +++ b/internal/api/resolver_mutation_studio.go @@ -33,7 +33,6 @@ func (r *mutationResolver) StudioCreate(ctx context.Context, input models.Studio newStudio := models.NewStudio() newStudio.Name = input.Name - newStudio.URL = translator.string(input.URL) newStudio.Rating = input.Rating100 newStudio.Favorite = translator.bool(input.Favorite) newStudio.Details = translator.string(input.Details) @@ -43,6 +42,15 @@ func (r *mutationResolver) StudioCreate(ctx context.Context, input models.Studio var err error + newStudio.URLs = models.NewRelatedStrings([]string{}) + if input.URL != nil { + newStudio.URLs.Add(*input.URL) + } + + if input.Urls != nil { + newStudio.URLs.Add(input.Urls...) + } + newStudio.ParentID, err = translator.intPtrFromString(input.ParentID) if err != nil { return nil, fmt.Errorf("converting parent id: %w", err) @@ -106,7 +114,6 @@ func (r *mutationResolver) StudioUpdate(ctx context.Context, input models.Studio updatedStudio.ID = studioID updatedStudio.Name = translator.optionalString(input.Name, "name") - updatedStudio.URL = translator.optionalString(input.URL, "url") updatedStudio.Details = translator.optionalString(input.Details, "details") updatedStudio.Rating = translator.optionalInt(input.Rating100, "rating100") updatedStudio.Favorite = translator.optionalBool(input.Favorite, "favorite") @@ -124,6 +131,26 @@ func (r *mutationResolver) StudioUpdate(ctx context.Context, input models.Studio return nil, fmt.Errorf("converting tag ids: %w", err) } + if translator.hasField("urls") { + // ensure url not included in the input + if err := r.validateNoLegacyURLs(translator); err != nil { + return nil, err + } + + updatedStudio.URLs = translator.updateStrings(input.Urls, "urls") + } else if translator.hasField("url") { + // handle legacy url field + legacyURLs := []string{} + if input.URL != nil { + legacyURLs = append(legacyURLs, *input.URL) + } + + updatedStudio.URLs = &models.UpdateStrings{ + Mode: models.RelationshipUpdateModeSet, + Values: legacyURLs, + } + } + // Process the base 64 encoded image string var imageData []byte imageIncluded := translator.hasField("image") @@ -163,6 +190,96 @@ func (r *mutationResolver) StudioUpdate(ctx context.Context, input models.Studio return r.getStudio(ctx, studioID) } +func (r *mutationResolver) BulkStudioUpdate(ctx context.Context, input BulkStudioUpdateInput) ([]*models.Studio, error) { + ids, err := stringslice.StringSliceToIntSlice(input.Ids) + if err != nil { + return nil, fmt.Errorf("converting ids: %w", err) + } + + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), + } + + // Populate performer from the input + partial := models.NewStudioPartial() + + partial.ParentID, err = translator.optionalIntFromString(input.ParentID, "parent_id") + if err != nil { + return nil, fmt.Errorf("converting parent id: %w", err) + } + + if translator.hasField("urls") { + // ensure url/twitter/instagram are not included in the input + if err := r.validateNoLegacyURLs(translator); err != nil { + return nil, err + } + + partial.URLs = translator.updateStringsBulk(input.Urls, "urls") + } else if translator.hasField("url") { + // handle legacy url field + legacyURLs := []string{} + if input.URL != nil { + legacyURLs = append(legacyURLs, *input.URL) + } + + partial.URLs = &models.UpdateStrings{ + Mode: models.RelationshipUpdateModeSet, + Values: legacyURLs, + } + } + + partial.Favorite = translator.optionalBool(input.Favorite, "favorite") + partial.Rating = translator.optionalInt(input.Rating100, "rating100") + partial.Details = translator.optionalString(input.Details, "details") + partial.IgnoreAutoTag = translator.optionalBool(input.IgnoreAutoTag, "ignore_auto_tag") + + partial.TagIDs, err = translator.updateIdsBulk(input.TagIds, "tag_ids") + if err != nil { + return nil, fmt.Errorf("converting tag ids: %w", err) + } + + ret := []*models.Studio{} + + // Start the transaction and save the performers + if err := r.withTxn(ctx, func(ctx context.Context) error { + qb := r.repository.Studio + + for _, id := range ids { + local := partial + local.ID = id + if err := studio.ValidateModify(ctx, local, qb); err != nil { + return err + } + + updated, err := qb.UpdatePartial(ctx, local) + if err != nil { + return err + } + + ret = append(ret, updated) + } + + return nil + }); err != nil { + return nil, err + } + + // execute post hooks outside of txn + var newRet []*models.Studio + for _, studio := range ret { + r.hookExecutor.ExecutePostHooks(ctx, studio.ID, hook.StudioUpdatePost, input, translator.getFields()) + + studio, err = r.getStudio(ctx, studio.ID) + if err != nil { + return nil, err + } + + newRet = append(newRet, studio) + } + + return newRet, nil +} + func (r *mutationResolver) StudioDestroy(ctx context.Context, input StudioDestroyInput) (bool, error) { id, err := strconv.Atoi(input.ID) if err != nil { diff --git a/internal/api/resolver_mutation_tag.go b/internal/api/resolver_mutation_tag.go index 1e8b6066a..05d756acf 100644 --- a/internal/api/resolver_mutation_tag.go +++ b/internal/api/resolver_mutation_tag.go @@ -39,6 +39,14 @@ func (r *mutationResolver) TagCreate(ctx context.Context, input TagCreateInput) newTag.Description = translator.string(input.Description) newTag.IgnoreAutoTag = translator.bool(input.IgnoreAutoTag) + var stashIDInputs models.StashIDInputs + for _, sid := range input.StashIds { + if sid != nil { + stashIDInputs = append(stashIDInputs, *sid) + } + } + newTag.StashIDs = models.NewRelatedStashIDs(stashIDInputs.ToStashIDs()) + var err error newTag.ParentIDs, err = translator.relatedIds(input.ParentIds) @@ -110,6 +118,14 @@ func (r *mutationResolver) TagUpdate(ctx context.Context, input TagUpdateInput) updatedTag.Aliases = translator.updateStrings(input.Aliases, "aliases") + var updateStashIDInputs models.StashIDInputs + for _, sid := range input.StashIds { + if sid != nil { + updateStashIDInputs = append(updateStashIDInputs, *sid) + } + } + updatedTag.StashIDs = translator.updateStashIDs(updateStashIDInputs, "stash_ids") + updatedTag.ParentIDs, err = translator.updateIds(input.ParentIds, "parent_ids") if err != nil { return nil, fmt.Errorf("converting parent tag ids: %w", err) diff --git a/internal/api/resolver_query_configuration.go b/internal/api/resolver_query_configuration.go index cfa22720b..8a20fcad1 100644 --- a/internal/api/resolver_query_configuration.go +++ b/internal/api/resolver_query_configuration.go @@ -82,6 +82,7 @@ func makeConfigGeneralResult() *ConfigGeneralResult { Stashes: config.GetStashPaths(), DatabasePath: config.GetDatabasePath(), BackupDirectoryPath: config.GetBackupDirectoryPath(), + DeleteTrashPath: config.GetDeleteTrashPath(), GeneratedPath: config.GetGeneratedPath(), MetadataPath: config.GetMetadataPath(), ConfigFilePath: config.GetConfigFile(), @@ -115,6 +116,7 @@ func makeConfigGeneralResult() *ConfigGeneralResult { LogOut: config.GetLogOut(), LogLevel: config.GetLogLevel(), LogAccess: config.GetLogAccess(), + LogFileMaxSize: config.GetLogFileMaxSize(), VideoExtensions: config.GetVideoExtensions(), ImageExtensions: config.GetImageExtensions(), GalleryExtensions: config.GetGalleryExtensions(), @@ -162,6 +164,7 @@ func makeConfigInterfaceResult() *ConfigInterfaceResult { disableDropdownCreate := config.GetDisableDropdownCreate() return &ConfigInterfaceResult{ + SfwContentMode: config.GetSFWContentMode(), MenuItems: menuItems, SoundOnPreview: &soundOnPreview, WallShowTitle: &wallShowTitle, diff --git a/internal/api/resolver_query_find_file.go b/internal/api/resolver_query_find_file.go new file mode 100644 index 000000000..ae53a89b4 --- /dev/null +++ b/internal/api/resolver_query_find_file.go @@ -0,0 +1,120 @@ +package api + +import ( + "context" + "errors" + "strconv" + + "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/sliceutil/stringslice" +) + +func (r *queryResolver) FindFile(ctx context.Context, id *string, path *string) (BaseFile, error) { + var ret models.File + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + qb := r.repository.File + var err error + switch { + case id != nil: + idInt, err := strconv.Atoi(*id) + if err != nil { + return err + } + var files []models.File + files, err = qb.Find(ctx, models.FileID(idInt)) + if err != nil { + return err + } + if len(files) > 0 { + ret = files[0] + } + case path != nil: + ret, err = qb.FindByPath(ctx, *path) + if err == nil && ret == nil { + return errors.New("file not found") + } + default: + return errors.New("either id or path must be provided") + } + + return err + }); err != nil { + return nil, err + } + + return convertBaseFile(ret), nil +} + +func (r *queryResolver) FindFiles( + ctx context.Context, + fileFilter *models.FileFilterType, + filter *models.FindFilterType, + ids []string, +) (ret *FindFilesResultType, err error) { + var fileIDs []models.FileID + if len(ids) > 0 { + fileIDsInt, err := stringslice.StringSliceToIntSlice(ids) + if err != nil { + return nil, err + } + + fileIDs = models.FileIDsFromInts(fileIDsInt) + } + + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + var files []models.File + var err error + + fields := collectQueryFields(ctx) + result := &models.FileQueryResult{} + + if len(fileIDs) > 0 { + files, err = r.repository.File.Find(ctx, fileIDs...) + if err == nil { + result.Count = len(files) + for _, f := range files { + if asVideo, ok := f.(*models.VideoFile); ok { + result.TotalDuration += asVideo.Duration + } + if asImage, ok := f.(*models.ImageFile); ok { + result.Megapixels += asImage.Megapixels() + } + + result.TotalSize += f.Base().Size + } + } + } else { + result, err = r.repository.File.Query(ctx, models.FileQueryOptions{ + QueryOptions: models.QueryOptions{ + FindFilter: filter, + Count: fields.Has("count"), + }, + FileFilter: fileFilter, + TotalDuration: fields.Has("duration"), + Megapixels: fields.Has("megapixels"), + TotalSize: fields.Has("size"), + }) + if err == nil { + files, err = result.Resolve(ctx) + } + } + + if err != nil { + return err + } + + ret = &FindFilesResultType{ + Count: result.Count, + Files: convertBaseFiles(files), + Duration: result.TotalDuration, + Megapixels: result.Megapixels, + Size: int(result.TotalSize), + } + + return nil + }); err != nil { + return nil, err + } + + return ret, nil +} diff --git a/internal/api/resolver_query_find_folder.go b/internal/api/resolver_query_find_folder.go new file mode 100644 index 000000000..a7a798dd1 --- /dev/null +++ b/internal/api/resolver_query_find_folder.go @@ -0,0 +1,100 @@ +package api + +import ( + "context" + "errors" + "strconv" + + "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/sliceutil/stringslice" +) + +func (r *queryResolver) FindFolder(ctx context.Context, id *string, path *string) (*models.Folder, error) { + var ret *models.Folder + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + qb := r.repository.Folder + var err error + switch { + case id != nil: + idInt, err := strconv.Atoi(*id) + if err != nil { + return err + } + ret, err = qb.Find(ctx, models.FolderID(idInt)) + if err != nil { + return err + } + case path != nil: + ret, err = qb.FindByPath(ctx, *path) + if err == nil && ret == nil { + return errors.New("folder not found") + } + default: + return errors.New("either id or path must be provided") + } + + return err + }); err != nil { + return nil, err + } + + return ret, nil +} + +func (r *queryResolver) FindFolders( + ctx context.Context, + folderFilter *models.FolderFilterType, + filter *models.FindFilterType, + ids []string, +) (ret *FindFoldersResultType, err error) { + var folderIDs []models.FolderID + if len(ids) > 0 { + folderIDsInt, err := stringslice.StringSliceToIntSlice(ids) + if err != nil { + return nil, err + } + + folderIDs = models.FolderIDsFromInts(folderIDsInt) + } + + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + var folders []*models.Folder + var err error + + fields := collectQueryFields(ctx) + result := &models.FolderQueryResult{} + + if len(folderIDs) > 0 { + folders, err = r.repository.Folder.FindMany(ctx, folderIDs) + if err == nil { + result.Count = len(folders) + } + } else { + result, err = r.repository.Folder.Query(ctx, models.FolderQueryOptions{ + QueryOptions: models.QueryOptions{ + FindFilter: filter, + Count: fields.Has("count"), + }, + FolderFilter: folderFilter, + }) + if err == nil { + folders, err = result.Resolve(ctx) + } + } + + if err != nil { + return err + } + + ret = &FindFoldersResultType{ + Count: result.Count, + Folders: folders, + } + + return nil + }); err != nil { + return nil, err + } + + return ret, nil +} diff --git a/internal/api/resolver_query_scraper.go b/internal/api/resolver_query_scraper.go index f0e89cd34..5875cd11e 100644 --- a/internal/api/resolver_query_scraper.go +++ b/internal/api/resolver_query_scraper.go @@ -201,7 +201,7 @@ func (r *queryResolver) ScrapeSingleScene(ctx context.Context, source scraper.So } // TODO - this should happen after any scene is scraped - if err := r.matchScenesRelationships(ctx, ret, *source.StashBoxEndpoint); err != nil { + if err := r.matchScenesRelationships(ctx, ret, b.Endpoint); err != nil { return nil, err } default: @@ -245,7 +245,7 @@ func (r *queryResolver) ScrapeMultiScenes(ctx context.Context, source scraper.So // just flatten the slice and pass it in flat := sliceutil.Flatten(ret) - if err := r.matchScenesRelationships(ctx, flat, *source.StashBoxEndpoint); err != nil { + if err := r.matchScenesRelationships(ctx, flat, b.Endpoint); err != nil { return nil, err } @@ -335,7 +335,7 @@ func (r *queryResolver) ScrapeSingleStudio(ctx context.Context, source scraper.S if len(ret) > 0 { if err := r.withReadTxn(ctx, func(ctx context.Context) error { for _, studio := range ret { - if err := match.ScrapedStudioHierarchy(ctx, r.repository.Studio, studio, *source.StashBoxEndpoint); err != nil { + if err := match.ScrapedStudioHierarchy(ctx, r.repository.Studio, studio, b.Endpoint); err != nil { return err } } diff --git a/internal/api/routes_performer.go b/internal/api/routes_performer.go index b27fdbd6c..8d5463d63 100644 --- a/internal/api/routes_performer.go +++ b/internal/api/routes_performer.go @@ -18,9 +18,14 @@ type PerformerFinder interface { GetImage(ctx context.Context, performerID int) ([]byte, error) } +type sfwConfig interface { + GetSFWContentMode() bool +} + type performerRoutes struct { routes performerFinder PerformerFinder + sfwConfig sfwConfig } func (rs performerRoutes) Routes() chi.Router { @@ -54,7 +59,7 @@ func (rs performerRoutes) Image(w http.ResponseWriter, r *http.Request) { } if len(image) == 0 { - image = getDefaultPerformerImage(performer.Name, performer.Gender) + image = getDefaultPerformerImage(performer.Name, performer.Gender, rs.sfwConfig.GetSFWContentMode()) } utils.ServeImage(w, r, image) diff --git a/internal/api/scraped_content.go b/internal/api/scraped_content.go index 6288812ef..f7d40c95d 100644 --- a/internal/api/scraped_content.go +++ b/internal/api/scraped_content.go @@ -135,6 +135,13 @@ func marshalScrapedGroups(content []scraper.ScrapedContent) ([]*models.ScrapedGr ret = append(ret, m) case models.ScrapedGroup: ret = append(ret, &m) + // it's possible that a scraper returns models.ScrapedMovie + case *models.ScrapedMovie: + g := m.ScrapedGroup() + ret = append(ret, &g) + case models.ScrapedMovie: + g := m.ScrapedGroup() + ret = append(ret, &g) default: return nil, fmt.Errorf("%w: cannot turn ScrapedContent into ScrapedGroup", models.ErrConversion) } diff --git a/internal/api/server.go b/internal/api/server.go index 5059e9a2a..9290c6512 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -322,6 +322,7 @@ func (s *Server) getPerformerRoutes() chi.Router { return performerRoutes{ routes: routes{txnManager: repo.TxnManager}, performerFinder: repo.Performer, + sfwConfig: s.manager.Config, }.Routes() } diff --git a/internal/api/urlbuilders/gallery.go b/internal/api/urlbuilders/gallery.go index 3e6c5ef08..2723781f2 100644 --- a/internal/api/urlbuilders/gallery.go +++ b/internal/api/urlbuilders/gallery.go @@ -9,12 +9,14 @@ import ( type GalleryURLBuilder struct { BaseURL string GalleryID string + UpdatedAt string } func NewGalleryURLBuilder(baseURL string, gallery *models.Gallery) GalleryURLBuilder { return GalleryURLBuilder{ BaseURL: baseURL, GalleryID: strconv.Itoa(gallery.ID), + UpdatedAt: strconv.FormatInt(gallery.UpdatedAt.Unix(), 10), } } @@ -23,5 +25,5 @@ func (b GalleryURLBuilder) GetPreviewURL() string { } func (b GalleryURLBuilder) GetCoverURL() string { - return b.BaseURL + "/gallery/" + b.GalleryID + "/cover" + return b.BaseURL + "/gallery/" + b.GalleryID + "/cover?t=" + b.UpdatedAt } diff --git a/internal/identify/scene.go b/internal/identify/scene.go index 847a140c5..789674693 100644 --- a/internal/identify/scene.go +++ b/internal/identify/scene.go @@ -153,6 +153,8 @@ func (g sceneRelationships) tags(ctx context.Context) ([]int, error) { tagIDs = originalTagIDs } + endpoint := g.result.source.RemoteSite + for _, t := range scraped { if t.StoredID != nil { // existing tag, just add it @@ -163,10 +165,9 @@ func (g sceneRelationships) tags(ctx context.Context) ([]int, error) { tagIDs = sliceutil.AppendUnique(tagIDs, int(tagID)) } else if createMissing { - newTag := models.NewTag() - newTag.Name = t.Name + newTag := t.ToTag(endpoint, nil) - err := g.tagCreator.Create(ctx, &newTag) + err := g.tagCreator.Create(ctx, newTag) if err != nil { return nil, fmt.Errorf("error creating tag: %w", err) } diff --git a/internal/log/logger.go b/internal/log/logger.go index 5f686d32d..cb07121a5 100644 --- a/internal/log/logger.go +++ b/internal/log/logger.go @@ -3,12 +3,14 @@ package log import ( "fmt" + "io" "os" "strings" "sync" "time" "github.com/sirupsen/logrus" + lumberjack "gopkg.in/natefinch/lumberjack.v2" ) type LogItem struct { @@ -41,8 +43,8 @@ func NewLogger() *Logger { } // Init initialises the logger based on a logging configuration -func (log *Logger) Init(logFile string, logOut bool, logLevel string) { - var file *os.File +func (log *Logger) Init(logFile string, logOut bool, logLevel string, logFileMaxSize int) { + var logger io.WriteCloser customFormatter := new(logrus.TextFormatter) customFormatter.TimestampFormat = "2006-01-02 15:04:05" customFormatter.ForceColors = true @@ -57,30 +59,38 @@ func (log *Logger) Init(logFile string, logOut bool, logLevel string) { // the access log colouring not being applied _, _ = customFormatter.Format(logrus.NewEntry(log.logger)) + // if size is 0, disable rotation if logFile != "" { - var err error - file, err = os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) - - if err != nil { - fmt.Printf("Could not open '%s' for log output due to error: %s\n", logFile, err.Error()) + if logFileMaxSize == 0 { + var err error + logger, err = os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + fmt.Fprintf(os.Stderr, "unable to open log file %s: %v\n", logFile, err) + } + } else { + logger = &lumberjack.Logger{ + Filename: logFile, + MaxSize: logFileMaxSize, // Megabytes + Compress: true, + } } } - if file != nil { + if logger != nil { if logOut { // log to file separately disabling colours fileFormatter := new(logrus.TextFormatter) fileFormatter.TimestampFormat = customFormatter.TimestampFormat fileFormatter.FullTimestamp = customFormatter.FullTimestamp log.logger.AddHook(&fileLogHook{ - Writer: file, + Writer: logger, Formatter: fileFormatter, }) } else { // logging to file only // turn off the colouring for the file customFormatter.ForceColors = false - log.logger.Out = file + log.logger.Out = logger } } diff --git a/internal/manager/config/config.go b/internal/manager/config/config.go index 1b627cbdd..c7b1c1fdf 100644 --- a/internal/manager/config/config.go +++ b/internal/manager/config/config.go @@ -16,9 +16,9 @@ import ( "golang.org/x/crypto/bcrypt" - "github.com/knadh/koanf" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/file" + "github.com/knadh/koanf/v2" "github.com/stashapp/stash/internal/identify" "github.com/stashapp/stash/pkg/fsutil" @@ -43,6 +43,9 @@ const ( Password = "password" MaxSessionAge = "max_session_age" + // SFWContentMode mode config key + SFWContentMode = "sfw_content_mode" + FFMpegPath = "ffmpeg_path" FFProbePath = "ffprobe_path" @@ -249,13 +252,15 @@ const ( DLNAPortDefault = 1338 // Logging options - LogFile = "logfile" - LogOut = "logout" - defaultLogOut = true - LogLevel = "loglevel" - defaultLogLevel = "Info" - LogAccess = "logaccess" - defaultLogAccess = true + LogFile = "logfile" + LogOut = "logout" + defaultLogOut = true + LogLevel = "loglevel" + defaultLogLevel = "Info" + LogAccess = "logaccess" + defaultLogAccess = true + LogFileMaxSize = "logfile_max_size" + defaultLogFileMaxSize = 0 // megabytes, default disabled // Default settings DefaultScanSettings = "defaults.scan_task" @@ -267,6 +272,9 @@ const ( DeleteGeneratedDefault = "defaults.delete_generated" deleteGeneratedDefaultDefault = true + // Trash/Recycle Bin options + DeleteTrashPath = "delete_trash_path" + // Desktop Integration Options NoBrowser = "nobrowser" NoBrowserDefault = false @@ -287,7 +295,7 @@ var ( defaultVideoExtensions = []string{"m4v", "mp4", "mov", "wmv", "avi", "mpg", "mpeg", "rmvb", "rm", "flv", "asf", "mkv", "webm", "f4v"} defaultImageExtensions = []string{"png", "jpg", "jpeg", "gif", "webp"} defaultGalleryExtensions = []string{"zip", "cbz"} - defaultMenuItems = []string{"scenes", "images", "movies", "markers", "galleries", "performers", "studios", "tags"} + defaultMenuItems = []string{"scenes", "images", "groups", "markers", "galleries", "performers", "studios", "tags"} ) type MissingConfigError struct { @@ -628,7 +636,15 @@ func (i *Config) getStringMapString(key string) map[string]string { return ret } -// GetStathPaths returns the configured stash library paths. +// GetSFW returns true if SFW mode is enabled. +// Default performer images are changed to more agnostic images when enabled. +func (i *Config) GetSFWContentMode() bool { + i.RLock() + defer i.RUnlock() + return i.getBool(SFWContentMode) +} + +// GetStashPaths returns the configured stash library paths. // Works opposite to the usual case - it will return the override // value only if the main value is not set. func (i *Config) GetStashPaths() StashConfigs { @@ -1456,6 +1472,14 @@ func (i *Config) GetDeleteGeneratedDefault() bool { return i.getBoolDefault(DeleteGeneratedDefault, deleteGeneratedDefaultDefault) } +func (i *Config) GetDeleteTrashPath() string { + return i.getString(DeleteTrashPath) +} + +func (i *Config) SetDeleteTrashPath(value string) { + i.SetString(DeleteTrashPath, value) +} + // GetDefaultIdentifySettings returns the default Identify task settings. // Returns nil if the settings could not be unmarshalled, or if it // has not been set. @@ -1625,6 +1649,16 @@ func (i *Config) GetLogAccess() bool { return i.getBoolDefault(LogAccess, defaultLogAccess) } +// GetLogFileMaxSize returns the maximum size of the log file in megabytes for lumberjack to rotate +func (i *Config) GetLogFileMaxSize() int { + value := i.getInt(LogFileMaxSize) + if value < 0 { + value = defaultLogFileMaxSize + } + + return value +} + // Max allowed graphql upload size in megabytes func (i *Config) GetMaxUploadSize() int64 { i.RLock() diff --git a/internal/manager/config/init.go b/internal/manager/config/init.go index 09f1c18bc..840b50b70 100644 --- a/internal/manager/config/init.go +++ b/internal/manager/config/init.go @@ -8,9 +8,9 @@ import ( "path/filepath" "strings" - "github.com/knadh/koanf" "github.com/knadh/koanf/providers/env" "github.com/knadh/koanf/providers/posflag" + "github.com/knadh/koanf/v2" "github.com/spf13/pflag" "github.com/stashapp/stash/pkg/fsutil" diff --git a/internal/manager/exclude_files.go b/internal/manager/exclude_files.go index 6c5452d0d..7ab24b51c 100644 --- a/internal/manager/exclude_files.go +++ b/internal/manager/exclude_files.go @@ -60,6 +60,10 @@ func generateRegexps(patterns []string) []*regexp.Regexp { var fileRegexps []*regexp.Regexp for _, pattern := range patterns { + if pattern == "" || pattern == " " { + logger.Warnf("Skipping empty exclude pattern") + continue + } if !strings.HasPrefix(pattern, "(?i)") { pattern = "(?i)" + pattern } diff --git a/internal/manager/generator_interactive_heatmap_speed.go b/internal/manager/generator_interactive_heatmap_speed.go index ac6ca53bd..d10ce5b19 100644 --- a/internal/manager/generator_interactive_heatmap_speed.go +++ b/internal/manager/generator_interactive_heatmap_speed.go @@ -28,7 +28,8 @@ type InteractiveHeatmapSpeedGenerator struct { type Script struct { // Version of Launchscript - Version string `json:"version"` + // #5600 - ignore version, don't validate type + Version json.RawMessage `json:"version"` // Inverted causes up and down movement to be flipped. Inverted bool `json:"inverted,omitempty"` // Range is the percentage of a full stroke to use. @@ -40,7 +41,7 @@ type Script struct { // Action is a move at a specific time. type Action struct { // At time in milliseconds the action should fire. - At int64 `json:"at"` + At float64 `json:"at"` // Pos is the place in percent to move to. Pos int `json:"pos"` @@ -109,8 +110,8 @@ func (g *InteractiveHeatmapSpeedGenerator) LoadFunscriptData(path string, sceneD // trim actions with negative timestamps to avoid index range errors when generating heatmap // #3181 - also trim actions that occur after the scene duration loggedBadTimestamp := false - sceneDurationMilli := int64(sceneDuration * 1000) - isValid := func(x int64) bool { + sceneDurationMilli := sceneDuration * 1000 + isValid := func(x float64) bool { return x >= 0 && x < sceneDurationMilli } @@ -132,7 +133,7 @@ func (g *InteractiveHeatmapSpeedGenerator) LoadFunscriptData(path string, sceneD func (funscript *Script) UpdateIntensityAndSpeed() { - var t1, t2 int64 + var t1, t2 float64 var p1, p2 int var intensity float64 for i := range funscript.Actions { @@ -241,13 +242,13 @@ func (gt GradientTable) GetYRange(t float64) [2]float64 { func (funscript Script) getGradientTable(numSegments int, sceneDurationMilli int64) GradientTable { const windowSize = 15 - const backfillThreshold = 500 + const backfillThreshold = float64(500) segments := make([]struct { count int intensity int yRange [2]float64 - at int64 + at float64 }, numSegments) gradient := make(GradientTable, numSegments) posList := []int{} @@ -297,7 +298,7 @@ func (funscript Script) getGradientTable(numSegments int, sceneDurationMilli int // Fill in gaps in segments for i := 0; i < numSegments; i++ { - segmentTS := (maxts / int64(numSegments)) * int64(i) + segmentTS := float64((maxts / int64(numSegments)) * int64(i)) // Empty segment - fill it with the previous up to backfillThreshold ms if segments[i].count == 0 { @@ -406,7 +407,8 @@ func ConvertFunscriptToCSV(funscriptPath string) ([]byte, error) { pos = convertRange(pos, 0, funscript.Range, 0, 100) } - buffer.WriteString(fmt.Sprintf("%d,%d\r\n", action.At, pos)) + // I don't know whether the csv format requires int or float, so for now we'll use int + buffer.WriteString(fmt.Sprintf("%d,%d\r\n", int(math.Round(action.At)), pos)) } return buffer.Bytes(), nil } diff --git a/internal/manager/manager.go b/internal/manager/manager.go index 4827a3e3d..2d47fd907 100644 --- a/internal/manager/manager.go +++ b/internal/manager/manager.go @@ -262,6 +262,10 @@ func (s *Manager) Setup(ctx context.Context, input SetupInput) error { cfg.SetString(config.Cache, input.CacheLocation) } + if input.SFWContentMode { + cfg.SetBool(config.SFWContentMode, true) + } + if input.StoreBlobsInDatabase { cfg.SetInterface(config.BlobsStorage, config.BlobStorageTypeDatabase) } else { @@ -322,6 +326,11 @@ func (s *Manager) BackupDatabase(download bool) (string, string, error) { backupPath = f.Name() backupName = s.Database.DatabaseBackupPath("") f.Close() + + // delete the temp file so that the backup operation can create it + if err := os.Remove(backupPath); err != nil { + return "", "", fmt.Errorf("could not remove temporary backup file %v: %w", backupPath, err) + } } else { backupDir := s.Config.GetBackupDirectoryPathOrDefault() if backupDir != "" { diff --git a/internal/manager/manager_tasks.go b/internal/manager/manager_tasks.go index b85a4c2cf..085c4459e 100644 --- a/internal/manager/manager_tasks.go +++ b/internal/manager/manager_tasks.go @@ -294,6 +294,7 @@ func (s *Manager) Clean(ctx context.Context, input CleanMetadataInput) int { Handlers: []file.CleanHandler{ &cleanHandler{}, }, + TrashPath: s.Config.GetDeleteTrashPath(), } j := cleanJob{ diff --git a/internal/manager/models.go b/internal/manager/models.go index 3e96e6182..b7c7232c5 100644 --- a/internal/manager/models.go +++ b/internal/manager/models.go @@ -21,6 +21,7 @@ type SetupInput struct { // Empty to indicate $HOME/.stash/config.yml default ConfigLocation string `json:"configLocation"` Stashes []*config.StashConfigInput `json:"stashes"` + SFWContentMode bool `json:"sfwContentMode"` // Empty to indicate default DatabaseFile string `json:"databaseFile"` // Empty to indicate default diff --git a/internal/manager/running_streams.go b/internal/manager/running_streams.go index c6b0c4665..18ac3b042 100644 --- a/internal/manager/running_streams.go +++ b/internal/manager/running_streams.go @@ -3,7 +3,9 @@ package manager import ( "context" "errors" + "mime" "net/http" + "path/filepath" "github.com/stashapp/stash/internal/manager/config" "github.com/stashapp/stash/internal/static" @@ -46,14 +48,17 @@ func (s *SceneServer) StreamSceneDirect(scene *models.Scene, w http.ResponseWrit sceneHash := scene.GetHash(config.GetInstance().GetVideoFileNamingAlgorithm()) - filepath := GetInstance().Paths.Scene.GetStreamPath(scene.Path, sceneHash) + fp := GetInstance().Paths.Scene.GetStreamPath(scene.Path, sceneHash) streamRequestCtx := ffmpeg.NewStreamRequestContext(w, r) // #2579 - hijacking and closing the connection here causes video playback to fail in Safari // We trust that the request context will be closed, so we don't need to call Cancel on the // returned context here. - _ = GetInstance().ReadLockManager.ReadLock(streamRequestCtx, filepath) - http.ServeFile(w, r, filepath) + _ = GetInstance().ReadLockManager.ReadLock(streamRequestCtx, fp) + _, filename := filepath.Split(fp) + contentDisposition := mime.FormatMediaType("inline", map[string]string{"filename": filename}) + w.Header().Set("Content-Disposition", contentDisposition) + http.ServeFile(w, r, fp) } func (s *SceneServer) ServeScreenshot(scene *models.Scene, w http.ResponseWriter, r *http.Request) { diff --git a/internal/manager/task_generate_markers.go b/internal/manager/task_generate_markers.go index f37c7aed1..cfe17926c 100644 --- a/internal/manager/task_generate_markers.go +++ b/internal/manager/task_generate_markers.go @@ -107,6 +107,12 @@ func (t *GenerateMarkersTask) generateMarker(videoFile *models.VideoFile, scene sceneHash := scene.GetHash(t.fileNamingAlgorithm) seconds := float64(sceneMarker.Seconds) + // check if marker past duration + if seconds > float64(videoFile.Duration) { + logger.Warnf("[generator] scene marker at %.2f seconds exceeds video duration of %.2f seconds, skipping", seconds, float64(videoFile.Duration)) + return + } + g := t.generator if err := g.MarkerPreviewVideo(context.TODO(), videoFile.Path, sceneHash, seconds, sceneMarker.EndSeconds, instance.Config.GetPreviewAudio()); err != nil { diff --git a/internal/manager/task_generate_screenshot.go b/internal/manager/task_generate_screenshot.go index 77ad2be34..2f4031586 100644 --- a/internal/manager/task_generate_screenshot.go +++ b/internal/manager/task_generate_screenshot.go @@ -32,6 +32,7 @@ func (t *GenerateCoverTask) Start(ctx context.Context) { return t.Scene.LoadPrimaryFile(ctx, r.File) }); err != nil { logger.Error(err) + return } if !required { diff --git a/internal/static/embed.go b/internal/static/embed.go index 91437a81f..665c5a892 100644 --- a/internal/static/embed.go +++ b/internal/static/embed.go @@ -8,12 +8,13 @@ import ( "io/fs" ) -//go:embed performer performer_male scene image gallery tag studio group +//go:embed performer performer_male performer_sfw scene image gallery tag studio group var data embed.FS const ( - Performer = "performer" - PerformerMale = "performer_male" + Performer = "performer" + PerformerMale = "performer_male" + DefaultSFWPerformerImage = "performer_sfw/performer.svg" Scene = "scene" DefaultSceneImage = "scene/scene.svg" diff --git a/internal/static/performer_sfw/performer.svg b/internal/static/performer_sfw/performer.svg new file mode 100644 index 000000000..24b444171 --- /dev/null +++ b/internal/static/performer_sfw/performer.svg @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/pkg/ffmpeg/codec_hardware.go b/pkg/ffmpeg/codec_hardware.go index 5151e7efe..bbbdbda6e 100644 --- a/pkg/ffmpeg/codec_hardware.go +++ b/pkg/ffmpeg/codec_hardware.go @@ -5,9 +5,11 @@ import ( "context" "fmt" "math" + "os" "regexp" "strconv" "strings" + "time" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/models" @@ -27,6 +29,7 @@ var ( VideoCodecIVP9 = makeVideoCodec("VP9 Intel Quick Sync Video (QSV)", "vp9_qsv") VideoCodecVVP9 = makeVideoCodec("VP9 VAAPI", "vp9_vaapi") VideoCodecVVPX = makeVideoCodec("VP8 VAAPI", "vp8_vaapi") + VideoCodecRK264 = makeVideoCodec("H264 Rockchip MPP (rkmpp)", "h264_rkmpp") ) const minHeight int = 480 @@ -43,6 +46,7 @@ func (f *FFMpeg) InitHWSupport(ctx context.Context) { VideoCodecI264C, VideoCodecV264, VideoCodecR264, + VideoCodecRK264, VideoCodecIVP9, VideoCodecVVP9, VideoCodecM264, @@ -64,12 +68,32 @@ func (f *FFMpeg) InitHWSupport(ctx context.Context) { args = args.Format("null") args = args.Output("-") - cmd := f.Command(ctx, args) + // #6064 - add timeout to context to prevent hangs + const hwTestTimeoutSecondsDefault = 1 + hwTestTimeoutSeconds := hwTestTimeoutSecondsDefault * time.Second + + // allow timeout to be overridden with environment variable + if timeout := os.Getenv("STASH_HW_TEST_TIMEOUT"); timeout != "" { + if seconds, err := strconv.Atoi(timeout); err == nil { + hwTestTimeoutSeconds = time.Duration(seconds) * time.Second + } + } + + testCtx, cancel := context.WithTimeout(ctx, hwTestTimeoutSeconds) + defer cancel() + + cmd := f.Command(testCtx, args) + logger.Tracef("[InitHWSupport] Testing codec %s: %v", codec, cmd.Args) var stderr bytes.Buffer cmd.Stderr = &stderr if err := cmd.Run(); err != nil { + if testCtx.Err() != nil { + logger.Debugf("[InitHWSupport] Codec %s test timed out after %d seconds", codec, hwTestTimeoutSeconds) + continue + } + errOutput := stderr.String() if len(errOutput) == 0 { @@ -179,6 +203,19 @@ func (f *FFMpeg) hwDeviceInit(args Args, toCodec VideoCodec, fullhw bool) Args { args = append(args, "-init_hw_device") args = append(args, "videotoolbox=vt") } + case VideoCodecRK264: + // Rockchip: always create rkmpp device and make it the filter device, so + // scale_rkrga and subsequent hwupload/hwmap operate in the right context. + args = append(args, "-init_hw_device") + args = append(args, "rkmpp=rk") + args = append(args, "-filter_hw_device") + args = append(args, "rk") + if fullhw { + args = append(args, "-hwaccel") + args = append(args, "rkmpp") + args = append(args, "-hwaccel_output_format") + args = append(args, "drm_prime") + } } return args @@ -211,6 +248,14 @@ func (f *FFMpeg) hwFilterInit(toCodec VideoCodec, fullhw bool) VideoFilter { videoFilter = videoFilter.Append("format=nv12") videoFilter = videoFilter.Append("hwupload") } + case VideoCodecRK264: + // For Rockchip full-hw, do NOT pre-map to rkrga here. scale_rkrga can + // consume DRM_PRIME frames directly when filter_hw_device is set. + // For non-fullhw, keep a sane software format. + if !fullhw { + videoFilter = videoFilter.Append("format=nv12") + videoFilter = videoFilter.Append("hwupload") + } } return videoFilter @@ -288,6 +333,9 @@ func (f *FFMpeg) hwApplyFullHWFilter(args VideoFilter, codec VideoCodec, fullhw if fullhw && f.version.Gteq(Version{major: 3, minor: 3}) { // Added in FFMpeg 3.3 args = args.Append("scale_qsv=format=nv12") } + case VideoCodecRK264: + // For Rockchip, no extra mapping here. If there is no scale filter, + // leave frames in DRM_PRIME for the encoder. } return args @@ -315,6 +363,14 @@ func (f *FFMpeg) hwApplyScaleTemplate(sargs string, codec VideoCodec, match []in } case VideoCodecM264: template = "scale_vt=$value" + case VideoCodecRK264: + // The original filter chain is a fallback for maximum compatibility: + // "scale_rkrga=$value:format=nv12,hwdownload,format=nv12,hwupload" + // It avoids hwmap(rkrga→rkmpp) failures (-38/-12) seen on some builds + // by downloading the scaled frame to system RAM and re-uploading it. + // The filter chain below uses a zero-copy approach, passing the hardware-scaled + // frame directly to the encoder. This is more efficient but may be less stable. + template = "scale_rkrga=$value" default: return VideoFilter(sargs) } @@ -323,12 +379,15 @@ func (f *FFMpeg) hwApplyScaleTemplate(sargs string, codec VideoCodec, match []in isIntel := codec == VideoCodecI264 || codec == VideoCodecI264C || codec == VideoCodecIVP9 // BUG: scale_vt doesn't call ff_scale_adjust_dimensions, thus cant accept negative size values isApple := codec == VideoCodecM264 + // Rockchip's scale_rkrga supports -1/-2; don't apply minus-one hack here. return VideoFilter(templateReplaceScale(sargs, template, match, vf, isIntel || isApple)) } // Returns the max resolution for a given codec, or a default func (f *FFMpeg) hwCodecMaxRes(codec VideoCodec) (int, int) { switch codec { + case VideoCodecRK264: + return 8192, 8192 case VideoCodecN264, VideoCodecN264H, VideoCodecI264, @@ -360,7 +419,8 @@ func (f *FFMpeg) hwCodecHLSCompatible() *VideoCodec { VideoCodecI264C, VideoCodecV264, VideoCodecR264, - VideoCodecM264: // Note that the Apple encoder sucks at startup, thus HLS quality is crap + VideoCodecM264, // Note that the Apple encoder sucks at startup, thus HLS quality is crap + VideoCodecRK264: return &element } } @@ -375,7 +435,8 @@ func (f *FFMpeg) hwCodecMP4Compatible() *VideoCodec { VideoCodecN264H, VideoCodecI264, VideoCodecI264C, - VideoCodecM264: + VideoCodecM264, + VideoCodecRK264: return &element } } diff --git a/pkg/file/clean.go b/pkg/file/clean.go index 8c54fd0e0..53b2e0612 100644 --- a/pkg/file/clean.go +++ b/pkg/file/clean.go @@ -18,7 +18,8 @@ type Cleaner struct { FS models.FS Repository Repository - Handlers []CleanHandler + Handlers []CleanHandler + TrashPath string } type cleanJob struct { @@ -392,7 +393,7 @@ func (j *cleanJob) shouldCleanFolder(ctx context.Context, f *models.Folder) bool func (j *cleanJob) deleteFile(ctx context.Context, fileID models.FileID, fn string) { // delete associated objects - fileDeleter := NewDeleter() + fileDeleter := NewDeleterWithTrash(j.TrashPath) r := j.Repository if err := r.WithTxn(ctx, func(ctx context.Context) error { fileDeleter.RegisterHooks(ctx) @@ -410,7 +411,7 @@ func (j *cleanJob) deleteFile(ctx context.Context, fileID models.FileID, fn stri func (j *cleanJob) deleteFolder(ctx context.Context, folderID models.FolderID, fn string) { // delete associated objects - fileDeleter := NewDeleter() + fileDeleter := NewDeleterWithTrash(j.TrashPath) r := j.Repository if err := r.WithTxn(ctx, func(ctx context.Context) error { fileDeleter.RegisterHooks(ctx) diff --git a/pkg/file/delete.go b/pkg/file/delete.go index 88eb5169e..c36068faa 100644 --- a/pkg/file/delete.go +++ b/pkg/file/delete.go @@ -58,20 +58,33 @@ func newRenamerRemoverImpl() renamerRemoverImpl { // Deleter is used to safely delete files and directories from the filesystem. // During a transaction, files and directories are marked for deletion using -// the Files and Dirs methods. This will rename the files/directories to be -// deleted. If the transaction is rolled back, then the files/directories can -// be restored to their original state with the Abort method. If the -// transaction is committed, the marked files are then deleted from the -// filesystem using the Complete method. +// the Files and Dirs methods. If TrashPath is set, files are moved to trash +// immediately. Otherwise, they are renamed with a .delete suffix. If the +// transaction is rolled back, then the files/directories can be restored to +// their original state with the Rollback method. If the transaction is +// committed, the marked files are then deleted from the filesystem using the +// Commit method. type Deleter struct { RenamerRemover RenamerRemover files []string dirs []string + TrashPath string // if set, files will be moved to this directory instead of being permanently deleted + trashedPaths map[string]string // map of original path -> trash path (only used when TrashPath is set) } func NewDeleter() *Deleter { return &Deleter{ RenamerRemover: newRenamerRemoverImpl(), + TrashPath: "", + trashedPaths: make(map[string]string), + } +} + +func NewDeleterWithTrash(trashPath string) *Deleter { + return &Deleter{ + RenamerRemover: newRenamerRemoverImpl(), + TrashPath: trashPath, + trashedPaths: make(map[string]string), } } @@ -92,6 +105,17 @@ func (d *Deleter) RegisterHooks(ctx context.Context) { // Abort should be called to restore marked files if this function returns an // error. func (d *Deleter) Files(paths []string) error { + return d.filesInternal(paths, false) +} + +// FilesWithoutTrash designates files to be deleted, bypassing the trash directory. +// Files will be permanently deleted even if TrashPath is configured. +// This is useful for deleting generated files that can be easily recreated. +func (d *Deleter) FilesWithoutTrash(paths []string) error { + return d.filesInternal(paths, true) +} + +func (d *Deleter) filesInternal(paths []string, bypassTrash bool) error { for _, p := range paths { // fail silently if the file does not exist if _, err := d.RenamerRemover.Stat(p); err != nil { @@ -103,7 +127,7 @@ func (d *Deleter) Files(paths []string) error { return fmt.Errorf("check file %q exists: %w", p, err) } - if err := d.renameForDelete(p); err != nil { + if err := d.renameForDelete(p, bypassTrash); err != nil { return fmt.Errorf("marking file %q for deletion: %w", p, err) } d.files = append(d.files, p) @@ -118,6 +142,17 @@ func (d *Deleter) Files(paths []string) error { // Abort should be called to restore marked files/directories if this function returns an // error. func (d *Deleter) Dirs(paths []string) error { + return d.dirsInternal(paths, false) +} + +// DirsWithoutTrash designates directories to be deleted, bypassing the trash directory. +// Directories will be permanently deleted even if TrashPath is configured. +// This is useful for deleting generated directories that can be easily recreated. +func (d *Deleter) DirsWithoutTrash(paths []string) error { + return d.dirsInternal(paths, true) +} + +func (d *Deleter) dirsInternal(paths []string, bypassTrash bool) error { for _, p := range paths { // fail silently if the file does not exist if _, err := d.RenamerRemover.Stat(p); err != nil { @@ -129,7 +164,7 @@ func (d *Deleter) Dirs(paths []string) error { return fmt.Errorf("check directory %q exists: %w", p, err) } - if err := d.renameForDelete(p); err != nil { + if err := d.renameForDelete(p, bypassTrash); err != nil { return fmt.Errorf("marking directory %q for deletion: %w", p, err) } d.dirs = append(d.dirs, p) @@ -150,33 +185,65 @@ func (d *Deleter) Rollback() { d.files = nil d.dirs = nil + d.trashedPaths = make(map[string]string) } // Commit deletes all files marked for deletion and clears the marked list. +// When using trash, files have already been moved during renameForDelete, so +// this just clears the tracking. Otherwise, permanently delete the .delete files. // Any errors encountered are logged. All files will be attempted, regardless // of the errors encountered. func (d *Deleter) Commit() { - for _, f := range d.files { - if err := d.RenamerRemover.Remove(f + deleteFileSuffix); err != nil { - logger.Warnf("Error deleting file %q: %v", f+deleteFileSuffix, err) + if d.TrashPath != "" { + // Files were already moved to trash during renameForDelete, just clear tracking + logger.Debugf("Commit: %d files and %d directories already in trash, clearing tracking", len(d.files), len(d.dirs)) + } else { + // Permanently delete files and directories marked with .delete suffix + for _, f := range d.files { + if err := d.RenamerRemover.Remove(f + deleteFileSuffix); err != nil { + logger.Warnf("Error deleting file %q: %v", f+deleteFileSuffix, err) + } } - } - for _, f := range d.dirs { - if err := d.RenamerRemover.RemoveAll(f + deleteFileSuffix); err != nil { - logger.Warnf("Error deleting directory %q: %v", f+deleteFileSuffix, err) + for _, f := range d.dirs { + if err := d.RenamerRemover.RemoveAll(f + deleteFileSuffix); err != nil { + logger.Warnf("Error deleting directory %q: %v", f+deleteFileSuffix, err) + } } } d.files = nil d.dirs = nil + d.trashedPaths = make(map[string]string) } -func (d *Deleter) renameForDelete(path string) error { +func (d *Deleter) renameForDelete(path string, bypassTrash bool) error { + if d.TrashPath != "" && !bypassTrash { + // Move file to trash immediately + trashDest, err := fsutil.MoveToTrash(path, d.TrashPath) + if err != nil { + return err + } + d.trashedPaths[path] = trashDest + logger.Infof("Moved %q to trash at %s", path, trashDest) + return nil + } + + // Standard behavior: rename with .delete suffix (or when bypassing trash) return d.RenamerRemover.Rename(path, path+deleteFileSuffix) } func (d *Deleter) renameForRestore(path string) error { + if d.TrashPath != "" { + // Restore file from trash + trashPath, ok := d.trashedPaths[path] + if !ok { + return fmt.Errorf("no trash path found for %q", path) + } + return d.RenamerRemover.Rename(trashPath, path) + } + + // Standard behavior: restore from .delete suffix return d.RenamerRemover.Rename(path+deleteFileSuffix, path) } diff --git a/pkg/file/folder_rename_detect.go b/pkg/file/folder_rename_detect.go index 4f6d31bd5..4c057461b 100644 --- a/pkg/file/folder_rename_detect.go +++ b/pkg/file/folder_rename_detect.go @@ -107,7 +107,8 @@ func (s *scanJob) detectFolderMove(ctx context.Context, file scanFile) (*models. info, err := d.Info() if err != nil { - return fmt.Errorf("reading info for %q: %w", path, err) + logger.Errorf("reading info for %q: %v", path, err) + return nil } if !s.acceptEntry(ctx, path, info) { diff --git a/pkg/file/image/orientation.go b/pkg/file/image/orientation.go index 84f5774cf..0d9ebb2e3 100644 --- a/pkg/file/image/orientation.go +++ b/pkg/file/image/orientation.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + "strings" "github.com/rwcarlsen/goexif/exif" "github.com/stashapp/stash/pkg/logger" @@ -33,7 +34,7 @@ func areDimensionsFlipped(fs models.FS, path string) (bool, error) { x, err := exif.Decode(r) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || strings.Contains(err.Error(), "failed to find exif") { // no exif data return false, nil } diff --git a/pkg/file/image/scan.go b/pkg/file/image/scan.go index a1d63f649..635f421e4 100644 --- a/pkg/file/image/scan.go +++ b/pkg/file/image/scan.go @@ -50,7 +50,7 @@ func (d *Decorator) Decorate(ctx context.Context, fs models.FS, f models.File) ( isClip := true // This list is derived from ffmpegImageThumbnail in pkg/image/thumbnail. If one gets updated, the other should be as well - for _, item := range []string{"png", "mjpeg", "webp", "bmp"} { + for _, item := range []string{"png", "mjpeg", "webp", "bmp", "jpegxl"} { if item == probe.VideoCodec { isClip = false } diff --git a/pkg/file/scan.go b/pkg/file/scan.go index 8b0ec956e..40f474f34 100644 --- a/pkg/file/scan.go +++ b/pkg/file/scan.go @@ -239,7 +239,8 @@ func (s *scanJob) queueFileFunc(ctx context.Context, f models.FS, zipFile *scanF info, err := d.Info() if err != nil { - return fmt.Errorf("reading info for %q: %w", path, err) + logger.Errorf("reading info for %q: %v", path, err) + return nil } if !s.acceptEntry(ctx, path, info) { diff --git a/pkg/fsutil/trash.go b/pkg/fsutil/trash.go new file mode 100644 index 000000000..9a3bed835 --- /dev/null +++ b/pkg/fsutil/trash.go @@ -0,0 +1,43 @@ +package fsutil + +import ( + "fmt" + "os" + "path/filepath" + "time" +) + +// MoveToTrash moves a file or directory to a custom trash directory. +// If a file with the same name already exists in the trash, a timestamp is appended. +// Returns the destination path where the file was moved to. +func MoveToTrash(sourcePath string, trashPath string) (string, error) { + // Get absolute path for the source + absSourcePath, err := filepath.Abs(sourcePath) + if err != nil { + return "", fmt.Errorf("failed to get absolute path: %w", err) + } + + // Ensure trash directory exists + if err := os.MkdirAll(trashPath, 0755); err != nil { + return "", fmt.Errorf("failed to create trash directory: %w", err) + } + + // Get the base name of the file/directory + baseName := filepath.Base(absSourcePath) + destPath := filepath.Join(trashPath, baseName) + + // If a file with the same name already exists in trash, append timestamp + if _, err := os.Stat(destPath); err == nil { + ext := filepath.Ext(baseName) + nameWithoutExt := baseName[:len(baseName)-len(ext)] + timestamp := time.Now().Format("20060102-150405") + destPath = filepath.Join(trashPath, fmt.Sprintf("%s_%s%s", nameWithoutExt, timestamp, ext)) + } + + // Move the file to trash using SafeMove to support cross-filesystem moves + if err := SafeMove(absSourcePath, destPath); err != nil { + return "", fmt.Errorf("failed to move to trash: %w", err) + } + + return destPath, nil +} diff --git a/pkg/image/delete.go b/pkg/image/delete.go index 69fba9bd6..aa3a9c1c8 100644 --- a/pkg/image/delete.go +++ b/pkg/image/delete.go @@ -19,6 +19,7 @@ type FileDeleter struct { } // MarkGeneratedFiles marks for deletion the generated files for the provided image. +// Generated files bypass trash and are permanently deleted since they can be regenerated. func (d *FileDeleter) MarkGeneratedFiles(image *models.Image) error { var files []string thumbPath := d.Paths.Generated.GetThumbnailPath(image.Checksum, models.DefaultGthumbWidth) @@ -32,7 +33,7 @@ func (d *FileDeleter) MarkGeneratedFiles(image *models.Image) error { files = append(files, prevPath) } - return d.Files(files) + return d.FilesWithoutTrash(files) } // Destroy destroys an image, optionally marking the file and generated files for deletion. diff --git a/pkg/match/scraped.go b/pkg/match/scraped.go index b66f39a35..d3039f4c6 100644 --- a/pkg/match/scraped.go +++ b/pkg/match/scraped.go @@ -45,7 +45,7 @@ func (r SceneRelationships) MatchRelationships(ctx context.Context, s *models.Sc } for _, t := range s.Tags { - err := ScrapedTag(ctx, r.TagFinder, t) + err := ScrapedTag(ctx, r.TagFinder, t, endpoint) if err != nil { return err } @@ -190,11 +190,29 @@ func ScrapedGroup(ctx context.Context, qb GroupNamesFinder, storedID *string, na // ScrapedTag matches the provided tag with the tags // in the database and sets the ID field if one is found. -func ScrapedTag(ctx context.Context, qb models.TagQueryer, s *models.ScrapedTag) error { +func ScrapedTag(ctx context.Context, qb models.TagQueryer, s *models.ScrapedTag, stashBoxEndpoint string) error { if s.StoredID != nil { return nil } + // Check if a tag with the StashID already exists + if stashBoxEndpoint != "" && s.RemoteSiteID != nil { + if finder, ok := qb.(models.TagFinder); ok { + tags, err := finder.FindByStashID(ctx, models.StashID{ + StashID: *s.RemoteSiteID, + Endpoint: stashBoxEndpoint, + }) + if err != nil { + return err + } + if len(tags) > 0 { + id := strconv.Itoa(tags[0].ID) + s.StoredID = &id + return nil + } + } + } + t, err := tag.ByName(ctx, qb, s.Name) if err != nil { diff --git a/pkg/models/file.go b/pkg/models/file.go index e6ce41d1e..63c30ba4d 100644 --- a/pkg/models/file.go +++ b/pkg/models/file.go @@ -9,15 +9,35 @@ import ( type FileQueryOptions struct { QueryOptions FileFilter *FileFilterType + + TotalDuration bool + Megapixels bool + TotalSize bool } type FileFilterType struct { - And *FileFilterType `json:"AND"` - Or *FileFilterType `json:"OR"` - Not *FileFilterType `json:"NOT"` + OperatorFilter[FileFilterType] // Filter by path Path *StringCriterionInput `json:"path"` + + Basename *StringCriterionInput `json:"basename"` + Dir *StringCriterionInput `json:"dir"` + ParentFolder *HierarchicalMultiCriterionInput `json:"parent_folder"` + ZipFile *MultiCriterionInput `json:"zip_file"` + ModTime *TimestampCriterionInput `json:"mod_time"` + Duplicated *PHashDuplicationCriterionInput `json:"duplicated"` + Hashes []*FingerprintFilterInput `json:"hashes"` + VideoFileFilter *VideoFileFilterInput `json:"video_file_filter"` + ImageFileFilter *ImageFileFilterInput `json:"image_file_filter"` + SceneCount *IntCriterionInput `json:"scene_count"` + ImageCount *IntCriterionInput `json:"image_count"` + GalleryCount *IntCriterionInput `json:"gallery_count"` + ScenesFilter *SceneFilterType `json:"scenes_filter"` + ImagesFilter *ImageFilterType `json:"images_filter"` + GalleriesFilter *GalleryFilterType `json:"galleries_filter"` + CreatedAt *TimestampCriterionInput `json:"created_at"` + UpdatedAt *TimestampCriterionInput `json:"updated_at"` } func PathsFileFilter(paths []string) *FileFilterType { @@ -53,10 +73,10 @@ func PathsFileFilter(paths []string) *FileFilterType { } type FileQueryResult struct { - // can't use QueryResult because id type is wrong - - IDs []FileID - Count int + QueryResult[FileID] + TotalDuration float64 + Megapixels float64 + TotalSize int64 getter FileGetter files []File diff --git a/pkg/models/filter.go b/pkg/models/filter.go index 2d25f6516..97d850a55 100644 --- a/pkg/models/filter.go +++ b/pkg/models/filter.go @@ -200,3 +200,31 @@ type CustomFieldCriterionInput struct { Value []any `json:"value"` Modifier CriterionModifier `json:"modifier"` } + +type FingerprintFilterInput struct { + Type string `json:"type"` + Value string `json:"value"` + // Hamming distance - defaults to 0 + Distance *int `json:"distance,omitempty"` +} + +type VideoFileFilterInput struct { + Format *StringCriterionInput `json:"format,omitempty"` + Resolution *ResolutionCriterionInput `json:"resolution,omitempty"` + Orientation *OrientationCriterionInput `json:"orientation,omitempty"` + Framerate *IntCriterionInput `json:"framerate,omitempty"` + Bitrate *IntCriterionInput `json:"bitrate,omitempty"` + VideoCodec *StringCriterionInput `json:"video_codec,omitempty"` + AudioCodec *StringCriterionInput `json:"audio_codec,omitempty"` + // in seconds + Duration *IntCriterionInput `json:"duration,omitempty"` + Captions *StringCriterionInput `json:"captions,omitempty"` + Interactive *bool `json:"interactive,omitempty"` + InteractiveSpeed *IntCriterionInput `json:"interactive_speed,omitempty"` +} + +type ImageFileFilterInput struct { + Format *StringCriterionInput `json:"format,omitempty"` + Resolution *ResolutionCriterionInput `json:"resolution,omitempty"` + Orientation *OrientationCriterionInput `json:"orientation,omitempty"` +} diff --git a/pkg/models/folder.go b/pkg/models/folder.go new file mode 100644 index 000000000..ada9e17b7 --- /dev/null +++ b/pkg/models/folder.go @@ -0,0 +1,92 @@ +package models + +import ( + "context" + "path/filepath" + "strings" +) + +type FolderQueryOptions struct { + QueryOptions + FolderFilter *FolderFilterType + + TotalDuration bool + Megapixels bool + TotalSize bool +} + +type FolderFilterType struct { + OperatorFilter[FolderFilterType] + + Path *StringCriterionInput `json:"path,omitempty"` + Basename *StringCriterionInput `json:"basename,omitempty"` + // Filter by parent directory path + Dir *StringCriterionInput `json:"dir,omitempty"` + ParentFolder *HierarchicalMultiCriterionInput `json:"parent_folder,omitempty"` + ZipFile *MultiCriterionInput `json:"zip_file,omitempty"` + // Filter by modification time + ModTime *TimestampCriterionInput `json:"mod_time,omitempty"` + GalleryCount *IntCriterionInput `json:"gallery_count,omitempty"` + // Filter by files that meet this criteria + FilesFilter *FileFilterType `json:"files_filter,omitempty"` + // Filter by related galleries that meet this criteria + GalleriesFilter *GalleryFilterType `json:"galleries_filter,omitempty"` + // Filter by creation time + CreatedAt *TimestampCriterionInput `json:"created_at,omitempty"` + // Filter by last update time + UpdatedAt *TimestampCriterionInput `json:"updated_at,omitempty"` +} + +func PathsFolderFilter(paths []string) *FileFilterType { + if paths == nil { + return nil + } + + sep := string(filepath.Separator) + + var ret *FileFilterType + var or *FileFilterType + for _, p := range paths { + newOr := &FileFilterType{} + if or != nil { + or.Or = newOr + } else { + ret = newOr + } + + or = newOr + + if !strings.HasSuffix(p, sep) { + p += sep + } + + or.Path = &StringCriterionInput{ + Modifier: CriterionModifierEquals, + Value: p + "%", + } + } + + return ret +} + +type FolderQueryResult struct { + QueryResult[FolderID] + + getter FolderGetter + folders []*Folder + resolveErr error +} + +func NewFolderQueryResult(folderGetter FolderGetter) *FolderQueryResult { + return &FolderQueryResult{ + getter: folderGetter, + } +} + +func (r *FolderQueryResult) Resolve(ctx context.Context) ([]*Folder, error) { + // cache results + if r.folders == nil && r.resolveErr == nil { + r.folders, r.resolveErr = r.getter.FindMany(ctx, r.IDs) + } + return r.folders, r.resolveErr +} diff --git a/pkg/models/gallery.go b/pkg/models/gallery.go index 73fa287d2..5b75febc5 100644 --- a/pkg/models/gallery.go +++ b/pkg/models/gallery.go @@ -59,6 +59,10 @@ type GalleryFilterType struct { StudiosFilter *StudioFilterType `json:"studios_filter"` // Filter by related tags that meet this criteria TagsFilter *TagFilterType `json:"tags_filter"` + // Filter by related files that meet this criteria + FilesFilter *FileFilterType `json:"files_filter"` + // Filter by related folders that meet this criteria + FoldersFilter *FolderFilterType `json:"folders_filter"` // Filter by created at CreatedAt *TimestampCriterionInput `json:"created_at"` // Filter by updated at diff --git a/pkg/models/group.go b/pkg/models/group.go index 6afda3f48..6943b1055 100644 --- a/pkg/models/group.go +++ b/pkg/models/group.go @@ -23,6 +23,8 @@ type GroupFilterType struct { TagCount *IntCriterionInput `json:"tag_count"` // Filter by date Date *DateCriterionInput `json:"date"` + // Filter by O counter + OCounter *IntCriterionInput `json:"o_counter"` // Filter by containing groups ContainingGroups *HierarchicalMultiCriterionInput `json:"containing_groups"` // Filter by sub groups diff --git a/pkg/models/image.go b/pkg/models/image.go index 370315159..4ab10eabf 100644 --- a/pkg/models/image.go +++ b/pkg/models/image.go @@ -57,6 +57,8 @@ type ImageFilterType struct { StudiosFilter *StudioFilterType `json:"studios_filter"` // Filter by related tags that meet this criteria TagsFilter *TagFilterType `json:"tags_filter"` + // Filter by related files that meet this criteria + FilesFilter *FileFilterType `json:"files_filter"` // Filter by created at CreatedAt *TimestampCriterionInput `json:"created_at"` // Filter by updated at @@ -106,7 +108,7 @@ type ImageQueryOptions struct { } type ImageQueryResult struct { - QueryResult + QueryResult[int] Megapixels float64 TotalSize float64 diff --git a/pkg/models/jsonschema/studio.go b/pkg/models/jsonschema/studio.go index 80ed97d92..a3706df66 100644 --- a/pkg/models/jsonschema/studio.go +++ b/pkg/models/jsonschema/studio.go @@ -12,7 +12,7 @@ import ( type Studio struct { Name string `json:"name,omitempty"` - URL string `json:"url,omitempty"` + URLs []string `json:"urls,omitempty"` ParentStudio string `json:"parent_studio,omitempty"` Image string `json:"image,omitempty"` CreatedAt json.JSONTime `json:"created_at,omitempty"` @@ -24,6 +24,9 @@ type Studio struct { StashIDs []models.StashID `json:"stash_ids,omitempty"` Tags []string `json:"tags,omitempty"` IgnoreAutoTag bool `json:"ignore_auto_tag,omitempty"` + + // deprecated - for import only + URL string `json:"url,omitempty"` } func (s Studio) Filename() string { diff --git a/pkg/models/jsonschema/tag.go b/pkg/models/jsonschema/tag.go index ed2bc1c9c..faab1bfb2 100644 --- a/pkg/models/jsonschema/tag.go +++ b/pkg/models/jsonschema/tag.go @@ -6,20 +6,22 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/stashapp/stash/pkg/fsutil" + "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/models/json" ) type Tag struct { - Name string `json:"name,omitempty"` - SortName string `json:"sort_name,omitempty"` - Description string `json:"description,omitempty"` - Favorite bool `json:"favorite,omitempty"` - Aliases []string `json:"aliases,omitempty"` - Image string `json:"image,omitempty"` - Parents []string `json:"parents,omitempty"` - IgnoreAutoTag bool `json:"ignore_auto_tag,omitempty"` - CreatedAt json.JSONTime `json:"created_at,omitempty"` - UpdatedAt json.JSONTime `json:"updated_at,omitempty"` + Name string `json:"name,omitempty"` + SortName string `json:"sort_name,omitempty"` + Description string `json:"description,omitempty"` + Favorite bool `json:"favorite,omitempty"` + Aliases []string `json:"aliases,omitempty"` + Image string `json:"image,omitempty"` + Parents []string `json:"parents,omitempty"` + IgnoreAutoTag bool `json:"ignore_auto_tag,omitempty"` + StashIDs []models.StashID `json:"stash_ids,omitempty"` + CreatedAt json.JSONTime `json:"created_at,omitempty"` + UpdatedAt json.JSONTime `json:"updated_at,omitempty"` } func (s Tag) Filename() string { diff --git a/pkg/models/mocks/FolderReaderWriter.go b/pkg/models/mocks/FolderReaderWriter.go index 968bed4ad..512925fd6 100644 --- a/pkg/models/mocks/FolderReaderWriter.go +++ b/pkg/models/mocks/FolderReaderWriter.go @@ -178,6 +178,52 @@ func (_m *FolderReaderWriter) FindByZipFileID(ctx context.Context, zipFileID mod return r0, r1 } +// FindMany provides a mock function with given fields: ctx, id +func (_m *FolderReaderWriter) FindMany(ctx context.Context, id []models.FolderID) ([]*models.Folder, error) { + ret := _m.Called(ctx, id) + + var r0 []*models.Folder + if rf, ok := ret.Get(0).(func(context.Context, []models.FolderID) []*models.Folder); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*models.Folder) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, []models.FolderID) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Query provides a mock function with given fields: ctx, options +func (_m *FolderReaderWriter) Query(ctx context.Context, options models.FolderQueryOptions) (*models.FolderQueryResult, error) { + ret := _m.Called(ctx, options) + + var r0 *models.FolderQueryResult + if rf, ok := ret.Get(0).(func(context.Context, models.FolderQueryOptions) *models.FolderQueryResult); ok { + r0 = rf(ctx, options) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.FolderQueryResult) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, models.FolderQueryOptions) error); ok { + r1 = rf(ctx, options) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Update provides a mock function with given fields: ctx, f func (_m *FolderReaderWriter) Update(ctx context.Context, f *models.Folder) error { ret := _m.Called(ctx, f) diff --git a/pkg/models/mocks/ImageReaderWriter.go b/pkg/models/mocks/ImageReaderWriter.go index 2bbf4ceeb..afc5efdb7 100644 --- a/pkg/models/mocks/ImageReaderWriter.go +++ b/pkg/models/mocks/ImageReaderWriter.go @@ -594,6 +594,27 @@ func (_m *ImageReaderWriter) OCountByPerformerID(ctx context.Context, performerI return r0, r1 } +// OCountByStudioID provides a mock function with given fields: ctx, studioID +func (_m *ImageReaderWriter) OCountByStudioID(ctx context.Context, studioID int) (int, error) { + ret := _m.Called(ctx, studioID) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, int) int); ok { + r0 = rf(ctx, studioID) + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int) error); ok { + r1 = rf(ctx, studioID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Query provides a mock function with given fields: ctx, options func (_m *ImageReaderWriter) Query(ctx context.Context, options models.ImageQueryOptions) (*models.ImageQueryResult, error) { ret := _m.Called(ctx, options) diff --git a/pkg/models/mocks/SceneReaderWriter.go b/pkg/models/mocks/SceneReaderWriter.go index 8e4e5ae5a..ef10c890d 100644 --- a/pkg/models/mocks/SceneReaderWriter.go +++ b/pkg/models/mocks/SceneReaderWriter.go @@ -1141,6 +1141,27 @@ func (_m *SceneReaderWriter) HasCover(ctx context.Context, sceneID int) (bool, e return r0, r1 } +// OCountByGroupID provides a mock function with given fields: ctx, groupID +func (_m *SceneReaderWriter) OCountByGroupID(ctx context.Context, groupID int) (int, error) { + ret := _m.Called(ctx, groupID) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, int) int); ok { + r0 = rf(ctx, groupID) + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int) error); ok { + r1 = rf(ctx, groupID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // OCountByPerformerID provides a mock function with given fields: ctx, performerID func (_m *SceneReaderWriter) OCountByPerformerID(ctx context.Context, performerID int) (int, error) { ret := _m.Called(ctx, performerID) @@ -1162,6 +1183,27 @@ func (_m *SceneReaderWriter) OCountByPerformerID(ctx context.Context, performerI return r0, r1 } +// OCountByStudioID provides a mock function with given fields: ctx, studioID +func (_m *SceneReaderWriter) OCountByStudioID(ctx context.Context, studioID int) (int, error) { + ret := _m.Called(ctx, studioID) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context, int) int); ok { + r0 = rf(ctx, studioID) + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int) error); ok { + r1 = rf(ctx, studioID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // PlayDuration provides a mock function with given fields: ctx func (_m *SceneReaderWriter) PlayDuration(ctx context.Context) (float64, error) { ret := _m.Called(ctx) diff --git a/pkg/models/mocks/StudioReaderWriter.go b/pkg/models/mocks/StudioReaderWriter.go index d4932ca71..481565d6f 100644 --- a/pkg/models/mocks/StudioReaderWriter.go +++ b/pkg/models/mocks/StudioReaderWriter.go @@ -360,6 +360,29 @@ func (_m *StudioReaderWriter) GetTagIDs(ctx context.Context, relatedID int) ([]i return r0, r1 } +// GetURLs provides a mock function with given fields: ctx, relatedID +func (_m *StudioReaderWriter) GetURLs(ctx context.Context, relatedID int) ([]string, error) { + ret := _m.Called(ctx, relatedID) + + var r0 []string + if rf, ok := ret.Get(0).(func(context.Context, int) []string); ok { + r0 = rf(ctx, relatedID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int) error); ok { + r1 = rf(ctx, relatedID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // HasImage provides a mock function with given fields: ctx, studioID func (_m *StudioReaderWriter) HasImage(ctx context.Context, studioID int) (bool, error) { ret := _m.Called(ctx, studioID) diff --git a/pkg/models/mocks/TagReaderWriter.go b/pkg/models/mocks/TagReaderWriter.go index a285b97bf..ac6b10584 100644 --- a/pkg/models/mocks/TagReaderWriter.go +++ b/pkg/models/mocks/TagReaderWriter.go @@ -427,6 +427,29 @@ func (_m *TagReaderWriter) FindBySceneMarkerID(ctx context.Context, sceneMarkerI return r0, r1 } +// FindByStashID provides a mock function with given fields: ctx, stashID +func (_m *TagReaderWriter) FindByStashID(ctx context.Context, stashID models.StashID) ([]*models.Tag, error) { + ret := _m.Called(ctx, stashID) + + var r0 []*models.Tag + if rf, ok := ret.Get(0).(func(context.Context, models.StashID) []*models.Tag); ok { + r0 = rf(ctx, stashID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*models.Tag) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, models.StashID) error); ok { + r1 = rf(ctx, stashID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FindByStudioID provides a mock function with given fields: ctx, studioID func (_m *TagReaderWriter) FindByStudioID(ctx context.Context, studioID int) ([]*models.Tag, error) { ret := _m.Called(ctx, studioID) @@ -565,6 +588,29 @@ func (_m *TagReaderWriter) GetParentIDs(ctx context.Context, relatedID int) ([]i return r0, r1 } +// GetStashIDs provides a mock function with given fields: ctx, relatedID +func (_m *TagReaderWriter) GetStashIDs(ctx context.Context, relatedID int) ([]models.StashID, error) { + ret := _m.Called(ctx, relatedID) + + var r0 []models.StashID + if rf, ok := ret.Get(0).(func(context.Context, int) []models.StashID); ok { + r0 = rf(ctx, relatedID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]models.StashID) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int) error); ok { + r1 = rf(ctx, relatedID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // HasImage provides a mock function with given fields: ctx, tagID func (_m *TagReaderWriter) HasImage(ctx context.Context, tagID int) (bool, error) { ret := _m.Called(ctx, tagID) diff --git a/pkg/models/model_file.go b/pkg/models/model_file.go index e9df57990..f6b8bdc51 100644 --- a/pkg/models/model_file.go +++ b/pkg/models/model_file.go @@ -79,6 +79,14 @@ func (i FileID) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(i.String())) } +func FileIDsFromInts(ids []int) []FileID { + ret := make([]FileID, len(ids)) + for i, id := range ids { + ret[i] = FileID(id) + } + return ret +} + // DirEntry represents a file or directory in the file system. type DirEntry struct { ZipFileID *FileID `json:"zip_file_id"` @@ -252,6 +260,10 @@ func (f ImageFile) GetHeight() int { return f.Height } +func (f ImageFile) Megapixels() float64 { + return float64(f.Width*f.Height) / 1e6 +} + func (f ImageFile) GetFormat() string { return f.Format } diff --git a/pkg/models/model_folder.go b/pkg/models/model_folder.go index 590cdd7bd..39897aa60 100644 --- a/pkg/models/model_folder.go +++ b/pkg/models/model_folder.go @@ -35,6 +35,14 @@ func (i FolderID) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(i.String())) } +func FolderIDsFromInts(ids []int) []FolderID { + ret := make([]FolderID, len(ids)) + for i, id := range ids { + ret[i] = FolderID(id) + } + return ret +} + // Folder represents a folder in the file system. type Folder struct { ID FolderID `json:"id"` diff --git a/pkg/models/model_scene_marker.go b/pkg/models/model_scene_marker.go index 778603315..8d723b391 100644 --- a/pkg/models/model_scene_marker.go +++ b/pkg/models/model_scene_marker.go @@ -30,6 +30,7 @@ type SceneMarkerPartial struct { Seconds OptionalFloat64 EndSeconds OptionalFloat64 PrimaryTagID OptionalInt + TagIDs *UpdateIDs SceneID OptionalInt CreatedAt OptionalTime UpdatedAt OptionalTime diff --git a/pkg/models/model_scraped_item.go b/pkg/models/model_scraped_item.go index 008a05c3d..417564db5 100644 --- a/pkg/models/model_scraped_item.go +++ b/pkg/models/model_scraped_item.go @@ -14,10 +14,14 @@ type ScrapedStudio struct { // Set if studio matched StoredID *string `json:"stored_id"` Name string `json:"name"` - URL *string `json:"url"` + URL *string `json:"url"` // deprecated + URLs []string `json:"urls"` Parent *ScrapedStudio `json:"parent"` Image *string `json:"image"` Images []string `json:"images"` + Details *string `json:"details"` + Aliases *string `json:"aliases"` + Tags []*ScrapedTag `json:"tags"` RemoteSiteID *string `json:"remote_site_id"` } @@ -38,8 +42,28 @@ func (s *ScrapedStudio) ToStudio(endpoint string, excluded map[string]bool) *Stu }) } - if s.URL != nil && !excluded["url"] { - ret.URL = *s.URL + // if URLs are provided, only use those + if len(s.URLs) > 0 { + if !excluded["urls"] { + ret.URLs = NewRelatedStrings(s.URLs) + } + } else { + urls := []string{} + if s.URL != nil && !excluded["url"] { + urls = append(urls, *s.URL) + } + + if len(urls) > 0 { + ret.URLs = NewRelatedStrings(urls) + } + } + + if s.Details != nil && !excluded["details"] { + ret.Details = *s.Details + } + + if s.Aliases != nil && *s.Aliases != "" && !excluded["aliases"] { + ret.Aliases = NewRelatedStrings(stringslice.FromString(*s.Aliases, ",")) } if s.Parent != nil && s.Parent.StoredID != nil && !excluded["parent"] && !excluded["parent_studio"] { @@ -74,8 +98,36 @@ func (s *ScrapedStudio) ToPartial(id string, endpoint string, excluded map[strin ret.Name = NewOptionalString(s.Name) } - if s.URL != nil && !excluded["url"] { - ret.URL = NewOptionalString(*s.URL) + if len(s.URLs) > 0 { + if !excluded["urls"] { + ret.URLs = &UpdateStrings{ + Values: s.URLs, + Mode: RelationshipUpdateModeSet, + } + } + } else { + urls := []string{} + if s.URL != nil && !excluded["url"] { + urls = append(urls, *s.URL) + } + + if len(urls) > 0 { + ret.URLs = &UpdateStrings{ + Values: urls, + Mode: RelationshipUpdateModeSet, + } + } + } + + if s.Details != nil && !excluded["details"] { + ret.Details = NewOptionalString(*s.Details) + } + + if s.Aliases != nil && !excluded["aliases"] { + ret.Aliases = &UpdateStrings{ + Values: stringslice.FromString(*s.Aliases, ","), + Mode: RelationshipUpdateModeSet, + } } if s.Parent != nil && !excluded["parent"] { @@ -395,12 +447,31 @@ func (p *ScrapedPerformer) ToPartial(endpoint string, excluded map[string]bool, type ScrapedTag struct { // Set if tag matched - StoredID *string `json:"stored_id"` - Name string `json:"name"` + StoredID *string `json:"stored_id"` + Name string `json:"name"` + RemoteSiteID *string `json:"remote_site_id"` } func (ScrapedTag) IsScrapedContent() {} +func (t *ScrapedTag) ToTag(endpoint string, excluded map[string]bool) *Tag { + currentTime := time.Now() + ret := NewTag() + ret.Name = t.Name + + if t.RemoteSiteID != nil && endpoint != "" { + ret.StashIDs = NewRelatedStashIDs([]StashID{ + { + Endpoint: endpoint, + StashID: *t.RemoteSiteID, + UpdatedAt: currentTime, + }, + }) + } + + return &ret +} + func ScrapedTagSortFunction(a, b *ScrapedTag) int { return strings.Compare(strings.ToLower(a.Name), strings.ToLower(b.Name)) } @@ -462,6 +533,7 @@ type ScrapedGroup struct { Date *string `json:"date"` Rating *string `json:"rating"` Director *string `json:"director"` + URL *string `json:"url"` // included for backward compatibility URLs []string `json:"urls"` Synopsis *string `json:"synopsis"` Studio *ScrapedStudio `json:"studio"` diff --git a/pkg/models/model_scraped_item_test.go b/pkg/models/model_scraped_item_test.go index 1e8edccb4..b6b44025f 100644 --- a/pkg/models/model_scraped_item_test.go +++ b/pkg/models/model_scraped_item_test.go @@ -11,6 +11,7 @@ import ( func Test_scrapedToStudioInput(t *testing.T) { const name = "name" url := "url" + url2 := "url2" emptyEndpoint := "" endpoint := "endpoint" remoteSiteID := "remoteSiteID" @@ -25,13 +26,33 @@ func Test_scrapedToStudioInput(t *testing.T) { "set all", &ScrapedStudio{ Name: name, + URLs: []string{url, url2}, URL: &url, RemoteSiteID: &remoteSiteID, }, endpoint, &Studio{ Name: name, - URL: url, + URLs: NewRelatedStrings([]string{url, url2}), + StashIDs: NewRelatedStashIDs([]StashID{ + { + Endpoint: endpoint, + StashID: remoteSiteID, + }, + }), + }, + }, + { + "set url instead of urls", + &ScrapedStudio{ + Name: name, + URL: &url, + RemoteSiteID: &remoteSiteID, + }, + endpoint, + &Studio{ + Name: name, + URLs: NewRelatedStrings([]string{url}), StashIDs: NewRelatedStashIDs([]StashID{ { Endpoint: endpoint, @@ -321,9 +342,12 @@ func TestScrapedStudio_ToPartial(t *testing.T) { fullStudio, stdArgs, StudioPartial{ - ID: id, - Name: NewOptionalString(name), - URL: NewOptionalString(url), + ID: id, + Name: NewOptionalString(name), + URLs: &UpdateStrings{ + Values: []string{url}, + Mode: RelationshipUpdateModeSet, + }, ParentID: NewOptionalInt(parentStoredID), StashIDs: &UpdateStashIDs{ StashIDs: append(existingStashIDs, StashID{ diff --git a/pkg/models/model_studio.go b/pkg/models/model_studio.go index 0f4a09bc2..8c7a687af 100644 --- a/pkg/models/model_studio.go +++ b/pkg/models/model_studio.go @@ -8,7 +8,6 @@ import ( type Studio struct { ID int `json:"id"` Name string `json:"name"` - URL string `json:"url"` ParentID *int `json:"parent_id"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` @@ -19,6 +18,7 @@ type Studio struct { IgnoreAutoTag bool `json:"ignore_auto_tag"` Aliases RelatedStrings `json:"aliases"` + URLs RelatedStrings `json:"urls"` TagIDs RelatedIDs `json:"tag_ids"` StashIDs RelatedStashIDs `json:"stash_ids"` } @@ -35,7 +35,6 @@ func NewStudio() Studio { type StudioPartial struct { ID int Name OptionalString - URL OptionalString ParentID OptionalInt // Rating expressed in 1-100 scale Rating OptionalInt @@ -46,6 +45,7 @@ type StudioPartial struct { IgnoreAutoTag OptionalBool Aliases *UpdateStrings + URLs *UpdateStrings TagIDs *UpdateIDs StashIDs *UpdateStashIDs } @@ -63,6 +63,12 @@ func (s *Studio) LoadAliases(ctx context.Context, l AliasLoader) error { }) } +func (s *Studio) LoadURLs(ctx context.Context, l URLLoader) error { + return s.URLs.load(func() ([]string, error) { + return l.GetURLs(ctx, s.ID) + }) +} + func (s *Studio) LoadTagIDs(ctx context.Context, l TagIDLoader) error { return s.TagIDs.load(func() ([]int, error) { return l.GetTagIDs(ctx, s.ID) diff --git a/pkg/models/model_tag.go b/pkg/models/model_tag.go index 0d845750f..4cd038f7e 100644 --- a/pkg/models/model_tag.go +++ b/pkg/models/model_tag.go @@ -15,9 +15,10 @@ type Tag struct { CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` - Aliases RelatedStrings `json:"aliases"` - ParentIDs RelatedIDs `json:"parent_ids"` - ChildIDs RelatedIDs `json:"tag_ids"` + Aliases RelatedStrings `json:"aliases"` + ParentIDs RelatedIDs `json:"parent_ids"` + ChildIDs RelatedIDs `json:"tag_ids"` + StashIDs RelatedStashIDs `json:"stash_ids"` } func NewTag() Tag { @@ -46,6 +47,12 @@ func (s *Tag) LoadChildIDs(ctx context.Context, l TagRelationLoader) error { }) } +func (s *Tag) LoadStashIDs(ctx context.Context, l StashIDLoader) error { + return s.StashIDs.load(func() ([]StashID, error) { + return l.GetStashIDs(ctx, s.ID) + }) +} + type TagPartial struct { Name OptionalString SortName OptionalString @@ -58,6 +65,7 @@ type TagPartial struct { Aliases *UpdateStrings ParentIDs *UpdateIDs ChildIDs *UpdateIDs + StashIDs *UpdateStashIDs } func NewTagPartial() TagPartial { diff --git a/pkg/models/paths/paths_generated.go b/pkg/models/paths/paths_generated.go index d87e1eed6..2b5f5003e 100644 --- a/pkg/models/paths/paths_generated.go +++ b/pkg/models/paths/paths_generated.go @@ -43,6 +43,9 @@ func (gp *generatedPaths) GetTmpPath(fileName string) string { // TempFile creates a temporary file using os.CreateTemp. // It is the equivalent of calling os.CreateTemp using Tmp and pattern. func (gp *generatedPaths) TempFile(pattern string) (*os.File, error) { + if err := gp.EnsureTmpDir(); err != nil { + logger.Warnf("Could not ensure existence of a temporary directory: %v", err) + } return os.CreateTemp(gp.Tmp, pattern) } diff --git a/pkg/models/query.go b/pkg/models/query.go index 1b2d347b9..a6e15bc4e 100644 --- a/pkg/models/query.go +++ b/pkg/models/query.go @@ -5,7 +5,7 @@ type QueryOptions struct { Count bool } -type QueryResult struct { - IDs []int +type QueryResult[T comparable] struct { + IDs []T Count int } diff --git a/pkg/models/repository_folder.go b/pkg/models/repository_folder.go index c3f82f529..671e8780d 100644 --- a/pkg/models/repository_folder.go +++ b/pkg/models/repository_folder.go @@ -5,6 +5,7 @@ import "context" // FolderGetter provides methods to get folders by ID. type FolderGetter interface { Find(ctx context.Context, id FolderID) (*Folder, error) + FindMany(ctx context.Context, id []FolderID) ([]*Folder, error) } // FolderFinder provides methods to find folders. @@ -16,6 +17,10 @@ type FolderFinder interface { FindByParentFolderID(ctx context.Context, parentFolderID FolderID) ([]*Folder, error) } +type FolderQueryer interface { + Query(ctx context.Context, options FolderQueryOptions) (*FolderQueryResult, error) +} + type FolderCounter interface { CountAllInPaths(ctx context.Context, p []string) (int, error) } @@ -47,6 +52,7 @@ type FolderFinderDestroyer interface { // FolderReader provides all methods to read folders. type FolderReader interface { FolderFinder + FolderQueryer FolderCounter } diff --git a/pkg/models/repository_image.go b/pkg/models/repository_image.go index 1455d7762..672ecd063 100644 --- a/pkg/models/repository_image.go +++ b/pkg/models/repository_image.go @@ -38,6 +38,7 @@ type ImageCounter interface { CountByGalleryID(ctx context.Context, galleryID int) (int, error) OCount(ctx context.Context) (int, error) OCountByPerformerID(ctx context.Context, performerID int) (int, error) + OCountByStudioID(ctx context.Context, studioID int) (int, error) } // ImageCreator provides methods to create images. diff --git a/pkg/models/repository_scene.go b/pkg/models/repository_scene.go index f0fff4ac7..8c2833470 100644 --- a/pkg/models/repository_scene.go +++ b/pkg/models/repository_scene.go @@ -44,6 +44,8 @@ type SceneCounter interface { CountMissingChecksum(ctx context.Context) (int, error) CountMissingOSHash(ctx context.Context) (int, error) OCountByPerformerID(ctx context.Context, performerID int) (int, error) + OCountByGroupID(ctx context.Context, groupID int) (int, error) + OCountByStudioID(ctx context.Context, studioID int) (int, error) } // SceneCreator provides methods to create scenes. diff --git a/pkg/models/repository_studio.go b/pkg/models/repository_studio.go index a2b9202f3..99f98bffc 100644 --- a/pkg/models/repository_studio.go +++ b/pkg/models/repository_studio.go @@ -77,6 +77,7 @@ type StudioReader interface { AliasLoader StashIDLoader TagIDLoader + URLLoader All(ctx context.Context) ([]*Studio, error) GetImage(ctx context.Context, studioID int) ([]byte, error) diff --git a/pkg/models/repository_tag.go b/pkg/models/repository_tag.go index 2b073cae0..a7f828f0b 100644 --- a/pkg/models/repository_tag.go +++ b/pkg/models/repository_tag.go @@ -25,6 +25,7 @@ type TagFinder interface { FindByStudioID(ctx context.Context, studioID int) ([]*Tag, error) FindByName(ctx context.Context, name string, nocase bool) (*Tag, error) FindByNames(ctx context.Context, names []string, nocase bool) ([]*Tag, error) + FindByStashID(ctx context.Context, stashID StashID) ([]*Tag, error) } // TagQueryer provides methods to query tags. @@ -87,6 +88,7 @@ type TagReader interface { AliasLoader TagRelationLoader + StashIDLoader All(ctx context.Context) ([]*Tag, error) GetImage(ctx context.Context, tagID int) ([]byte, error) diff --git a/pkg/models/scene.go b/pkg/models/scene.go index c7be343d9..f0a863bf7 100644 --- a/pkg/models/scene.go +++ b/pkg/models/scene.go @@ -111,6 +111,8 @@ type SceneFilterType struct { MoviesFilter *GroupFilterType `json:"movies_filter"` // Filter by related markers that meet this criteria MarkersFilter *SceneMarkerFilterType `json:"markers_filter"` + // Filter by related files that meet this criteria + FilesFilter *FileFilterType `json:"files_filter"` // Filter by created at CreatedAt *TimestampCriterionInput `json:"created_at"` // Filter by updated at @@ -126,7 +128,7 @@ type SceneQueryOptions struct { } type SceneQueryResult struct { - QueryResult + QueryResult[int] TotalDuration float64 TotalSize float64 diff --git a/pkg/models/stash_ids.go b/pkg/models/stash_ids.go index 7751c2ef0..d761e959f 100644 --- a/pkg/models/stash_ids.go +++ b/pkg/models/stash_ids.go @@ -79,10 +79,23 @@ func (s StashIDInputs) ToStashIDs() StashIDs { return nil } - ret := make(StashIDs, len(s)) - for i, v := range s { - ret[i] = v.ToStashID() + // #2800 - deduplicate StashIDs based on endpoint and stash_id + ret := make(StashIDs, 0, len(s)) + seen := make(map[string]map[string]bool) + + for _, v := range s { + stashID := v.ToStashID() + + if seen[stashID.Endpoint] == nil { + seen[stashID.Endpoint] = make(map[string]bool) + } + + if !seen[stashID.Endpoint][stashID.StashID] { + seen[stashID.Endpoint][stashID.StashID] = true + ret = append(ret, stashID) + } } + return ret } diff --git a/pkg/models/studio.go b/pkg/models/studio.go index 03ea8a84d..171168129 100644 --- a/pkg/models/studio.go +++ b/pkg/models/studio.go @@ -47,9 +47,10 @@ type StudioFilterType struct { } type StudioCreateInput struct { - Name string `json:"name"` - URL *string `json:"url"` - ParentID *string `json:"parent_id"` + Name string `json:"name"` + URL *string `json:"url"` // deprecated + Urls []string `json:"urls"` + ParentID *string `json:"parent_id"` // This should be a URL or a base64 encoded data URL Image *string `json:"image"` StashIds []StashIDInput `json:"stash_ids"` @@ -62,10 +63,11 @@ type StudioCreateInput struct { } type StudioUpdateInput struct { - ID string `json:"id"` - Name *string `json:"name"` - URL *string `json:"url"` - ParentID *string `json:"parent_id"` + ID string `json:"id"` + Name *string `json:"name"` + URL *string `json:"url"` // deprecated + Urls []string `json:"urls"` + ParentID *string `json:"parent_id"` // This should be a URL or a base64 encoded data URL Image *string `json:"image"` StashIds []StashIDInput `json:"stash_ids"` diff --git a/pkg/performer/import.go b/pkg/performer/import.go index 3aaacdb8b..622af2b1a 100644 --- a/pkg/performer/import.go +++ b/pkg/performer/import.go @@ -233,7 +233,7 @@ func performerJSONToPerformer(performerJSON jsonschema.Performer) models.Perform } if len(urls) > 0 { - newPerformer.URLs = models.NewRelatedStrings([]string{performerJSON.URL}) + newPerformer.URLs = models.NewRelatedStrings(urls) } } diff --git a/pkg/plugin/examples/react-component/README.md b/pkg/plugin/examples/react-component/README.md index 5a42a3749..383b47235 100644 --- a/pkg/plugin/examples/react-component/README.md +++ b/pkg/plugin/examples/react-component/README.md @@ -1,7 +1,7 @@ This is a reference React component plugin. It replaces the `details` part of scene cards with a list of performers and tags. To build: -- run `yarn install --frozen-lockfile` -- run `yarn run build` +- run `pnpm install --frozen-lockfile` +- run `npm run build` This will copy the plugin files into the `dist` directory. These files can be copied to a `plugins` directory. diff --git a/pkg/plugin/examples/react-component/package.json b/pkg/plugin/examples/react-component/package.json index b37205d9c..1c07e5774 100644 --- a/pkg/plugin/examples/react-component/package.json +++ b/pkg/plugin/examples/react-component/package.json @@ -5,11 +5,11 @@ "author": "WithoutPants", "license": "AGPL-3.0", "scripts": { - "compile:ts": "yarn tsc", - "compile:sass": "yarn sass src/testReact.scss dist/testReact.css", + "compile:ts": "npm run tsc", + "compile:sass": "npm run sass src/testReact.scss dist/testReact.css", "copy:yml": "cpx \"src/testReact.yml\" \"dist\"", - "compile": "yarn run compile:ts && yarn run compile:sass", - "build": "yarn run compile && yarn run copy:yml" + "compile": "npm run compile:ts && npm run compile:sass", + "build": "npm run compile && npm run copy:yml" }, "devDependencies": { "@types/react": "^18.2.31", diff --git a/pkg/plugin/examples/react-component/pnpm-lock.yaml b/pkg/plugin/examples/react-component/pnpm-lock.yaml new file mode 100644 index 000000000..d19c17347 --- /dev/null +++ b/pkg/plugin/examples/react-component/pnpm-lock.yaml @@ -0,0 +1,1578 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@types/react': + specifier: ^18.2.31 + version: 18.3.26 + '@types/react-dom': + specifier: ^18.2.14 + version: 18.3.7(@types/react@18.3.26) + cpx: + specifier: ^1.5.0 + version: 1.5.0 + sass: + specifier: ^1.69.4 + version: 1.93.2 + typescript: + specifier: ^5.2.2 + version: 5.9.3 + +packages: + + '@parcel/watcher-android-arm64@2.5.1': + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.1': + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.1': + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.1': + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.1': + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.1': + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.1': + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.1': + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.1': + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.1': + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.1': + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.1': + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.1': + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} + + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + peerDependencies: + '@types/react': ^18.0.0 + + '@types/react@18.3.26': + resolution: {integrity: sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==} + + anymatch@1.3.2: + resolution: {integrity: sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==} + + arr-diff@2.0.0: + resolution: {integrity: sha512-dtXTVMkh6VkEEA7OhXnN1Ecb8aAGFdZ1LFxtOCoqj4qkyOJMt7+qs6Ahdy6p/NQCPYsRSXXivhSB/J5E9jmYKA==} + engines: {node: '>=0.10.0'} + + arr-diff@4.0.0: + resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} + engines: {node: '>=0.10.0'} + + arr-flatten@1.1.0: + resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} + engines: {node: '>=0.10.0'} + + arr-union@3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + + array-unique@0.2.1: + resolution: {integrity: sha512-G2n5bG5fSUCpnsXz4+8FUkYsGPkNfLn9YvS66U5qbTIXI2Ynnlo4Bi42bWv+omKUCqz+ejzfClwne0alJWJPhg==} + engines: {node: '>=0.10.0'} + + array-unique@0.3.2: + resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} + engines: {node: '>=0.10.0'} + + assign-symbols@1.0.0: + resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} + engines: {node: '>=0.10.0'} + + async-each@1.0.6: + resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==} + + atob@2.1.2: + resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} + engines: {node: '>= 4.5.0'} + hasBin: true + + babel-runtime@6.26.0: + resolution: {integrity: sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base@0.11.2: + resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} + engines: {node: '>=0.10.0'} + + binary-extensions@1.13.1: + resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} + engines: {node: '>=0.10.0'} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + braces@1.8.5: + resolution: {integrity: sha512-xU7bpz2ytJl1bH9cgIurjpg/n8Gohy9GTw81heDYLJQ4RU60dlyJsa+atVF2pI0yMMvKxI9HkKwjePCj5XI1hw==} + engines: {node: '>=0.10.0'} + + braces@2.3.2: + resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} + engines: {node: '>=0.10.0'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + cache-base@1.0.1: + resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} + engines: {node: '>=0.10.0'} + + chokidar@1.7.0: + resolution: {integrity: sha512-mk8fAWcRUOxY7btlLtitj3A45jOwSAxH4tOFOoEGbVsl6cL6pPMWUy7dwZ/canfj3QEdP6FHSnf/l1c6/WkzVg==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + class-utils@0.3.6: + resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} + engines: {node: '>=0.10.0'} + + collection-visit@1.0.0: + resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} + engines: {node: '>=0.10.0'} + + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + copy-descriptor@0.1.1: + resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} + engines: {node: '>=0.10.0'} + + core-js@2.6.12: + resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} + deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cpx@1.5.0: + resolution: {integrity: sha512-jHTjZhsbg9xWgsP2vuNW2jnnzBX+p4T+vNI9Lbjzs1n4KhOfa22bQppiFYLsWQKd8TzmL5aSP/Me3yfsCwXbDA==} + hasBin: true + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + + define-property@0.2.5: + resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} + engines: {node: '>=0.10.0'} + + define-property@1.0.0: + resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} + engines: {node: '>=0.10.0'} + + define-property@2.0.2: + resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} + engines: {node: '>=0.10.0'} + + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + expand-brackets@0.1.5: + resolution: {integrity: sha512-hxx03P2dJxss6ceIeri9cmYOT4SRs3Zk3afZwWpOsRqLqprhTR8u++SlC+sFGsQr7WGFPdMF7Gjc1njDLDK6UA==} + engines: {node: '>=0.10.0'} + + expand-brackets@2.1.4: + resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} + engines: {node: '>=0.10.0'} + + expand-range@1.8.2: + resolution: {integrity: sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA==} + engines: {node: '>=0.10.0'} + + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend-shallow@3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + + extglob@0.3.2: + resolution: {integrity: sha512-1FOj1LOwn42TMrruOHGt18HemVnbwAmAak7krWk+wa93KXxGbK+2jpezm+ytJYDaBX0/SPLZFHKM7m+tKobWGg==} + engines: {node: '>=0.10.0'} + + extglob@2.0.4: + resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} + engines: {node: '>=0.10.0'} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + filename-regex@2.0.1: + resolution: {integrity: sha512-BTCqyBaWBTsauvnHiE8i562+EdJj+oUpkqWp2R1iCoR8f6oo8STRu3of7WJJ0TqWtxN50a5YFpzYK4Jj9esYfQ==} + engines: {node: '>=0.10.0'} + + fill-range@2.2.4: + resolution: {integrity: sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==} + engines: {node: '>=0.10.0'} + + fill-range@4.0.0: + resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} + engines: {node: '>=0.10.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-index@0.1.1: + resolution: {integrity: sha512-uJ5vWrfBKMcE6y2Z8834dwEZj9mNGxYa3t3I53OwFeuZ8D9oc2E5zcsrkuhX6h4iYrjhiv0T3szQmxlAV9uxDg==} + + for-in@1.0.2: + resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} + engines: {node: '>=0.10.0'} + + for-own@0.1.5: + resolution: {integrity: sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==} + engines: {node: '>=0.10.0'} + + fragment-cache@0.2.1: + resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} + engines: {node: '>=0.10.0'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@1.2.13: + resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} + engines: {node: '>= 4.0'} + os: [darwin] + deprecated: Upgrade to fsevents v2 to mitigate potential security issues + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-value@2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} + + glob-base@0.3.0: + resolution: {integrity: sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==} + engines: {node: '>=0.10.0'} + + glob-parent@2.0.0: + resolution: {integrity: sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==} + + glob2base@0.0.12: + resolution: {integrity: sha512-ZyqlgowMbfj2NPjxaZZ/EtsXlOch28FRXgMd64vqZWk1bT9+wvSRLYD1om9M7QfQru51zJPAT17qXm4/zd+9QA==} + engines: {node: '>= 0.10'} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-value@0.3.1: + resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} + engines: {node: '>=0.10.0'} + + has-value@1.0.0: + resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} + engines: {node: '>=0.10.0'} + + has-values@0.1.4: + resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} + engines: {node: '>=0.10.0'} + + has-values@1.0.0: + resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} + engines: {node: '>=0.10.0'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + immutable@5.1.4: + resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-accessor-descriptor@1.0.1: + resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} + engines: {node: '>= 0.10'} + + is-binary-path@1.0.1: + resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==} + engines: {node: '>=0.10.0'} + + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-descriptor@1.0.1: + resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} + engines: {node: '>= 0.4'} + + is-descriptor@0.1.7: + resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==} + engines: {node: '>= 0.4'} + + is-descriptor@1.0.3: + resolution: {integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==} + engines: {node: '>= 0.4'} + + is-dotfile@1.0.3: + resolution: {integrity: sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg==} + engines: {node: '>=0.10.0'} + + is-equal-shallow@0.1.3: + resolution: {integrity: sha512-0EygVC5qPvIyb+gSz7zdD5/AAoS6Qrx1e//6N4yv4oNm30kqvdmG66oZFWVlQHUWe5OjP08FuTw2IdT0EOTcYA==} + engines: {node: '>=0.10.0'} + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + is-extendable@1.0.1: + resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} + engines: {node: '>=0.10.0'} + + is-extglob@1.0.0: + resolution: {integrity: sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==} + engines: {node: '>=0.10.0'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@2.0.1: + resolution: {integrity: sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@2.1.0: + resolution: {integrity: sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==} + engines: {node: '>=0.10.0'} + + is-number@3.0.0: + resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} + engines: {node: '>=0.10.0'} + + is-number@4.0.0: + resolution: {integrity: sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + + is-posix-bracket@0.1.1: + resolution: {integrity: sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ==} + engines: {node: '>=0.10.0'} + + is-primitive@2.0.0: + resolution: {integrity: sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q==} + engines: {node: '>=0.10.0'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isobject@2.1.0: + resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} + engines: {node: '>=0.10.0'} + + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + + kind-of@3.2.2: + resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} + engines: {node: '>=0.10.0'} + + kind-of@4.0.0: + resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} + engines: {node: '>=0.10.0'} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + map-cache@0.2.2: + resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} + engines: {node: '>=0.10.0'} + + map-visit@1.0.0: + resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} + engines: {node: '>=0.10.0'} + + math-random@1.0.4: + resolution: {integrity: sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==} + + micromatch@2.3.11: + resolution: {integrity: sha512-LnU2XFEk9xxSJ6rfgAry/ty5qwUTyHYOBU0g4R6tIw5ljwgGIBmiKhRWLw5NpMOnrgUNcDJ4WMp8rl3sYVHLNA==} + engines: {node: '>=0.10.0'} + + micromatch@3.1.10: + resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} + engines: {node: '>=0.10.0'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mixin-deep@1.3.2: + resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} + engines: {node: '>=0.10.0'} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + nan@2.23.0: + resolution: {integrity: sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==} + + nanomatch@1.2.13: + resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} + engines: {node: '>=0.10.0'} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + normalize-path@2.1.1: + resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} + engines: {node: '>=0.10.0'} + + object-copy@0.1.0: + resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} + engines: {node: '>=0.10.0'} + + object-visit@1.0.1: + resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} + engines: {node: '>=0.10.0'} + + object.omit@2.0.1: + resolution: {integrity: sha512-UiAM5mhmIuKLsOvrL+B0U2d1hXHF3bFYWIuH1LMpuV2EJEHG1Ntz06PgLEHjm6VFd87NpH8rastvPoyv6UW2fA==} + engines: {node: '>=0.10.0'} + + object.pick@1.3.0: + resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} + engines: {node: '>=0.10.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + parse-glob@3.0.4: + resolution: {integrity: sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA==} + engines: {node: '>=0.10.0'} + + pascalcase@0.1.1: + resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} + engines: {node: '>=0.10.0'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + posix-character-classes@0.1.1: + resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} + engines: {node: '>=0.10.0'} + + preserve@0.2.0: + resolution: {integrity: sha512-s/46sYeylUfHNjI+sA/78FAHlmIuKqI9wNnzEOGehAlUUYeObv5C2mOinXBjyUyWmJ2SfcS2/ydApH4hTF4WXQ==} + engines: {node: '>=0.10.0'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + randomatic@3.1.1: + resolution: {integrity: sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==} + engines: {node: '>= 0.10.0'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readdirp@2.2.1: + resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} + engines: {node: '>=0.10'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + regenerator-runtime@0.11.1: + resolution: {integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==} + + regex-cache@0.4.4: + resolution: {integrity: sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==} + engines: {node: '>=0.10.0'} + + regex-not@1.0.2: + resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} + engines: {node: '>=0.10.0'} + + remove-trailing-separator@1.1.0: + resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} + + repeat-element@1.1.4: + resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} + engines: {node: '>=0.10.0'} + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + + resolve-url@0.2.1: + resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} + deprecated: https://github.com/lydell/resolve-url#deprecated + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + ret@0.1.15: + resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} + engines: {node: '>=0.12'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex@1.1.0: + resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + + sass@1.93.2: + resolution: {integrity: sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==} + engines: {node: '>=14.0.0'} + hasBin: true + + set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + + snapdragon-node@2.1.1: + resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} + engines: {node: '>=0.10.0'} + + snapdragon-util@3.0.1: + resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} + engines: {node: '>=0.10.0'} + + snapdragon@0.8.2: + resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} + engines: {node: '>=0.10.0'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-resolve@0.5.3: + resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} + deprecated: See https://github.com/lydell/source-map-resolve#deprecated + + source-map-url@0.4.1: + resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} + deprecated: See https://github.com/lydell/source-map-url#deprecated + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + split-string@3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + + static-extend@0.1.2: + resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} + engines: {node: '>=0.10.0'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + subarg@1.0.0: + resolution: {integrity: sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + to-object-path@0.3.0: + resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} + engines: {node: '>=0.10.0'} + + to-regex-range@2.1.1: + resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} + engines: {node: '>=0.10.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + to-regex@3.0.2: + resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} + engines: {node: '>=0.10.0'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + union-value@1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} + + unset-value@1.0.0: + resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} + engines: {node: '>=0.10.0'} + + urix@0.1.0: + resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} + deprecated: Please see https://github.com/lydell/urix#deprecated + + use@3.1.1: + resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} + engines: {node: '>=0.10.0'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + +snapshots: + + '@parcel/watcher-android-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-x64@2.5.1': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.1': + optional: true + + '@parcel/watcher-win32-arm64@2.5.1': + optional: true + + '@parcel/watcher-win32-ia32@2.5.1': + optional: true + + '@parcel/watcher-win32-x64@2.5.1': + optional: true + + '@parcel/watcher@2.5.1': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 + optional: true + + '@types/prop-types@15.7.15': {} + + '@types/react-dom@18.3.7(@types/react@18.3.26)': + dependencies: + '@types/react': 18.3.26 + + '@types/react@18.3.26': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.1.3 + + anymatch@1.3.2: + dependencies: + micromatch: 2.3.11 + normalize-path: 2.1.1 + + arr-diff@2.0.0: + dependencies: + arr-flatten: 1.1.0 + + arr-diff@4.0.0: {} + + arr-flatten@1.1.0: {} + + arr-union@3.1.0: {} + + array-unique@0.2.1: {} + + array-unique@0.3.2: {} + + assign-symbols@1.0.0: {} + + async-each@1.0.6: {} + + atob@2.1.2: {} + + babel-runtime@6.26.0: + dependencies: + core-js: 2.6.12 + regenerator-runtime: 0.11.1 + + balanced-match@1.0.2: {} + + base@0.11.2: + dependencies: + cache-base: 1.0.1 + class-utils: 0.3.6 + component-emitter: 1.3.1 + define-property: 1.0.0 + isobject: 3.0.1 + mixin-deep: 1.3.2 + pascalcase: 0.1.1 + + binary-extensions@1.13.1: {} + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + optional: true + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + braces@1.8.5: + dependencies: + expand-range: 1.8.2 + preserve: 0.2.0 + repeat-element: 1.1.4 + + braces@2.3.2: + dependencies: + arr-flatten: 1.1.0 + array-unique: 0.3.2 + extend-shallow: 2.0.1 + fill-range: 4.0.0 + isobject: 3.0.1 + repeat-element: 1.1.4 + snapdragon: 0.8.2 + snapdragon-node: 2.1.1 + split-string: 3.1.0 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + optional: true + + cache-base@1.0.1: + dependencies: + collection-visit: 1.0.0 + component-emitter: 1.3.1 + get-value: 2.0.6 + has-value: 1.0.0 + isobject: 3.0.1 + set-value: 2.0.1 + to-object-path: 0.3.0 + union-value: 1.0.1 + unset-value: 1.0.0 + + chokidar@1.7.0: + dependencies: + anymatch: 1.3.2 + async-each: 1.0.6 + glob-parent: 2.0.0 + inherits: 2.0.4 + is-binary-path: 1.0.1 + is-glob: 2.0.1 + path-is-absolute: 1.0.1 + readdirp: 2.2.1 + optionalDependencies: + fsevents: 1.2.13 + transitivePeerDependencies: + - supports-color + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + class-utils@0.3.6: + dependencies: + arr-union: 3.1.0 + define-property: 0.2.5 + isobject: 3.0.1 + static-extend: 0.1.2 + + collection-visit@1.0.0: + dependencies: + map-visit: 1.0.0 + object-visit: 1.0.1 + + component-emitter@1.3.1: {} + + concat-map@0.0.1: {} + + copy-descriptor@0.1.1: {} + + core-js@2.6.12: {} + + core-util-is@1.0.3: {} + + cpx@1.5.0: + dependencies: + babel-runtime: 6.26.0 + chokidar: 1.7.0 + duplexer: 0.1.2 + glob: 7.2.3 + glob2base: 0.0.12 + minimatch: 3.1.2 + mkdirp: 0.5.6 + resolve: 1.22.11 + safe-buffer: 5.2.1 + shell-quote: 1.8.3 + subarg: 1.0.0 + transitivePeerDependencies: + - supports-color + + csstype@3.1.3: {} + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + decode-uri-component@0.2.2: {} + + define-property@0.2.5: + dependencies: + is-descriptor: 0.1.7 + + define-property@1.0.0: + dependencies: + is-descriptor: 1.0.3 + + define-property@2.0.2: + dependencies: + is-descriptor: 1.0.3 + isobject: 3.0.1 + + detect-libc@1.0.3: + optional: true + + duplexer@0.1.2: {} + + expand-brackets@0.1.5: + dependencies: + is-posix-bracket: 0.1.1 + + expand-brackets@2.1.4: + dependencies: + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + posix-character-classes: 0.1.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + expand-range@1.8.2: + dependencies: + fill-range: 2.2.4 + + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend-shallow@3.0.2: + dependencies: + assign-symbols: 1.0.0 + is-extendable: 1.0.1 + + extglob@0.3.2: + dependencies: + is-extglob: 1.0.0 + + extglob@2.0.4: + dependencies: + array-unique: 0.3.2 + define-property: 1.0.0 + expand-brackets: 2.1.4 + extend-shallow: 2.0.1 + fragment-cache: 0.2.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + file-uri-to-path@1.0.0: + optional: true + + filename-regex@2.0.1: {} + + fill-range@2.2.4: + dependencies: + is-number: 2.1.0 + isobject: 2.1.0 + randomatic: 3.1.1 + repeat-element: 1.1.4 + repeat-string: 1.6.1 + + fill-range@4.0.0: + dependencies: + extend-shallow: 2.0.1 + is-number: 3.0.0 + repeat-string: 1.6.1 + to-regex-range: 2.1.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + optional: true + + find-index@0.1.1: {} + + for-in@1.0.2: {} + + for-own@0.1.5: + dependencies: + for-in: 1.0.2 + + fragment-cache@0.2.1: + dependencies: + map-cache: 0.2.2 + + fs.realpath@1.0.0: {} + + fsevents@1.2.13: + dependencies: + bindings: 1.5.0 + nan: 2.23.0 + optional: true + + function-bind@1.1.2: {} + + get-value@2.0.6: {} + + glob-base@0.3.0: + dependencies: + glob-parent: 2.0.0 + is-glob: 2.0.1 + + glob-parent@2.0.0: + dependencies: + is-glob: 2.0.1 + + glob2base@0.0.12: + dependencies: + find-index: 0.1.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + graceful-fs@4.2.11: {} + + has-value@0.3.1: + dependencies: + get-value: 2.0.6 + has-values: 0.1.4 + isobject: 2.1.0 + + has-value@1.0.0: + dependencies: + get-value: 2.0.6 + has-values: 1.0.0 + isobject: 3.0.1 + + has-values@0.1.4: {} + + has-values@1.0.0: + dependencies: + is-number: 3.0.0 + kind-of: 4.0.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + immutable@5.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-accessor-descriptor@1.0.1: + dependencies: + hasown: 2.0.2 + + is-binary-path@1.0.1: + dependencies: + binary-extensions: 1.13.1 + + is-buffer@1.1.6: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-descriptor@1.0.1: + dependencies: + hasown: 2.0.2 + + is-descriptor@0.1.7: + dependencies: + is-accessor-descriptor: 1.0.1 + is-data-descriptor: 1.0.1 + + is-descriptor@1.0.3: + dependencies: + is-accessor-descriptor: 1.0.1 + is-data-descriptor: 1.0.1 + + is-dotfile@1.0.3: {} + + is-equal-shallow@0.1.3: + dependencies: + is-primitive: 2.0.0 + + is-extendable@0.1.1: {} + + is-extendable@1.0.1: + dependencies: + is-plain-object: 2.0.4 + + is-extglob@1.0.0: {} + + is-extglob@2.1.1: + optional: true + + is-glob@2.0.1: + dependencies: + is-extglob: 1.0.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + optional: true + + is-number@2.1.0: + dependencies: + kind-of: 3.2.2 + + is-number@3.0.0: + dependencies: + kind-of: 3.2.2 + + is-number@4.0.0: {} + + is-number@7.0.0: + optional: true + + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + + is-posix-bracket@0.1.1: {} + + is-primitive@2.0.0: {} + + is-windows@1.0.2: {} + + isarray@1.0.0: {} + + isobject@2.1.0: + dependencies: + isarray: 1.0.0 + + isobject@3.0.1: {} + + kind-of@3.2.2: + dependencies: + is-buffer: 1.1.6 + + kind-of@4.0.0: + dependencies: + is-buffer: 1.1.6 + + kind-of@6.0.3: {} + + map-cache@0.2.2: {} + + map-visit@1.0.0: + dependencies: + object-visit: 1.0.1 + + math-random@1.0.4: {} + + micromatch@2.3.11: + dependencies: + arr-diff: 2.0.0 + array-unique: 0.2.1 + braces: 1.8.5 + expand-brackets: 0.1.5 + extglob: 0.3.2 + filename-regex: 2.0.1 + is-extglob: 1.0.0 + is-glob: 2.0.1 + kind-of: 3.2.2 + normalize-path: 2.1.1 + object.omit: 2.0.1 + parse-glob: 3.0.4 + regex-cache: 0.4.4 + + micromatch@3.1.10: + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + braces: 2.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + extglob: 2.0.4 + fragment-cache: 0.2.1 + kind-of: 6.0.3 + nanomatch: 1.2.13 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + optional: true + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimist@1.2.8: {} + + mixin-deep@1.3.2: + dependencies: + for-in: 1.0.2 + is-extendable: 1.0.1 + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + ms@2.0.0: {} + + nan@2.23.0: + optional: true + + nanomatch@1.2.13: + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + fragment-cache: 0.2.1 + is-windows: 1.0.2 + kind-of: 6.0.3 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + node-addon-api@7.1.1: + optional: true + + normalize-path@2.1.1: + dependencies: + remove-trailing-separator: 1.1.0 + + object-copy@0.1.0: + dependencies: + copy-descriptor: 0.1.1 + define-property: 0.2.5 + kind-of: 3.2.2 + + object-visit@1.0.1: + dependencies: + isobject: 3.0.1 + + object.omit@2.0.1: + dependencies: + for-own: 0.1.5 + is-extendable: 0.1.1 + + object.pick@1.3.0: + dependencies: + isobject: 3.0.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + parse-glob@3.0.4: + dependencies: + glob-base: 0.3.0 + is-dotfile: 1.0.3 + is-extglob: 1.0.0 + is-glob: 2.0.1 + + pascalcase@0.1.1: {} + + path-is-absolute@1.0.1: {} + + path-parse@1.0.7: {} + + picomatch@2.3.1: + optional: true + + posix-character-classes@0.1.1: {} + + preserve@0.2.0: {} + + process-nextick-args@2.0.1: {} + + randomatic@3.1.1: + dependencies: + is-number: 4.0.0 + kind-of: 6.0.3 + math-random: 1.0.4 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readdirp@2.2.1: + dependencies: + graceful-fs: 4.2.11 + micromatch: 3.1.10 + readable-stream: 2.3.8 + transitivePeerDependencies: + - supports-color + + readdirp@4.1.2: {} + + regenerator-runtime@0.11.1: {} + + regex-cache@0.4.4: + dependencies: + is-equal-shallow: 0.1.3 + + regex-not@1.0.2: + dependencies: + extend-shallow: 3.0.2 + safe-regex: 1.1.0 + + remove-trailing-separator@1.1.0: {} + + repeat-element@1.1.4: {} + + repeat-string@1.6.1: {} + + resolve-url@0.2.1: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + ret@0.1.15: {} + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-regex@1.1.0: + dependencies: + ret: 0.1.15 + + sass@1.93.2: + dependencies: + chokidar: 4.0.3 + immutable: 5.1.4 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.1 + + set-value@2.0.1: + dependencies: + extend-shallow: 2.0.1 + is-extendable: 0.1.1 + is-plain-object: 2.0.4 + split-string: 3.1.0 + + shell-quote@1.8.3: {} + + snapdragon-node@2.1.1: + dependencies: + define-property: 1.0.0 + isobject: 3.0.1 + snapdragon-util: 3.0.1 + + snapdragon-util@3.0.1: + dependencies: + kind-of: 3.2.2 + + snapdragon@0.8.2: + dependencies: + base: 0.11.2 + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + map-cache: 0.2.2 + source-map: 0.5.7 + source-map-resolve: 0.5.3 + use: 3.1.1 + transitivePeerDependencies: + - supports-color + + source-map-js@1.2.1: {} + + source-map-resolve@0.5.3: + dependencies: + atob: 2.1.2 + decode-uri-component: 0.2.2 + resolve-url: 0.2.1 + source-map-url: 0.4.1 + urix: 0.1.0 + + source-map-url@0.4.1: {} + + source-map@0.5.7: {} + + split-string@3.1.0: + dependencies: + extend-shallow: 3.0.2 + + static-extend@0.1.2: + dependencies: + define-property: 0.2.5 + object-copy: 0.1.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + subarg@1.0.0: + dependencies: + minimist: 1.2.8 + + supports-preserve-symlinks-flag@1.0.0: {} + + to-object-path@0.3.0: + dependencies: + kind-of: 3.2.2 + + to-regex-range@2.1.1: + dependencies: + is-number: 3.0.0 + repeat-string: 1.6.1 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + optional: true + + to-regex@3.0.2: + dependencies: + define-property: 2.0.2 + extend-shallow: 3.0.2 + regex-not: 1.0.2 + safe-regex: 1.1.0 + + typescript@5.9.3: {} + + union-value@1.0.1: + dependencies: + arr-union: 3.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + set-value: 2.0.1 + + unset-value@1.0.0: + dependencies: + has-value: 0.3.1 + isobject: 3.0.1 + + urix@0.1.0: {} + + use@3.1.1: {} + + util-deprecate@1.0.2: {} + + wrappy@1.0.2: {} diff --git a/pkg/plugin/examples/react-component/src/testReact.tsx b/pkg/plugin/examples/react-component/src/testReact.tsx index d2733fb26..677e13aac 100644 --- a/pkg/plugin/examples/react-component/src/testReact.tsx +++ b/pkg/plugin/examples/react-component/src/testReact.tsx @@ -192,7 +192,7 @@ interface IPluginApi { ); }; - PluginApi.register.route("/plugin/test-react", TestPage); + PluginApi.register.route("/plugins/test-react", TestPage); PluginApi.patch.before("SettingsToolsSection", function (props: any) { const { @@ -206,7 +206,7 @@ interface IPluginApi { {props.children} + @@ -232,7 +232,7 @@ interface IPluginApi { - - ); + return ; } } @@ -169,6 +160,7 @@ export const ImageCard: React.FC = ( = ({ image }) => { const history = useHistory(); const Toast = useToast(); const intl = useIntl(); - const { configuration } = useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const [incrementO] = useImageIncrementO(image.id); const [decrementO] = useImageDecrementO(image.id); @@ -156,7 +157,7 @@ const ImagePage: React.FC = ({ image }) => { function onDeleteDialogClosed(deleted: boolean) { setIsDeleteAlertOpen(false); if (deleted) { - history.goBack(); + goBackOrReplace(history, "/images"); } } @@ -369,6 +370,7 @@ const ImagePage: React.FC = ({ image }) => { = ({ return ( <> setTitle(value)} /> setCode(value)} /> setURLs(value)} /> setDate(value)} /> setPhotographer(value)} /> setStudio(value)} @@ -196,6 +202,7 @@ export const ImageScrapeDialog: React.FC = ({ onCreateNew={createNewStudio} /> setPerformers(value)} @@ -204,6 +211,7 @@ export const ImageScrapeDialog: React.FC = ({ /> {scrapedTagsRow} setDetails(value)} diff --git a/ui/v2.5/src/components/Images/ImageList.tsx b/ui/v2.5/src/components/Images/ImageList.tsx index 12eb264b1..0e3753480 100644 --- a/ui/v2.5/src/components/Images/ImageList.tsx +++ b/ui/v2.5/src/components/Images/ImageList.tsx @@ -1,10 +1,4 @@ -import React, { - useCallback, - useState, - useMemo, - MouseEvent, - useContext, -} from "react"; +import React, { useCallback, useState, useMemo, MouseEvent } from "react"; import { FormattedNumber, useIntl } from "react-intl"; import cloneDeep from "lodash-es/cloneDeep"; import { useHistory } from "react-router-dom"; @@ -20,10 +14,10 @@ import { ImageWallItem } from "./ImageWallItem"; import { EditImagesDialog } from "./EditImagesDialog"; import { DeleteImagesDialog } from "./DeleteImagesDialog"; import "flexbin/flexbin.css"; -import Gallery from "react-photo-gallery"; +import Gallery, { RenderImageProps } from "react-photo-gallery"; import { ExportDialog } from "../Shared/ExportDialog"; import { objectTitle } from "src/core/files"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { ImageGridCard } from "./ImageGridCard"; import { View } from "../List/views"; import { IItemListOperation } from "../List/FilteredListToolbar"; @@ -35,12 +29,27 @@ interface IImageWallProps { currentPage: number; pageCount: number; handleImageOpen: (index: number) => void; + zoomIndex: number; } -const ImageWall: React.FC = ({ images, handleImageOpen }) => { - const { configuration } = useContext(ConfigurationContext); +const zoomWidths = [280, 340, 480, 640]; +const breakpointZoomHeights = [ + { minWidth: 576, heights: [100, 120, 240, 360] }, + { minWidth: 768, heights: [120, 160, 240, 480] }, + { minWidth: 1200, heights: [120, 160, 240, 300] }, + { minWidth: 1400, heights: [160, 240, 300, 480] }, +]; + +const ImageWall: React.FC = ({ + images, + zoomIndex, + handleImageOpen, +}) => { + const { configuration } = useConfigurationContext(); const uiConfig = configuration?.ui; + const containerRef = React.useRef(null); + let photos: { src: string; srcSet?: string | string[] | undefined; @@ -57,8 +66,8 @@ const ImageWall: React.FC = ({ images, handleImageOpen }) => { image.paths.preview != "" ? image.paths.preview! : image.paths.thumbnail!, - width: image.visual_files[0].width, - height: image.visual_files[0].height, + width: image.visual_files?.[0]?.width ?? 0, + height: image.visual_files?.[0]?.height ?? 0, tabIndex: index, key: image.id, loading: "lazy", @@ -76,21 +85,53 @@ const ImageWall: React.FC = ({ images, handleImageOpen }) => { ); function columns(containerWidth: number) { - let preferredSize = 300; + let preferredSize = zoomWidths[zoomIndex]; let columnCount = containerWidth / preferredSize; return Math.round(columnCount); } + const targetRowHeight = useCallback( + (containerWidth: number) => { + let zoomHeight = 280; + breakpointZoomHeights.forEach((e) => { + if (containerWidth >= e.minWidth) { + zoomHeight = e.heights[zoomIndex]; + } + }); + return zoomHeight; + }, + [zoomIndex] + ); + + // set the max height as a factor of the targetRowHeight + // this allows some images to be taller than the target row height + // but prevents images from becoming too tall when there is a small number of items + const maxHeightFactor = 1.3; + + const renderImage = useCallback( + (props: RenderImageProps) => { + // #6165 - only use targetRowHeight in row direction + const maxHeight = + props.direction === "column" + ? props.photo.height + : targetRowHeight(containerRef.current?.offsetWidth ?? 0) * + maxHeightFactor; + return ; + }, + [targetRowHeight] + ); + return ( -
+
{photos.length ? ( ) : null}
@@ -211,6 +252,7 @@ const ImageListImages: React.FC = ({ currentPage={filter.currentPage} pageCount={pageCount} handleImageOpen={handleImageOpen} + zoomIndex={filter.zoomIndex} /> ); } @@ -416,7 +458,6 @@ export const ImageList: React.FC = ({ selectable > = ( - props: IImageWallProps +export const ImageWallItem: React.FC = ( + props: RenderImageProps & IExtraProps ) => { + const height = Math.min(props.maxHeight, props.photo.height); + const zoomFactor = height / props.photo.height; + const width = props.photo.width * zoomFactor; + type style = Record; var imgStyle: style = { margin: props.margin, @@ -45,12 +39,13 @@ export const ImageWallItem: React.FC = ( diff --git a/ui/v2.5/src/components/List/EditFilterDialog.tsx b/ui/v2.5/src/components/List/EditFilterDialog.tsx index 4b31ac31a..3f0f486b8 100644 --- a/ui/v2.5/src/components/List/EditFilterDialog.tsx +++ b/ui/v2.5/src/components/List/EditFilterDialog.tsx @@ -1,7 +1,6 @@ import cloneDeep from "lodash-es/cloneDeep"; import React, { useCallback, - useContext, useEffect, useMemo, useRef, @@ -14,7 +13,7 @@ import { CriterionOption, } from "src/models/list-filter/criteria/criterion"; import { FormattedMessage, useIntl } from "react-intl"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { ListFilterModel } from "src/models/list-filter/filter"; import { getFilterOptions } from "src/models/list-filter/factory"; import { FilterTags } from "./FilterTags"; @@ -29,11 +28,16 @@ import { import { useCompare, usePrevious } from "src/hooks/state"; import { CriterionType } from "src/models/list-filter/types"; import { useToast } from "src/hooks/Toast"; -import { useConfigureUI } from "src/core/StashService"; -import { FilterMode } from "src/core/generated-graphql"; +import { useConfigureUI, useSaveFilter } from "src/core/StashService"; +import { + FilterMode, + SavedFilterDataFragment, +} from "src/core/generated-graphql"; import { useFocusOnce } from "src/utils/focus"; import Mousetrap from "mousetrap"; import ScreenUtils from "src/utils/screen"; +import { LoadFilterDialog, SaveFilterDialog } from "./SavedFilterList"; +import { SearchTermInput } from "./ListFilter"; interface ICriterionList { criteria: string[]; @@ -45,6 +49,7 @@ interface ICriterionList { optionSelected: (o?: CriterionOption) => void; onRemoveCriterion: (c: string) => void; onTogglePin: (c: CriterionOption) => void; + externallySelected?: boolean; } const CriterionOptionList: React.FC = ({ @@ -57,7 +62,11 @@ const CriterionOptionList: React.FC = ({ optionSelected, onRemoveCriterion, onTogglePin, + externallySelected = false, }) => { + const { configuration } = useConfigurationContext(); + const { sfwContentMode } = configuration.interface; + const prevCriterion = usePrevious(currentCriterion); const scrolled = useRef(false); @@ -96,14 +105,19 @@ const CriterionOptionList: React.FC = ({ // scrolling to the current criterion doesn't work well when the // dialog is already open, so limit to when we click on the // criterion from the external tags - if (!scrolled.current && type && criteriaRefs[type]?.current) { + if ( + externallySelected && + !scrolled.current && + type && + criteriaRefs[type]?.current + ) { criteriaRefs[type].current!.scrollIntoView({ behavior: "smooth", block: "start", }); scrolled.current = true; } - }, [currentCriterion, criteriaRefs, type]); + }, [externallySelected, currentCriterion, criteriaRefs, type]); function getReleventCriterion(t: CriterionType) { if (currentCriterion?.criterionOption.type === t) { @@ -136,7 +150,9 @@ const CriterionOptionList: React.FC = ({ className="collapse-icon fa-fw" icon={type === c.type ? faChevronDown : faChevronRight} /> - + {criteria.some((cc) => c.type === cc) && ( - +
+ + +
+
+ + +
diff --git a/ui/v2.5/src/components/List/FilterTags.tsx b/ui/v2.5/src/components/List/FilterTags.tsx index a384f05ca..5597cae79 100644 --- a/ui/v2.5/src/components/List/FilterTags.tsx +++ b/ui/v2.5/src/components/List/FilterTags.tsx @@ -1,32 +1,46 @@ -import React, { PropsWithChildren } from "react"; -import { Badge, BadgeProps, Button } from "react-bootstrap"; +import React, { + PropsWithChildren, + useEffect, + useLayoutEffect, + useReducer, + useRef, +} from "react"; +import { Badge, BadgeProps, Button, Overlay, Popover } from "react-bootstrap"; import { Criterion } from "src/models/list-filter/criteria/criterion"; import { FormattedMessage, useIntl } from "react-intl"; import { Icon } from "../Shared/Icon"; -import { faTimes } from "@fortawesome/free-solid-svg-icons"; +import { faMagnifyingGlass, faTimes } from "@fortawesome/free-solid-svg-icons"; import { BsPrefixProps, ReplaceProps } from "react-bootstrap/esm/helpers"; import { CustomFieldsCriterion } from "src/models/list-filter/criteria/custom-fields"; +import { useDebounce } from "src/hooks/debounce"; +import cx from "classnames"; +import { useConfigurationContext } from "src/hooks/Config"; type TagItemProps = PropsWithChildren< ReplaceProps<"span", BsPrefixProps<"span"> & BadgeProps> >; export const TagItem: React.FC = (props) => { - const { children } = props; + const { className, children, ...others } = props; return ( - + {children} ); }; export const FilterTag: React.FC<{ + className?: string; label: React.ReactNode; onClick: React.MouseEventHandler; onRemove: React.MouseEventHandler; -}> = ({ label, onClick, onRemove }) => { +}> = ({ className, label, onClick, onRemove }) => { return ( - + {label} - - )} - + - {showEditFilter && ( - showEditFilter()} - view={view} - withSidebar={!!onToggleSidebar} - /> - )} - 0} - onEdit={onEdit} - onDelete={onDelete} + - - - + showEditFilter()} count={filter.count()} /> - + + setFilter(filter.setSortBy(e ?? undefined))} + onChangeSortDirection={() => setFilter(filter.toggleSortDirection())} + onReshuffleRandomSort={() => setFilter(filter.reshuffleRandomSort())} + /> + + setFilter(filter.setPageSize(size))} + /> + + 0} + onEdit={onEdit} + onDelete={onDelete} + /> + + ); }; diff --git a/ui/v2.5/src/components/List/Filters/BooleanFilter.tsx b/ui/v2.5/src/components/List/Filters/BooleanFilter.tsx index 18df1b9f1..657e9ddbd 100644 --- a/ui/v2.5/src/components/List/Filters/BooleanFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/BooleanFilter.tsx @@ -54,6 +54,7 @@ interface ISidebarFilter { option: CriterionOption; filter: ListFilterModel; setFilter: (f: ListFilterModel) => void; + sectionID?: string; } export const SidebarBooleanFilter: React.FC = ({ @@ -61,6 +62,7 @@ export const SidebarBooleanFilter: React.FC = ({ option, filter, setFilter, + sectionID, }) => { const intl = useIntl(); @@ -127,6 +129,7 @@ export const SidebarBooleanFilter: React.FC = ({ onUnselect={onUnselect} selected={selected} singleValue + sectionID={sectionID} /> ); diff --git a/ui/v2.5/src/components/List/Filters/FilterButton.tsx b/ui/v2.5/src/components/List/Filters/FilterButton.tsx index b92ddcf0d..63e026df2 100644 --- a/ui/v2.5/src/components/List/Filters/FilterButton.tsx +++ b/ui/v2.5/src/components/List/Filters/FilterButton.tsx @@ -1,28 +1,32 @@ -import React, { useMemo } from "react"; +import React from "react"; import { Badge, Button } from "react-bootstrap"; -import { ListFilterModel } from "src/models/list-filter/filter"; import { faFilter } from "@fortawesome/free-solid-svg-icons"; import { Icon } from "src/components/Shared/Icon"; import { useIntl } from "react-intl"; interface IFilterButtonProps { - filter: ListFilterModel; + count?: number; onClick: () => void; + title?: string; } export const FilterButton: React.FC = ({ - filter, + count = 0, onClick, + title, }) => { const intl = useIntl(); - const count = useMemo(() => filter.count(), [filter]); + + if (!title) { + title = intl.formatMessage({ id: "search_filter.edit_filter" }); + } return ( +
+ } + sectionID={savedFiltersSectionID} > { - Mousetrap.bind("/", (e) => { - if (!showSidebar) { - setShowSidebar(true); - e.preventDefault(); - } - }); - - return () => { - Mousetrap.unbind("/"); - }; - }, [showSidebar, setShowSidebar]); - // Hide the sidebar when the user presses the "Esc" key useEffect(() => { Mousetrap.bind("esc", (e) => { diff --git a/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx b/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx index ef309ecde..200c16917 100644 --- a/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx @@ -321,18 +321,24 @@ export function useCriterion( return { criterion, setCriterion }; } +export interface IUseQueryHookProps { + q: string; + filter?: ListFilterModel; + filterHook?: (filter: ListFilterModel) => ListFilterModel; + skip: boolean; +} + export function useQueryState( - useQuery: ( - q: string, - filter: ListFilterModel, - skip: boolean - ) => ILoadResults, + useQuery: (props: IUseQueryHookProps) => ILoadResults, filter: ListFilterModel, - skip: boolean + skip: boolean, + options?: { + filterHook?: (filter: ListFilterModel) => ListFilterModel; + } ) { const [query, setQuery] = useState(""); const { results: queryResults } = useCacheResults( - useQuery(query, filter, skip) + useQuery({ q: query, filter, filterHook: options?.filterHook, skip }) ); return { query, setQuery, queryResults }; @@ -431,11 +437,8 @@ export function useLabeledIdFilterState(props: { option: CriterionOption; filter: ListFilterModel; setFilter: (f: ListFilterModel) => void; - useQuery: ( - q: string, - filter: ListFilterModel, - skip: boolean - ) => ILoadResults; + filterHook?: (filter: ListFilterModel) => ListFilterModel; + useQuery: (props: IUseQueryHookProps) => ILoadResults; singleValue?: boolean; hierarchical?: boolean; includeSubMessageID?: string; @@ -444,6 +447,7 @@ export function useLabeledIdFilterState(props: { option, filter, setFilter, + filterHook, useQuery, singleValue = false, hierarchical = false, @@ -456,7 +460,8 @@ export function useLabeledIdFilterState(props: { const { query, setQuery, queryResults } = useQueryState( useQuery, filter, - skip + skip, + { filterHook } ); const { criterion, setCriterion } = useCriterion(option, filter, setFilter); diff --git a/ui/v2.5/src/components/List/Filters/PathFilter.tsx b/ui/v2.5/src/components/List/Filters/PathFilter.tsx index 97711ebef..ac44302c5 100644 --- a/ui/v2.5/src/components/List/Filters/PathFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/PathFilter.tsx @@ -2,7 +2,7 @@ import React from "react"; import { Form } from "react-bootstrap"; import { FolderSelect } from "src/components/Shared/FolderSelect/FolderSelect"; import { CriterionModifier } from "src/core/generated-graphql"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { ModifierCriterion, CriterionValue, @@ -17,7 +17,7 @@ export const PathFilter: React.FC = ({ criterion, onValueChanged, }) => { - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const libraryPaths = configuration?.general.stashes.map((s) => s.path); // don't show folder select for regex diff --git a/ui/v2.5/src/components/List/Filters/PerformersFilter.tsx b/ui/v2.5/src/components/List/Filters/PerformersFilter.tsx index 84e3dd19b..3df19593f 100644 --- a/ui/v2.5/src/components/List/Filters/PerformersFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/PerformersFilter.tsx @@ -12,6 +12,7 @@ import { sortByRelevance } from "src/utils/query"; import { ListFilterModel } from "src/models/list-filter/filter"; import { CriterionOption } from "src/models/list-filter/criteria/criterion"; import { + IUseQueryHookProps, makeQueryVariables, setObjectFilter, useLabeledIdFilterState, @@ -69,13 +70,12 @@ function sortResults( }); } -function usePerformerQueryFilter( - query: string, - f?: ListFilterModel, - skip?: boolean -) { +function usePerformerQueryFilter(props: IUseQueryHookProps) { + const { q: query, filter: f, skip, filterHook } = props; + const appliedFilter = filterHook && f ? filterHook(f.clone()) : f; + const { data, loading } = useFindPerformersForSelectQuery({ - variables: queryVariables(query, f), + variables: queryVariables(query, appliedFilter), skip, }); @@ -88,7 +88,7 @@ function usePerformerQueryFilter( } function usePerformerQuery(query: string, skip?: boolean) { - return usePerformerQueryFilter(query, undefined, skip); + return usePerformerQueryFilter({ q: query, skip: !!skip }); } const PerformersFilter: React.FC = ({ @@ -109,15 +109,18 @@ export const SidebarPerformersFilter: React.FC<{ option: CriterionOption; filter: ListFilterModel; setFilter: (f: ListFilterModel) => void; -}> = ({ title, option, filter, setFilter }) => { + filterHook?: (f: ListFilterModel) => ListFilterModel; + sectionID?: string; +}> = ({ title, option, filter, setFilter, filterHook, sectionID }) => { const state = useLabeledIdFilterState({ filter, setFilter, + filterHook, option, useQuery: usePerformerQueryFilter, }); - return ; + return ; }; export default PerformersFilter; diff --git a/ui/v2.5/src/components/List/Filters/RatingFilter.tsx b/ui/v2.5/src/components/List/Filters/RatingFilter.tsx index 86d6a905b..9f5c8f8c9 100644 --- a/ui/v2.5/src/components/List/Filters/RatingFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/RatingFilter.tsx @@ -12,7 +12,7 @@ import { defaultRatingStarPrecision, defaultRatingSystemOptions, } from "src/utils/rating"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { RatingCriterion } from "src/models/list-filter/criteria/rating"; import { ListFilterModel } from "src/models/list-filter/filter"; import { Option, SidebarListFilter } from "./SidebarListFilter"; @@ -77,6 +77,7 @@ interface ISidebarFilter { option: CriterionOption; filter: ListFilterModel; setFilter: (f: ListFilterModel) => void; + sectionID?: string; } const any = "any"; @@ -87,6 +88,7 @@ export const SidebarRatingFilter: React.FC = ({ option, filter, setFilter, + sectionID, }) => { const intl = useIntl(); @@ -115,7 +117,7 @@ export const SidebarRatingFilter: React.FC = ({ [noneLabel] ); - const { configuration: config } = React.useContext(ConfigurationContext); + const { configuration: config } = useConfigurationContext(); const ratingSystemOptions = config?.ui.ratingSystemOptions ?? defaultRatingSystemOptions; @@ -199,6 +201,7 @@ export const SidebarRatingFilter: React.FC = ({ singleValue preCandidates={ratingValue === null ? ratingStars : undefined} preSelected={ratingValue !== null ? ratingStars : undefined} + sectionID={sectionID} />
diff --git a/ui/v2.5/src/components/List/Filters/SidebarAgeFilter.tsx b/ui/v2.5/src/components/List/Filters/SidebarAgeFilter.tsx new file mode 100644 index 000000000..3a6449ab6 --- /dev/null +++ b/ui/v2.5/src/components/List/Filters/SidebarAgeFilter.tsx @@ -0,0 +1,310 @@ +import React, { useEffect, useMemo, useState } from "react"; +import { CriterionModifier } from "../../../core/generated-graphql"; +import { CriterionOption } from "../../../models/list-filter/criteria/criterion"; +import { NumberCriterion } from "src/models/list-filter/criteria/criterion"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { Option, SidebarListFilter } from "./SidebarListFilter"; +import { DoubleRangeInput } from "src/components/Shared/DoubleRangeInput"; +import { useDebounce } from "src/hooks/debounce"; + +interface ISidebarFilter { + title?: React.ReactNode; + option: CriterionOption; + filter: ListFilterModel; + setFilter: (f: ListFilterModel) => void; + sectionID?: string; +} + +// Age presets +const AGE_PRESETS = [ + { id: "18-25", label: "18-25", min: 18, max: 25 }, + { id: "25-35", label: "25-35", min: 25, max: 35 }, + { id: "35-45", label: "35-45", min: 35, max: 45 }, + { id: "45-60", label: "45-60", min: 45, max: 60 }, + { id: "60+", label: "60+", min: 60, max: null }, +]; + +const MAX_AGE = 60; // Maximum age for the slider +const MAX_LABEL = "60+"; // Display label for maximum age + +export const SidebarAgeFilter: React.FC = ({ + title, + option, + filter, + setFilter, + sectionID, +}) => { + const criteria = filter.criteriaFor(option.type) as NumberCriterion[]; + const criterion = criteria.length > 0 ? criteria[0] : null; + + // Get current values from criterion + const currentMin = criterion?.value?.value ?? 18; + const currentMax = criterion?.value?.value2 ?? MAX_AGE; + + const [sliderMin, setSliderMin] = useState(currentMin); + const [sliderMax, setSliderMax] = useState(currentMax); + const [minInput, setMinInput] = useState(currentMin.toString()); + const [maxInput, setMaxInput] = useState( + currentMax >= MAX_AGE ? MAX_LABEL : currentMax.toString() + ); + + // Reset slider when criterion is removed externally (via filter tag X) + useEffect(() => { + if (!criterion) { + setSliderMin(18); + setSliderMax(MAX_AGE); + setMinInput("18"); + setMaxInput(MAX_LABEL); + } + }, [criterion]); + + // Determine which preset is selected + const selectedPreset = useMemo(() => { + if (!criterion) return null; + + // Check if current values match any preset + for (const preset of AGE_PRESETS) { + if (preset.max === null) { + // For "60+" preset + if ( + criterion.modifier === CriterionModifier.GreaterThan && + criterion.value.value === preset.min + ) { + return preset.id; + } + } else { + // For range presets + if ( + criterion.modifier === CriterionModifier.Between && + criterion.value.value === preset.min && + criterion.value.value2 === preset.max + ) { + return preset.id; + } + } + } + + // Check if it's a custom range or custom GreaterThan + if ( + criterion.modifier === CriterionModifier.Between || + criterion.modifier === CriterionModifier.GreaterThan + ) { + return "custom"; + } + + return null; + }, [criterion]); + + const options: Option[] = useMemo(() => { + return AGE_PRESETS.map((preset) => ({ + id: preset.id, + label: preset.label, + className: "age-preset", + })); + }, []); + + const selected: Option[] = useMemo(() => { + if (!selectedPreset) return []; + if (selectedPreset === "custom") return []; + + const preset = AGE_PRESETS.find((p) => p.id === selectedPreset); + if (preset) { + return [ + { + id: preset.id, + label: preset.label, + className: "age-preset", + }, + ]; + } + return []; + }, [selectedPreset]); + + function onSelectPreset(item: Option) { + const preset = AGE_PRESETS.find((p) => p.id === item.id); + if (!preset) return; + + setSliderMin(preset.min); + setSliderMax(preset.max ?? MAX_AGE); + setMinInput(preset.min.toString()); + setMaxInput(preset.max === null ? MAX_LABEL : preset.max.toString()); + + const currentCriteria = filter.criteriaFor( + option.type + ) as NumberCriterion[]; + const currentCriterion = + currentCriteria.length > 0 ? currentCriteria[0] : null; + const newCriterion = currentCriterion + ? currentCriterion.clone() + : option.makeCriterion(); + + if (preset.max === null) { + // "60+" - use GreaterThan + newCriterion.modifier = CriterionModifier.GreaterThan; + newCriterion.value.value = preset.min; + newCriterion.value.value2 = undefined; + } else { + // Range preset - use Between + newCriterion.modifier = CriterionModifier.Between; + newCriterion.value.value = preset.min; + newCriterion.value.value2 = preset.max; + } + + setFilter(filter.replaceCriteria(option.type, [newCriterion])); + } + + function onUnselectPreset() { + setSliderMin(18); + setSliderMax(MAX_AGE); + setMinInput("18"); + setMaxInput(MAX_LABEL); + setFilter(filter.removeCriterion(option.type)); + } + + // Parse age input (supports formats like "25", "100+") + function parseAgeInput(input: string): number | null { + const trimmed = input.trim().toLowerCase(); + + if (trimmed === "max" || trimmed === MAX_LABEL.toLowerCase()) { + return MAX_AGE; + } + + const age = parseInt(trimmed); + if (isNaN(age) || age < 18 || age > MAX_AGE) { + return null; + } + + return age; + } + + // Filter update + function updateFilter(min: number, max: number) { + // If slider is at full range (18 to max), remove the filter entirely + if (min === 18 && max >= MAX_AGE) { + setFilter(filter.removeCriterion(option.type)); + return; + } + + const currentCriteria = filter.criteriaFor( + option.type + ) as NumberCriterion[]; + const currentCriterion = + currentCriteria.length > 0 ? currentCriteria[0] : null; + const newCriterion = currentCriterion + ? currentCriterion.clone() + : option.makeCriterion(); + + // If max is at MAX_AGE (but min > 18), use GreaterThan + if (max >= MAX_AGE) { + newCriterion.modifier = CriterionModifier.GreaterThan; + newCriterion.value.value = min; + newCriterion.value.value2 = undefined; + } else { + newCriterion.modifier = CriterionModifier.Between; + newCriterion.value.value = min; + newCriterion.value.value2 = max; + } + + setFilter(filter.replaceCriteria(option.type, [newCriterion])); + } + + const updateFilterDebounceMS = 300; + const debounceUpdateFilter = useDebounce( + updateFilter, + updateFilterDebounceMS + ); + + function handleSliderChange(min: number, max: number) { + setSliderMin(min); + setSliderMax(max); + setMinInput(min.toString()); + setMaxInput(max >= MAX_AGE ? MAX_LABEL : max.toString()); + + debounceUpdateFilter(min, max); + } + + function handleMinInputChange(value: string) { + setMinInput(value); + } + + function handleMaxInputChange(value: string) { + setMaxInput(value); + } + + function handleMinInputBlur() { + const parsed = parseAgeInput(minInput); + if (parsed !== null && parsed >= 18 && parsed < sliderMax) { + handleSliderChange(parsed, sliderMax); + } else { + // Reset to current value if invalid + setMinInput(sliderMin.toString()); + } + } + + function handleMaxInputBlur() { + const parsed = parseAgeInput(maxInput); + if (parsed !== null && parsed > sliderMin && parsed <= MAX_AGE) { + handleSliderChange(sliderMin, parsed); + } else { + // Reset to current value if invalid + setMaxInput(sliderMax >= MAX_AGE ? MAX_LABEL : sliderMax.toString()); + } + } + + const customSlider = ( +
+ handleSliderChange(min, max)} + minInput={ + handleMinInputChange(e.target.value)} + onBlur={handleMinInputBlur} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.currentTarget.blur(); + } + }} + placeholder="18" + /> + } + maxInput={ + handleMaxInputChange(e.target.value)} + onBlur={handleMaxInputBlur} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.currentTarget.blur(); + } + }} + placeholder={MAX_LABEL} + /> + } + /> +
+ ); + + return ( + + ); +}; diff --git a/ui/v2.5/src/components/List/Filters/SidebarDurationFilter.tsx b/ui/v2.5/src/components/List/Filters/SidebarDurationFilter.tsx new file mode 100644 index 000000000..ff4b780af --- /dev/null +++ b/ui/v2.5/src/components/List/Filters/SidebarDurationFilter.tsx @@ -0,0 +1,360 @@ +import React, { useEffect, useMemo, useState } from "react"; +import { CriterionModifier } from "../../../core/generated-graphql"; +import { CriterionOption } from "../../../models/list-filter/criteria/criterion"; +import { DurationCriterion } from "src/models/list-filter/criteria/criterion"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { Option, SidebarListFilter } from "./SidebarListFilter"; +import TextUtils from "src/utils/text"; +import { DoubleRangeInput } from "src/components/Shared/DoubleRangeInput"; +import { useDebounce } from "src/hooks/debounce"; + +interface ISidebarFilter { + title?: React.ReactNode; + option: CriterionOption; + filter: ListFilterModel; + setFilter: (f: ListFilterModel) => void; + sectionID?: string; +} + +// Duration presets in seconds +const DURATION_PRESETS = [ + { id: "0-5", label: "0-5 min", min: 0, max: 300 }, + { id: "5-10", label: "5-10 min", min: 300, max: 600 }, + { id: "10-20", label: "10-20 min", min: 600, max: 1200 }, + { id: "20-40", label: "20-40 min", min: 1200, max: 2400 }, + { id: "40+", label: "40+ min", min: 2400, max: null }, +]; + +const MAX_DURATION = 7200; // 2 hours in seconds for the slider +const MAX_LABEL = "2+ hrs"; // Display label for maximum duration + +// Custom step values: 0, 2min (120s), 5min (300s), then 5 minute intervals +const DURATION_STEPS = [ + 0, 120, 300, 600, 900, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300, 3600, + 3900, 4200, 4500, 4800, 5100, 5400, 5700, 6000, 6300, 6600, 6900, 7200, +]; + +// Snap a value to the nearest valid step +function snapToStep(value: number): number { + if (value <= 0) return 0; + if (value >= MAX_DURATION) return MAX_DURATION; + + // Find the closest step + let closest = DURATION_STEPS[0]; + let minDiff = Math.abs(value - closest); + + for (const step of DURATION_STEPS) { + const diff = Math.abs(value - step); + if (diff < minDiff) { + minDiff = diff; + closest = step; + } + } + + return closest; +} + +export const SidebarDurationFilter: React.FC = ({ + title, + option, + filter, + setFilter, + sectionID, +}) => { + const criteria = filter.criteriaFor(option.type) as DurationCriterion[]; + const criterion = criteria.length > 0 ? criteria[0] : null; + + // Get current values from criterion + const currentMin = criterion?.value?.value ?? 0; + const currentMax = criterion?.value?.value2 ?? MAX_DURATION; + + const [sliderMin, setSliderMin] = useState(currentMin); + const [sliderMax, setSliderMax] = useState(currentMax); + const [minInput, setMinInput] = useState( + currentMin === 0 ? "0m" : TextUtils.secondsAsTimeString(currentMin) + ); + const [maxInput, setMaxInput] = useState( + currentMax >= MAX_DURATION + ? MAX_LABEL + : TextUtils.secondsAsTimeString(currentMax) + ); + + // Reset slider when criterion is removed externally (via filter tag X) + useEffect(() => { + if (!criterion) { + setSliderMin(0); + setSliderMax(MAX_DURATION); + setMinInput("0m"); + setMaxInput(MAX_LABEL); + } + }, [criterion]); + + // Determine which preset is selected + const selectedPreset = useMemo(() => { + if (!criterion) return null; + + // Check if current values match any preset + for (const preset of DURATION_PRESETS) { + if (preset.max === null) { + // For "40+ min" preset + if ( + criterion.modifier === CriterionModifier.GreaterThan && + criterion.value.value === preset.min + ) { + return preset.id; + } + } else { + // For range presets + if ( + criterion.modifier === CriterionModifier.Between && + criterion.value.value === preset.min && + criterion.value.value2 === preset.max + ) { + return preset.id; + } + } + } + + // Check if it's a custom range or custom GreaterThan + if ( + criterion.modifier === CriterionModifier.Between || + criterion.modifier === CriterionModifier.GreaterThan + ) { + return "custom"; + } + + return null; + }, [criterion]); + + const options: Option[] = useMemo(() => { + return DURATION_PRESETS.map((preset) => ({ + id: preset.id, + label: preset.label, + className: "duration-preset", + })); + }, []); + + const selected: Option[] = useMemo(() => { + if (!selectedPreset) return []; + if (selectedPreset === "custom") return []; + + const preset = DURATION_PRESETS.find((p) => p.id === selectedPreset); + if (preset) { + return [ + { + id: preset.id, + label: preset.label, + className: "duration-preset", + }, + ]; + } + return []; + }, [selectedPreset]); + + function onSelectPreset(item: Option) { + const preset = DURATION_PRESETS.find((p) => p.id === item.id); + if (!preset) return; + + const newCriterion = criterion ? criterion.clone() : option.makeCriterion(); + + if (preset.max === null) { + // "40+ min" - use GreaterThan + newCriterion.modifier = CriterionModifier.GreaterThan; + newCriterion.value.value = preset.min; + newCriterion.value.value2 = undefined; + } else { + // Range preset - use Between + newCriterion.modifier = CriterionModifier.Between; + newCriterion.value.value = preset.min; + newCriterion.value.value2 = preset.max; + } + + setSliderMin(preset.min); + setSliderMax(preset.max ?? MAX_DURATION); + setMinInput( + preset.min === 0 ? "0m" : TextUtils.secondsAsTimeString(preset.min) + ); + setMaxInput( + preset.max === null + ? MAX_LABEL + : TextUtils.secondsAsTimeString(preset.max) + ); + setFilter(filter.replaceCriteria(option.type, [newCriterion])); + } + + function onUnselectPreset() { + setFilter(filter.removeCriterion(option.type)); + setSliderMin(0); + setSliderMax(MAX_DURATION); + setMinInput("0m"); + setMaxInput(MAX_LABEL); + } + + // Parse time input (supports formats like "10", "1:30", "1:30:00", "2+ hrs") + function parseTimeInput(input: string): number | null { + const trimmed = input.trim().toLowerCase(); + + if (trimmed === "max" || trimmed === MAX_LABEL.toLowerCase()) { + return MAX_DURATION; + } + + // Try to parse as pure number (minutes) + const minutesOnly = parseFloat(trimmed); + if (!isNaN(minutesOnly) && trimmed.indexOf(":") === -1) { + return Math.round(minutesOnly * 60); + } + + // Parse HH:MM:SS or MM:SS format + const parts = trimmed.split(":").map((p) => parseInt(p)); + if (parts.some(isNaN)) { + return null; + } + + if (parts.length === 2) { + // MM:SS + return parts[0] * 60 + parts[1]; + } else if (parts.length === 3) { + // HH:MM:SS + return parts[0] * 3600 + parts[1] * 60 + parts[2]; + } + + return null; + } + + // Debounced filter update + function updateFilter(min: number, max: number) { + // If slider is at full range (0 to max), remove the filter entirely + if (min === 0 && max >= MAX_DURATION) { + setFilter(filter.removeCriterion(option.type)); + return; + } + + const newCriterion = criterion ? criterion.clone() : option.makeCriterion(); + + // If max is at MAX_DURATION (but min > 0), use GreaterThan + if (max >= MAX_DURATION) { + newCriterion.modifier = CriterionModifier.GreaterThan; + newCriterion.value.value = min; + newCriterion.value.value2 = undefined; + } else { + newCriterion.modifier = CriterionModifier.Between; + newCriterion.value.value = min; + newCriterion.value.value2 = max; + } + + setFilter(filter.replaceCriteria(option.type, [newCriterion])); + } + + const updateFilterDebounceMS = 300; + const debounceUpdateFilter = useDebounce( + updateFilter, + updateFilterDebounceMS + ); + + function handleSliderChange(min: number, max: number) { + if (min < 0 || max > MAX_DURATION || min >= max) { + return; + } + + setSliderMin(min); + setSliderMax(max); + setMinInput(min === 0 ? "0m" : TextUtils.secondsAsTimeString(min)); + setMaxInput( + max >= MAX_DURATION ? MAX_LABEL : TextUtils.secondsAsTimeString(max) + ); + + debounceUpdateFilter(min, max); + } + + function handleMinInputChange(value: string) { + setMinInput(value); + } + + function handleMaxInputChange(value: string) { + setMaxInput(value); + } + + function handleMinInputBlur() { + const parsed = parseTimeInput(minInput); + if (parsed !== null && parsed >= 0 && parsed < sliderMax) { + handleSliderChange(parsed, sliderMax); + } else { + // Reset to current value if invalid + setMinInput( + sliderMin === 0 ? "0m" : TextUtils.secondsAsTimeString(sliderMin) + ); + } + } + + function handleMaxInputBlur() { + const parsed = parseTimeInput(maxInput); + if (parsed !== null && parsed > sliderMin && parsed <= MAX_DURATION) { + handleSliderChange(sliderMin, parsed); + } else { + // Reset to current value if invalid + setMaxInput( + sliderMax >= MAX_DURATION + ? MAX_LABEL + : TextUtils.secondsAsTimeString(sliderMax) + ); + } + } + + const customSlider = ( + handleMinInputChange(e.target.value)} + onBlur={handleMinInputBlur} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.currentTarget.blur(); + } + }} + placeholder="0:00" + /> + } + maxInput={ + handleMaxInputChange(e.target.value)} + onBlur={handleMaxInputBlur} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.currentTarget.blur(); + } + }} + placeholder={MAX_LABEL} + /> + } + min={0} + max={MAX_DURATION} + value={[sliderMin, sliderMax]} + onChange={(vals) => { + handleSliderChange(snapToStep(vals[0]), snapToStep(vals[1])); + }} + /> + ); + + return ( + + ); +}; diff --git a/ui/v2.5/src/components/List/Filters/SidebarListFilter.tsx b/ui/v2.5/src/components/List/Filters/SidebarListFilter.tsx index 71a56f23d..fe9b7987c 100644 --- a/ui/v2.5/src/components/List/Filters/SidebarListFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/SidebarListFilter.tsx @@ -276,6 +276,8 @@ export const SidebarListFilter: React.FC<{ preCandidates?: React.ReactNode; postCandidates?: React.ReactNode; onOpen?: () => void; + // used to store open/closed state in SidebarStateContext + sectionID?: string; }> = ({ title, selected, @@ -292,6 +294,7 @@ export const SidebarListFilter: React.FC<{ preSelected, postSelected, onOpen, + sectionID, }) => { // TODO - sort items? @@ -325,6 +328,7 @@ export const SidebarListFilter: React.FC<{ {preSelected ?
{preSelected}
: null} diff --git a/ui/v2.5/src/components/List/Filters/StudiosFilter.tsx b/ui/v2.5/src/components/List/Filters/StudiosFilter.tsx index e9c05013d..e922e688a 100644 --- a/ui/v2.5/src/components/List/Filters/StudiosFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/StudiosFilter.tsx @@ -10,6 +10,7 @@ import { sortByRelevance } from "src/utils/query"; import { CriterionOption } from "src/models/list-filter/criteria/criterion"; import { ListFilterModel } from "src/models/list-filter/filter"; import { + IUseQueryHookProps, makeQueryVariables, setObjectFilter, useLabeledIdFilterState, @@ -56,13 +57,12 @@ function sortResults( }); } -function useStudioQueryFilter( - query: string, - filter?: ListFilterModel, - skip?: boolean -) { +function useStudioQueryFilter(props: IUseQueryHookProps) { + const { q: query, filter: f, skip, filterHook } = props; + const appliedFilter = filterHook && f ? filterHook(f.clone()) : f; + const { data, loading } = useFindStudiosForSelectQuery({ - variables: queryVariables(query, filter), + variables: queryVariables(query, appliedFilter), skip, }); @@ -75,7 +75,7 @@ function useStudioQueryFilter( } function useStudioQuery(query: string, skip?: boolean) { - return useStudioQueryFilter(query, undefined, skip); + return useStudioQueryFilter({ q: query, skip: !!skip }); } const StudiosFilter: React.FC = ({ @@ -97,10 +97,13 @@ export const SidebarStudiosFilter: React.FC<{ option: CriterionOption; filter: ListFilterModel; setFilter: (f: ListFilterModel) => void; -}> = ({ title, option, filter, setFilter }) => { + filterHook?: (f: ListFilterModel) => ListFilterModel; + sectionID?: string; +}> = ({ title, option, filter, setFilter, filterHook, sectionID }) => { const state = useLabeledIdFilterState({ filter, setFilter, + filterHook, option, useQuery: useStudioQueryFilter, singleValue: true, @@ -108,7 +111,7 @@ export const SidebarStudiosFilter: React.FC<{ includeSubMessageID: "subsidiary_studios", }); - return ; + return ; }; export default StudiosFilter; diff --git a/ui/v2.5/src/components/List/Filters/TagsFilter.tsx b/ui/v2.5/src/components/List/Filters/TagsFilter.tsx index 0a3f8c942..f4c618ffa 100644 --- a/ui/v2.5/src/components/List/Filters/TagsFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/TagsFilter.tsx @@ -10,6 +10,7 @@ import { sortByRelevance } from "src/utils/query"; import { CriterionOption } from "src/models/list-filter/criteria/criterion"; import { ListFilterModel } from "src/models/list-filter/filter"; import { + IUseQueryHookProps, makeQueryVariables, setObjectFilter, useLabeledIdFilterState, @@ -65,13 +66,12 @@ function sortResults( }); } -function useTagQueryFilter( - query: string, - filter?: ListFilterModel, - skip?: boolean -) { +function useTagQueryFilter(props: IUseQueryHookProps) { + const { q: query, filter: f, skip, filterHook } = props; + const appliedFilter = filterHook && f ? filterHook(f.clone()) : f; + const { data, loading } = useFindTagsForSelectQuery({ - variables: queryVariables(query, filter), + variables: queryVariables(query, appliedFilter), skip, }); @@ -84,7 +84,7 @@ function useTagQueryFilter( } function useTagQuery(query: string, skip?: boolean) { - return useTagQueryFilter(query, undefined, skip); + return useTagQueryFilter({ q: query, skip: !!skip }); } const TagsFilter: React.FC = ({ criterion, setCriterion }) => { @@ -102,17 +102,20 @@ export const SidebarTagsFilter: React.FC<{ option: CriterionOption; filter: ListFilterModel; setFilter: (f: ListFilterModel) => void; -}> = ({ title, option, filter, setFilter }) => { + filterHook?: (f: ListFilterModel) => ListFilterModel; + sectionID?: string; +}> = ({ title, option, filter, setFilter, filterHook, sectionID }) => { const state = useLabeledIdFilterState({ filter, setFilter, + filterHook, option, useQuery: useTagQueryFilter, hierarchical: true, includeSubMessageID: "sub_tags", }); - return ; + return ; }; export default TagsFilter; diff --git a/ui/v2.5/src/components/List/ItemList.tsx b/ui/v2.5/src/components/List/ItemList.tsx index 4ffeff766..b68077b55 100644 --- a/ui/v2.5/src/components/List/ItemList.tsx +++ b/ui/v2.5/src/components/List/ItemList.tsx @@ -1,7 +1,6 @@ import React, { PropsWithChildren, useCallback, - useContext, useEffect, useMemo, useState, @@ -43,7 +42,9 @@ import { IItemListOperation, } from "./FilteredListToolbar"; import { PagedList } from "./PagedList"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; +import { useZoomKeybinds } from "./ZoomSlider"; +import { DisplayMode } from "src/models/list-filter/types"; interface IFilteredItemList { filterStateProps: IFilterStateHook; @@ -55,7 +56,7 @@ export function useFilteredItemList< T extends QueryResult, E extends IHasID = IHasID >(props: IFilteredItemList) { - const { configuration: config } = useContext(ConfigurationContext); + const { configuration: config } = useConfigurationContext(); // States const filterState = useFilterState({ @@ -113,7 +114,6 @@ export function useFilteredItemList< interface IItemListProps { view?: View; - zoomable?: boolean; otherOperations?: IItemListOperation[]; renderContent: ( result: T, @@ -145,7 +145,6 @@ export const ItemList = ( ) => { const { view, - zoomable, otherOperations, renderContent, renderEditDialog, @@ -217,6 +216,15 @@ export const ItemList = ( showEditFilter, }); + const zoomable = + filter.displayMode === DisplayMode.Grid || + filter.displayMode === DisplayMode.Wall; + + useZoomKeybinds({ + zoomIndex: zoomable ? filter.zoomIndex : undefined, + onChangeZoom: (zoom) => updateFilter(filter.setZoom(zoom)), + }); + useEffect(() => { if (addKeybinds) { const unbindExtras = addKeybinds(result, effectiveFilter, selectedIds); @@ -393,7 +401,7 @@ export const ItemListContext = ( children, } = props; - const { configuration: config } = useContext(ConfigurationContext); + const { configuration: config } = useConfigurationContext(); const emptyFilter = useMemo( () => @@ -409,12 +417,7 @@ export const ItemListContext = ( new ListFilterModel(filterMode, config, { defaultSortBy: defaultSort }) ); - const { defaultFilter, loading: defaultFilterLoading } = useDefaultFilter( - emptyFilter, - view - ); - - if (defaultFilterLoading) return null; + const { defaultFilter } = useDefaultFilter(emptyFilter, view); return ( diff --git a/ui/v2.5/src/components/List/ListFilter.tsx b/ui/v2.5/src/components/List/ListFilter.tsx index 4933c7e75..ff3be0360 100644 --- a/ui/v2.5/src/components/List/ListFilter.tsx +++ b/ui/v2.5/src/components/List/ListFilter.tsx @@ -1,4 +1,3 @@ -import cloneDeep from "lodash-es/cloneDeep"; import React, { useCallback, useEffect, @@ -23,19 +22,18 @@ import { import { Icon } from "../Shared/Icon"; import { ListFilterModel } from "src/models/list-filter/filter"; import useFocus from "src/utils/focus"; -import { FormattedMessage, useIntl } from "react-intl"; -import { SavedFilterDropdown } from "./SavedFilterList"; +import { useIntl } from "react-intl"; import { faCaretDown, faCaretUp, faCheck, faRandom, } from "@fortawesome/free-solid-svg-icons"; -import { FilterButton } from "./Filters/FilterButton"; import { useDebounce } from "src/hooks/debounce"; -import { View } from "./views"; import { ClearableInput } from "../Shared/ClearableInput"; import { useStopWheelScroll } from "src/utils/form"; +import { ISortByOption } from "src/models/list-filter/filter-options"; +import { useConfigurationContext } from "src/hooks/Config"; export function useDebouncedSearchInput( filter: ListFilterModel, @@ -230,70 +228,42 @@ export const PageSizeSelector: React.FC<{ ); }; -interface IListFilterProps { - onFilterUpdate: (newFilter: ListFilterModel) => void; - filter: ListFilterModel; - view?: View; - openFilterDialog: () => void; - withSidebar?: boolean; -} - -export const ListFilter: React.FC = ({ - onFilterUpdate, - filter, - openFilterDialog, - view, - withSidebar, +export const SortBySelect: React.FC<{ + className?: string; + sortBy: string | undefined; + sortDirection: SortDirectionEnum; + options: ISortByOption[]; + onChangeSortBy: (eventKey: string | null) => void; + onChangeSortDirection: () => void; + onReshuffleRandomSort: () => void; +}> = ({ + className, + sortBy, + sortDirection, + options, + onChangeSortBy, + onChangeSortDirection, + onReshuffleRandomSort, }) => { - const filterOptions = filter.options; - const intl = useIntl(); + const { configuration } = useConfigurationContext(); + const { sfwContentMode } = configuration.interface; - useEffect(() => { - Mousetrap.bind("r", () => onReshuffleRandomSort()); - - return () => { - Mousetrap.unbind("r"); - }; - }); - - function onChangePageSize(pp: number) { - const newFilter = cloneDeep(filter); - newFilter.itemsPerPage = pp; - newFilter.currentPage = 1; - onFilterUpdate(newFilter); - } - - function onChangeSortDirection() { - const newFilter = cloneDeep(filter); - if (filter.sortDirection === SortDirectionEnum.Asc) { - newFilter.sortDirection = SortDirectionEnum.Desc; - } else { - newFilter.sortDirection = SortDirectionEnum.Asc; - } - - onFilterUpdate(newFilter); - } - - function onChangeSortBy(eventKey: string | null) { - const newFilter = cloneDeep(filter); - newFilter.sortBy = eventKey ?? undefined; - newFilter.currentPage = 1; - onFilterUpdate(newFilter); - } - - function onReshuffleRandomSort() { - const newFilter = cloneDeep(filter); - newFilter.currentPage = 1; - newFilter.randomSeed = -1; - onFilterUpdate(newFilter); - } + const currentSortBy = options.find((o) => o.value === sortBy); + const currentSortByMessageID = currentSortBy + ? !sfwContentMode + ? currentSortBy.messageID + : currentSortBy.sfwMessageID ?? currentSortBy.messageID + : ""; function renderSortByOptions() { - return filterOptions.sortByOptions + return options .map((o) => { + const messageID = !sfwContentMode + ? o.messageID + : o.sfwMessageID ?? o.messageID; return { - message: intl.formatMessage({ id: o.messageID }), + message: intl.formatMessage({ id: messageID }), value: o.value, }; }) @@ -304,102 +274,55 @@ export const ListFilter: React.FC = ({ key={option.value} className="bg-secondary text-white" eventKey={option.value} + data-value={option.value} > {option.message} )); } - function render() { - const currentSortBy = filterOptions.sortByOptions.find( - (o) => o.value === filter.sortBy - ); - - return ( - <> - {!withSidebar && ( -
- -
- )} - - {!withSidebar && ( - - { - onFilterUpdate(f); - }} - view={view} - /> - - - - } - > - openFilterDialog()} - filter={filter} - /> - - - )} - - - - - {currentSortBy - ? intl.formatMessage({ id: currentSortBy.messageID }) - : ""} - - - - {renderSortByOptions()} - - - {filter.sortDirection === SortDirectionEnum.Asc - ? intl.formatMessage({ id: "ascending" }) - : intl.formatMessage({ id: "descending" })} - + return ( + + + + {currentSortBy + ? intl.formatMessage({ id: currentSortByMessageID }) + : ""} + + + + {renderSortByOptions()} + + + {sortDirection === SortDirectionEnum.Asc + ? intl.formatMessage({ id: "ascending" }) + : intl.formatMessage({ id: "descending" })} + + } + > + - - {filter.sortBy === "random" && ( - - {intl.formatMessage({ id: "actions.reshuffle" })} - - } - > - - - )} - - - - - ); - } - - return render(); + /> + + + {sortBy === "random" && ( + + {intl.formatMessage({ id: "actions.reshuffle" })} + + } + > + + + )} + + ); }; diff --git a/ui/v2.5/src/components/List/ListOperationButtons.tsx b/ui/v2.5/src/components/List/ListOperationButtons.tsx index 8ea21df98..2d8e83039 100644 --- a/ui/v2.5/src/components/List/ListOperationButtons.tsx +++ b/ui/v2.5/src/components/List/ListOperationButtons.tsx @@ -1,11 +1,5 @@ -import React, { PropsWithChildren, useEffect } from "react"; -import { - Button, - ButtonGroup, - Dropdown, - OverlayTrigger, - Tooltip, -} from "react-bootstrap"; +import React, { PropsWithChildren, useEffect, useMemo } from "react"; +import { Button, ButtonGroup, Dropdown } from "react-bootstrap"; import Mousetrap from "mousetrap"; import { FormattedMessage, useIntl } from "react-intl"; import { IconDefinition } from "@fortawesome/fontawesome-svg-core"; @@ -15,24 +9,48 @@ import { faPencilAlt, faTrash, } from "@fortawesome/free-solid-svg-icons"; +import cx from "classnames"; +import { createPortal } from "react-dom"; -export const OperationDropdown: React.FC> = ({ - children, -}) => { +export const OperationDropdown: React.FC< + PropsWithChildren<{ + className?: string; + menuPortalTarget?: HTMLElement; + }> +> = ({ className, menuPortalTarget, children }) => { if (!children) return null; + const menu = ( + + {children} + + ); + return ( - + - - {children} - + {menuPortalTarget ? createPortal(menu, menuPortalTarget) : menu} ); }; +export const OperationDropdownItem: React.FC<{ + text: string; + onClick: () => void; + className?: string; +}> = ({ text, onClick, className }) => { + return ( + + {text} + + ); +}; + export interface IListFilterOperation { text: string; onClick: () => void; @@ -84,8 +102,8 @@ export const ListOperationButtons: React.FC = ({ }; }); - function maybeRenderButtons() { - const buttons = (otherOperations ?? []).filter((o) => { + const buttons = useMemo(() => { + const ret = (otherOperations ?? []).filter((o) => { if (!o.icon) { return false; } @@ -96,16 +114,17 @@ export const ListOperationButtons: React.FC = ({ return o.isDisplayed(); }); + if (itemsSelected) { if (onEdit) { - buttons.push({ + ret.push({ icon: faPencilAlt, text: intl.formatMessage({ id: "actions.edit" }), onClick: onEdit, }); } if (onDelete) { - buttons.push({ + ret.push({ icon: faTrash, text: intl.formatMessage({ id: "actions.delete" }), onClick: onDelete, @@ -114,58 +133,57 @@ export const ListOperationButtons: React.FC = ({ } } - if (buttons.length > 0) { - return ( - - {buttons.map((button) => { - return ( - {button.text}} - key={button.text} - > - - - ); - })} - - ); - } - } + return ret; + }, [otherOperations, itemsSelected, onEdit, onDelete, intl]); - function renderSelectAll() { - if (onSelectAll) { - return ( - onSelectAll?.()} - > - - - ); - } - } + const operationButtons = useMemo(() => { + return ( + <> + {buttons.map((button) => { + return ( + + ); + })} + + ); + }, [buttons]); - function renderSelectNone() { - if (onSelectNone) { - return ( - onSelectNone?.()} - > - - - ); + const moreDropdown = useMemo(() => { + function renderSelectAll() { + if (onSelectAll) { + return ( + onSelectAll?.()} + > + + + ); + } + } + + function renderSelectNone() { + if (onSelectNone) { + return ( + onSelectNone?.()} + > + + + ); + } } - } - function renderMore() { const options = [renderSelectAll(), renderSelectNone()].filter((o) => o); if (otherOperations) { @@ -200,13 +218,19 @@ export const ListOperationButtons: React.FC = ({ {options.length > 0 ? options : undefined} ); + }, [otherOperations, onSelectAll, onSelectNone]); + + // don't render anything if there are no buttons or operations + if (buttons.length === 0 && !moreDropdown) { + return null; } return ( <> - {maybeRenderButtons()} - - {renderMore()} + + {operationButtons} + {moreDropdown} + ); }; diff --git a/ui/v2.5/src/components/List/ListResultsHeader.tsx b/ui/v2.5/src/components/List/ListResultsHeader.tsx new file mode 100644 index 000000000..8a1bba05e --- /dev/null +++ b/ui/v2.5/src/components/List/ListResultsHeader.tsx @@ -0,0 +1,73 @@ +import React from "react"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { Pagination, PaginationIndex } from "../List/Pagination"; +import { ButtonToolbar } from "react-bootstrap"; +import { ListViewOptions } from "../List/ListViewOptions"; +import { PageSizeSelector, SortBySelect } from "../List/ListFilter"; +import cx from "classnames"; + +export const ListResultsHeader: React.FC<{ + className?: string; + loading: boolean; + filter: ListFilterModel; + totalCount: number; + metadataByline?: React.ReactNode; + onChangeFilter: (filter: ListFilterModel) => void; +}> = ({ + className, + loading, + filter, + totalCount, + metadataByline, + onChangeFilter, +}) => { + return ( + +
+ + onChangeFilter(filter.setSortBy(s ?? undefined)) + } + onChangeSortDirection={() => + onChangeFilter(filter.toggleSortDirection()) + } + onReshuffleRandomSort={() => + onChangeFilter(filter.reshuffleRandomSort()) + } + /> + onChangeFilter(filter.setPageSize(s))} + /> + + onChangeFilter(filter.setDisplayMode(mode)) + } + onSetZoom={(zoom) => onChangeFilter(filter.setZoom(zoom))} + /> +
+
+ onChangeFilter(filter.changePage(page))} + /> + +
+
+
+ ); +}; diff --git a/ui/v2.5/src/components/List/ListToolbar.tsx b/ui/v2.5/src/components/List/ListToolbar.tsx new file mode 100644 index 000000000..25ee281c0 --- /dev/null +++ b/ui/v2.5/src/components/List/ListToolbar.tsx @@ -0,0 +1,141 @@ +import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { faTimes } from "@fortawesome/free-solid-svg-icons"; +import { FilterTags } from "../List/FilterTags"; +import cx from "classnames"; +import { Button, ButtonGroup, ButtonToolbar } from "react-bootstrap"; +import { FilterButton } from "../List/Filters/FilterButton"; +import { Icon } from "../Shared/Icon"; +import { SearchTermInput } from "../List/ListFilter"; +import { Criterion } from "src/models/list-filter/criteria/criterion"; +import { SidebarToggleButton } from "../Shared/Sidebar"; +import { PatchComponent } from "src/patch"; +import { SavedFilterDropdown } from "./SavedFilterList"; +import { View } from "./views"; + +export const ToolbarFilterSection: React.FC<{ + filter: ListFilterModel; + onToggleSidebar: () => void; + onSetFilter: (filter: ListFilterModel) => void; + onEditCriterion: (c?: Criterion) => void; + onRemoveCriterion: (criterion: Criterion, valueIndex?: number) => void; + onRemoveAllCriterion: () => void; + onEditSearchTerm: () => void; + onRemoveSearchTerm: () => void; + view?: View; +}> = PatchComponent( + "ToolbarFilterSection", + ({ + filter, + onToggleSidebar, + onSetFilter, + onEditCriterion, + onRemoveCriterion, + onRemoveAllCriterion, + onEditSearchTerm, + onRemoveSearchTerm, + view, + }) => { + const { criteria, searchTerm } = filter; + + return ( + <> +
+ +
+
+ + + + onEditCriterion()} + count={criteria.length} + /> + + +
+ + ); + } +); + +export const ToolbarSelectionSection: React.FC<{ + selected: number; + onToggleSidebar: () => void; + operations?: React.ReactNode; + onSelectAll: () => void; + onSelectNone: () => void; +}> = PatchComponent( + "ToolbarSelectionSection", + ({ selected, onToggleSidebar, operations, onSelectAll, onSelectNone }) => { + const intl = useIntl(); + + return ( +
+
+ + + {selected} selected + +
+ {operations} +
+
+ ); + } +); + +// TODO - rename to FilteredListToolbar once all list components have been updated +// TODO - and expose to plugins +export const FilteredListToolbar2: React.FC<{ + className?: string; + hasSelection: boolean; + filterSection: React.ReactNode; + selectionSection: React.ReactNode; + operationSection: React.ReactNode; +}> = ({ + className, + hasSelection, + filterSection, + selectionSection, + operationSection, +}) => { + return ( + + {!hasSelection ? filterSection : selectionSection} + {!hasSelection ? ( +
+ {operationSection} +
+ ) : null} +
+ ); +}; diff --git a/ui/v2.5/src/components/List/ListViewOptions.tsx b/ui/v2.5/src/components/List/ListViewOptions.tsx index e83ff9290..b681e086d 100644 --- a/ui/v2.5/src/components/List/ListViewOptions.tsx +++ b/ui/v2.5/src/components/List/ListViewOptions.tsx @@ -1,8 +1,16 @@ import React, { useEffect, useRef, useState } from "react"; import Mousetrap from "mousetrap"; -import { Button, Dropdown, Overlay, Popover } from "react-bootstrap"; +import { + Button, + ButtonGroup, + Dropdown, + Overlay, + OverlayTrigger, + Popover, + Tooltip, +} from "react-bootstrap"; import { DisplayMode } from "src/models/list-filter/types"; -import { useIntl } from "react-intl"; +import { IntlShape, useIntl } from "react-intl"; import { Icon } from "../Shared/Icon"; import { faChevronDown, @@ -53,6 +61,10 @@ function getLabelId(option: DisplayMode) { return `display_mode.${displayModeId}`; } +function getLabel(intl: IntlShape, option: DisplayMode) { + return intl.formatMessage({ id: getLabelId(option) }); +} + export const ListViewOptions: React.FC = ({ zoomIndex, onSetZoom, @@ -60,9 +72,6 @@ export const ListViewOptions: React.FC = ({ onSetDisplayMode, displayModeOptions, }) => { - const minZoom = 0; - const maxZoom = 3; - const intl = useIntl(); const overlayTarget = useRef(null); @@ -84,18 +93,20 @@ export const ListViewOptions: React.FC = ({ onSetDisplayMode(DisplayMode.Wall); } }); + Mousetrap.bind("v t", () => { + if (displayModeOptions.includes(DisplayMode.Tagger)) { + onSetDisplayMode(DisplayMode.Tagger); + } + }); return () => { Mousetrap.unbind("v g"); Mousetrap.unbind("v l"); Mousetrap.unbind("v w"); + Mousetrap.unbind("v t"); }; }); - function getLabel(option: DisplayMode) { - return intl.formatMessage({ id: getLabelId(option) }); - } - function onChangeZoom(v: number) { if (onSetZoom) { onSetZoom(v); @@ -110,7 +121,7 @@ export const ListViewOptions: React.FC = ({ variant="secondary" title={intl.formatMessage( { id: "display_mode.label_current" }, - { current: getLabel(displayMode) } + { current: getLabel(intl, displayMode) } )} onClick={() => setShowOptions(!showOptions)} > @@ -130,11 +141,10 @@ export const ListViewOptions: React.FC = ({
{onSetZoom && zoomIndex !== undefined && - displayMode === DisplayMode.Grid ? ( + (displayMode === DisplayMode.Grid || + displayMode === DisplayMode.Wall) ? (
@@ -149,7 +159,7 @@ export const ListViewOptions: React.FC = ({ onSetDisplayMode(option); }} > - {getLabel(option)} + {getLabel(intl, option)} ))}
@@ -160,3 +170,48 @@ export const ListViewOptions: React.FC = ({ ); }; + +export const ListViewButtonGroup: React.FC = ({ + zoomIndex, + onSetZoom, + displayMode, + onSetDisplayMode, + displayModeOptions, +}) => { + const intl = useIntl(); + + return ( + <> + {displayModeOptions.length > 1 && ( + + {displayModeOptions.map((option) => ( + + {getLabel(intl, option)} + + } + > + + + ))} + + )} +
+ {onSetZoom && + zoomIndex !== undefined && + (displayMode === DisplayMode.Grid || + displayMode === DisplayMode.Wall) ? ( + + ) : null} +
+ + ); +}; diff --git a/ui/v2.5/src/components/List/Pagination.tsx b/ui/v2.5/src/components/List/Pagination.tsx index e117b532e..bfa6697ee 100644 --- a/ui/v2.5/src/components/List/Pagination.tsx +++ b/ui/v2.5/src/components/List/Pagination.tsx @@ -44,7 +44,7 @@ const PageCount: React.FC<{ useStopWheelScroll(pageInput); const pageOptions = useMemo(() => { - const maxPagesToShow = 10; + const maxPagesToShow = 1000; const min = Math.max(1, currentPage - maxPagesToShow / 2); const max = Math.min(min + maxPagesToShow, totalPages); const pages = []; diff --git a/ui/v2.5/src/components/List/SavedFilterList.tsx b/ui/v2.5/src/components/List/SavedFilterList.tsx index cbeeaa70a..df1d6136a 100644 --- a/ui/v2.5/src/components/List/SavedFilterList.tsx +++ b/ui/v2.5/src/components/List/SavedFilterList.tsx @@ -30,12 +30,15 @@ import { faBookmark, faSave, faTimes } from "@fortawesome/free-solid-svg-icons"; import { AlertModal } from "../Shared/Alert"; import cx from "classnames"; import { TruncatedInlineText } from "../Shared/TruncatedText"; +import { OperationButton } from "../Shared/OperationButton"; +import { createPortal } from "react-dom"; const ExistingSavedFilterList: React.FC<{ name: string; - setName: (name: string) => void; - existing: { name: string; id: string }[]; -}> = ({ name, setName, existing }) => { + onSelect: (value: SavedFilterDataFragment) => void; + savedFilters: SavedFilterDataFragment[]; + disabled?: boolean; +}> = ({ name, onSelect, savedFilters: existing, disabled = false }) => { const filtered = useMemo(() => { if (!name) return existing; @@ -51,7 +54,8 @@ const ExistingSavedFilterList: React.FC<{ @@ -64,7 +68,8 @@ const ExistingSavedFilterList: React.FC<{ export const SaveFilterDialog: React.FC<{ mode: FilterMode; onClose: (name?: string, id?: string) => void; -}> = ({ mode, onClose }) => { + isSaving?: boolean; +}> = ({ mode, onClose, isSaving = false }) => { const intl = useIntl(); const [filterName, setFilterName] = useState(""); @@ -79,6 +84,74 @@ export const SaveFilterDialog: React.FC<{ return ( + + + + + + + + + setFilterName(e.target.value)} + disabled={isSaving} + /> + + + setFilterName(f.name)} + savedFilters={data?.findSavedFilters ?? []} + /> + + {!!overwritingFilter && ( + + + + )} + + + + onClose(filterName, overwritingFilter?.id)} + > + {intl.formatMessage({ id: "actions.save" })} + + + + ); +}; + +export const LoadFilterDialog: React.FC<{ + mode: FilterMode; + onClose: (filter?: SavedFilterDataFragment) => void; +}> = ({ mode, onClose }) => { + const intl = useIntl(); + const [filterName, setFilterName] = useState(""); + + const { data } = useFindSavedFilters(mode); + + return ( + + + + @@ -94,31 +167,14 @@ export const SaveFilterDialog: React.FC<{ onClose(f)} + savedFilters={data?.findSavedFilters ?? []} /> - - {!!overwritingFilter && ( - - - - )} - ); @@ -166,7 +222,7 @@ const OverwriteAlert: React.FC<{ void; view?: View; + menuPortalTarget?: Element | DocumentFragment; } export const SavedFilterList: React.FC = ({ @@ -786,8 +843,15 @@ export const SavedFilterDropdown: React.FC = (props) => { )); SavedFilterDropdownRef.displayName = "SavedFilterDropdown"; + const menu = ( + + ); + return ( - + = (props) => { - + {props.menuPortalTarget + ? createPortal(menu, props.menuPortalTarget) + : menu} ); }; diff --git a/ui/v2.5/src/components/List/ZoomSlider.tsx b/ui/v2.5/src/components/List/ZoomSlider.tsx index dff8e4f57..093b5ec7a 100644 --- a/ui/v2.5/src/components/List/ZoomSlider.tsx +++ b/ui/v2.5/src/components/List/ZoomSlider.tsx @@ -2,19 +2,14 @@ import React, { useEffect } from "react"; import Mousetrap from "mousetrap"; import { Form } from "react-bootstrap"; -export interface IZoomSelectProps { - minZoom: number; - maxZoom: number; - zoomIndex: number; - onChangeZoom: (v: number) => void; -} +const minZoom = 0; +const maxZoom = 3; -export const ZoomSelect: React.FC = ({ - minZoom, - maxZoom, - zoomIndex, - onChangeZoom, -}) => { +export function useZoomKeybinds(props: { + zoomIndex: number | undefined; + onChangeZoom: (v: number) => void; +}) { + const { zoomIndex, onChangeZoom } = props; useEffect(() => { Mousetrap.bind("+", () => { if (zoomIndex !== undefined && zoomIndex < maxZoom) { @@ -32,7 +27,17 @@ export const ZoomSelect: React.FC = ({ Mousetrap.unbind("-"); }; }); +} +export interface IZoomSelectProps { + zoomIndex: number; + onChangeZoom: (v: number) => void; +} + +export const ZoomSelect: React.FC = ({ + zoomIndex, + onChangeZoom, +}) => { return ( div > :not(:first-child) { + margin-left: 0.25rem; + } + } + + .search-term-row { + align-items: center; + display: flex; + gap: 0.5rem; + justify-content: space-between; + margin-bottom: 0.5rem; + margin-left: 1.5rem; + margin-right: 1rem; + + .search-term-input { + flex-basis: 75%; + } + + @include media-breakpoint-down(xs) { + flex-wrap: wrap; + + > span { + width: 100%; + } + + .search-term-input { + flex-basis: 100%; + } + } + } + .filter-tags { border-top: 1px solid rgb(16 22 26 / 40%); padding: 1rem 1rem 0 1rem; @@ -412,11 +454,22 @@ input[type="range"].zoom-slider { } } -.filter-tags .clear-all-button { - color: $text-color; - // to match filter pills - line-height: 16px; - padding: 0; +.filter-tags { + display: flex; + justify-content: center; + margin-bottom: 0.5rem; + + .more-tags { + background-color: transparent; + color: #fff; + } + + .clear-all-button { + color: $text-color; + // to match filter pills + line-height: 16px; + padding: 0; + } } .filter-button { @@ -695,7 +748,7 @@ input[type="range"].zoom-slider { background-color: #202b33; position: sticky; top: 0; - z-index: 100; + z-index: 1; } td:first-child { @@ -864,6 +917,8 @@ input[type="range"].zoom-slider { } .filtered-list-toolbar { + align-items: center; + gap: 0.5rem; justify-content: center; margin-bottom: 0.5rem; @@ -881,8 +936,10 @@ input[type="range"].zoom-slider { } } - .btn.display-mode-select { - margin-left: 0.5rem; + // set the width of the zoom-slider-container to prevent buttons moving when + // the slider appears/disappears + .zoom-slider-container { + min-width: 60px; } } @@ -894,10 +951,6 @@ input[type="range"].zoom-slider { } } -.search-term-input { - margin-right: 0.5rem; -} - .custom-field-filter { align-items: center; display: flex; @@ -929,40 +982,454 @@ input[type="range"].zoom-slider { } .sidebar { + // make controls slightly larger on mobile + @include media-breakpoint-down(xs) { + .btn, + .form-control { + font-size: 1.25rem; + } + } + .sidebar-search-container { display: flex; margin-bottom: 0.5rem; - margin-top: 0.25rem; } .search-term-input { flex-grow: 1; - margin-right: 0.25rem; + margin-right: 0; .clearable-text-field { height: 100%; } } + + .edit-filter-button { + width: 100%; + } + + .sidebar-footer { + background-color: $body-bg; + bottom: 0; + display: none; + padding: 0.5rem; + position: sticky; + + @include media-breakpoint-down(xs) { + display: flex; + justify-content: center; + } + } } @include media-breakpoint-down(xs) { - .sidebar .search-term-input { - margin-right: 0.5rem; + .sidebar .sidebar-search-container { + margin-top: 0.25rem; } } .pagination-footer { - background-color: $body-bg; + background-color: transparent; bottom: $navbar-height; - padding: 0.5rem 1rem; + margin: auto; + padding: 0.5rem 1rem 0.75rem; position: sticky; + width: fit-content; z-index: 10; @include media-breakpoint-up(sm) { bottom: 0; } + .pagination.btn-group { + box-shadow: 0 8px 10px 2px rgb(0 0 0 / 30%); + } + .pagination { margin-bottom: 0; + + .btn:disabled { + color: #888; + opacity: 1; + } } } + +// hide sidebar Edit Filter button on larger screens +@include media-breakpoint-up(md) { + .sidebar .edit-filter-button { + display: none; + } +} + +// the following refers to the new FilteredListToolbar2 component +// ensure the rules here don't conflict with the original filtered-list-toolbar above +// TODO - replace with only .filtered-list-toolbar once all lists use the new toolbar +.scene-list-toolbar { + &.filtered-list-toolbar { + align-items: center; + background-color: $body-bg; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin-bottom: 0; + row-gap: 1rem; + + > div { + align-items: center; + display: flex; + gap: 0.5rem; + justify-content: flex-start; + + &:last-child { + flex-shrink: 0; + justify-content: flex-end; + } + } + } + + &.filtered-list-toolbar { + flex-wrap: nowrap; + gap: 1rem; + // offset the main padding + margin-top: -0.5rem; + padding-bottom: 0.5rem; + padding-top: 0.5rem; + position: sticky; + top: $navbar-height; + z-index: 10; + + @include media-breakpoint-down(xs) { + top: 0; + } + + // hide drop down menu items for play and create new + // when the buttons are visible + @include media-breakpoint-up(sm) { + .scene-list-operations { + .play-item, + .create-new-item { + display: none; + } + } + } + + // hide play and create new buttons on xs screens + // show these in the drop down menu instead + @include media-breakpoint-down(xs) { + .play-button, + .create-new-button { + display: none; + } + } + + .toolbar-selection-section, + div.filter-section { + border: 1px solid $secondary; + border-radius: 0.25rem; + flex-grow: 1; + overflow-x: hidden; + } + + div.toolbar-selection-section { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: center; + + .sidebar-toggle-button { + margin-right: 0.5rem; + } + + .selected-items-info { + align-items: center; + display: flex; + } + + > div:first-child, + > div:last-child { + flex: 1; + } + + > div:last-child { + display: flex; + justify-content: flex-end; + } + + .scene-list-operations { + display: flex; + } + + // on smaller viewports move the operation buttons to the right + @include media-breakpoint-down(md) { + div.scene-list-operations { + flex: 1; + justify-content: flex-end; + order: 3; + } + + > div:last-child { + flex: 0; + order: 2; + } + } + } + + // on larger viewports, move the operation buttons to the center + @include media-breakpoint-up(lg) { + div.toolbar-selection-section div.scene-list-operations { + justify-content: center; + + > .btn-group { + gap: 0.5rem; + } + } + + div.toolbar-selection-section .empty-space { + flex: 1; + order: 3; + } + } + + .search-container { + border-right: 1px solid $secondary; + display: flex; + margin-right: -0.5rem; + min-width: calc($sidebar-width - 15px); + padding-right: 10px; + + .search-term-input { + margin-right: 0; + width: 100%; + + .clearable-text-field { + height: 100%; + } + } + } + + .filter-tags { + flex-grow: 1; + flex-wrap: nowrap; + justify-content: flex-start; + margin-bottom: 0; + + // account for filter button, and toggle sidebar buttons with gaps + width: calc(100% - 70px - 1rem); + + @include media-breakpoint-down(xs) { + overflow-x: auto; + scrollbar-width: thin; + } + + .tag-item { + white-space: nowrap; + } + } + } +} + +// hide the search box in the toolbar when sidebar is shown on larger screens +// larger screens don't overlap the sidebar +@include media-breakpoint-up(md) { + .sidebar-pane:not(.hide-sidebar) .filtered-list-toolbar .search-container { + display: none; + } +} +// hide the search box when sidebar is hidden on smaller screens +@include media-breakpoint-down(md) { + .sidebar-pane.hide-sidebar .filtered-list-toolbar .search-container { + display: none; + } +} + +// hide the filter and saved filters icon buttons when sidebar is shown on smaller screens +@include media-breakpoint-down(sm) { + .sidebar-pane:not(.hide-sidebar) .filtered-list-toolbar { + .filter-button, + .saved-filter-dropdown { + display: none; + } + } + + // adjust the width of the filter-tags as well + .sidebar-pane:not(.hide-sidebar) .filtered-list-toolbar .filter-tags { + width: calc(100% - 35px - 0.5rem); + } +} + +// move the sidebar toggle to the left on larger viewports +@include media-breakpoint-up(md) { + .filtered-list-toolbar .filter-section { + .sidebar-toggle-button { + margin-left: 0; + } + + .filter-tags { + order: 2; + } + } +} + +// hide the search term tag item when the search box is visible +@include media-breakpoint-up(lg) { + // TODO - remove scene-list-toolbar when all lists use the new toolbar + .scene-list-toolbar.filtered-list-toolbar + .filter-tags + .search-term-filter-tag { + display: none; + } +} +@include media-breakpoint-down(md) { + // TODO - remove scene-list-toolbar when all lists use the new toolbar + .sidebar-pane:not(.hide-sidebar) + .scene-list-toolbar.filtered-list-toolbar + .filter-tags + .search-term-filter-tag { + display: none; + } +} + +// TODO - remove scene-list-toolbar when all lists use the new toolbar +.detail-body .scene-list-toolbar.filtered-list-toolbar { + top: calc($sticky-detail-header-height + $navbar-height); + + @include media-breakpoint-down(xs) { + top: 0; + } +} + +#more-criteria-popover { + box-shadow: 0 8px 10px 2px rgb(0 0 0 / 30%); + max-width: 400px; + padding: 0.25rem; +} + +.list-results-header { + align-items: flex-start; + background-color: $body-bg; + display: flex; + + > div { + align-items: center; + display: flex; + flex: 1; + gap: 0.5rem; + justify-content: flex-start; + + &.pagination-index-container { + justify-content: center; + } + + &:last-child { + flex-shrink: 0; + justify-content: flex-end; + } + } +} + +.list-results-header .pagination-index-container { + display: flex; + flex-direction: column; + gap: 0.5rem; + + .pagination { + // hidden by default. Can be shown via css override if needed + display: none; + margin: 0; + } +} + +.list-results-header { + gap: 0.25rem; + margin-bottom: 0.5rem; + + .paginationIndex { + margin: 0; + } + + // move pagination info to right on medium screens + @include media-breakpoint-down(md) { + & > .empty-space { + flex: 0; + } + + & > div.pagination-index-container { + align-items: flex-end; + order: 3; + } + } + + // center the header on smaller screens + @include media-breakpoint-down(sm) { + & > div, + & > div.pagination-index-container { + flex-basis: 100%; + justify-content: center; + margin-left: auto; + margin-right: auto; + } + + & > div.pagination-index-container { + align-items: center; + } + } +} + +// sidebar visible styling +.sidebar-pane:not(.hide-sidebar) .list-results-header { + // move pagination info to right on medium screens when sidebar + @include media-breakpoint-down(lg) { + & > .empty-space { + flex: 0; + } + + & > div.pagination-index-container { + justify-content: flex-end; + order: 3; + } + } + + // center the header on smaller screens when sidebar is visible + @include media-breakpoint-down(md) { + & > div, + & > div.pagination-index-container { + flex-basis: 100%; + justify-content: center; + margin-left: auto; + margin-right: auto; + } + } +} + +// Duration slider styles +.duration-slider, +.age-slider-container { + padding: 0.5rem 0 1rem; + width: 100%; +} + +.duration-label-input, +.age-label-input { + background: transparent; + border: 1px solid transparent; + border-radius: 0.25rem; + color: $text-color; + font-size: 0.875rem; + font-weight: 500; + padding: 0.125rem 0.25rem; + width: 4rem; + + &:hover { + border-color: $secondary; + } + + &:focus { + border-color: $primary; + outline: none; + } +} + +.duration-preset { + cursor: pointer; +} diff --git a/ui/v2.5/src/components/List/util.ts b/ui/v2.5/src/components/List/util.ts index bb85145e7..c15c3335a 100644 --- a/ui/v2.5/src/components/List/util.ts +++ b/ui/v2.5/src/components/List/util.ts @@ -1,17 +1,24 @@ -import { useCallback, useContext, useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import Mousetrap from "mousetrap"; import { ListFilterModel } from "src/models/list-filter/filter"; import { useHistory, useLocation } from "react-router-dom"; import { isEqual, isFunction } from "lodash-es"; import { QueryResult } from "@apollo/client"; import { IHasID } from "src/utils/data"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { View } from "./views"; import { usePrevious } from "src/hooks/state"; import * as GQL from "src/core/generated-graphql"; import { DisplayMode } from "src/models/list-filter/types"; import { Criterion } from "src/models/list-filter/criteria/criterion"; +function locationEquals( + loc1: ReturnType | undefined, + loc2: ReturnType +) { + return loc1 && loc1.pathname === loc2.pathname && loc1.search === loc2.search; +} + export function useFilterURL( filter: ListFilterModel, setFilter: React.Dispatch>, @@ -24,6 +31,7 @@ export function useFilterURL( const history = useHistory(); const location = useLocation(); + const prevLocation = usePrevious(location); // when the filter changes, update the URL const updateFilter = useCallback( @@ -47,7 +55,8 @@ export function useFilterURL( // and updates the filter accordingly. useEffect(() => { // don't apply if active is false - if (!active) return; + // also don't apply if location is unchanged + if (!active || locationEquals(prevLocation, location)) return; // re-init to load default filter on empty new query params if (!location.search) { @@ -73,7 +82,8 @@ export function useFilterURL( }); }, [ active, - location.search, + prevLocation, + location, defaultFilter, setFilter, updateFilter, @@ -84,7 +94,7 @@ export function useFilterURL( } export function useDefaultFilter(emptyFilter: ListFilterModel, view?: View) { - const { configuration: config, loading } = useContext(ConfigurationContext); + const { configuration: config } = useConfigurationContext(); const defaultFilter = useMemo(() => { if (view && config?.ui.defaultFilters?.[view]) { @@ -104,9 +114,9 @@ export function useDefaultFilter(emptyFilter: ListFilterModel, view?: View) { } }, [view, config?.ui.defaultFilters, emptyFilter]); - const retFilter = loading ? undefined : defaultFilter ?? emptyFilter; + const retFilter = defaultFilter ?? emptyFilter; - return { defaultFilter: retFilter, loading }; + return { defaultFilter: retFilter }; } function useEmptyFilter(props: { @@ -148,14 +158,14 @@ export function useFilterState( const emptyFilter = useEmptyFilter({ filterMode, defaultSort, config }); - const { defaultFilter, loading } = useDefaultFilter(emptyFilter, view); + const { defaultFilter } = useDefaultFilter(emptyFilter, view); const { setFilter } = useFilterURL(filter, setFilterState, { defaultFilter, active: useURL, }); - return { loading, filter, setFilter }; + return { filter, setFilter }; } export function useFilterOperations(props: { @@ -196,9 +206,12 @@ export function useFilterOperations(props: { [setFilter] ); - const clearAllCriteria = useCallback(() => { - setFilter((cv) => cv.clearCriteria()); - }, [setFilter]); + const clearAllCriteria = useCallback( + (includeSearchTerm = false) => { + setFilter((cv) => cv.clearCriteria(includeSearchTerm)); + }, + [setFilter] + ); return { setPage, diff --git a/ui/v2.5/src/components/MainNavbar.tsx b/ui/v2.5/src/components/MainNavbar.tsx index 98bbc26c6..caee46f0c 100644 --- a/ui/v2.5/src/components/MainNavbar.tsx +++ b/ui/v2.5/src/components/MainNavbar.tsx @@ -11,7 +11,7 @@ import { MessageDescriptor, useIntl, } from "react-intl"; -import { Nav, Navbar, Button, Fade } from "react-bootstrap"; +import { Nav, Navbar, Button } from "react-bootstrap"; import { IconDefinition } from "@fortawesome/fontawesome-svg-core"; import { LinkContainer } from "react-router-bootstrap"; import { Link, NavLink, useLocation, useHistory } from "react-router-dom"; @@ -19,7 +19,7 @@ import Mousetrap from "mousetrap"; import SessionUtils from "src/utils/session"; import { Icon } from "src/components/Shared/Icon"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { ManualStateContext } from "./Help/context"; import { SettingsButton } from "./SettingsButton"; import { @@ -103,7 +103,6 @@ const allMenuItems: IMenuItem[] = [ href: "/scenes", icon: faPlayCircle, hotkey: "g s", - userCreatable: true, }, { name: "images", @@ -182,7 +181,7 @@ const MainNavbarUtilityItems = PatchComponent( export const MainNavbar: React.FC = () => { const history = useHistory(); const location = useLocation(); - const { configuration, loading } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const { openManual } = React.useContext(ManualStateContext); const [expanded, setExpanded] = useState(false); @@ -360,35 +359,31 @@ export const MainNavbar: React.FC = () => { ref={navbarRef} > - - <> - - {menuItems.map(({ href, icon, message }) => ( - - - - - - ))} - - - - + + {menuItems.map(({ href, icon, message }) => ( + + + + + + ))} + + diff --git a/ui/v2.5/src/components/Performers/EditPerformersDialog.tsx b/ui/v2.5/src/components/Performers/EditPerformersDialog.tsx index 71fcbedd9..677ac3aa1 100644 --- a/ui/v2.5/src/components/Performers/EditPerformersDialog.tsx +++ b/ui/v2.5/src/components/Performers/EditPerformersDialog.tsx @@ -27,6 +27,8 @@ import { BulkUpdateTextInput } from "../Shared/BulkUpdateTextInput"; import { faPencilAlt } from "@fortawesome/free-solid-svg-icons"; import * as FormUtils from "src/utils/form"; import { CountrySelect } from "../Shared/CountrySelect"; +import { useConfigurationContext } from "src/hooks/Config"; +import cx from "classnames"; interface IListOperationProps { selected: GQL.SlimPerformerDataFragment[]; @@ -61,6 +63,10 @@ export const EditPerformersDialog: React.FC = ( ) => { const intl = useIntl(); const Toast = useToast(); + + const { configuration } = useConfigurationContext(); + const { sfwContentMode } = configuration.interface; + const [tagIds, setTagIds] = useState({ mode: GQL.BulkUpdateIdMode.Add, }); @@ -204,7 +210,7 @@ export const EditPerformersDialog: React.FC = ( setter: (newValue: string | undefined) => void ) { return ( - + @@ -218,9 +224,13 @@ export const EditPerformersDialog: React.FC = ( } function render() { + // sfw class needs to be set because it is outside body + return ( = ( }} isRunning={isUpdating} > - + {FormUtils.renderLabel({ title: intl.formatMessage({ id: "rating" }), })} @@ -322,7 +332,7 @@ export const EditPerformersDialog: React.FC = ( setPenisLength(v) )} - + diff --git a/ui/v2.5/src/components/Performers/PerformerCard.tsx b/ui/v2.5/src/components/Performers/PerformerCard.tsx index 02e2a68fd..5f7a26d42 100644 --- a/ui/v2.5/src/components/Performers/PerformerCard.tsx +++ b/ui/v2.5/src/components/Performers/PerformerCard.tsx @@ -6,7 +6,6 @@ import NavUtils from "src/utils/navigation"; import TextUtils from "src/utils/text"; import { GridCard } from "../Shared/GridCard/GridCard"; import { CountryFlag } from "../Shared/CountryFlag"; -import { SweatDrops } from "../Shared/SweatDrops"; import { HoverPopover } from "../Shared/HoverPopover"; import { Icon } from "../Shared/Icon"; import { TagLink } from "../Shared/TagLink"; @@ -17,12 +16,16 @@ import { } from "src/models/list-filter/criteria/criterion"; import { PopoverCountButton } from "../Shared/PopoverCountButton"; import GenderIcon from "./GenderIcon"; -import { faTag } from "@fortawesome/free-solid-svg-icons"; +import { faLink, faTag } from "@fortawesome/free-solid-svg-icons"; +import { faInstagram, faTwitter } from "@fortawesome/free-brands-svg-icons"; import { RatingBanner } from "../Shared/RatingBanner"; import { usePerformerUpdate } from "src/core/StashService"; import { ILabeledId } from "src/models/list-filter/types"; import { FavoriteIcon } from "../Shared/FavoriteIcon"; import { PatchComponent } from "src/patch"; +import { ExternalLinksButton } from "../Shared/ExternalLinksButton"; +import { useConfigurationContext } from "src/hooks/Config"; +import { OCounterButton } from "../Shared/CountButton"; export interface IPerformerCardExtraCriteria { scenes?: ModifierCriterion[]; @@ -100,16 +103,7 @@ const PerformerCardPopovers: React.FC = PatchComponent( function maybeRenderOCounter() { if (!performer.o_counter) return; - return ( -
- -
- ); + return ; } function maybeRenderTagPopoverButton() { @@ -176,6 +170,8 @@ const PerformerCardPopovers: React.FC = PatchComponent( const PerformerCardOverlays: React.FC = PatchComponent( "PerformerCard.Overlays", ({ performer }) => { + const { configuration } = useConfigurationContext(); + const uiConfig = configuration?.ui; const [updatePerformer] = usePerformerUpdate(); function onToggleFavorite(v: boolean) { @@ -215,6 +211,63 @@ const PerformerCardOverlays: React.FC = PatchComponent( } } + function maybeRenderLinks() { + if (!uiConfig?.showLinksOnPerformerCard) { + return; + } + + if (performer.urls && performer.urls.length > 0) { + const twitter = performer.urls.filter((u) => + u.match(/https?:\/\/(?:www\.)?(?:twitter|x).com\//) + ); + const instagram = performer.urls.filter((u) => + u.match(/https?:\/\/(?:www\.)?instagram.com\//) + ); + const others = performer.urls.filter( + (u) => !twitter.includes(u) && !instagram.includes(u) + ); + + return ( +
+ {twitter.length > 0 && ( + + )} + {instagram.length > 0 && ( + + )} + {others.length > 0 && ( + + )} +
+ ); + } + } + return ( <> = PatchComponent( className="hide-not-favorite" /> {maybeRenderRatingBanner()} + {maybeRenderLinks()} {maybeRenderFlag()} ); diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx index 03530c52e..dd72d0025 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx @@ -16,7 +16,7 @@ import { DetailsEditNavbar } from "src/components/Shared/DetailsEditNavbar"; import { ErrorMessage } from "src/components/Shared/ErrorMessage"; import { LoadingIndicator } from "src/components/Shared/LoadingIndicator"; import { useToast } from "src/hooks/Toast"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { RatingSystem } from "src/components/Shared/Rating/RatingSystem"; import { CompressedPerformerDetailsPanel, @@ -47,6 +47,8 @@ import { HeaderImage } from "src/components/Shared/DetailsPage/HeaderImage"; import { LightboxLink } from "src/hooks/Lightbox/LightboxLink"; import { PatchComponent } from "src/patch"; import { ILightboxImage } from "src/hooks/Lightbox/types"; +import { goBackOrReplace } from "src/utils/history"; +import { OCounterButton } from "src/components/Shared/CountButton"; interface IProps { performer: GQL.PerformerDataFragment; @@ -238,7 +240,7 @@ const PerformerPage: React.FC = PatchComponent( const intl = useIntl(); // Configuration settings - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const uiConfig = configuration?.ui; const abbreviateCounter = uiConfig?.abbreviateCounters ?? false; const enableBackgroundImage = @@ -330,7 +332,7 @@ const PerformerPage: React.FC = PatchComponent( return; } - history.goBack(); + goBackOrReplace(history, "/performers"); } function toggleEditing(value?: boolean) { @@ -422,12 +424,17 @@ const PerformerPage: React.FC = PatchComponent( - setRating(value)} - clickToRate - withoutContext - /> +
+ setRating(value)} + clickToRate + withoutContext + /> + {!!performer.o_counter && ( + + )} +
{!isEditing && ( = } fullWidth={fullWidth} /> - + {performer.country ? ( = ({ const [scrapedPerformer, setScrapedPerformer] = useState(); - const { configuration: stashConfig } = React.useContext(ConfigurationContext); + const { configuration: stashConfig } = useConfigurationContext(); const intl = useIntl(); @@ -466,7 +466,6 @@ export const PerformerEditPanel: React.FC = ({ setScraper(undefined); } else { setScrapedPerformer(result); - updateStashIDs(performerResult.remote_site_id); } } diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerScrapeDialog.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerScrapeDialog.tsx index eb5f26a83..ad7e44d6d 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerScrapeDialog.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerScrapeDialog.tsx @@ -63,6 +63,7 @@ function renderScrapedGenderRow( ) { return ( renderScrapedGender(result)} @@ -113,6 +114,7 @@ function renderScrapedCircumcisedRow( return ( renderScrapedCircumcised(result)} renderNewField={() => @@ -146,6 +148,22 @@ export const PerformerScrapeDialog: React.FC = ( return; } + // #6257 - it is possible (though unsupported) to have multiple stash IDs for the same + // endpoint; in that case, we should prefer the one matching the scraped remote site ID + // if it exists + const stashIDs = (props.performer.stash_ids ?? []).filter( + (s) => s.endpoint === endpoint + ); + if (stashIDs.length > 1 && props.scraped.remote_site_id) { + const matchingID = stashIDs.find( + (s) => s.stash_id === props.scraped.remote_site_id + ); + if (matchingID) { + return matchingID.stash_id; + } + } + + // otherwise, return the first stash ID for the endpoint return props.performer.stash_ids?.find((s) => s.endpoint === endpoint) ?.stash_id; } @@ -385,16 +403,19 @@ export const PerformerScrapeDialog: React.FC = ( return ( <> setName(value)} /> setDisambiguation(value)} /> setAliases(value)} @@ -405,46 +426,55 @@ export const PerformerScrapeDialog: React.FC = ( (value) => setGender(value) )} setBirthdate(value)} /> setDeathDate(value)} /> setEthnicity(value)} /> setCountry(value)} /> setHairColor(value)} /> setEyeColor(value)} /> setWeight(value)} /> setHeight(value)} /> setPenisLength(value)} @@ -455,42 +485,50 @@ export const PerformerScrapeDialog: React.FC = ( (value) => setCircumcised(value) )} setMeasurements(value)} /> setFakeTits(value)} /> setCareerLength(value)} /> setTattoos(value)} /> setPiercings(value)} /> setURLs(value)} /> setDetails(value)} /> {scrapedTagsRow} = ( onChange={(value) => setImage(value)} /> = ({ selectable > = ({ placement = "top", target, }) => { - const { configuration: config } = React.useContext(ConfigurationContext); + const { configuration: config } = useConfigurationContext(); const showPerformerCardOnHover = config?.ui.showTagCardOnHover ?? true; diff --git a/ui/v2.5/src/components/Performers/PerformerSelect.tsx b/ui/v2.5/src/components/Performers/PerformerSelect.tsx index d31dc3ec7..f10519897 100644 --- a/ui/v2.5/src/components/Performers/PerformerSelect.tsx +++ b/ui/v2.5/src/components/Performers/PerformerSelect.tsx @@ -13,7 +13,7 @@ import { queryFindPerformersByIDForSelect, queryFindPerformersForSelect, } from "src/core/StashService"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { useIntl } from "react-intl"; import { defaultMaxOptionsShown } from "src/core/config"; import { ListFilterModel } from "src/models/list-filter/filter"; @@ -82,12 +82,12 @@ const _PerformerSelect: React.FC< > = (props) => { const [createPerformer] = usePerformerCreate(); - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const intl = useIntl(); const maxOptionsShown = configuration?.ui.maxOptionsShown ?? defaultMaxOptionsShown; const defaultCreatable = - !configuration?.interface.disableDropdownCreate.performer ?? true; + !configuration?.interface.disableDropdownCreate.performer; async function loadPerformers(input: string): Promise { const filter = new ListFilterModel(GQL.FilterMode.Performers); diff --git a/ui/v2.5/src/components/Performers/styles.scss b/ui/v2.5/src/components/Performers/styles.scss index f76816f05..1840ad960 100644 --- a/ui/v2.5/src/components/Performers/styles.scss +++ b/ui/v2.5/src/components/Performers/styles.scss @@ -35,12 +35,33 @@ .rating-number .form-control { width: inherit; } + + // The following min-width declarations prevent + // the performer's O-Count from moving around + // when hovering over rating stars + .rating-stars-precision-full .star-rating-number { + min-width: 0.75rem; + } + + .rating-stars-precision-half .star-rating-number, + .rating-stars-precision-tenth .star-rating-number { + min-width: 1.45rem; + } + + .rating-stars-precision-quarter .star-rating-number { + min-width: 2rem; + } } .alias { font-weight: bold; } + .quality-group { + display: inline-flex; + margin-top: 0.25rem; + } + // the detail element ids are the same as field type name // which don't follow the correct convention /* stylelint-disable selector-class-pattern */ @@ -86,6 +107,10 @@ .thumbnail-section { position: relative; + + .instagram { + color: pink; + } } &-image { diff --git a/ui/v2.5/src/components/SceneDuplicateChecker/SceneDuplicateChecker.tsx b/ui/v2.5/src/components/SceneDuplicateChecker/SceneDuplicateChecker.tsx index 2d8114935..d396a01f4 100644 --- a/ui/v2.5/src/components/SceneDuplicateChecker/SceneDuplicateChecker.tsx +++ b/ui/v2.5/src/components/SceneDuplicateChecker/SceneDuplicateChecker.tsx @@ -79,7 +79,24 @@ export const SceneDuplicateChecker: React.FC = () => { }, }); - const scenes = data?.findDuplicateScenes ?? []; + const getGroupTotalSize = (group: GQL.SlimSceneDataFragment[]) => { + // Sum all file sizes across all scenes in the group + return group.reduce((groupTotal, scene) => { + const sceneTotal = scene.files.reduce( + (fileTotal, file) => fileTotal + file.size, + 0 + ); + return groupTotal + sceneTotal; + }, 0); + }; + + const scenes = useMemo(() => { + const groups = data?.findDuplicateScenes ?? []; + // Sort by total file size descending (largest groups first) + return [...groups].sort((a, b) => { + return getGroupTotalSize(b) - getGroupTotalSize(a); + }); + }, [data?.findDuplicateScenes]); const { data: missingPhash } = GQL.useFindScenesQuery({ variables: { diff --git a/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx b/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx index 5749f6331..77c0d2b19 100644 --- a/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx +++ b/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx @@ -1,7 +1,6 @@ import React, { KeyboardEvent, useCallback, - useContext, useEffect, useMemo, useRef, @@ -23,6 +22,7 @@ import "./vtt-thumbnails"; import "./big-buttons"; import "./track-activity"; import "./vrmode"; +import "./media-session"; import cx from "classnames"; import { useSceneSaveActivity, @@ -31,7 +31,7 @@ import { import * as GQL from "src/core/generated-graphql"; import { ScenePlayerScrubber } from "./ScenePlayerScrubber"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { ConnectionState, InteractiveContext, @@ -120,6 +120,22 @@ function handleHotkeys(player: VideoJsPlayer, event: videojs.KeyboardEvent) { return; } + const skipButtons = player.skipButtons(); + if (skipButtons) { + // handle multimedia keys + switch (event.key) { + case "MediaTrackNext": + if (!skipButtons.onNext) return; + skipButtons.onNext(); + break; + case "MediaTrackPrevious": + if (!skipButtons.onPrevious) return; + skipButtons.onPrevious(); + break; + // MediaPlayPause handled by videojs + } + } + switch (event.which) { case 32: // space case 13: // enter @@ -224,7 +240,7 @@ export const ScenePlayer: React.FC = PatchComponent( onNext, onPrevious, }) => { - const { configuration } = useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const interfaceConfig = configuration?.interface; const uiConfig = configuration?.ui; const videoRef = useRef(null); @@ -354,7 +370,9 @@ export const ScenePlayer: React.FC = PatchComponent( }, }, plugins: { - airPlay: {}, + airPlay: { + addButtonToControlBar: uiConfig?.enableChromecast ?? false, + }, chromecast: {}, vttThumbnails: { showTimestamp: true, @@ -380,6 +398,7 @@ export const ScenePlayer: React.FC = PatchComponent( pauseBeforeLooping: false, createButtons: uiConfig?.showAbLoopControls ?? false, }, + mediaSession: {}, }, }; @@ -413,7 +432,7 @@ export const ScenePlayer: React.FC = PatchComponent( }; // empty deps - only init once // showAbLoopControls is necessary to re-init the player when the config changes - }, [uiConfig?.showAbLoopControls]); + }, [uiConfig?.showAbLoopControls, uiConfig?.enableChromecast]); useEffect(() => { const player = getPlayer(); @@ -857,6 +876,23 @@ export const ScenePlayer: React.FC = PatchComponent( return () => player.off("ended"); }, [getPlayer, onComplete]); + // set up mediaSession plugin + useEffect(() => { + const player = getPlayer(); + if (!player) return; + + // set up mediasession plugin + // get performer names as array + const performers = scene?.performers.map((p) => p.name).join(", "); + player + .mediaSession() + .setMetadata( + scene?.title ?? "Stash", + scene?.studio?.name ?? performers ?? "Stash", + scene.paths.screenshot || "" + ); + }, [getPlayer, scene]); + function onScrubberScroll() { if (started.current) { getPlayer()?.pause(); diff --git a/ui/v2.5/src/components/ScenePlayer/markers.ts b/ui/v2.5/src/components/ScenePlayer/markers.ts index 83a695c1b..6215f7f47 100644 --- a/ui/v2.5/src/components/ScenePlayer/markers.ts +++ b/ui/v2.5/src/components/ScenePlayer/markers.ts @@ -5,6 +5,7 @@ export interface IMarker { title: string; seconds: number; end_seconds?: number | null; + primaryTag: { name: string }; } interface IMarkersOptions { @@ -85,8 +86,13 @@ class MarkersPlugin extends videojs.getPlugin("plugin") { markerSet.dot.toggleAttribute("marker-tooltip-shown", true); // Set background color based on tag (if available) - if (marker.title && this.tagColors[marker.title]) { - markerSet.dot.style.backgroundColor = this.tagColors[marker.title]; + if ( + marker.primaryTag && + marker.primaryTag.name && + this.tagColors[marker.primaryTag.name] + ) { + markerSet.dot.style.backgroundColor = + this.tagColors[marker.primaryTag.name]; } markerSet.dot.addEventListener("mouseenter", () => { this.showMarkerTooltip(marker.title); @@ -152,8 +158,12 @@ class MarkersPlugin extends videojs.getPlugin("plugin") { rangeDiv.style.display = "none"; // Initially hidden // Set background color based on tag (if available) - if (marker.title && this.tagColors[marker.title]) { - rangeDiv.style.backgroundColor = this.tagColors[marker.title]; + if ( + marker.primaryTag && + marker.primaryTag.name && + this.tagColors[marker.primaryTag.name] + ) { + rangeDiv.style.backgroundColor = this.tagColors[marker.primaryTag.name]; } markerSet.range = rangeDiv; diff --git a/ui/v2.5/src/components/ScenePlayer/media-session.ts b/ui/v2.5/src/components/ScenePlayer/media-session.ts new file mode 100644 index 000000000..b3ce2d0ea --- /dev/null +++ b/ui/v2.5/src/components/ScenePlayer/media-session.ts @@ -0,0 +1,71 @@ +import videojs, { VideoJsPlayer } from "video.js"; + +class MediaSessionPlugin extends videojs.getPlugin("plugin") { + constructor(player: VideoJsPlayer) { + super(player); + + player.ready(() => { + player.addClass("vjs-media-session"); + this.setActionHandlers(); + }); + + player.on("play", () => { + this.updatePlaybackState(); + }); + + player.on("pause", () => { + this.updatePlaybackState(); + }); + this.updatePlaybackState(); + } + + // manually set poster since it's only set on useEffect + public setMetadata(title: string, artist: string, poster: string): void { + if ("mediaSession" in navigator) { + navigator.mediaSession.metadata = new MediaMetadata({ + title, + artist, + artwork: [ + { + src: poster || this.player.poster() || "", + type: "image/jpeg", + }, + ], + }); + } + } + + private updatePlaybackState(): void { + if ("mediaSession" in navigator) { + const playbackState = this.player.paused() ? "paused" : "playing"; + navigator.mediaSession.playbackState = playbackState; + } + } + + private setActionHandlers(): void { + // method initialization + navigator.mediaSession.setActionHandler("play", () => { + this.player.play(); + }); + navigator.mediaSession.setActionHandler("pause", () => { + this.player.pause(); + }); + navigator.mediaSession.setActionHandler("nexttrack", () => { + this.player.skipButtons()?.handleForward(); + }); + navigator.mediaSession.setActionHandler("previoustrack", () => { + this.player.skipButtons()?.handleBackward(); + }); + } +} + +videojs.registerPlugin("mediaSession", MediaSessionPlugin); + +/* eslint-disable @typescript-eslint/naming-convention */ +declare module "video.js" { + interface VideoJsPlayer { + mediaSession: () => MediaSessionPlugin; + } +} + +export default MediaSessionPlugin; diff --git a/ui/v2.5/src/components/ScenePlayer/util.ts b/ui/v2.5/src/components/ScenePlayer/util.ts index a63ab6a2e..8c6fb8010 100644 --- a/ui/v2.5/src/components/ScenePlayer/util.ts +++ b/ui/v2.5/src/components/ScenePlayer/util.ts @@ -2,5 +2,6 @@ import videojs from "video.js"; export const VIDEO_PLAYER_ID = "VideoJsPlayer"; -export const getPlayerPosition = () => - videojs.getPlayer(VIDEO_PLAYER_ID)?.currentTime(); +export const getPlayer = () => videojs.getPlayer(VIDEO_PLAYER_ID); + +export const getPlayerPosition = () => getPlayer()?.currentTime(); diff --git a/ui/v2.5/src/components/Scenes/DeleteScenesDialog.tsx b/ui/v2.5/src/components/Scenes/DeleteScenesDialog.tsx index 88f133a80..56cbd69b0 100644 --- a/ui/v2.5/src/components/Scenes/DeleteScenesDialog.tsx +++ b/ui/v2.5/src/components/Scenes/DeleteScenesDialog.tsx @@ -4,7 +4,7 @@ import { useScenesDestroy } from "src/core/StashService"; import * as GQL from "src/core/generated-graphql"; import { ModalComponent } from "src/components/Shared/Modal"; import { useToast } from "src/hooks/Toast"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { FormattedMessage, useIntl } from "react-intl"; import { faTrashAlt } from "@fortawesome/free-solid-svg-icons"; import { objectPath } from "src/core/files"; @@ -34,7 +34,7 @@ export const DeleteScenesDialog: React.FC = ( { count: props.selected.length, singularEntity, pluralEntity } ); - const { configuration: config } = React.useContext(ConfigurationContext); + const { configuration: config } = useConfigurationContext(); const [deleteFile, setDeleteFile] = useState( config?.defaults.deleteFile ?? false @@ -94,6 +94,11 @@ export const DeleteScenesDialog: React.FC = ( } }); + const deleteTrashPath = config?.general.deleteTrashPath; + const deleteAlertId = deleteTrashPath + ? "dialogs.delete_alert_to_trash" + : "dialogs.delete_alert"; + return (

@@ -103,7 +108,7 @@ export const DeleteScenesDialog: React.FC = ( singularEntity: intl.formatMessage({ id: "file" }), pluralEntity: intl.formatMessage({ id: "files" }), }} - id="dialogs.delete_alert" + id={deleteAlertId} />

    diff --git a/ui/v2.5/src/components/Scenes/EditSceneMarkersDialog.tsx b/ui/v2.5/src/components/Scenes/EditSceneMarkersDialog.tsx new file mode 100644 index 000000000..bb1d8067b --- /dev/null +++ b/ui/v2.5/src/components/Scenes/EditSceneMarkersDialog.tsx @@ -0,0 +1,200 @@ +import React, { useEffect, useMemo, useState } from "react"; +import { Form } from "react-bootstrap"; +import { FormattedMessage, useIntl } from "react-intl"; +import { useBulkSceneMarkerUpdate } from "src/core/StashService"; +import * as GQL from "src/core/generated-graphql"; +import { ModalComponent } from "../Shared/Modal"; +import { useToast } from "src/hooks/Toast"; +import { MultiSet } from "../Shared/MultiSet"; +import { + getAggregateState, + getAggregateStateObject, +} from "src/utils/bulkUpdate"; +import { BulkUpdateTextInput } from "../Shared/BulkUpdateTextInput"; +import { faPencilAlt } from "@fortawesome/free-solid-svg-icons"; +import { TagSelect } from "../Shared/Select"; + +interface IListOperationProps { + selected: GQL.SceneMarkerDataFragment[]; + onClose: (applied: boolean) => void; +} + +const scenemarkerFields = ["title"]; + +export const EditSceneMarkersDialog: React.FC = ( + props: IListOperationProps +) => { + const intl = useIntl(); + const Toast = useToast(); + + const [updateInput, setUpdateInput] = + useState({ + ids: props.selected.map((scenemarker) => { + return scenemarker.id; + }), + }); + + const [tagIds, setTagIds] = useState({ + mode: GQL.BulkUpdateIdMode.Add, + }); + + const [updateSceneMarkers] = useBulkSceneMarkerUpdate(); + + // Network state + const [isUpdating, setIsUpdating] = useState(false); + + const aggregateState = useMemo(() => { + const updateState: Partial = {}; + const state = props.selected; + let updateTagIds: string[] = []; + let first = true; + + state.forEach((scenemarker: GQL.SceneMarkerDataFragment) => { + getAggregateStateObject( + updateState, + scenemarker, + scenemarkerFields, + first + ); + + // sceneMarker data fragment doesn't have primary_tag_id, so handle separately + updateState.primary_tag_id = getAggregateState( + updateState.primary_tag_id, + scenemarker.primary_tag.id, + first + ); + + const thisTagIDs = (scenemarker.tags ?? []).map((p) => p.id).sort(); + + updateTagIds = getAggregateState(updateTagIds, thisTagIDs, first) ?? []; + + first = false; + }); + + return { state: updateState, tagIds: updateTagIds }; + }, [props.selected]); + + // update initial state from aggregate + useEffect(() => { + setUpdateInput((current) => ({ ...current, ...aggregateState.state })); + }, [aggregateState]); + + function setUpdateField(input: Partial) { + setUpdateInput((current) => ({ ...current, ...input })); + } + + function getSceneMarkerInput(): GQL.BulkSceneMarkerUpdateInput { + const sceneMarkerInput: GQL.BulkSceneMarkerUpdateInput = { + ...updateInput, + tag_ids: tagIds, + }; + + return sceneMarkerInput; + } + + async function onSave() { + setIsUpdating(true); + try { + await updateSceneMarkers({ + variables: { + input: getSceneMarkerInput(), + }, + }); + Toast.success( + intl.formatMessage( + { id: "toast.updated_entity" }, + { + entity: intl.formatMessage({ id: "markers" }).toLocaleLowerCase(), + } + ) + ); + props.onClose(true); + } catch (e) { + Toast.error(e); + } + setIsUpdating(false); + } + + function renderTextField( + name: string, + value: string | undefined | null, + setter: (newValue: string | undefined) => void, + area: boolean = false + ) { + return ( + + + + + setter(newValue)} + unsetDisabled={props.selected.length < 2} + as={area ? "textarea" : undefined} + /> + + ); + } + + function render() { + return ( + props.onClose(false), + text: intl.formatMessage({ id: "actions.cancel" }), + variant: "secondary", + }} + isRunning={isUpdating} + > +
    + {renderTextField("title", updateInput.title, (newValue) => + setUpdateField({ title: newValue }) + )} + + + + + + setUpdateField({ primary_tag_id: t[0]?.id })} + ids={ + updateInput.primary_tag_id ? [updateInput.primary_tag_id] : [] + } + /> + + + + + + + setTagIds((v) => ({ ...v, ids: itemIDs }))} + onSetMode={(newMode) => + setTagIds((v) => ({ ...v, mode: newMode })) + } + existingIds={aggregateState.tagIds ?? []} + ids={tagIds.ids ?? []} + mode={tagIds.mode} + menuPortalTarget={document.body} + /> + +
    +
    + ); + } + + return render(); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneCard.tsx b/ui/v2.5/src/components/Scenes/SceneCard.tsx index 99b910f67..2cb4a9af3 100644 --- a/ui/v2.5/src/components/Scenes/SceneCard.tsx +++ b/ui/v2.5/src/components/Scenes/SceneCard.tsx @@ -6,12 +6,11 @@ import * as GQL from "src/core/generated-graphql"; import { Icon } from "../Shared/Icon"; import { GalleryLink, TagLink, SceneMarkerLink } from "../Shared/TagLink"; import { HoverPopover } from "../Shared/HoverPopover"; -import { SweatDrops } from "../Shared/SweatDrops"; import { TruncatedText } from "../Shared/TruncatedText"; import NavUtils from "src/utils/navigation"; import TextUtils from "src/utils/text"; import { SceneQueue } from "src/models/sceneQueue"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { PerformerPopoverButton } from "../Shared/PerformerPopoverButton"; import { GridCard } from "../Shared/GridCard/GridCard"; import { RatingBanner } from "../Shared/RatingBanner"; @@ -30,6 +29,7 @@ import { PatchComponent } from "src/patch"; import { StudioOverlay } from "../Shared/GridCard/StudioOverlay"; import { GroupTag } from "../Groups/GroupTag"; import { FileSize } from "../Shared/FileSize"; +import { OCounterButton } from "../Shared/CountButton"; interface IScenePreviewProps { isPortrait: boolean; @@ -218,16 +218,7 @@ const SceneCardPopovers = PatchComponent( function maybeRenderOCounter() { if (props.scene.o_counter) { - return ( -
    - -
    - ); + return ; } } @@ -353,7 +344,7 @@ const SceneCardImage = PatchComponent( "SceneCard.Image", (props: ISceneCardProps) => { const history = useHistory(); - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const cont = configuration?.interface.continuePlaylistDefault ?? false; const file = useMemo( @@ -437,7 +428,7 @@ const SceneCardImage = PatchComponent( export const SceneCard = PatchComponent( "SceneCard", (props: ISceneCardProps) => { - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const file = useMemo( () => (props.scene.files.length > 0 ? props.scene.files[0] : undefined), diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/ExternalPlayerButton.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/ExternalPlayerButton.tsx index b17dfb6bb..3701f4138 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/ExternalPlayerButton.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/ExternalPlayerButton.tsx @@ -29,7 +29,7 @@ export const ExternalPlayerButton: React.FC = ({ const streamURL = new URL(stream); if (isAndroid) { const scheme = streamURL.protocol.slice(0, -1); - streamURL.hash = `Intent;action=android.intent.action.VIEW;scheme=${scheme};type=video/mp4;S.title=${encodeURI( + streamURL.hash = `Intent;action=android.intent.action.VIEW;scheme=${scheme};type=video/mp4;S.title=${encodeURIComponent( title )};end`; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/OCounterButton.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/OCounterButton.tsx index 8fdb7dfd7..d8963df4d 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/OCounterButton.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/OCounterButton.tsx @@ -1,10 +1,11 @@ -import { faBan, faMinus } from "@fortawesome/free-solid-svg-icons"; +import { faBan, faMinus, faThumbsUp } from "@fortawesome/free-solid-svg-icons"; import React, { useState } from "react"; import { Button, ButtonGroup, Dropdown, DropdownButton } from "react-bootstrap"; import { useIntl } from "react-intl"; import { Icon } from "src/components/Shared/Icon"; import { LoadingIndicator } from "src/components/Shared/LoadingIndicator"; import { SweatDrops } from "src/components/Shared/SweatDrops"; +import { useConfigurationContext } from "src/hooks/Config"; export interface IOCounterButtonProps { value: number; @@ -17,6 +18,12 @@ export const OCounterButton: React.FC = ( props: IOCounterButtonProps ) => { const intl = useIntl(); + const { configuration } = useConfigurationContext(); + const { sfwContentMode } = configuration.interface; + + const icon = !sfwContentMode ? : ; + const messageID = !sfwContentMode ? "o_count" : "o_count_sfw"; + const [loading, setLoading] = useState(false); async function increment() { @@ -44,9 +51,9 @@ export const OCounterButton: React.FC = ( className="minimal pr-1" onClick={increment} variant="secondary" - title={intl.formatMessage({ id: "o_counter" })} + title={intl.formatMessage({ id: messageID })} > - + {icon} {props.value} ); diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx index c4088654a..aee6ab344 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx @@ -3,7 +3,6 @@ import React, { useEffect, useState, useMemo, - useContext, useRef, useLayoutEffect, } from "react"; @@ -32,7 +31,7 @@ import SceneQueue, { QueuedScene } from "src/models/sceneQueue"; import { ListFilterModel } from "src/models/list-filter/filter"; import Mousetrap from "mousetrap"; import { OrganizedButton } from "./OrganizedButton"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { getPlayerPosition } from "src/components/ScenePlayer/util"; import { faEllipsisV, @@ -51,6 +50,7 @@ import { lazyComponent } from "src/utils/lazyComponent"; import cx from "classnames"; import { TruncatedText } from "src/components/Shared/TruncatedText"; import { PatchComponent, PatchContainerComponent } from "src/patch"; +import { goBackOrReplace } from "src/utils/history"; const SubmitStashBoxDraft = lazyComponent( () => import("src/components/Dialogs/SubmitDraft") @@ -183,7 +183,7 @@ const ScenePage: React.FC = PatchComponent("ScenePage", (props) => { const intl = useIntl(); const [updateScene] = useSceneUpdate(); const [generateScreenshot] = useSceneGenerateScreenshot(); - const { configuration } = useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const [showDraftModal, setShowDraftModal] = useState(false); const boxes = configuration?.general?.stashBoxes ?? []; @@ -247,6 +247,12 @@ const ScenePage: React.FC = PatchComponent("ScenePage", (props) => { Mousetrap.bind("p p", () => onQueuePrevious()); Mousetrap.bind("p r", () => onQueueRandom()); Mousetrap.bind(",", () => setCollapsed(!collapsed)); + Mousetrap.bind("c c", () => { + onGenerateScreenshot(getPlayerPosition()); + }); + Mousetrap.bind("c d", () => { + onGenerateScreenshot(); + }); return () => { Mousetrap.unbind("a"); @@ -260,6 +266,8 @@ const ScenePage: React.FC = PatchComponent("ScenePage", (props) => { Mousetrap.unbind("p p"); Mousetrap.unbind("p r"); Mousetrap.unbind(","); + Mousetrap.unbind("c c"); + Mousetrap.unbind("c d"); }; }); @@ -680,7 +688,7 @@ const SceneLoader: React.FC> = ({ match, }) => { const { id } = match.params; - const { configuration } = useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const { data, loading, error } = useFindScene(id); const [scene, setScene] = useState(); @@ -909,7 +917,7 @@ const SceneLoader: React.FC> = ({ ) { loadScene(queueScenes[currentQueueIndex + 1].id); } else { - history.goBack(); + goBackOrReplace(history, "/scenes"); } } diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx index 69b378787..e56ea265b 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx @@ -19,7 +19,7 @@ import ImageUtils from "src/utils/image"; import { getStashIDs } from "src/utils/stashIds"; import { useFormik } from "formik"; import { Prompt } from "react-router-dom"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { IGroupEntry, SceneGroupTable } from "./SceneGroupTable"; import { faSearch } from "@fortawesome/free-solid-svg-icons"; import { objectTitle } from "src/core/files"; @@ -103,7 +103,7 @@ export const SceneEditPanel: React.FC = ({ setStudio(scene.studio ?? null); }, [scene.studio]); - const { configuration: stashConfig } = React.useContext(ConfigurationContext); + const { configuration: stashConfig } = useConfigurationContext(); // Network state const [isLoading, setIsLoading] = useState(false); diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneHistoryPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneHistoryPanel.tsx index 1ac9dd5a2..2ba587a2b 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneHistoryPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneHistoryPanel.tsx @@ -21,6 +21,7 @@ import { useSceneResetActivity, } from "src/core/StashService"; import * as GQL from "src/core/generated-graphql"; +import { useConfigurationContext } from "src/hooks/Config"; import { useToast } from "src/hooks/Toast"; import { TextField } from "src/utils/field"; import TextUtils from "src/utils/text"; @@ -172,6 +173,9 @@ export const SceneHistoryPanel: React.FC = ({ scene }) => { const intl = useIntl(); const Toast = useToast(); + const { configuration } = useConfigurationContext(); + const { sfwContentMode } = configuration.interface; + const [dialogs, setDialogs] = React.useState({ playHistory: false, oHistory: false, @@ -299,6 +303,9 @@ export const SceneHistoryPanel: React.FC = ({ scene }) => { } function maybeRenderDialogs() { + const clearHistoryMessageID = sfwContentMode + ? "dialogs.clear_o_history_confirm_sfw" + : "dialogs.clear_play_history_confirm"; return ( <> = ({ scene }) => { /> handleClearODates()} onCancel={() => setDialogPartial({ oHistory: false })} @@ -351,6 +358,11 @@ export const SceneHistoryPanel: React.FC = ({ scene }) => { ) as string[]; const oHistory = (scene.o_history ?? []).filter((h) => h != null) as string[]; + const oHistoryMessageID = sfwContentMode ? "o_history_sfw" : "o_history"; + const noneMessageID = sfwContentMode + ? "odate_recorded_no_sfw" + : "odate_recorded_no"; + return (
    {maybeRenderDialogs()} @@ -401,7 +413,7 @@ export const SceneHistoryPanel: React.FC = ({ scene }) => {
    - + @@ -427,7 +439,7 @@ export const SceneHistoryPanel: React.FC = ({ scene }) => {
    handleDeleteODate(t)} /> diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneScrapeDialog.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneScrapeDialog.tsx index d6acfabfb..7be291bd2 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneScrapeDialog.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneScrapeDialog.tsx @@ -133,7 +133,8 @@ export const SceneScrapeDialog: React.FC = ({ const { tags, newTags, scrapedTagsRow } = useScrapedTags( sceneTags, - scraped.tags + scraped.tags, + endpoint ); const [details, setDetails] = useState>( @@ -148,6 +149,7 @@ export const SceneScrapeDialog: React.FC = ({ scrapeResult: studio, setScrapeResult: setStudio, setNewObject: setNewStudio, + endpoint, }); const createNewPerformer = useCreateScrapedPerformer({ @@ -155,6 +157,7 @@ export const SceneScrapeDialog: React.FC = ({ setScrapeResult: setPerformers, newObjects: newPerformers, setNewObjects: setNewPerformers, + endpoint, }); const createNewGroup = useCreateScrapedGroup({ @@ -162,6 +165,7 @@ export const SceneScrapeDialog: React.FC = ({ setScrapeResult: setGroups, newObjects: newGroups, setNewObjects: setNewGroups, + endpoint, }); const intl = useIntl(); @@ -214,32 +218,38 @@ export const SceneScrapeDialog: React.FC = ({ return ( <> setTitle(value)} /> setCode(value)} /> setURLs(value)} /> setDate(value)} /> setDirector(value)} /> setStudio(value)} @@ -247,6 +257,7 @@ export const SceneScrapeDialog: React.FC = ({ onCreateNew={createNewStudio} /> setPerformers(value)} @@ -255,6 +266,7 @@ export const SceneScrapeDialog: React.FC = ({ ageFromDate={date.useNewValue ? date.newValue : date.originalValue} /> setGroups(value)} @@ -263,17 +275,20 @@ export const SceneScrapeDialog: React.FC = ({ /> {scrapedTagsRow} setDetails(value)} /> setStashID(value)} /> { - history.push(queue.makeLink(sceneID, options)); + (queue: SceneQueue, sceneID: string, options?: IPlaySceneOptions) => { + history.push( + queue.makeLink(sceneID, { autoPlay, continue: cont, ...options }) + ); }, - [history] + [history, cont, autoPlay] ); return playScene; } function usePlaySelected(selectedIds: Set) { - const { configuration: config } = useContext(ConfigurationContext); const playScene = usePlayScene(); const playSelected = useCallback(() => { // populate queue and go to first scene const sceneIDs = Array.from(selectedIds.values()); const queue = SceneQueue.fromSceneIDList(sceneIDs); - const autoPlay = config?.interface.autostartVideoOnPlaySelected ?? false; - playScene(queue, sceneIDs[0], { autoPlay }); - }, [selectedIds, config?.interface.autostartVideoOnPlaySelected, playScene]); + + playScene(queue, sceneIDs[0]); + }, [selectedIds, playScene]); return playSelected; } +function usePlayFirst() { + const playScene = usePlayScene(); + + const playFirst = useCallback( + (queue: SceneQueue, sceneID: string, index: number) => { + // populate queue and go to first scene + playScene(queue, sceneID, { sceneIndex: index }); + }, + [playScene] + ); + + return playFirst; +} + function usePlayRandom(filter: ListFilterModel, count: number) { - const { configuration: config } = useContext(ConfigurationContext); const playScene = usePlayScene(); const playRandom = useCallback(async () => { @@ -130,15 +177,9 @@ function usePlayRandom(filter: ListFilterModel, count: number) { if (scene) { // navigate to the image player page const queue = SceneQueue.fromListFilterModel(filterCopy); - const autoPlay = config?.interface.autostartVideoOnPlaySelected ?? false; - playScene(queue, scene.id, { sceneIndex: index, autoPlay }); + playScene(queue, scene.id, { sceneIndex: index }); } - }, [ - filter, - count, - config?.interface.autostartVideoOnPlaySelected, - playScene, - ]); + }, [filter, count, playScene]); return playRandom; } @@ -166,7 +207,7 @@ const SceneList: React.FC<{ }> = ({ scenes, filter, selectedIds, onSelectChange, fromGroupId }) => { const queue = useMemo(() => SceneQueue.fromListFilterModel(filter), [filter]); - if (scenes.length === 0) { + if (scenes.length === 0 && filter.displayMode !== DisplayMode.Tagger) { return null; } @@ -193,7 +234,13 @@ const SceneList: React.FC<{ ); } if (filter.displayMode === DisplayMode.Wall) { - return ; + return ( + + ); } if (filter.displayMode === DisplayMode.Tagger) { return ; @@ -209,36 +256,60 @@ const ScenesFilterSidebarSections = PatchContainerComponent( const SidebarContent: React.FC<{ filter: ListFilterModel; setFilter: (filter: ListFilterModel) => void; + filterHook?: (filter: ListFilterModel) => ListFilterModel; view?: View; sidebarOpen: boolean; onClose?: () => void; showEditFilter: (editingCriterion?: string) => void; -}> = ({ filter, setFilter, view, showEditFilter, sidebarOpen, onClose }) => { + count?: number; + focus?: ReturnType; +}> = ({ + filter, + setFilter, + filterHook, + view, + showEditFilter, + sidebarOpen, + onClose, + count, + focus, +}) => { + const showResultsId = + count !== undefined ? "actions.show_count_results" : "actions.show_results"; + + const hideStudios = view === View.StudioScenes; + return ( <> - } - data-type={StudiosCriterionOption.type} - option={StudiosCriterionOption} - filter={filter} - setFilter={setFilter} - /> + {!hideStudios && ( + } + data-type={StudiosCriterionOption.type} + option={StudiosCriterionOption} + filter={filter} + setFilter={setFilter} + filterHook={filterHook} + sectionID="studios" + /> + )} } data-type={PerformersCriterionOption.type} option={PerformersCriterionOption} filter={filter} setFilter={setFilter} + filterHook={filterHook} + sectionID="performers" /> } @@ -246,6 +317,8 @@ const SidebarContent: React.FC<{ option={TagsCriterionOption} filter={filter} setFilter={setFilter} + filterHook={filterHook} + sectionID="tags" /> } @@ -253,6 +326,22 @@ const SidebarContent: React.FC<{ option={RatingCriterionOption} filter={filter} setFilter={setFilter} + sectionID="rating" + /> + } + option={DurationCriterionOption} + filter={filter} + setFilter={setFilter} + sectionID="duration" + /> + } + data-type={HasMarkersCriterionOption.type} + option={HasMarkersCriterionOption} + filter={filter} + setFilter={setFilter} + sectionID="hasMarkers" /> } @@ -260,12 +349,118 @@ const SidebarContent: React.FC<{ option={OrganizedCriterionOption} filter={filter} setFilter={setFilter} + sectionID="organized" + /> + } + option={PerformerAgeCriterionOption} + filter={filter} + setFilter={setFilter} + sectionID="performer_age" /> + +
    + +
    ); }; +interface IOperations { + text: string; + onClick: () => void; + isDisplayed?: () => boolean; + className?: string; +} + +const SceneListOperations: React.FC<{ + items: number; + hasSelection: boolean; + operations: IOperations[]; + onEdit: () => void; + onDelete: () => void; + onPlay: () => void; + onCreateNew: () => void; +}> = ({ + items, + hasSelection, + operations, + onEdit, + onDelete, + onPlay, + onCreateNew, +}) => { + const intl = useIntl(); + + return ( +
    + + {!!items && ( + + )} + {!hasSelection && ( + + )} + + {hasSelection && ( + <> + + + + )} + + + {operations.map((o) => { + if (o.isDisplayed && !o.isDisplayed()) { + return null; + } + + return ( + + ); + })} + + +
    + ); +}; + interface IFilteredScenes { filterHook?: (filter: ListFilterModel) => ListFilterModel; defaultSort?: string; @@ -278,6 +473,9 @@ export const FilteredSceneList = (props: IFilteredScenes) => { const intl = useIntl(); const history = useHistory(); + const searchFocus = useFocus(); + const [, setSearchFocus] = searchFocus; + const { filterHook, defaultSort, view, alterQuery, fromGroupId } = props; // States @@ -285,6 +483,8 @@ export const FilteredSceneList = (props: IFilteredScenes) => { showSidebar, setShowSidebar, loading: sidebarStateLoading, + sectionOpen, + setSectionOpen, } = useSidebarState(view); const { filterState, queryResult, modalState, listSelect, showEditFilter } = @@ -303,7 +503,7 @@ export const FilteredSceneList = (props: IFilteredScenes) => { }, }); - const { filter, setFilter, loading: filterLoading } = filterState; + const { filter, setFilter } = filterState; const { effectiveFilter, result, cachedResult, items, totalCount } = queryResult; @@ -312,6 +512,7 @@ export const FilteredSceneList = (props: IFilteredScenes) => { selectedIds, selectedItems, onSelectChange, + onSelectAll, onSelectNone, hasSelection, } = listSelect; @@ -330,6 +531,29 @@ export const FilteredSceneList = (props: IFilteredScenes) => { setShowSidebar, }); + useEffect(() => { + Mousetrap.bind("e", () => { + if (hasSelection) { + onEdit?.(); + } + }); + + Mousetrap.bind("d d", () => { + if (hasSelection) { + onDelete?.(); + } + }); + + return () => { + Mousetrap.unbind("e"); + Mousetrap.unbind("d d"); + }; + }); + useZoomKeybinds({ + zoomIndex: filter.zoomIndex, + onChangeZoom: (zoom) => setFilter(filter.setZoom(zoom)), + }); + const onCloseEditDelete = useCloseEditDelete({ closeModal, onSelectNone, @@ -337,13 +561,36 @@ export const FilteredSceneList = (props: IFilteredScenes) => { }); const metadataByline = useMemo(() => { - if (cachedResult.loading) return ""; + if (cachedResult.loading) return null; - return renderMetadataByline(cachedResult) ?? ""; + return renderMetadataByline(cachedResult) ?? null; }, [cachedResult]); + const queue = useMemo(() => SceneQueue.fromListFilterModel(filter), [filter]); + + const playRandom = usePlayRandom(effectiveFilter, totalCount); const playSelected = usePlaySelected(selectedIds); - const playRandom = usePlayRandom(filter, totalCount); + const playFirst = usePlayFirst(); + + function onCreateNew() { + history.push("/scenes/new"); + } + + function onPlay() { + if (items.length === 0) { + return; + } + + // if there are selected items, play those + if (hasSelection) { + playSelected(); + return; + } + + // otherwise, play the first item in the list + const sceneID = items[0].id; + playFirst(queue, sceneID, 0); + } function onExport(all: boolean) { showModal( @@ -381,16 +628,51 @@ export const FilteredSceneList = (props: IFilteredScenes) => { ); } - const otherOperations: IListFilterOperation[] = [ + function onEdit() { + showModal( + + ); + } + + function onDelete() { + showModal( + + ); + } + + const otherOperations = [ { - text: intl.formatMessage({ id: "actions.play_selected" }), - onClick: playSelected, + text: intl.formatMessage({ id: "actions.play" }), + onClick: () => onPlay(), + isDisplayed: () => items.length > 0, + className: "play-item", + }, + { + text: intl.formatMessage( + { id: "actions.create_entity" }, + { entityType: intl.formatMessage({ id: "scene" }) } + ), + onClick: () => onCreateNew(), + isDisplayed: () => !hasSelection, + className: "create-new-item", + }, + { + text: intl.formatMessage({ id: "actions.select_all" }), + onClick: () => onSelectAll(), + isDisplayed: () => totalCount > 0, + }, + { + text: intl.formatMessage({ id: "actions.select_none" }), + onClick: () => onSelectNone(), isDisplayed: () => hasSelection, - icon: faPlay, }, { text: intl.formatMessage({ id: "actions.play_random" }), onClick: playRandom, + isDisplayed: () => totalCount > 1, }, { text: `${intl.formatMessage({ id: "actions.generate" })}…`, @@ -432,7 +714,19 @@ export const FilteredSceneList = (props: IFilteredScenes) => { ]; // render - if (filterLoading || sidebarStateLoading) return null; + if (sidebarStateLoading) return null; + + const operations = ( + + ); return ( @@ -443,84 +737,90 @@ export const FilteredSceneList = (props: IFilteredScenes) => { > {modal} - - setShowSidebar(false)}> - setShowSidebar(false)} - /> - -
    - - showModal( - - ) - } - onDelete={() => { - showModal( - - ); - }} - operations={otherOperations} - onToggleSidebar={() => setShowSidebar((v) => !v)} - zoomable - /> - - showEditFilter(c.criterionOption.type)} - onRemoveCriterion={removeCriterion} - onRemoveAll={() => clearAllCriteria()} - /> - - - - - + + setShowSidebar(false)}> + setShowSidebar(false)} + count={cachedResult.loading ? undefined : totalCount} + focus={searchFocus} + /> + + + setShowSidebar(!showSidebar)} + onEditCriterion={(c) => + showEditFilter(c?.criterionOption.type) + } + onRemoveCriterion={removeCriterion} + onRemoveAllCriterion={() => clearAllCriteria(true)} + onEditSearchTerm={() => { + setShowSidebar(true); + setSearchFocus(true); + }} + onRemoveSearchTerm={() => + setFilter(filter.clearSearchTerm()) + } + view={view} + /> + } + selectionSection={ + setShowSidebar(!showSidebar)} + onSelectAll={() => onSelectAll()} + onSelectNone={() => onSelectNone()} + operations={operations} + /> + } + operationSection={operations} /> - - {totalCount > filter.itemsPerPage && ( -
    - setFilter(newFilter)} + /> + + + -
    - )} -
    -
    + + + {totalCount > filter.itemsPerPage && ( +
    + +
    + )} + + +
    ); diff --git a/ui/v2.5/src/components/Scenes/SceneMarkerCard.tsx b/ui/v2.5/src/components/Scenes/SceneMarkerCard.tsx index 644decf42..e76beda0a 100644 --- a/ui/v2.5/src/components/Scenes/SceneMarkerCard.tsx +++ b/ui/v2.5/src/components/Scenes/SceneMarkerCard.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from "react"; +import { useMemo } from "react"; import { Button, ButtonGroup } from "react-bootstrap"; import * as GQL from "src/core/generated-graphql"; import { Icon } from "../Shared/Icon"; @@ -6,7 +6,7 @@ import { TagLink } from "../Shared/TagLink"; import { HoverPopover } from "../Shared/HoverPopover"; import NavUtils from "src/utils/navigation"; import TextUtils from "src/utils/text"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { GridCard } from "../Shared/GridCard/GridCard"; import { faTag } from "@fortawesome/free-solid-svg-icons"; import { markerTitle } from "src/core/markers"; @@ -109,7 +109,7 @@ const SceneMarkerCardDetails = (props: ISceneMarkerCardProps) => { }; const SceneMarkerCardImage = (props: ISceneMarkerCardProps) => { - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const file = useMemo( () => diff --git a/ui/v2.5/src/components/Scenes/SceneMarkerList.tsx b/ui/v2.5/src/components/Scenes/SceneMarkerList.tsx index f28ac718b..3ae595b7c 100644 --- a/ui/v2.5/src/components/Scenes/SceneMarkerList.tsx +++ b/ui/v2.5/src/components/Scenes/SceneMarkerList.tsx @@ -16,6 +16,7 @@ import { MarkerWallPanel } from "./SceneMarkerWallPanel"; import { View } from "../List/views"; import { SceneMarkerCardsGrid } from "./SceneMarkerCardsGrid"; import { DeleteSceneMarkersDialog } from "./DeleteSceneMarkersDialog"; +import { EditSceneMarkersDialog } from "./EditSceneMarkersDialog"; function getItems(result: GQL.FindSceneMarkersQueryResult) { return result?.data?.findSceneMarkers?.scene_markers ?? []; @@ -95,7 +96,10 @@ export const SceneMarkerList: React.FC = ({ if (filter.displayMode === DisplayMode.Wall) { return ( - + ); } @@ -111,6 +115,15 @@ export const SceneMarkerList: React.FC = ({ } } + function renderEditDialog( + selectedMarkers: GQL.SceneMarkerDataFragment[], + onClose: (applied: boolean) => void + ) { + return ( + + ); + } + function renderDeleteDialog( selectedSceneMarkers: GQL.SceneMarkerDataFragment[], onClose: (confirmed: boolean) => void @@ -135,11 +148,11 @@ export const SceneMarkerList: React.FC = ({ selectable > diff --git a/ui/v2.5/src/components/Scenes/SceneMarkerRecommendationRow.tsx b/ui/v2.5/src/components/Scenes/SceneMarkerRecommendationRow.tsx new file mode 100644 index 000000000..7559d609a --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneMarkerRecommendationRow.tsx @@ -0,0 +1,59 @@ +import React from "react"; +import { Link } from "react-router-dom"; +import { useFindSceneMarkers } from "src/core/StashService"; +import Slider from "@ant-design/react-slick"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { getSlickSliderSettings } from "src/core/recommendations"; +import { RecommendationRow } from "../FrontPage/RecommendationRow"; +import { FormattedMessage } from "react-intl"; +import { SceneMarkerCard } from "./SceneMarkerCard"; + +interface IProps { + isTouch: boolean; + filter: ListFilterModel; + header: string; +} + +export const SceneMarkerRecommendationRow: React.FC = (props) => { + const result = useFindSceneMarkers(props.filter); + const cardCount = result.data?.findSceneMarkers.count; + + if (!result.loading && !cardCount) { + return null; + } + + return ( + + + + } + > + + {result.loading + ? [...Array(props.filter.itemsPerPage)].map((i) => ( +
    + )) + : result.data?.findSceneMarkers.scene_markers.map((marker, index) => ( + + ))} +
    +
    + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneMarkerWallPanel.tsx b/ui/v2.5/src/components/Scenes/SceneMarkerWallPanel.tsx index f240b36e6..0349fae0f 100644 --- a/ui/v2.5/src/components/Scenes/SceneMarkerWallPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneMarkerWallPanel.tsx @@ -1,17 +1,11 @@ -import React, { - useCallback, - useContext, - useEffect, - useMemo, - useState, -} from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import * as GQL from "src/core/generated-graphql"; import Gallery, { GalleryI, PhotoProps, RenderImageProps, } from "react-photo-gallery"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { objectTitle } from "src/core/files"; import { Link, useHistory } from "react-router-dom"; import { TruncatedText } from "../Shared/TruncatedText"; @@ -39,15 +33,23 @@ interface IMarkerPhoto { onError?: (photo: PhotoProps) => void; } -export const MarkerWallItem: React.FC> = ( - props: RenderImageProps -) => { - const { configuration } = useContext(ConfigurationContext); +interface IExtraProps { + maxHeight: number; +} + +export const MarkerWallItem: React.FC< + RenderImageProps & IExtraProps +> = (props: RenderImageProps & IExtraProps) => { + const { configuration } = useConfigurationContext(); const playSound = configuration?.interface.soundOnPreview ?? false; const showTitle = configuration?.interface.wallShowTitle ?? false; const [active, setActive] = useState(false); + const height = Math.min(props.maxHeight, props.photo.height); + const zoomFactor = height / props.photo.height; + const width = props.photo.width * zoomFactor; + type style = Record; var divStyle: style = { margin: props.margin, @@ -79,8 +81,8 @@ export const MarkerWallItem: React.FC> = ( role="button" style={{ ...divStyle, - width: props.photo.width, - height: props.photo.height, + width, + height, }} > > = ( loop={video} muted={!video || !playSound || !active} autoPlay={video} + playsInline={video} key={props.photo.key} src={props.photo.src} - width={props.photo.width} - height={props.photo.height} + width={width} + height={height} alt={props.photo.alt} onMouseEnter={() => setActive(true)} onMouseLeave={() => setActive(false)} @@ -120,6 +123,7 @@ export const MarkerWallItem: React.FC> = ( interface IMarkerWallProps { markers: GQL.SceneMarkerDataFragment[]; + zoomIndex: number; } // HACK: typescript doesn't allow Gallery to accept a parameter for some reason @@ -152,11 +156,18 @@ function getDimensions(file?: IFile) { }; } -const defaultTargetRowHeight = 250; +const breakpointZoomHeights = [ + { minWidth: 576, heights: [100, 120, 240, 360] }, + { minWidth: 768, heights: [120, 160, 240, 480] }, + { minWidth: 1200, heights: [120, 160, 240, 300] }, + { minWidth: 1400, heights: [160, 240, 300, 480] }, +]; -const MarkerWall: React.FC = ({ markers }) => { +const MarkerWall: React.FC = ({ markers, zoomIndex }) => { const history = useHistory(); + const containerRef = React.useRef(null); + const margin = 3; const direction = "row"; @@ -202,12 +213,41 @@ const MarkerWall: React.FC = ({ markers }) => { return Math.round(columnCount); } - const renderImage = useCallback((props: RenderImageProps) => { - return ; - }, []); + const targetRowHeight = useCallback( + (containerWidth: number) => { + let zoomHeight = 280; + breakpointZoomHeights.forEach((e) => { + if (containerWidth >= e.minWidth) { + zoomHeight = e.heights[zoomIndex]; + } + }); + return zoomHeight; + }, + [zoomIndex] + ); + + // set the max height as a factor of the targetRowHeight + // this allows some images to be taller than the target row height + // but prevents images from becoming too tall when there is a small number of items + const maxHeightFactor = 1.3; + + const renderImage = useCallback( + (props: RenderImageProps) => { + return ( + + ); + }, + [targetRowHeight] + ); return ( -
    +
    {photos.length ? ( = ({ markers }) => { margin={margin} direction={direction} columns={columns} - targetRowHeight={defaultTargetRowHeight} + targetRowHeight={targetRowHeight} /> ) : null}
    @@ -225,10 +265,12 @@ const MarkerWall: React.FC = ({ markers }) => { interface IMarkerWallPanelProps { markers: GQL.SceneMarkerDataFragment[]; + zoomIndex: number; } export const MarkerWallPanel: React.FC = ({ markers, + zoomIndex, }) => { - return ; + return ; }; diff --git a/ui/v2.5/src/components/Scenes/SceneMergeDialog.tsx b/ui/v2.5/src/components/Scenes/SceneMergeDialog.tsx index 52b3ea67c..511ca2351 100644 --- a/ui/v2.5/src/components/Scenes/SceneMergeDialog.tsx +++ b/ui/v2.5/src/components/Scenes/SceneMergeDialog.tsx @@ -206,13 +206,7 @@ const SceneMergeDetails: React.FC = ({ setCode( new ScrapeResult(dest.code, sources.find((s) => s.code)?.code, !dest.code) ); - setURL( - new ScrapeResult( - dest.urls, - sources.find((s) => s.urls)?.urls, - !dest.urls?.length - ) - ); + setURL(new ScrapeResult(dest.urls, uniq(all.map((s) => s.urls).flat()))); setDate( new ScrapeResult(dest.date, sources.find((s) => s.date)?.date, !dest.date) ); @@ -311,8 +305,7 @@ const SceneMergeDetails: React.FC = ({ .filter((s, index, a) => { // remove entries with duplicate endpoints return index === a.findIndex((ss) => ss.endpoint === s.endpoint); - }), - !dest.stash_ids.length + }) ) ); @@ -379,27 +372,32 @@ const SceneMergeDetails: React.FC = ({ return ( <> setTitle(value)} /> setCode(value)} /> setURL(value)} /> setDate(value)} /> ( @@ -411,6 +409,7 @@ const SceneMergeDetails: React.FC = ({ onChange={(value) => setRating(value)} /> ( @@ -432,6 +431,7 @@ const SceneMergeDetails: React.FC = ({ onChange={(value) => setOCounter(value)} /> ( @@ -453,6 +453,7 @@ const SceneMergeDetails: React.FC = ({ onChange={(value) => setPlayCount(value)} /> ( @@ -476,6 +477,7 @@ const SceneMergeDetails: React.FC = ({ onChange={(value) => setPlayDuration(value)} /> ( @@ -499,32 +501,38 @@ const SceneMergeDetails: React.FC = ({ onChange={(value) => setGalleries(value)} /> setStudio(value)} /> setPerformers(value)} ageFromDate={date.useNewValue ? date.newValue : date.originalValue} /> setGroups(value)} /> setTags(value)} /> setDetails(value)} /> ( @@ -546,6 +554,7 @@ const SceneMergeDetails: React.FC = ({ onChange={(value) => setOrganized(value)} /> ( @@ -557,6 +566,7 @@ const SceneMergeDetails: React.FC = ({ onChange={(value) => setStashIDs(value)} /> & ExtraSceneProps > = (props) => { - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const intl = useIntl(); const maxOptionsShown = configuration?.ui.maxOptionsShown ?? defaultMaxOptionsShown; diff --git a/ui/v2.5/src/components/Scenes/SceneWallPanel.tsx b/ui/v2.5/src/components/Scenes/SceneWallPanel.tsx index 546a1488a..3f5020793 100644 --- a/ui/v2.5/src/components/Scenes/SceneWallPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneWallPanel.tsx @@ -1,10 +1,4 @@ -import React, { - useCallback, - useContext, - useEffect, - useMemo, - useState, -} from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import * as GQL from "src/core/generated-graphql"; import { SceneQueue } from "src/models/sceneQueue"; import Gallery, { @@ -12,7 +6,7 @@ import Gallery, { PhotoProps, RenderImageProps, } from "react-photo-gallery"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { objectTitle } from "src/core/files"; import { Link, useHistory } from "react-router-dom"; import { TruncatedText } from "../Shared/TruncatedText"; @@ -26,15 +20,23 @@ interface IScenePhoto { onError?: (photo: PhotoProps) => void; } -export const SceneWallItem: React.FC> = ( - props: RenderImageProps -) => { +interface IExtraProps { + maxHeight: number; +} + +export const SceneWallItem: React.FC< + RenderImageProps & IExtraProps +> = (props: RenderImageProps & IExtraProps) => { const intl = useIntl(); - const { configuration } = useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const playSound = configuration?.interface.soundOnPreview ?? false; const showTitle = configuration?.interface.wallShowTitle ?? false; + const height = Math.min(props.maxHeight, props.photo.height); + const zoomFactor = height / props.photo.height; + const width = props.photo.width * zoomFactor; + const [active, setActive] = useState(false); type style = Record; @@ -72,8 +74,8 @@ export const SceneWallItem: React.FC> = ( role="button" style={{ ...divStyle, - width: props.photo.width, - height: props.photo.height, + width, + height, }} > > = ( loop={video} muted={!video || !playSound || !active} autoPlay={video} + playsInline={video} key={props.photo.key} src={props.photo.src} - width={props.photo.width} - height={props.photo.height} + width={width} + height={height} alt={props.photo.alt} onMouseEnter={() => setActive(true)} onMouseLeave={() => setActive(false)} @@ -126,16 +129,28 @@ function getDimensions(s: GQL.SlimSceneDataFragment) { interface ISceneWallProps { scenes: GQL.SlimSceneDataFragment[]; sceneQueue?: SceneQueue; + zoomIndex: number; } // HACK: typescript doesn't allow Gallery to accept a parameter for some reason const SceneGallery = Gallery as unknown as GalleryI; -const defaultTargetRowHeight = 250; +const breakpointZoomHeights = [ + { minWidth: 576, heights: [100, 120, 240, 360] }, + { minWidth: 768, heights: [120, 160, 240, 480] }, + { minWidth: 1200, heights: [120, 160, 240, 300] }, + { minWidth: 1400, heights: [160, 240, 300, 480] }, +]; -const SceneWall: React.FC = ({ scenes, sceneQueue }) => { +const SceneWall: React.FC = ({ + scenes, + sceneQueue, + zoomIndex, +}) => { const history = useHistory(); + const containerRef = React.useRef(null); + const margin = 3; const direction = "row"; @@ -186,12 +201,41 @@ const SceneWall: React.FC = ({ scenes, sceneQueue }) => { return Math.round(columnCount); } - const renderImage = useCallback((props: RenderImageProps) => { - return ; - }, []); + const targetRowHeight = useCallback( + (containerWidth: number) => { + let zoomHeight = 280; + breakpointZoomHeights.forEach((e) => { + if (containerWidth >= e.minWidth) { + zoomHeight = e.heights[zoomIndex]; + } + }); + return zoomHeight; + }, + [zoomIndex] + ); + + // set the max height as a factor of the targetRowHeight + // this allows some images to be taller than the target row height + // but prevents images from becoming too tall when there is a small number of items + const maxHeightFactor = 1.3; + + const renderImage = useCallback( + (props: RenderImageProps) => { + return ( + + ); + }, + [targetRowHeight] + ); return ( -
    +
    {photos.length ? ( = ({ scenes, sceneQueue }) => { margin={margin} direction={direction} columns={columns} - targetRowHeight={defaultTargetRowHeight} + targetRowHeight={targetRowHeight} /> ) : null}
    @@ -210,11 +254,15 @@ const SceneWall: React.FC = ({ scenes, sceneQueue }) => { interface ISceneWallPanelProps { scenes: GQL.SlimSceneDataFragment[]; sceneQueue?: SceneQueue; + zoomIndex: number; } export const SceneWallPanel: React.FC = ({ scenes, sceneQueue, + zoomIndex, }) => { - return ; + return ( + + ); }; diff --git a/ui/v2.5/src/components/Scenes/styles.scss b/ui/v2.5/src/components/Scenes/styles.scss index 61a4cdbac..3b00130b1 100644 --- a/ui/v2.5/src/components/Scenes/styles.scss +++ b/ui/v2.5/src/components/Scenes/styles.scss @@ -902,51 +902,6 @@ input[type="range"].blue-slider { } } -.scene-list .filtered-list-toolbar { - display: flex; - flex-wrap: wrap; - row-gap: 1rem; - - & > div { - display: flex; - flex: 1; - flex-wrap: nowrap; - - &:first-child { - justify-content: flex-start; - } - - &:nth-child(2) { - justify-content: center; - } - - &:last-child { - justify-content: flex-end; - } - - @include media-breakpoint-down(xs) { - &:nth-child(2) { - justify-content: flex-end; - } - - &:last-child { - display: none; - } - } - } -} - -.scene-list.hide-sidebar .sidebar-toggle-button { - transition-delay: 0.1s; - transition-duration: 0; - transition-property: opacity; -} - -.scene-list:not(.hide-sidebar) .sidebar-toggle-button { - opacity: 0; - pointer-events: none; -} - .scene-wall, .marker-wall { .wall-item { @@ -1003,3 +958,9 @@ input[type="range"].blue-slider { } } } + +.table-list.scene-table { + // Set max height to viewport height minus estimated header/footer height + // TODO - this will need to be rolled out to other tables + max-height: calc(100dvh - 210px); +} diff --git a/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx b/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx index 1802fefe7..ba93385b5 100644 --- a/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx +++ b/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx @@ -200,6 +200,7 @@ export const SettingsInterfacePanel: React.FC = PatchComponent( onChange={(v) => saveInterface({ language: v })} > + @@ -219,7 +220,8 @@ export const SettingsInterfacePanel: React.FC = PatchComponent( - + + @@ -232,11 +234,20 @@ export const SettingsInterfacePanel: React.FC = PatchComponent( + + saveInterface({ sfwContentMode: v })} + /> +
    @@ -467,6 +478,7 @@ export const SettingsInterfacePanel: React.FC = PatchComponent( onChange={(v) => saveUI({ showChildTagContent: v })} /> + + + saveUI({ showLinksOnPerformerCard: v })} + /> + + { value={general.backupDirectoryPath ?? undefined} onChange={(v) => saveGeneral({ backupDirectoryPath: v })} /> + + saveGeneral({ deleteTrashPath: v })} + /> @@ -465,6 +473,14 @@ export const SettingsConfigurationPanel: React.FC = () => { checked={general.logAccess ?? false} onChange={(v) => saveGeneral({ logAccess: v })} /> + + saveGeneral({ logFileMaxSize: v })} + /> ); diff --git a/ui/v2.5/src/components/Settings/SettingsToolsPanel.tsx b/ui/v2.5/src/components/Settings/SettingsToolsPanel.tsx index 8168ffb99..e3577a499 100644 --- a/ui/v2.5/src/components/Settings/SettingsToolsPanel.tsx +++ b/ui/v2.5/src/components/Settings/SettingsToolsPanel.tsx @@ -5,33 +5,49 @@ import { Link } from "react-router-dom"; import { Setting } from "./Inputs"; import { SettingSection } from "./SettingSection"; import { PatchContainerComponent } from "src/patch"; +import { ExternalLink } from "../Shared/ExternalLink"; const SettingsToolsSection = PatchContainerComponent("SettingsToolsSection"); export const SettingsToolsPanel: React.FC = () => { return ( - - - - - - } - /> + <> + + + + + + } + /> + + + + + + + + } + /> - - - - } - /> - - + + + + } + /> + + + ); }; diff --git a/ui/v2.5/src/components/Settings/Tasks/DataManagementTasks.tsx b/ui/v2.5/src/components/Settings/Tasks/DataManagementTasks.tsx index e093dc60a..c36e076f4 100644 --- a/ui/v2.5/src/components/Settings/Tasks/DataManagementTasks.tsx +++ b/ui/v2.5/src/components/Settings/Tasks/DataManagementTasks.tsx @@ -22,7 +22,7 @@ import { SettingSection } from "../SettingSection"; import { BooleanSetting, Setting } from "../Inputs"; import { ManualLink } from "src/components/Help/context"; import { Icon } from "src/components/Shared/Icon"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { FolderSelect } from "src/components/Shared/FolderSelect/FolderSelect"; import { faMinus, @@ -44,7 +44,7 @@ const CleanDialog: React.FC = ({ onClose, }) => { const intl = useIntl(); - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const libraryPaths = configuration?.general.stashes.map((s) => s.path); diff --git a/ui/v2.5/src/components/Settings/Tasks/DirectorySelectionDialog.tsx b/ui/v2.5/src/components/Settings/Tasks/DirectorySelectionDialog.tsx index 9fdaf09f4..87a58f292 100644 --- a/ui/v2.5/src/components/Settings/Tasks/DirectorySelectionDialog.tsx +++ b/ui/v2.5/src/components/Settings/Tasks/DirectorySelectionDialog.tsx @@ -9,7 +9,7 @@ import { useIntl } from "react-intl"; import { Icon } from "src/components/Shared/Icon"; import { ModalComponent } from "src/components/Shared/Modal"; import { FolderSelect } from "src/components/Shared/FolderSelect/FolderSelect"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; interface IDirectorySelectionDialogProps { animation?: boolean; @@ -22,7 +22,7 @@ export const DirectorySelectionDialog: React.FC< IDirectorySelectionDialogProps > = ({ animation, allowEmpty = false, initialPaths = [], onClose }) => { const intl = useIntl(); - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const libraryPaths = configuration?.general.stashes.map((s) => s.path); diff --git a/ui/v2.5/src/components/Settings/Tasks/LibraryTasks.tsx b/ui/v2.5/src/components/Settings/Tasks/LibraryTasks.tsx index 1cab7cfb6..605e37933 100644 --- a/ui/v2.5/src/components/Settings/Tasks/LibraryTasks.tsx +++ b/ui/v2.5/src/components/Settings/Tasks/LibraryTasks.tsx @@ -7,7 +7,7 @@ import { mutateMetadataGenerate, } from "src/core/StashService"; import { withoutTypename } from "src/utils/data"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { IdentifyDialog } from "../../Dialogs/IdentifyDialog/IdentifyDialog"; import * as GQL from "src/core/generated-graphql"; import { DirectorySelectionDialog } from "./DirectorySelectionDialog"; @@ -123,7 +123,7 @@ export const LibraryTasks: React.FC = () => { type DialogOpenState = typeof dialogOpen; - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const [configRead, setConfigRead] = useState(false); useEffect(() => { @@ -160,30 +160,6 @@ export const LibraryTasks: React.FC = () => { setGenerateOptions(withoutTypename(generate)); } - if (configuration?.general) { - const { general } = configuration; - setGenerateOptions((existing) => ({ - ...existing, - previewOptions: { - ...existing.previewOptions, - previewSegments: - general.previewSegments ?? - existing.previewOptions?.previewSegments, - previewSegmentDuration: - general.previewSegmentDuration ?? - existing.previewOptions?.previewSegmentDuration, - previewExcludeStart: - general.previewExcludeStart ?? - existing.previewOptions?.previewExcludeStart, - previewExcludeEnd: - general.previewExcludeEnd ?? - existing.previewOptions?.previewExcludeEnd, - previewPreset: - general.previewPreset ?? existing.previewOptions?.previewPreset, - }, - })); - } - setConfigRead(true); } }, [configuration, configRead, taskDefaults, loading]); @@ -291,7 +267,30 @@ export const LibraryTasks: React.FC = () => { async function onGenerateClicked() { try { - await mutateMetadataGenerate(generateOptions); + // insert preview options here instead of loading them + const general = configuration?.general; + + await mutateMetadataGenerate({ + ...generateOptions, + previewOptions: { + ...generateOptions.previewOptions, + previewSegments: + general?.previewSegments ?? + generateOptions.previewOptions?.previewSegments, + previewSegmentDuration: + general?.previewSegmentDuration ?? + generateOptions.previewOptions?.previewSegmentDuration, + previewExcludeStart: + general?.previewExcludeStart ?? + generateOptions.previewOptions?.previewExcludeStart, + previewExcludeEnd: + general?.previewExcludeEnd ?? + generateOptions.previewOptions?.previewExcludeEnd, + previewPreset: + general?.previewPreset ?? + generateOptions.previewOptions?.previewPreset, + }, + }); Toast.success( intl.formatMessage( { id: "config.tasks.added_job_to_queue" }, diff --git a/ui/v2.5/src/components/Setup/Setup.tsx b/ui/v2.5/src/components/Setup/Setup.tsx index 00228f9b0..27f9b4e58 100644 --- a/ui/v2.5/src/components/Setup/Setup.tsx +++ b/ui/v2.5/src/components/Setup/Setup.tsx @@ -1,4 +1,4 @@ -import React, { useState, useContext, useCallback } from "react"; +import React, { useState, useCallback } from "react"; import { FormattedMessage, useIntl } from "react-intl"; import { Alert, @@ -15,7 +15,7 @@ import { useSystemStatus, } from "src/core/StashService"; import { useHistory } from "react-router-dom"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import StashConfiguration from "../Settings/StashConfiguration"; import { Icon } from "../Shared/Icon"; import { LoadingIndicator } from "../Shared/LoadingIndicator"; @@ -511,16 +511,32 @@ const BlobsSection: React.FC<{ }; const SetPathsStep: React.FC = ({ goBack, next }) => { - const { configuration } = useSetupContext(); + const { configuration, setupState } = useSetupContext(); const [showStashAlert, setShowStashAlert] = useState(false); - const [stashes, setStashes] = useState([]); - const [databaseFile, setDatabaseFile] = useState(""); - const [generatedLocation, setGeneratedLocation] = useState(""); - const [cacheLocation, setCacheLocation] = useState(""); - const [storeBlobsInDatabase, setStoreBlobsInDatabase] = useState(false); - const [blobsLocation, setBlobsLocation] = useState(""); + const [stashes, setStashes] = useState( + setupState.stashes ?? [] + ); + const [sfwContentMode, setSfwContentMode] = useState( + setupState.sfwContentMode ?? false + ); + + const [databaseFile, setDatabaseFile] = useState( + setupState.databaseFile ?? "" + ); + const [generatedLocation, setGeneratedLocation] = useState( + setupState.generatedLocation ?? "" + ); + const [cacheLocation, setCacheLocation] = useState( + setupState.cacheLocation ?? "" + ); + const [storeBlobsInDatabase, setStoreBlobsInDatabase] = useState( + setupState.storeBlobsInDatabase ?? false + ); + const [blobsLocation, setBlobsLocation] = useState( + setupState.blobsLocation ?? "" + ); const overrideDatabase = configuration?.general.databasePath; const overrideGenerated = configuration?.general.generatedPath; @@ -543,6 +559,7 @@ const SetPathsStep: React.FC = ({ goBack, next }) => { cacheLocation, blobsLocation: storeBlobsInDatabase ? "" : blobsLocation, storeBlobsInDatabase, + sfwContentMode, }; next(input); } @@ -582,6 +599,22 @@ const SetPathsStep: React.FC = ({ goBack, next }) => { /> + +

    + +

    +

    + +

    + + } + onChange={() => setSfwContentMode(!sfwContentMode)} + /> + +
    {overrideDatabase ? null : ( = ({ stash }) => { }; const ConfirmStep: React.FC = ({ goBack, next }) => { - const { configuration, pathDir, pathJoin, pwd, setupState } = - useSetupContext(); + const { + configuration, + pathDir, + pathJoin, + setupState, + homeDirPath, + workingDir, + } = useSetupContext(); + // if unset, means use homeDirPath const cfgFile = setupState.configLocation - ? setupState.configLocation - : pathJoin(pwd, "config.yml"); + ? pathJoin(workingDir, setupState.configLocation) + : pathJoin(homeDirPath, "config.yml"); const cfgDir = pathDir(cfgFile); const stashes = setupState.stashes ?? []; const { @@ -933,8 +973,7 @@ const FinishStep: React.FC = ({ goBack }) => { export const Setup: React.FC = () => { const intl = useIntl(); - const { configuration, loading: configLoading } = - useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const [saveUI] = useConfigureUI(); @@ -1005,7 +1044,7 @@ export const Setup: React.FC = () => { } } - if (configLoading || statusLoading) { + if (statusLoading) { return ; } diff --git a/ui/v2.5/src/components/Shared/BulkUpdateTextInput.tsx b/ui/v2.5/src/components/Shared/BulkUpdateTextInput.tsx index 542ab5b3b..cf78798e1 100644 --- a/ui/v2.5/src/components/Shared/BulkUpdateTextInput.tsx +++ b/ui/v2.5/src/components/Shared/BulkUpdateTextInput.tsx @@ -7,6 +7,7 @@ import { Icon } from "./Icon"; interface IBulkUpdateTextInputProps extends FormControlProps { valueChanged: (value: string | undefined) => void; unsetDisabled?: boolean; + as?: React.ElementType; } export const BulkUpdateTextInput: React.FC = ({ @@ -24,6 +25,7 @@ export const BulkUpdateTextInput: React.FC = ({ {...props} className="input-control" type="text" + as={props.as} value={props.value ?? ""} placeholder={ props.value === undefined diff --git a/ui/v2.5/src/components/Shared/CollapseButton.tsx b/ui/v2.5/src/components/Shared/CollapseButton.tsx index d0b192162..0d05f6e64 100644 --- a/ui/v2.5/src/components/Shared/CollapseButton.tsx +++ b/ui/v2.5/src/components/Shared/CollapseButton.tsx @@ -3,7 +3,7 @@ import { faChevronRight, faChevronUp, } from "@fortawesome/free-solid-svg-icons"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { Button, Collapse, CollapseProps } from "react-bootstrap"; import { Icon } from "./Icon"; @@ -12,22 +12,27 @@ interface IProps { text: React.ReactNode; collapseProps?: Partial; outsideCollapse?: React.ReactNode; - onOpen?: () => void; + onOpenChanged?: (o: boolean) => void; + open?: boolean; } export const CollapseButton: React.FC> = ( props: React.PropsWithChildren ) => { - const [open, setOpen] = useState(false); + const [open, setOpen] = useState(props.open ?? false); function toggleOpen() { const nv = !open; setOpen(nv); - if (props.onOpen && nv) { - props.onOpen(); - } + props.onOpenChanged?.(nv); } + useEffect(() => { + if (props.open !== undefined) { + setOpen(props.open); + } + }, [props.open]); + return (
    diff --git a/ui/v2.5/src/components/Shared/CountButton.tsx b/ui/v2.5/src/components/Shared/CountButton.tsx index 1519c104b..ad099c2f5 100644 --- a/ui/v2.5/src/components/Shared/CountButton.tsx +++ b/ui/v2.5/src/components/Shared/CountButton.tsx @@ -1,10 +1,11 @@ -import { faEye } from "@fortawesome/free-solid-svg-icons"; +import { faEye, faThumbsUp } from "@fortawesome/free-solid-svg-icons"; import React from "react"; import { Button, ButtonGroup } from "react-bootstrap"; import { Icon } from "src/components/Shared/Icon"; import { SweatDrops } from "./SweatDrops"; import cx from "classnames"; import { useIntl } from "react-intl"; +import { useConfigurationContext } from "src/hooks/Config"; interface ICountButtonProps { value: number; @@ -63,11 +64,17 @@ export const ViewCountButton: React.FC = (props) => { export const OCounterButton: React.FC = (props) => { const intl = useIntl(); + const { configuration } = useConfigurationContext(); + const { sfwContentMode } = configuration.interface; + + const icon = !sfwContentMode ? : ; + const messageID = !sfwContentMode ? "o_count" : "o_count_sfw"; + return ( } - title={intl.formatMessage({ id: "o_count" })} + icon={icon} + title={intl.formatMessage({ id: messageID })} countTitle={intl.formatMessage({ id: "actions.view_history" })} /> ); diff --git a/ui/v2.5/src/components/Shared/DeleteFilesDialog.tsx b/ui/v2.5/src/components/Shared/DeleteFilesDialog.tsx index e7d5af9ac..7d790539b 100644 --- a/ui/v2.5/src/components/Shared/DeleteFilesDialog.tsx +++ b/ui/v2.5/src/components/Shared/DeleteFilesDialog.tsx @@ -2,6 +2,7 @@ import React, { useState } from "react"; import { mutateDeleteFiles } from "src/core/StashService"; import { ModalComponent } from "./Modal"; import { useToast } from "src/hooks/Toast"; +import { ConfigurationContext } from "src/hooks/Config"; import { FormattedMessage, useIntl } from "react-intl"; import { faTrashAlt } from "@fortawesome/free-solid-svg-icons"; @@ -40,6 +41,9 @@ export const DeleteFilesDialog: React.FC = ( // Network state const [isDeleting, setIsDeleting] = useState(false); + const context = React.useContext(ConfigurationContext); + const config = context?.configuration; + async function onDelete() { setIsDeleting(true); try { @@ -56,6 +60,11 @@ export const DeleteFilesDialog: React.FC = ( function renderDeleteFileAlert() { const deletedFiles = props.selected.map((f) => f.path); + const deleteTrashPath = config?.general.deleteTrashPath; + const deleteAlertId = deleteTrashPath + ? "dialogs.delete_alert_to_trash" + : "dialogs.delete_alert"; + return (

    @@ -65,7 +74,7 @@ export const DeleteFilesDialog: React.FC = ( singularEntity: intl.formatMessage({ id: "file" }), pluralEntity: intl.formatMessage({ id: "files" }), }} - id="dialogs.delete_alert" + id={deleteAlertId} />

      diff --git a/ui/v2.5/src/components/Shared/DetailItem.tsx b/ui/v2.5/src/components/Shared/DetailItem.tsx index a92f75868..76b595127 100644 --- a/ui/v2.5/src/components/Shared/DetailItem.tsx +++ b/ui/v2.5/src/components/Shared/DetailItem.tsx @@ -3,6 +3,7 @@ import { FormattedMessage } from "react-intl"; interface IDetailItem { id?: string | null; + className?: string; label?: React.ReactNode; value?: React.ReactNode; labelTitle?: string; @@ -13,6 +14,7 @@ interface IDetailItem { export const DetailItem: React.FC = ({ id, + className = "", label, value, labelTitle, @@ -30,7 +32,7 @@ export const DetailItem: React.FC = ({ const sanitisedID = id.replace(/_/g, "-"); return ( -
      +
      {message} {fullWidth ? ":" : ""} diff --git a/ui/v2.5/src/components/Shared/DoubleRangeInput.tsx b/ui/v2.5/src/components/Shared/DoubleRangeInput.tsx new file mode 100644 index 000000000..1d8e7fbfe --- /dev/null +++ b/ui/v2.5/src/components/Shared/DoubleRangeInput.tsx @@ -0,0 +1,61 @@ +import React from "react"; + +export const DoubleRangeInput: React.FC<{ + className?: string; + minInput: React.ReactNode; + maxInput: React.ReactNode; + min?: number; + max: number; + value: [number, number]; + onChange(value: [number, number]): void; +}> = ({ + className = "", + minInput, + maxInput, + min = 0, + max, + value, + onChange, +}) => { + const minValue = value[0]; + const maxValue = value[1]; + + return ( +
      +
      + {minInput} + {maxInput} +
      +
      + { + const rawValue = parseInt(e.target.value); + if (rawValue < maxValue) { + onChange([rawValue, maxValue]); + } + }} + className="double-range-slider double-range-slider-min" + /> + { + const rawValue = parseInt(e.target.value); + if (rawValue > minValue) { + onChange([minValue, rawValue]); + } + }} + className="double-range-slider double-range-slider-max" + /> +
      +
      + ); +}; diff --git a/ui/v2.5/src/components/Shared/ExternalLinksButton.tsx b/ui/v2.5/src/components/Shared/ExternalLinksButton.tsx index 7d8072d07..e35a1a992 100644 --- a/ui/v2.5/src/components/Shared/ExternalLinksButton.tsx +++ b/ui/v2.5/src/components/Shared/ExternalLinksButton.tsx @@ -12,9 +12,10 @@ export const ExternalLinksButton: React.FC<{ icon?: IconDefinition; urls: string[]; className?: string; + openIfSingle?: boolean; }> = PatchComponent( "ExternalLinksButton", - ({ urls, icon = faLink, className = "" }) => { + ({ urls, icon = faLink, className = "", openIfSingle = false }) => { if (!urls.length) { return null; } @@ -36,14 +37,27 @@ export const ExternalLinksButton: React.FC<{ document.body ); - return ( - - + if (openIfSingle && urls.length === 1) { + return ( + - - - - ); + + ); + } else { + return ( + + + + + + + ); + } } ); diff --git a/ui/v2.5/src/components/Shared/GridCard/StudioOverlay.tsx b/ui/v2.5/src/components/Shared/GridCard/StudioOverlay.tsx index 875b122d8..9bfd25071 100644 --- a/ui/v2.5/src/components/Shared/GridCard/StudioOverlay.tsx +++ b/ui/v2.5/src/components/Shared/GridCard/StudioOverlay.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from "react"; import { Link } from "react-router-dom"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; interface IStudio { id: string; @@ -11,7 +11,7 @@ interface IStudio { export const StudioOverlay: React.FC<{ studio: IStudio | null | undefined; }> = ({ studio }) => { - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const configValue = configuration?.interface.showStudioAsText; diff --git a/ui/v2.5/src/components/Shared/PopoverCountButton.tsx b/ui/v2.5/src/components/Shared/PopoverCountButton.tsx index 79a36bd9d..d652ff6ad 100644 --- a/ui/v2.5/src/components/Shared/PopoverCountButton.tsx +++ b/ui/v2.5/src/components/Shared/PopoverCountButton.tsx @@ -11,14 +11,14 @@ import React from "react"; import { Button, OverlayTrigger, Tooltip } from "react-bootstrap"; import { FormattedNumber, useIntl } from "react-intl"; import { Link } from "react-router-dom"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import TextUtils from "src/utils/text"; import { Icon } from "./Icon"; export const Count: React.FC<{ count: number; }> = ({ count }) => { - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const abbreviateCounter = configuration?.ui.abbreviateCounters ?? false; if (!abbreviateCounter) { diff --git a/ui/v2.5/src/components/Shared/Rating/RatingStars.tsx b/ui/v2.5/src/components/Shared/Rating/RatingStars.tsx index 5339044a1..f83c556fc 100644 --- a/ui/v2.5/src/components/Shared/Rating/RatingStars.tsx +++ b/ui/v2.5/src/components/Shared/Rating/RatingStars.tsx @@ -228,21 +228,16 @@ export const RatingStars = PatchComponent( ); }; - const maybeRenderStarRatingNumber = () => { + const maybeGetStarRatingNumber = () => { const ratingFraction = getCurrentSelectedRating(); if ( !ratingFraction || (ratingFraction.rating == 0 && ratingFraction.fraction == 0) ) { - return; + return ""; } - return ( - - {ratingFraction.rating + ratingFraction.fraction} - {suffix} - - ); + return ratingFraction.rating + ratingFraction.fraction + suffix; }; const precisionClassName = `rating-stars-precision-${props.precision}`; @@ -252,7 +247,7 @@ export const RatingStars = PatchComponent( {Array.from(Array(max)).map((value, index) => renderRatingButton(index + 1) )} - {maybeRenderStarRatingNumber()} + {maybeGetStarRatingNumber()}
      ); } diff --git a/ui/v2.5/src/components/Shared/Rating/RatingSystem.tsx b/ui/v2.5/src/components/Shared/Rating/RatingSystem.tsx index a0a11c363..11103acf8 100644 --- a/ui/v2.5/src/components/Shared/Rating/RatingSystem.tsx +++ b/ui/v2.5/src/components/Shared/Rating/RatingSystem.tsx @@ -1,5 +1,4 @@ -import React from "react"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { defaultRatingStarPrecision, defaultRatingSystemOptions, @@ -23,7 +22,7 @@ export interface IRatingSystemProps { export const RatingSystem = PatchComponent( "RatingSystem", (props: IRatingSystemProps) => { - const { configuration: config } = React.useContext(ConfigurationContext); + const { configuration: config } = useConfigurationContext(); const ratingSystemOptions = config?.ui.ratingSystemOptions ?? defaultRatingSystemOptions; diff --git a/ui/v2.5/src/components/Shared/RatingBanner.tsx b/ui/v2.5/src/components/Shared/RatingBanner.tsx index d152b8b52..d94b26433 100644 --- a/ui/v2.5/src/components/Shared/RatingBanner.tsx +++ b/ui/v2.5/src/components/Shared/RatingBanner.tsx @@ -1,4 +1,4 @@ -import React, { useContext } from "react"; +import React from "react"; import { FormattedMessage } from "react-intl"; import { convertToRatingFormat, @@ -6,14 +6,14 @@ import { RatingStarPrecision, RatingSystemType, } from "src/utils/rating"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; interface IProps { rating?: number | null; } export const RatingBanner: React.FC = ({ rating }) => { - const { configuration: config } = useContext(ConfigurationContext); + const { configuration: config } = useConfigurationContext(); const ratingSystemOptions = config?.ui.ratingSystemOptions ?? defaultRatingSystemOptions; const isLegacy = diff --git a/ui/v2.5/src/components/Shared/ScrapeDialog/ScrapeDialog.tsx b/ui/v2.5/src/components/Shared/ScrapeDialog/ScrapeDialog.tsx index 59d5f3985..b67c55f41 100644 --- a/ui/v2.5/src/components/Shared/ScrapeDialog/ScrapeDialog.tsx +++ b/ui/v2.5/src/components/Shared/ScrapeDialog/ScrapeDialog.tsx @@ -24,6 +24,7 @@ import { CountrySelect } from "../CountrySelect"; import { StringListInput } from "../StringListInput"; import { ImageSelector } from "../ImageSelector"; import { ScrapeResult } from "./scrapeResult"; +import { useConfigurationContext } from "src/hooks/Config"; interface IScrapedFieldProps { result: ScrapeResult; @@ -31,6 +32,7 @@ interface IScrapedFieldProps { interface IScrapedRowProps extends IScrapedFieldProps { className?: string; + field: string; title: string; renderOriginalField: (result: ScrapeResult) => JSX.Element | undefined; renderNewField: (result: ScrapeResult) => JSX.Element | undefined; @@ -105,7 +107,10 @@ export const ScrapeDialogRow = (props: IScrapedRowProps) => { } return ( - + {props.title} @@ -175,6 +180,8 @@ function getNameString(value: string) { interface IScrapedInputGroupRowProps { title: string; + field: string; + className?: string; placeholder?: string; result: ScrapeResult; locked?: boolean; @@ -187,6 +194,8 @@ export const ScrapedInputGroupRow: React.FC = ( return ( ( = (props) => { interface IScrapedStringListRowProps { title: string; + field: string; placeholder?: string; result: ScrapeResult; locked?: boolean; @@ -253,6 +263,7 @@ export const ScrapedStringListRow: React.FC = ( ( = ( return ( ( = (props) => { interface IScrapedImageRowProps { title: string; + field: string; className?: string; result: ScrapeResult; onChange: (value: ScrapeResult) => void; @@ -355,6 +368,7 @@ export const ScrapedImageRow: React.FC = (props) => { return ( ( = (props) => { interface IScrapedImagesRowProps { title: string; + field: string; className?: string; result: ScrapeResult; images: string[]; @@ -397,6 +412,7 @@ export const ScrapedImagesRow: React.FC = (props) => { return ( ( = ( props: IScrapeDialogProps ) => { const intl = useIntl(); + const { configuration } = useConfigurationContext(); + const { sfwContentMode } = configuration.interface; + return ( = ( text: intl.formatMessage({ id: "actions.cancel" }), variant: "secondary", }} - modalProps={{ size: "lg", dialogClassName: "scrape-dialog" }} + modalProps={{ + size: "lg", + dialogClassName: `scrape-dialog ${sfwContentMode ? "sfw-mode" : ""}`, + }} >
      @@ -479,6 +501,7 @@ export const ScrapeDialog: React.FC = ( interface IScrapedCountryRowProps { title: string; + field: string; result: ScrapeResult; onChange: (value: ScrapeResult) => void; locked?: boolean; @@ -487,6 +510,7 @@ interface IScrapedCountryRowProps { export const ScrapedCountryRow: React.FC = ({ title, + field, result, onChange, locked, @@ -494,6 +518,7 @@ export const ScrapedCountryRow: React.FC = ({ }) => ( ( ; onChange: (value: ObjectScrapeResult) => void; newStudio?: GQL.ScrapedStudio; @@ -25,6 +26,7 @@ function getObjectName(value: T) { export const ScrapedStudioRow: React.FC = ({ title, + field, result, onChange, newStudio, @@ -41,7 +43,9 @@ export const ScrapedStudioRow: React.FC = ({ const value = resultValue ? [resultValue] : []; const selectValue = value.map((p) => { - const aliases: string[] = []; + const aliases: string[] = p.aliases + ? p.aliases.split(",").map((a) => a.trim()) + : []; return { id: p.stored_id ?? "", name: p.name ?? "", @@ -55,10 +59,11 @@ export const ScrapedStudioRow: React.FC = ({ isDisabled={!isNew} onSelect={(items) => { if (onChangeFn) { - const { id, ...data } = items[0]; + const { id, aliases, ...data } = items[0]; onChangeFn({ ...data, stored_id: id, + aliases: aliases?.join(", "), }); } }} @@ -70,6 +75,7 @@ export const ScrapedStudioRow: React.FC = ({ return ( renderScrapedStudio(result)} renderNewField={() => @@ -89,6 +95,7 @@ export const ScrapedStudioRow: React.FC = ({ interface IScrapedObjectsRow { title: string; + field: string; result: ScrapeResult; onChange: (value: ScrapeResult) => void; newObjects?: T[]; @@ -104,6 +111,7 @@ interface IScrapedObjectsRow { export const ScrapedObjectsRow = (props: IScrapedObjectsRow) => { const { title, + field, result, onChange, newObjects, @@ -115,6 +123,7 @@ export const ScrapedObjectsRow = (props: IScrapedObjectsRow) => { return ( renderObjects(result)} renderNewField={() => @@ -139,7 +148,15 @@ type IScrapedObjectRowImpl = Omit< export const ScrapedPerformersRow: React.FC< IScrapedObjectRowImpl & { ageFromDate?: string | null } -> = ({ title, result, onChange, newObjects, onCreateNew, ageFromDate }) => { +> = ({ + title, + field, + result, + onChange, + newObjects, + onCreateNew, + ageFromDate, +}) => { const performersCopy = useMemo(() => { return ( newObjects?.map((p) => { @@ -188,6 +205,7 @@ export const ScrapedPerformersRow: React.FC< return ( title={title} + field={field} result={result} renderObjects={renderScrapedPerformers} onChange={onChange} @@ -200,7 +218,7 @@ export const ScrapedPerformersRow: React.FC< export const ScrapedGroupsRow: React.FC< IScrapedObjectRowImpl -> = ({ title, result, onChange, newObjects, onCreateNew }) => { +> = ({ title, field, result, onChange, newObjects, onCreateNew }) => { const groupsCopy = useMemo(() => { return ( newObjects?.map((p) => { @@ -248,6 +266,7 @@ export const ScrapedGroupsRow: React.FC< return ( title={title} + field={field} result={result} renderObjects={renderScrapedGroups} onChange={onChange} @@ -260,7 +279,7 @@ export const ScrapedGroupsRow: React.FC< export const ScrapedTagsRow: React.FC< IScrapedObjectRowImpl -> = ({ title, result, onChange, newObjects, onCreateNew }) => { +> = ({ title, field, result, onChange, newObjects, onCreateNew }) => { function renderScrapedTags( scrapeResult: ScrapeResult, isNew?: boolean, @@ -294,6 +313,7 @@ export const ScrapedTagsRow: React.FC< return ( title={title} + field={field} result={result} renderObjects={renderScrapedTags} onChange={onChange} diff --git a/ui/v2.5/src/components/Shared/ScrapeDialog/createObjects.ts b/ui/v2.5/src/components/Shared/ScrapeDialog/createObjects.ts index c4ba3a3e7..e2d09294a 100644 --- a/ui/v2.5/src/components/Shared/ScrapeDialog/createObjects.ts +++ b/ui/v2.5/src/components/Shared/ScrapeDialog/createObjects.ts @@ -46,6 +46,7 @@ interface IUseCreateNewStudioProps { scrapeResult: ObjectScrapeResult ) => void; setNewObject: (newObject: GQL.ScrapedStudio | undefined) => void; + endpoint?: string; } export function useCreateScrapedStudio(props: IUseCreateNewStudioProps) { @@ -54,12 +55,33 @@ export function useCreateScrapedStudio(props: IUseCreateNewStudioProps) { const { scrapeResult, setScrapeResult, setNewObject } = props; async function createNewStudio(toCreate: GQL.ScrapedStudio) { + const input: GQL.StudioCreateInput = { + name: toCreate.name, + urls: toCreate.urls, + aliases: + toCreate.aliases + ?.split(",") + .map((a) => a.trim()) + .filter((a) => a) || [], + details: toCreate.details, + image: toCreate.image, + tag_ids: (toCreate.tags ?? []) + .filter((t) => t.stored_id) + .map((t) => t.stored_id!), + }; + + if (props.endpoint && toCreate.remote_site_id) { + input.stash_ids = [ + { + endpoint: props.endpoint, + stash_id: toCreate.remote_site_id, + }, + ]; + } + const result = await createStudio({ variables: { - input: { - name: toCreate.name, - url: toCreate.url, - }, + input, }, }); @@ -81,6 +103,7 @@ interface IUseCreateNewObjectProps { setScrapeResult: (scrapeResult: ScrapeResult) => void; newObjects: T[]; setNewObjects: (newObject: T[]) => void; + endpoint?: string; } export function useCreateScrapedPerformer( @@ -91,7 +114,7 @@ export function useCreateScrapedPerformer( const { scrapeResult, setScrapeResult, newObjects, setNewObjects } = props; async function createNewPerformer(toCreate: GQL.ScrapedPerformer) { - const input = scrapedPerformerToCreateInput(toCreate); + const input = scrapedPerformerToCreateInput(toCreate, props.endpoint); const result = await createPerformer({ variables: { input }, @@ -168,7 +191,18 @@ export function useCreateScrapedTag( const { scrapeResult, setScrapeResult, newObjects, setNewObjects } = props; async function createNewTag(toCreate: GQL.ScrapedTag) { - const input: GQL.TagCreateInput = { name: toCreate.name ?? "" }; + const input: GQL.TagCreateInput = { + name: toCreate.name ?? "", + }; + + if (props.endpoint && toCreate.remote_site_id) { + input.stash_ids = [ + { + endpoint: props.endpoint, + stash_id: toCreate.remote_site_id, + }, + ]; + } const result = await createTag({ variables: { input }, diff --git a/ui/v2.5/src/components/Shared/ScrapeDialog/scrapedTags.tsx b/ui/v2.5/src/components/Shared/ScrapeDialog/scrapedTags.tsx index 5527138d1..f298a6eeb 100644 --- a/ui/v2.5/src/components/Shared/ScrapeDialog/scrapedTags.tsx +++ b/ui/v2.5/src/components/Shared/ScrapeDialog/scrapedTags.tsx @@ -9,7 +9,8 @@ import { ScrapedTagsRow } from "./ScrapedObjectsRow"; export function useScrapedTags( existingTags: Tag[], - scrapedTags?: GQL.Maybe + scrapedTags?: GQL.Maybe, + endpoint?: string ) { const intl = useIntl(); const [tags, setTags] = useState>( @@ -33,10 +34,12 @@ export function useScrapedTags( setScrapeResult: setTags, newObjects: newTags, setNewObjects: setNewTags, + endpoint, }); const scrapedTagsRow = ( setTags(value)} diff --git a/ui/v2.5/src/components/Shared/Select.tsx b/ui/v2.5/src/components/Shared/Select.tsx index 4ae547cfe..4eea52a38 100644 --- a/ui/v2.5/src/components/Shared/Select.tsx +++ b/ui/v2.5/src/components/Shared/Select.tsx @@ -15,7 +15,7 @@ import CreatableSelect from "react-select/creatable"; import * as GQL from "src/core/generated-graphql"; import { useMarkerStrings } from "src/core/StashService"; import { SelectComponents } from "react-select/dist/declarations/src/components"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { objectTitle } from "src/core/files"; import { defaultMaxOptionsShown } from "src/core/config"; import { useDebounce } from "src/hooks/debounce"; @@ -108,7 +108,7 @@ const getSelectedItems = (selectedItems: OnChangeValue) => { const LimitedSelectMenu = ( props: MenuListProps> ) => { - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const maxOptionsShown = configuration?.ui.maxOptionsShown ?? defaultMaxOptionsShown; @@ -496,6 +496,7 @@ export const ListSelect = (props: IListSelect) => { type DisableOption = Option & { isDisabled?: boolean; + className?: string; }; interface ICheckBoxSelectProps { @@ -510,7 +511,17 @@ export const CheckBoxSelect: React.FC = ({ onChange, }) => { const Option = (props: OptionProps) => ( - + , + HTMLDivElement + > + } + > ; + +// this needs to correspond to the CSS media query that overlaps the sidebar over content +const fixedSidebarMediaQuery = "only screen and (max-width: 767px)"; export const Sidebar: React.FC< PropsWithChildren<{ @@ -54,14 +60,53 @@ export const SidebarPane: React.FC< ); }; +export const SidebarPaneContent: React.FC = ({ children }) => { + return
      {children}
      ; +}; + +interface IContext { + sectionOpen: SidebarSectionStates; + setSectionOpen: (section: string, open: boolean) => void; +} + +export const SidebarStateContext = React.createContext(null); + export const SidebarSection: React.FC< PropsWithChildren<{ text: React.ReactNode; className?: string; outsideCollapse?: React.ReactNode; onOpen?: () => void; + // used to store open/closed state in SidebarStateContext + sectionID?: string; }> -> = ({ className = "", text, outsideCollapse, onOpen, children }) => { +> = ({ + className = "", + text, + outsideCollapse, + onOpen, + sectionID = "", + children, +}) => { + // this is optional + const contextState = React.useContext(SidebarStateContext); + const openState = + !contextState || !sectionID + ? undefined + : contextState.sectionOpen[sectionID] ?? undefined; + + function onOpenInternal(open: boolean) { + if (contextState && sectionID) { + contextState.setSectionOpen(sectionID, open); + } + } + + useEffect(() => { + if (openState && onOpen) { + onOpen(); + } + }, [openState, onOpen]); + const collapseProps: Partial = { mountOnEnter: true, unmountOnExit: true, @@ -72,69 +117,27 @@ export const SidebarSection: React.FC< collapseProps={collapseProps} text={text} outsideCollapse={outsideCollapse} - onOpen={onOpen} + onOpenChanged={onOpenInternal} + open={openState} > {children} ); }; -export const SidebarIcon: React.FC = () => ( - <> - {/* From: https://iconduck.com/icons/19707/sidebar -MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. */} - - - - - -); - -export const SidebarToolbar: React.FC<{ - onClose?: () => void; -}> = ({ onClose, children }) => { +export const SidebarToggleButton: React.FC<{ + onClick: () => void; +}> = ({ onClick }) => { const intl = useIntl(); - return ( - - {onClose ? ( - - ) : null} - {children} - + ); }; @@ -146,6 +149,7 @@ export function defaultShowSidebar() { export function useSidebarState(view?: View) { const [interfaceLocalForage, setInterfaceLocalForage] = useInterfaceLocalForage(); + const history = useHistory(); const { data: interfaceLocalForageData, loading } = interfaceLocalForage; @@ -154,6 +158,7 @@ export function useSidebarState(view?: View) { }, [view, interfaceLocalForageData]); const [showSidebar, setShowSidebar] = useState(); + const [sectionOpen, setSectionOpen] = useState(); // set initial state once loading is done useEffect(() => { @@ -168,7 +173,17 @@ export function useSidebarState(view?: View) { // only show sidebar by default on large screens setShowSidebar(!!viewConfig.showSidebar && defaultShowSidebar()); - }, [view, loading, showSidebar, viewConfig.showSidebar]); + setSectionOpen( + (history.location.state as { sectionOpen?: SidebarSectionStates }) + ?.sectionOpen || {} + ); + }, [ + view, + loading, + showSidebar, + viewConfig.showSidebar, + history.location.state, + ]); const onSetShowSidebar = useCallback( (show: boolean | ((prevState: boolean | undefined) => boolean)) => { @@ -190,9 +205,28 @@ export function useSidebarState(view?: View) { [showSidebar, setInterfaceLocalForage, view, viewConfig] ); + const onSetSectionOpen = useCallback( + (section: string, open: boolean) => { + const newSectionOpen = { ...sectionOpen, [section]: open }; + setSectionOpen(newSectionOpen); + if (view === undefined) return; + + history.replace({ + ...history.location, + state: { + ...(history.location.state as {}), + sectionOpen: newSectionOpen, + }, + }); + }, + [sectionOpen, view, history] + ); + return { showSidebar: showSidebar ?? defaultShowSidebar(), + sectionOpen: sectionOpen || {}, setShowSidebar: onSetShowSidebar, + setSectionOpen: onSetSectionOpen, loading: showSidebar === undefined, }; } diff --git a/ui/v2.5/src/components/Shared/StashID.tsx b/ui/v2.5/src/components/Shared/StashID.tsx index 00bddf58e..847dd7ab2 100644 --- a/ui/v2.5/src/components/Shared/StashID.tsx +++ b/ui/v2.5/src/components/Shared/StashID.tsx @@ -1,16 +1,16 @@ import React, { useMemo } from "react"; import { StashId } from "src/core/generated-graphql"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { getStashboxBase } from "src/utils/stashbox"; import { ExternalLink } from "./ExternalLink"; -export type LinkType = "performers" | "scenes" | "studios"; +export type LinkType = "performers" | "scenes" | "studios" | "tags"; export const StashIDPill: React.FC<{ stashID: Pick; linkType: LinkType; }> = ({ stashID, linkType }) => { - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const { endpoint, stash_id } = stashID; diff --git a/ui/v2.5/src/components/Shared/TagLink.tsx b/ui/v2.5/src/components/Shared/TagLink.tsx index a59ac83cb..e572a76f8 100644 --- a/ui/v2.5/src/components/Shared/TagLink.tsx +++ b/ui/v2.5/src/components/Shared/TagLink.tsx @@ -36,7 +36,7 @@ const SortNameLinkComponent: React.FC = ({ {children} @@ -55,7 +55,7 @@ const CommonLinkComponent: React.FC = ({ children, }) => { return ( - + {children} ); diff --git a/ui/v2.5/src/components/Shared/styles.scss b/ui/v2.5/src/components/Shared/styles.scss index c80c92fdd..2da24774b 100644 --- a/ui/v2.5/src/components/Shared/styles.scss +++ b/ui/v2.5/src/components/Shared/styles.scss @@ -755,8 +755,6 @@ button.btn.favorite-button { } } -$sidebar-width: 250px; - .sidebar-pane { display: flex; @@ -774,8 +772,9 @@ $sidebar-width: 250px; .sidebar { bottom: 0; left: 0; - margin-top: 4rem; + margin-top: $navbar-height; overflow-y: auto; + padding-top: 0.5rem; position: fixed; scrollbar-gutter: stable; top: 0; @@ -787,6 +786,14 @@ $sidebar-width: 250px; margin-left: -$sidebar-width; } + &.hide-sidebar .sidebar + div { + width: 100%; + } + + &:not(.hide-sidebar) .sidebar + div { + width: calc(100% - $sidebar-width); + } + > :nth-child(2) { flex-grow: 1; padding-left: 0.5rem; @@ -798,7 +805,7 @@ $sidebar-width: 250px; } } - @include media-breakpoint-up(xl) { + @include media-breakpoint-up(md) { transition: margin-left 0.1s; &:not(.hide-sidebar) { @@ -890,8 +897,7 @@ $sticky-header-height: calc(50px + 3.3rem); padding-left: 0; position: sticky; - // sticky detail header is 50px + 3.3rem - top: calc(50px + 3.3rem); + top: calc($sticky-detail-header-height + $navbar-height); .sidebar-toolbar { padding-top: 15px; @@ -904,12 +910,12 @@ $sticky-header-height: calc(50px + 3.3rem); } // on smaller viewports we want the sidebar to overlap content - @include media-breakpoint-down(lg) { + @include media-breakpoint-down(sm) { .sidebar-pane:not(.hide-sidebar) .sidebar { margin-right: -$sidebar-width; } - .sidebar-pane > :nth-child(2) { + .sidebar-pane > .sidebar-pane-content { transition: none; } } @@ -918,7 +924,6 @@ $sticky-header-height: calc(50px + 3.3rem); flex: 100% 0 0; height: calc(100vh - 4rem); max-height: calc(100vh - 4rem); - padding-top: 0; top: 0; } @@ -930,17 +935,114 @@ $sticky-header-height: calc(50px + 3.3rem); display: none; } } - @include media-breakpoint-up(xl) { + @include media-breakpoint-up(md) { .sidebar-pane:not(.hide-sidebar) { > :nth-child(2) { margin-left: 0; } } + } - .sidebar-pane.hide-sidebar { - > :nth-child(2) { - padding-left: 15px; - } + .sidebar-pane.hide-sidebar { + > :nth-child(2) { + padding-left: 15px; } } } + +// Duration slider styles +.duration-slider-container { + padding: 0.5rem 0 1rem; + width: 100%; +} + +.double-range-input-labels { + color: $text-color; + display: flex; + font-size: 0.875rem; + font-weight: 500; + justify-content: space-between; + margin-bottom: 0.5rem; + padding: 0 0.25rem; + + input[type="text"] { + &:first-child { + text-align: left; + } + + &:last-child { + text-align: right; + } + } +} + +.double-range-sliders { + height: 22px; + position: relative; +} + +.double-range-slider { + pointer-events: none; + position: absolute; + width: 100%; + + &::-webkit-slider-thumb { + appearance: none; + background-color: $primary; + border: 2px solid $primary; + border-radius: 50%; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + cursor: pointer; + height: 18px; + pointer-events: all; + position: relative; + width: 18px; + } + + &::-moz-range-thumb { + appearance: none; + background-color: $primary; + border: 2px solid $primary; + border-radius: 50%; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + cursor: pointer; + height: 18px; + pointer-events: all; + position: relative; + width: 18px; + } + + &::-ms-thumb { + appearance: none; + background-color: $primary; + border: 2px solid $primary; + border-radius: 50%; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + cursor: pointer; + height: 18px; + pointer-events: all; + position: relative; + width: 18px; + } +} + +.double-range-slider-min { + z-index: 1; +} + +input[type="range"].double-range-slider-max { + z-index: 2; + + // combining these into one rule doesn't work for some reason + &::-webkit-slider-runnable-track { + background: transparent; + } + + &::-moz-range-track { + background: transparent; + } + + &::-ms-track { + background: transparent; + } +} diff --git a/ui/v2.5/src/components/Studios/EditStudiosDialog.tsx b/ui/v2.5/src/components/Studios/EditStudiosDialog.tsx new file mode 100644 index 000000000..293a8dfb3 --- /dev/null +++ b/ui/v2.5/src/components/Studios/EditStudiosDialog.tsx @@ -0,0 +1,245 @@ +import React, { useEffect, useMemo, useState } from "react"; +import { Col, Form, Row } from "react-bootstrap"; +import { FormattedMessage, useIntl } from "react-intl"; +import { useBulkStudioUpdate } from "src/core/StashService"; +import * as GQL from "src/core/generated-graphql"; +import { ModalComponent } from "../Shared/Modal"; +import { useToast } from "src/hooks/Toast"; +import { MultiSet } from "../Shared/MultiSet"; +import { RatingSystem } from "../Shared/Rating/RatingSystem"; +import { + getAggregateInputValue, + getAggregateState, + getAggregateStateObject, +} from "src/utils/bulkUpdate"; +import { IndeterminateCheckbox } from "../Shared/IndeterminateCheckbox"; +import { BulkUpdateTextInput } from "../Shared/BulkUpdateTextInput"; +import { faPencilAlt } from "@fortawesome/free-solid-svg-icons"; +import * as FormUtils from "src/utils/form"; +import { StudioSelect } from "../Shared/Select"; + +interface IListOperationProps { + selected: GQL.SlimStudioDataFragment[]; + onClose: (applied: boolean) => void; +} + +const studioFields = ["favorite", "rating100", "details", "ignore_auto_tag"]; + +export const EditStudiosDialog: React.FC = ( + props: IListOperationProps +) => { + const intl = useIntl(); + const Toast = useToast(); + + const [updateInput, setUpdateInput] = useState({ + ids: props.selected.map((studio) => { + return studio.id; + }), + }); + + const [tagIds, setTagIds] = useState({ + mode: GQL.BulkUpdateIdMode.Add, + }); + + const [updateStudios] = useBulkStudioUpdate(); + + // Network state + const [isUpdating, setIsUpdating] = useState(false); + + const aggregateState = useMemo(() => { + const updateState: Partial = {}; + const state = props.selected; + let updateTagIds: string[] = []; + let first = true; + + state.forEach((studio: GQL.SlimStudioDataFragment) => { + getAggregateStateObject(updateState, studio, studioFields, first); + + // studio data fragment doesn't have parent_id, so handle separately + updateState.parent_id = getAggregateState( + updateState.parent_id, + studio.parent_studio?.id, + first + ); + + const studioTagIDs = (studio.tags ?? []).map((p) => p.id).sort(); + + updateTagIds = getAggregateState(updateTagIds, studioTagIDs, first) ?? []; + + first = false; + }); + + return { state: updateState, tagIds: updateTagIds }; + }, [props.selected]); + + // update initial state from aggregate + useEffect(() => { + setUpdateInput((current) => ({ ...current, ...aggregateState.state })); + }, [aggregateState]); + + function setUpdateField(input: Partial) { + setUpdateInput((current) => ({ ...current, ...input })); + } + + function getStudioInput(): GQL.BulkStudioUpdateInput { + const studioInput: GQL.BulkStudioUpdateInput = { + ...updateInput, + tag_ids: tagIds, + }; + + // we don't have unset functionality for the rating star control + // so need to determine if we are setting a rating or not + studioInput.rating100 = getAggregateInputValue( + updateInput.rating100, + aggregateState.state.rating100 + ); + + return studioInput; + } + + async function onSave() { + setIsUpdating(true); + try { + await updateStudios({ + variables: { + input: getStudioInput(), + }, + }); + Toast.success( + intl.formatMessage( + { id: "toast.updated_entity" }, + { + entity: intl.formatMessage({ id: "studios" }).toLocaleLowerCase(), + } + ) + ); + props.onClose(true); + } catch (e) { + Toast.error(e); + } + setIsUpdating(false); + } + + function renderTextField( + name: string, + value: string | undefined | null, + setter: (newValue: string | undefined) => void, + area: boolean = false + ) { + return ( + + + + + setter(newValue)} + unsetDisabled={props.selected.length < 2} + as={area ? "textarea" : undefined} + /> + + ); + } + + function render() { + return ( + props.onClose(false), + text: intl.formatMessage({ id: "actions.cancel" }), + variant: "secondary", + }} + isRunning={isUpdating} + > + + {FormUtils.renderLabel({ + title: intl.formatMessage({ id: "parent_studio" }), + })} + + + setUpdateField({ + parent_id: items.length > 0 ? items[0]?.id : undefined, + }) + } + ids={updateInput.parent_id ? [updateInput.parent_id] : []} + isDisabled={isUpdating} + menuPortalTarget={document.body} + /> + + + + {FormUtils.renderLabel({ + title: intl.formatMessage({ id: "rating" }), + })} + + + setUpdateField({ rating100: value ?? undefined }) + } + disabled={isUpdating} + /> + + + + + setUpdateField({ favorite: checked })} + checked={updateInput.favorite ?? undefined} + label={intl.formatMessage({ id: "favourite" })} + /> + + + + + + + setTagIds((v) => ({ ...v, ids: itemIDs }))} + onSetMode={(newMode) => + setTagIds((v) => ({ ...v, mode: newMode })) + } + existingIds={aggregateState.tagIds ?? []} + ids={tagIds.ids ?? []} + mode={tagIds.mode} + menuPortalTarget={document.body} + /> + + + {renderTextField( + "details", + updateInput.details, + (newValue) => setUpdateField({ details: newValue }), + true + )} + + + + setUpdateField({ ignore_auto_tag: checked }) + } + checked={updateInput.ignore_auto_tag ?? undefined} + /> + + + + ); + } + + return render(); +}; diff --git a/ui/v2.5/src/components/Studios/StudioCard.tsx b/ui/v2.5/src/components/Studios/StudioCard.tsx index 5cd1cc209..01b2b5c5a 100644 --- a/ui/v2.5/src/components/Studios/StudioCard.tsx +++ b/ui/v2.5/src/components/Studios/StudioCard.tsx @@ -13,6 +13,7 @@ import { RatingBanner } from "../Shared/RatingBanner"; import { FavoriteIcon } from "../Shared/FavoriteIcon"; import { useStudioUpdate } from "src/core/StashService"; import { faTag } from "@fortawesome/free-solid-svg-icons"; +import { OCounterButton } from "../Shared/CountButton"; interface IProps { studio: GQL.StudioDataFragment; @@ -175,6 +176,12 @@ export const StudioCard: React.FC = ({ ); } + function maybeRenderOCounter() { + if (!studio.o_counter) return; + + return ; + } + function maybeRenderPopoverButtonGroup() { if ( studio.scene_count || @@ -182,6 +189,7 @@ export const StudioCard: React.FC = ({ studio.gallery_count || studio.group_count || studio.performer_count || + studio.o_counter || studio.tags.length > 0 ) { return ( @@ -194,6 +202,7 @@ export const StudioCard: React.FC = ({ {maybeRenderGalleriesPopoverButton()} {maybeRenderPerformersPopoverButton()} {maybeRenderTagPopoverButton()} + {maybeRenderOCounter()} ); diff --git a/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx b/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx index 2140af340..2edc53fe1 100644 --- a/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx +++ b/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx @@ -18,7 +18,7 @@ import { ModalComponent } from "src/components/Shared/Modal"; import { LoadingIndicator } from "src/components/Shared/LoadingIndicator"; import { ErrorMessage } from "src/components/Shared/ErrorMessage"; import { useToast } from "src/hooks/Toast"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { StudioScenesPanel } from "./StudioScenesPanel"; import { StudioGalleriesPanel } from "./StudioGalleriesPanel"; import { StudioImagesPanel } from "./StudioImagesPanel"; @@ -47,6 +47,8 @@ import { FavoriteIcon } from "src/components/Shared/FavoriteIcon"; import { ExternalLinkButtons } from "src/components/Shared/ExternalLinksButton"; import { AliasList } from "src/components/Shared/DetailsPage/AliasList"; import { HeaderImage } from "src/components/Shared/DetailsPage/HeaderImage"; +import { goBackOrReplace } from "src/utils/history"; +import { OCounterButton } from "src/components/Shared/CountButton"; interface IProps { studio: GQL.StudioDataFragment; @@ -263,7 +265,7 @@ const StudioPage: React.FC = ({ studio, tabKey }) => { const intl = useIntl(); // Configuration settings - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const uiConfig = configuration?.ui; const abbreviateCounter = uiConfig?.abbreviateCounters ?? false; const enableBackgroundImage = uiConfig?.enableStudioBackgroundImage ?? false; @@ -286,11 +288,6 @@ const StudioPage: React.FC = ({ studio, tabKey }) => { const showAllCounts = uiConfig?.showChildStudioContent; - // make array of url so that it doesn't re-render on every change - const urls = useMemo(() => { - return studio?.url ? [studio.url] : []; - }, [studio.url]); - const studioImage = useMemo(() => { const existingPath = studio.image_path; if (isEditing) { @@ -378,7 +375,7 @@ const StudioPage: React.FC = ({ studio, tabKey }) => { return; } - history.goBack(); + goBackOrReplace(history, "/studios"); } function renderDeleteAlert() { @@ -470,17 +467,22 @@ const StudioPage: React.FC = ({ studio, tabKey }) => { favorite={studio.favorite} onToggleFavorite={(v) => setFavorite(v)} /> - + - setRating(value)} - clickToRate - withoutContext - /> +
      + setRating(value)} + clickToRate + withoutContext + /> + {!!studio.o_counter && ( + + )} +
      {!isEditing && ( = ({ ); } + function renderURLs() { + if (!studio.urls?.length) { + return; + } + + return ( +
        + {studio.urls.map((url) => ( +
      • + + {url} + +
      • + ))} +
      + ); + } + return (
      + = ({ const schema = yup.object({ name: yup.string().required(), - url: yup.string().ensure(), + urls: yup.array(yup.string().required()).defined(), details: yup.string().ensure(), parent_id: yup.string().required().nullable(), aliases: yupUniqueAliases(intl, "name"), @@ -60,7 +60,7 @@ export const StudioEditPanel: React.FC = ({ const initialValues = { id: studio.id, name: studio.name ?? "", - url: studio.url ?? "", + urls: studio.urls ?? [], details: studio.details ?? "", parent_id: studio.parent_studio?.id ?? null, aliases: studio.aliases ?? [], @@ -187,7 +187,7 @@ export const StudioEditPanel: React.FC = ({
      {renderInputField("name")} {renderStringListField("aliases")} - {renderInputField("url")} + {renderStringListField("urls")} {renderInputField("details", "textarea")} {renderParentStudioField()} {renderTagsField()} diff --git a/ui/v2.5/src/components/Studios/StudioList.tsx b/ui/v2.5/src/components/Studios/StudioList.tsx index dd67f560b..e548467a1 100644 --- a/ui/v2.5/src/components/Studios/StudioList.tsx +++ b/ui/v2.5/src/components/Studios/StudioList.tsx @@ -17,6 +17,7 @@ import { DeleteEntityDialog } from "../Shared/DeleteEntityDialog"; import { StudioTagger } from "../Tagger/studios/StudioTagger"; import { StudioCardGrid } from "./StudioCardGrid"; import { View } from "../List/views"; +import { EditStudiosDialog } from "./EditStudiosDialog"; function getItems(result: GQL.FindStudiosQueryResult) { return result?.data?.findStudios?.studios ?? []; @@ -161,6 +162,13 @@ export const StudioList: React.FC = ({ ); } + function renderEditDialog( + selectedStudios: GQL.SlimStudioDataFragment[], + onClose: (applied: boolean) => void + ) { + return ; + } + function renderDeleteDialog( selectedStudios: GQL.SlimStudioDataFragment[], onClose: (confirmed: boolean) => void @@ -188,11 +196,11 @@ export const StudioList: React.FC = ({ selectable > diff --git a/ui/v2.5/src/components/Studios/StudioSelect.tsx b/ui/v2.5/src/components/Studios/StudioSelect.tsx index 7b22b7f22..7305aa60d 100644 --- a/ui/v2.5/src/components/Studios/StudioSelect.tsx +++ b/ui/v2.5/src/components/Studios/StudioSelect.tsx @@ -13,7 +13,7 @@ import { queryFindStudiosByIDForSelect, queryFindStudiosForSelect, } from "src/core/StashService"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { useIntl } from "react-intl"; import { defaultMaxOptionsShown, IUIConfig } from "src/core/config"; import { ListFilterModel } from "src/models/list-filter/filter"; @@ -65,12 +65,12 @@ const _StudioSelect: React.FC< > = (props) => { const [createStudio] = useStudioCreate(); - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const intl = useIntl(); const maxOptionsShown = (configuration?.ui as IUIConfig).maxOptionsShown ?? defaultMaxOptionsShown; const defaultCreatable = - !configuration?.interface.disableDropdownCreate.studio ?? true; + !configuration?.interface.disableDropdownCreate.studio; const exclude = useMemo(() => props.excludeIds ?? [], [props.excludeIds]); diff --git a/ui/v2.5/src/components/Studios/styles.scss b/ui/v2.5/src/components/Studios/styles.scss index eaab21d10..0526902b7 100644 --- a/ui/v2.5/src/components/Studios/styles.scss +++ b/ui/v2.5/src/components/Studios/styles.scss @@ -41,6 +41,27 @@ width: auto; } + .quality-group { + display: inline-flex; + margin-top: 0.25rem; + } + + // The following min-width declarations prevent + // the O-Count from moving around + // when hovering over rating stars + .rating-stars-precision-full .star-rating-number { + min-width: 0.75rem; + } + + .rating-stars-precision-half .star-rating-number, + .rating-stars-precision-tenth .star-rating-number { + min-width: 1.45rem; + } + + .rating-stars-precision-quarter .star-rating-number { + min-width: 2rem; + } + // the detail element ids are the same as field type name // which don't follow the correct convention /* stylelint-disable selector-class-pattern */ @@ -49,5 +70,9 @@ display: none; } } + + .detail-item.urls ul { + list-style-type: none; + } /* stylelint-enable selector-class-pattern */ } diff --git a/ui/v2.5/src/components/Tagger/config.ts b/ui/v2.5/src/components/Tagger/config.ts index 78515f550..c30db7da2 100644 --- a/ui/v2.5/src/components/Tagger/config.ts +++ b/ui/v2.5/src/components/Tagger/config.ts @@ -1,10 +1,10 @@ -import { useCallback, useContext } from "react"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useCallback } from "react"; +import { useConfigurationContext } from "src/hooks/Config"; import { initialConfig, ITaggerConfig } from "./constants"; import { useConfigureUISetting } from "src/core/StashService"; export function useTaggerConfig() { - const { configuration: stashConfig } = useContext(ConfigurationContext); + const { configuration: stashConfig } = useConfigurationContext(); const [saveUISetting] = useConfigureUISetting(); const config = stashConfig?.ui.taggerConfig ?? initialConfig; diff --git a/ui/v2.5/src/components/Tagger/context.tsx b/ui/v2.5/src/components/Tagger/context.tsx index 9b1e996de..8557cc94a 100644 --- a/ui/v2.5/src/components/Tagger/context.tsx +++ b/ui/v2.5/src/components/Tagger/context.tsx @@ -17,7 +17,7 @@ import { useTagCreate, } from "src/core/StashService"; import { useToast } from "src/hooks/Toast"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { ITaggerSource, SCRAPER_PREFIX, STASH_BOX_PREFIX } from "./constants"; import { errorToString } from "src/utils"; import { mergeStudioStashIDs } from "./utils"; @@ -117,7 +117,7 @@ export const TaggerContext: React.FC = ({ children }) => { const stopping = useRef(false); - const { configuration: stashConfig } = React.useContext(ConfigurationContext); + const { configuration: stashConfig } = useConfigurationContext(); const { config, setConfig } = useTaggerConfig(); const Scrapers = useListSceneScrapers(); @@ -173,16 +173,41 @@ export const TaggerContext: React.FC = ({ children }) => { setSources(stashboxSources.concat(scraperSources)); }, [Scrapers.data, stashConfig]); + // set the current source on load useEffect(() => { - if (sources.length && !currentSource) { - setCurrentSource(sources[0]); + if (!sources.length || currentSource) { + return; } - }, [sources, currentSource]); + // First, see if we have a saved endpoint. + if (config.selectedEndpoint) { + let source = sources.find( + (s) => s.sourceInput.stash_box_endpoint == config.selectedEndpoint + ); + if (source) { + setCurrentSource(source); + return; + } + } + // Otherwise, just use the first source. + setCurrentSource(sources[0]); + }, [sources, currentSource, config]); + // clear the search results when the source changes useEffect(() => { setSearchResults({}); }, [currentSource]); + // keep selected endpoint in config in sync with current source + useEffect(() => { + const selectedEndpoint = currentSource?.sourceInput.stash_box_endpoint; + if (selectedEndpoint && selectedEndpoint !== config.selectedEndpoint) { + setConfig({ + ...config, + selectedEndpoint, + }); + } + }, [currentSource, config, setConfig]); + function getPendingFingerprints() { const endpoint = currentSource?.sourceInput.stash_box_endpoint; if (!config || !endpoint) return []; @@ -568,7 +593,12 @@ export const TaggerContext: React.FC = ({ children }) => { return { ...r, performers: r.performers.map((p) => { - if (p.name === performer.name) { + // Match by remote_site_id if available, otherwise fall back to name + const matches = performer.remote_site_id + ? p.remote_site_id === performer.remote_site_id + : p.name === performer.name; + + if (matches) { return { ...p, stored_id: performerID, @@ -680,15 +710,28 @@ export const TaggerContext: React.FC = ({ children }) => { return r; } + let resultStudio = r.studio; + if (resultStudio.name === studio.name) { + resultStudio = { + ...resultStudio, + stored_id: studioID, + }; + } + + // #5821 - set the stored_id of the parent studio if it matches too + if (resultStudio.parent?.name === studio.name) { + resultStudio = { + ...resultStudio, + parent: { + ...resultStudio.parent, + stored_id: studioID, + }, + }; + } + return { ...r, - studio: - r.studio.name === studio.name - ? { - ...r.studio, - stored_id: studioID, - } - : r.studio, + studio: resultStudio, }; }); diff --git a/ui/v2.5/src/components/Tagger/performers/Config.tsx b/ui/v2.5/src/components/Tagger/performers/Config.tsx index a839e1ae6..0d5316735 100644 --- a/ui/v2.5/src/components/Tagger/performers/Config.tsx +++ b/ui/v2.5/src/components/Tagger/performers/Config.tsx @@ -1,7 +1,7 @@ import React, { Dispatch, useState } from "react"; import { Badge, Button, Card, Collapse, Form } from "react-bootstrap"; import { FormattedMessage } from "react-intl"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { ITaggerConfig } from "../constants"; import PerformerFieldSelector from "../PerformerFieldSelector"; @@ -13,7 +13,7 @@ interface IConfigProps { } const Config: React.FC = ({ show, config, setConfig }) => { - const { configuration: stashConfig } = React.useContext(ConfigurationContext); + const { configuration: stashConfig } = useConfigurationContext(); const [showExclusionModal, setShowExclusionModal] = useState(false); const excludedFields = config.excludedPerformerFields ?? []; diff --git a/ui/v2.5/src/components/Tagger/performers/PerformerTagger.tsx b/ui/v2.5/src/components/Tagger/performers/PerformerTagger.tsx index f0c87ff57..a6e2bcd1c 100755 --- a/ui/v2.5/src/components/Tagger/performers/PerformerTagger.tsx +++ b/ui/v2.5/src/components/Tagger/performers/PerformerTagger.tsx @@ -16,7 +16,7 @@ import { performerMutationImpactedQueries, } from "src/core/StashService"; import { Manual } from "src/components/Help/Manual"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import StashSearchResult from "./StashSearchResult"; import PerformerConfig from "./Config"; @@ -620,7 +620,7 @@ interface ITaggerProps { export const PerformerTagger: React.FC = ({ performers }) => { const jobsSubscribe = useJobsSubscribe(); const intl = useIntl(); - const { configuration: stashConfig } = React.useContext(ConfigurationContext); + const { configuration: stashConfig } = useConfigurationContext(); const { config, setConfig } = useTaggerConfig(); const [showConfig, setShowConfig] = useState(false); const [showManual, setShowManual] = useState(false); diff --git a/ui/v2.5/src/components/Tagger/scenes/SceneTagger.tsx b/ui/v2.5/src/components/Tagger/scenes/SceneTagger.tsx index 922ecc473..34c86e57c 100755 --- a/ui/v2.5/src/components/Tagger/scenes/SceneTagger.tsx +++ b/ui/v2.5/src/components/Tagger/scenes/SceneTagger.tsx @@ -12,7 +12,7 @@ import Config from "./Config"; import { TaggerScene } from "./TaggerScene"; import { SceneTaggerModals } from "./sceneTaggerModals"; import { SceneSearchResults } from "./StashSearchResult"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { faCog } from "@fortawesome/free-solid-svg-icons"; import { useLightbox } from "src/hooks/Lightbox/hooks"; @@ -26,7 +26,7 @@ const Scene: React.FC<{ const intl = useIntl(); const { currentSource, doSceneQuery, doSceneFragmentScrape, loading } = useContext(TaggerStateContext); - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const cont = configuration?.interface.continuePlaylistDefault ?? false; @@ -211,6 +211,10 @@ export const Tagger: React.FC = ({ scenes, queue }) => { return; } + if (scenes.length === 0) { + return; + } + if (loadingMulti) { return ( + )} + + : + +
      +
      +
        + {text.map((t, i) => ( +
      • + + {truncate ? : t} + +
      • + ))} +
      +
      +
      + ); + } + function maybeRenderStashBoxLink() { if (!link) return; @@ -103,7 +141,10 @@ const StudioDetails: React.FC = ({
      {maybeRenderField("name", studio.name, !isNew)} - {maybeRenderField("url", studio.url)} + {maybeRenderURLListField("urls", studio.urls)} + {maybeRenderField("details", studio.details)} + {maybeRenderField("aliases", studio.aliases)} + {maybeRenderField("tags", studio.tags?.map((t) => t.name).join(", "))} {maybeRenderField("parent_studio", studio.parent?.name, false)} {maybeRenderStashBoxLink()}
      @@ -191,9 +232,17 @@ const StudioModal: React.FC = ({ const studioData: GQL.StudioCreateInput = { name: studio.name, - url: studio.url, + urls: studio.urls, image: studio.image, parent_id: studio.parent?.stored_id, + details: studio.details, + aliases: studio.aliases + ?.split(",") + .map((a) => a.trim()) + .filter((a) => a), + tag_ids: studio.tags?.map((t) => t.stored_id).filter((id) => id) as + | string[] + | undefined, }; // stashid handling code @@ -221,8 +270,16 @@ const StudioModal: React.FC = ({ parentData = { name: studio.parent?.name, - url: studio.parent?.url, + urls: studio.parent?.urls, image: studio.parent?.image, + details: studio.parent?.details, + aliases: studio.parent?.aliases + ?.split(",") + .map((a) => a.trim()) + .filter((a) => a), + tag_ids: studio.parent?.tags + ?.map((t) => t.stored_id) + .filter((id) => id) as string[] | undefined, }; // stashid handling code diff --git a/ui/v2.5/src/components/Tagger/scenes/TaggerScene.tsx b/ui/v2.5/src/components/Tagger/scenes/TaggerScene.tsx index db36bf404..4825ebcfd 100644 --- a/ui/v2.5/src/components/Tagger/scenes/TaggerScene.tsx +++ b/ui/v2.5/src/components/Tagger/scenes/TaggerScene.tsx @@ -19,7 +19,7 @@ import { faImage, } from "@fortawesome/free-solid-svg-icons"; import { objectPath, objectTitle } from "src/core/files"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { SceneQueue } from "src/models/sceneQueue"; interface ITaggerSceneDetails { @@ -154,7 +154,7 @@ export const TaggerScene: React.FC> = ({ const history = useHistory(); - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const cont = configuration?.interface.continuePlaylistDefault ?? false; async function query() { diff --git a/ui/v2.5/src/components/Tagger/studios/Config.tsx b/ui/v2.5/src/components/Tagger/studios/Config.tsx index 9dd9f6856..ddfd17b1e 100644 --- a/ui/v2.5/src/components/Tagger/studios/Config.tsx +++ b/ui/v2.5/src/components/Tagger/studios/Config.tsx @@ -1,7 +1,7 @@ import React, { Dispatch, useState } from "react"; import { Badge, Button, Card, Collapse, Form } from "react-bootstrap"; import { FormattedMessage } from "react-intl"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { ITaggerConfig } from "../constants"; import StudioFieldSelector from "./StudioFieldSelector"; @@ -13,7 +13,7 @@ interface IConfigProps { } const Config: React.FC = ({ show, config, setConfig }) => { - const { configuration: stashConfig } = React.useContext(ConfigurationContext); + const { configuration: stashConfig } = useConfigurationContext(); const [showExclusionModal, setShowExclusionModal] = useState(false); const excludedFields = config.excludedStudioFields ?? []; diff --git a/ui/v2.5/src/components/Tagger/studios/StudioTagger.tsx b/ui/v2.5/src/components/Tagger/studios/StudioTagger.tsx index b8fbefdb5..78553e518 100644 --- a/ui/v2.5/src/components/Tagger/studios/StudioTagger.tsx +++ b/ui/v2.5/src/components/Tagger/studios/StudioTagger.tsx @@ -17,7 +17,7 @@ import { evictQueries, } from "src/core/StashService"; import { Manual } from "src/components/Help/Manual"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import StashSearchResult from "./StashSearchResult"; import StudioConfig from "./Config"; @@ -669,7 +669,7 @@ interface ITaggerProps { export const StudioTagger: React.FC = ({ studios }) => { const jobsSubscribe = useJobsSubscribe(); const intl = useIntl(); - const { configuration: stashConfig } = React.useContext(ConfigurationContext); + const { configuration: stashConfig } = useConfigurationContext(); const { config, setConfig } = useTaggerConfig(); const [showConfig, setShowConfig] = useState(false); const [showManual, setShowManual] = useState(false); diff --git a/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx b/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx index 7cded1934..e0bc11e37 100644 --- a/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx +++ b/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx @@ -19,7 +19,7 @@ import { ModalComponent } from "src/components/Shared/Modal"; import { LoadingIndicator } from "src/components/Shared/LoadingIndicator"; import { Icon } from "src/components/Shared/Icon"; import { useToast } from "src/hooks/Toast"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { tagRelationHook } from "src/core/tags"; import { TagScenesPanel } from "./TagScenesPanel"; import { TagMarkersPanel } from "./TagMarkersPanel"; @@ -49,6 +49,7 @@ import { ExpandCollapseButton } from "src/components/Shared/CollapseButton"; import { FavoriteIcon } from "src/components/Shared/FavoriteIcon"; import { AliasList } from "src/components/Shared/DetailsPage/AliasList"; import { HeaderImage } from "src/components/Shared/DetailsPage/HeaderImage"; +import { goBackOrReplace } from "src/utils/history"; interface IProps { tag: GQL.TagDataFragment; @@ -292,7 +293,7 @@ const TagPage: React.FC = ({ tag, tabKey }) => { const intl = useIntl(); // Configuration settings - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const uiConfig = configuration?.ui; const abbreviateCounter = uiConfig?.abbreviateCounters ?? false; const enableBackgroundImage = uiConfig?.enableTagBackgroundImage ?? false; @@ -420,7 +421,7 @@ const TagPage: React.FC = ({ tag, tabKey }) => { return; } - history.goBack(); + goBackOrReplace(history, "/tags"); } function renderDeleteAlert() { diff --git a/ui/v2.5/src/components/Tags/TagDetails/TagDetailsPanel.tsx b/ui/v2.5/src/components/Tags/TagDetails/TagDetailsPanel.tsx index 9e368aa8b..92c92d072 100644 --- a/ui/v2.5/src/components/Tags/TagDetails/TagDetailsPanel.tsx +++ b/ui/v2.5/src/components/Tags/TagDetails/TagDetailsPanel.tsx @@ -1,6 +1,7 @@ import React from "react"; import { TagLink } from "src/components/Shared/TagLink"; import { DetailItem } from "src/components/Shared/DetailItem"; +import { StashIDPill } from "src/components/Shared/StashID"; import * as GQL from "src/core/generated-graphql"; interface ITagDetails { @@ -51,6 +52,22 @@ export const TagDetailsPanel: React.FC = ({ tag, fullWidth }) => { ); } + function renderStashIDs() { + if (!tag.stash_ids?.length) { + return; + } + + return ( +
        + {tag.stash_ids.map((stashID) => ( +
      • + +
      • + ))} +
      + ); + } + return (
      = ({ tag, fullWidth }) => { value={renderChildrenField()} fullWidth={fullWidth} /> +
      ); }; diff --git a/ui/v2.5/src/components/Tags/TagDetails/TagEditPanel.tsx b/ui/v2.5/src/components/Tags/TagDetails/TagEditPanel.tsx index da79b6c4e..41756953b 100644 --- a/ui/v2.5/src/components/Tags/TagDetails/TagEditPanel.tsx +++ b/ui/v2.5/src/components/Tags/TagDetails/TagEditPanel.tsx @@ -14,6 +14,7 @@ import { useToast } from "src/hooks/Toast"; import { handleUnsavedChanges } from "src/utils/navigation"; import { formikUtils } from "src/utils/form"; import { yupFormikValidate, yupUniqueAliases } from "src/utils/yup"; +import { getStashIDs } from "src/utils/stashIds"; import { Tag, TagSelect } from "../TagSelect"; interface ITagEditPanel { @@ -52,6 +53,7 @@ export const TagEditPanel: React.FC = ({ parent_ids: yup.array(yup.string().required()).defined(), child_ids: yup.array(yup.string().required()).defined(), ignore_auto_tag: yup.boolean().defined(), + stash_ids: yup.mixed().defined(), image: yup.string().nullable().optional(), }); @@ -63,6 +65,7 @@ export const TagEditPanel: React.FC = ({ parent_ids: (tag?.parents ?? []).map((t) => t.id), child_ids: (tag?.children ?? []).map((t) => t.id), ignore_auto_tag: tag?.ignore_auto_tag ?? false, + stash_ids: getStashIDs(tag?.stash_ids), }; type InputValues = yup.InferType; @@ -140,10 +143,12 @@ export const TagEditPanel: React.FC = ({ ImageUtils.onImageChange(event, onImageLoad); } - const { renderField, renderInputField, renderStringListField } = formikUtils( - intl, - formik - ); + const { + renderField, + renderInputField, + renderStringListField, + renderStashIDsField, + } = formikUtils(intl, formik); function renderParentTagsField() { const title = intl.formatMessage({ id: "parent_tags" }); @@ -210,6 +215,7 @@ export const TagEditPanel: React.FC = ({ {renderInputField("description", "textarea")} {renderParentTagsField()} {renderSubTagsField()} + {renderStashIDsField("stash_ids", "tags")}
      {renderInputField("ignore_auto_tag", "checkbox")} diff --git a/ui/v2.5/src/components/Tags/TagList.tsx b/ui/v2.5/src/components/Tags/TagList.tsx index cbde60a5c..ca866bbb9 100644 --- a/ui/v2.5/src/components/Tags/TagList.tsx +++ b/ui/v2.5/src/components/Tags/TagList.tsx @@ -367,7 +367,6 @@ export const TagList: React.FC = ({ filterHook, alterQuery }) => { > = ({ placement = "top", target, }) => { - const { configuration: config } = React.useContext(ConfigurationContext); + const { configuration: config } = useConfigurationContext(); const showTagCardOnHover = config?.ui.showTagCardOnHover ?? true; diff --git a/ui/v2.5/src/components/Tags/TagSelect.tsx b/ui/v2.5/src/components/Tags/TagSelect.tsx index 2f6fb9a3e..5b8da7a6d 100644 --- a/ui/v2.5/src/components/Tags/TagSelect.tsx +++ b/ui/v2.5/src/components/Tags/TagSelect.tsx @@ -13,7 +13,7 @@ import { queryFindTagsByIDForSelect, queryFindTagsForSelect, } from "src/core/StashService"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { useIntl } from "react-intl"; import { defaultMaxOptionsShown } from "src/core/config"; import { ListFilterModel } from "src/models/list-filter/filter"; @@ -67,12 +67,11 @@ export type TagSelectProps = IFilterProps & const _TagSelect: React.FC = (props) => { const [createTag] = useTagCreate(); - const { configuration } = React.useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const intl = useIntl(); const maxOptionsShown = configuration?.ui.maxOptionsShown ?? defaultMaxOptionsShown; - const defaultCreatable = - !configuration?.interface.disableDropdownCreate.tag ?? true; + const defaultCreatable = !configuration?.interface.disableDropdownCreate.tag; const exclude = useMemo(() => props.excludeIds ?? [], [props.excludeIds]); diff --git a/ui/v2.5/src/components/Wall/WallItem.tsx b/ui/v2.5/src/components/Wall/WallItem.tsx index 5811b7543..959ac1617 100644 --- a/ui/v2.5/src/components/Wall/WallItem.tsx +++ b/ui/v2.5/src/components/Wall/WallItem.tsx @@ -12,7 +12,7 @@ import TextUtils from "src/utils/text"; import NavUtils from "src/utils/navigation"; import cx from "classnames"; import { SceneQueue } from "src/models/sceneQueue"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { markerTitle } from "src/core/markers"; import { objectTitle } from "src/core/files"; @@ -128,7 +128,7 @@ export const WallItem = ({ }: IWallItemProps) => { const [active, setActive] = useState(false); const itemEl = useRef(null); - const { configuration: config } = React.useContext(ConfigurationContext); + const { configuration: config } = useConfigurationContext(); const showTextContainer = config?.interface.wallShowTitle ?? true; diff --git a/ui/v2.5/src/core/StashService.ts b/ui/v2.5/src/core/StashService.ts index a7679a5d5..100f25199 100644 --- a/ui/v2.5/src/core/StashService.ts +++ b/ui/v2.5/src/core/StashService.ts @@ -1486,6 +1486,16 @@ export const useSceneMarkerUpdate = () => }, }); +export const useBulkSceneMarkerUpdate = () => + GQL.useBulkSceneMarkerUpdateMutation({ + update(cache, result) { + if (!result.data?.bulkSceneMarkerUpdate) return; + + evictTypeFields(cache, sceneMarkerMutationImpactedTypeFields); + evictQueries(cache, sceneMarkerMutationImpactedQueries); + }, + }); + export const useSceneMarkerDestroy = () => GQL.useSceneMarkerDestroyMutation({ update(cache, result, { variables }) { @@ -1613,17 +1623,30 @@ export const mutateAddGalleryImages = (input: GQL.GalleryAddInput) => }, }); +function evictCover(cache: ApolloCache, gallery_id: string) { + const fields: Partial, "paths" | "cover">> = {}; + fields.paths = (paths) => { + if (!("cover" in paths)) { + return paths; + } + const coverUrl = new URL(paths.cover); + coverUrl.search = "?t=" + Math.floor(Date.now() / 1000); + return { ...paths, cover: coverUrl.toString() }; + }; + fields.cover = (_value, { DELETE }) => DELETE; + cache.modify({ + id: cache.identify({ __typename: "Gallery", id: gallery_id }), + fields, + }); +} + export const mutateSetGalleryCover = (input: GQL.GallerySetCoverInput) => client.mutate({ mutation: GQL.SetGalleryCoverDocument, variables: input, update(cache, result) { if (!result.data?.setGalleryCover) return; - - cache.evict({ - id: cache.identify({ __typename: "Gallery", id: input.gallery_id }), - fieldName: "cover", - }); + evictCover(cache, input.gallery_id); }, }); @@ -1633,11 +1656,7 @@ export const mutateResetGalleryCover = (input: GQL.GalleryResetCoverInput) => variables: input, update(cache, result) { if (!result.data?.resetGalleryCover) return; - - cache.evict({ - id: cache.identify({ __typename: "Gallery", id: input.gallery_id }), - fieldName: "cover", - }); + evictCover(cache, input.gallery_id); }, }); @@ -1898,6 +1917,16 @@ export const useStudioUpdate = () => }, }); +export const useBulkStudioUpdate = () => + GQL.useBulkStudioUpdateMutation({ + update(cache, result) { + if (!result.data?.bulkStudioUpdate) return; + + evictTypeFields(cache, studioMutationImpactedTypeFields); + evictQueries(cache, studioMutationImpactedQueries); + }, + }); + export const useStudioDestroy = (input: GQL.StudioDestroyInput) => GQL.useStudioDestroyMutation({ variables: input, diff --git a/ui/v2.5/src/core/config.ts b/ui/v2.5/src/core/config.ts index c1aa404f2..36d915eeb 100644 --- a/ui/v2.5/src/core/config.ts +++ b/ui/v2.5/src/core/config.ts @@ -45,6 +45,7 @@ export interface IUIConfig { showChildTagContent?: boolean; showChildStudioContent?: boolean; + showLinksOnPerformerCard?: boolean; showTagCardOnHover?: boolean; abbreviateCounters?: boolean; @@ -165,5 +166,6 @@ export function generatePremadeFrontPageContent(intl: IntlShape) { recentlyAdded(intl, FilterMode.Groups, "groups"), recentlyAdded(intl, FilterMode.Studios, "studios"), recentlyAdded(intl, FilterMode.Performers, "performers"), + recentlyAdded(intl, FilterMode.SceneMarkers, "markers"), ]; } diff --git a/ui/v2.5/src/core/files.ts b/ui/v2.5/src/core/files.ts index d17d34d16..b90d10193 100644 --- a/ui/v2.5/src/core/files.ts +++ b/ui/v2.5/src/core/files.ts @@ -6,7 +6,7 @@ export interface IFile { } interface IObjectWithFiles { - files?: IFile[]; + files?: GQL.Maybe; } export interface IObjectWithTitleFiles extends IObjectWithFiles { diff --git a/ui/v2.5/src/core/galleries.ts b/ui/v2.5/src/core/galleries.ts index bedc2453e..722ba8d3b 100644 --- a/ui/v2.5/src/core/galleries.ts +++ b/ui/v2.5/src/core/galleries.ts @@ -6,7 +6,7 @@ interface IFile { } interface IGallery { - files: IFile[]; + files: GQL.Maybe; folder?: GQL.Maybe; } diff --git a/ui/v2.5/src/core/performers.ts b/ui/v2.5/src/core/performers.ts index 455ada9f9..9712c9824 100644 --- a/ui/v2.5/src/core/performers.ts +++ b/ui/v2.5/src/core/performers.ts @@ -84,9 +84,14 @@ export function sortPerformers(performers: T[]) { } export const scrapedPerformerToCreateInput = ( - toCreate: GQL.ScrapedPerformer + toCreate: GQL.ScrapedPerformer, + endpoint?: string ) => { - const aliases = toCreate.aliases?.split(",").map((a) => a.trim()); + const aliases = + toCreate.aliases + ?.split(",") + .map((a) => a.trim()) + .filter((a) => a) || []; const input: GQL.PerformerCreateInput = { name: toCreate.name ?? "", @@ -118,5 +123,15 @@ export const scrapedPerformerToCreateInput = ( : undefined, circumcised: stringToCircumcised(toCreate.circumcised), }; + + if (endpoint && toCreate.remote_site_id) { + input.stash_ids = [ + { + endpoint, + stash_id: toCreate.remote_site_id, + }, + ]; + } + return input; }; diff --git a/ui/v2.5/src/docs/en/Changelog/v0290.md b/ui/v2.5/src/docs/en/Changelog/v0290.md new file mode 100644 index 000000000..51ca93e5d --- /dev/null +++ b/ui/v2.5/src/docs/en/Changelog/v0290.md @@ -0,0 +1,76 @@ +### ✨ New Features +* Redesigned the scenes page with filter sidebar. ([#5714](https://github.com/stashapp/stash/pull/5714)) +* Added Performers tab to Group details page. ([#5895](https://github.com/stashapp/stash/pull/5895)) +* Added configurable rate limit to stash-box connection options. ([#5764](https://github.com/stashapp/stash/pull/5764)) + + +### 🎨 Improvements +* **[0.29.2]** Returned saved filters button to the top toolbar in the Scene list. ([#6215](https://github.com/stashapp/stash/pull/6215)) +* **[0.29.2]** Top pagination can now be optionally shown in the scene list with [custom css](https://github.com/stashapp/stash/pull/6234#issue-3593190476). ([#6234](https://github.com/stashapp/stash/pull/6234)) +* **[0.29.2]** Restyled the scene list toolbar based on user feedback. ([#6215](https://github.com/stashapp/stash/pull/6215)) +* **[0.29.2]** Sidebar section collapsed state is now saved in the browser history. ([#6217](https://github.com/stashapp/stash/pull/6217)) +* **[0.29.2]** Increased the number of pages in pagination dropdown to 1000. ([#6207](https://github.com/stashapp/stash/pull/6207)) +* Revamped the scene and marker wall views. ([#5816](https://github.com/stashapp/stash/pull/5816)) +* Added zoom functionality to wall views. ([#6011](https://github.com/stashapp/stash/pull/6011)) +* Added search term field to the Edit Filter dialog. ([#6082](https://github.com/stashapp/stash/pull/6082)) +* Added load and save filter buttons to the Edit Filter dialog. ([#6092](https://github.com/stashapp/stash/pull/6092)) +* Restyled UI error messages. ([#5813](https://github.com/stashapp/stash/pull/5813)) +* Changed default modifier of `path` criterion to `includes` instead of `equals`. ([#5968](https://github.com/stashapp/stash/pull/5968)) +* Added internationalisation to login page. ([#5765](https://github.com/stashapp/stash/pull/5765)) +* Added Performer and Tag popovers to scene edit page. ([#5739](https://github.com/stashapp/stash/pull/5739)) +* Tags are now sorted by name in scrape and merge dialogs. ([#5752](https://github.com/stashapp/stash/pull/5752)) +* Related stash-box is now shown with IDs in tagger view. ([#5879](https://github.com/stashapp/stash/pull/5879)) +* UI now navigates to previous page when deleting an item. ([#5818](https://github.com/stashapp/stash/pull/5818)) +* All URLs will now be submitted when submitting a draft to stash-box. ([#5894](https://github.com/stashapp/stash/pull/5894)) +* Made funscript parsing more fault tolerant. ([#5978](https://github.com/stashapp/stash/pull/5978)) +* Added link to gallery in image lightbox. ([#6012](https://github.com/stashapp/stash/pull/6012)) +* Provide correct filename when downloading scene video. ([#6119](https://github.com/stashapp/stash/pull/6119)) +* Support hardware next/previous keys for scene navigation. ([#5553](https://github.com/stashapp/stash/pull/5553)) +* Duplicate checker now sorts largest file groups first. ([#6133](https://github.com/stashapp/stash/pull/6133)) +* Show gallery cover in Gallery edit panel. ([#5935](https://github.com/stashapp/stash/pull/5935)) +* Backups will now be created in the same directory as the database, then moved to the configured backup directory. This avoids potential corruption when backing up over a network share. ([#6137](https://github.com/stashapp/stash/pull/6137)) +* Added graphql playground link to tools panel. ([#5807](https://github.com/stashapp/stash/pull/5807)) +* Include IP address in login errors in log. ([#5760](https://github.com/stashapp/stash/pull/5760)) + +### 🐛 Bug fixes +* **[0.29.3]** Fixed sidebar filter contents not loading. ([#6240](https://github.com/stashapp/stash/pull/6240)) +* **[0.29.2]** Fixed Play Random not playing from the current filtered scenes on scene list sub-pages. ([#6202](https://github.com/stashapp/stash/pull/6202)) +* **[0.29.2]** Fixed infinite loop in Group Sub-Groups panel. ([#6212](https://github.com/stashapp/stash/pull/6212)) +* **[0.29.2]** Page no longer scrolls when selecting criterion for the first time in the Edit Filter dialog. ([#6205](https://github.com/stashapp/stash/pull/6205)) +* **[0.29.2]** Zoom slider is no longer shown on mobile devices. ([#6206](https://github.com/stashapp/stash/pull/6206)) +* **[0.29.2]** Fixed trailing space sometimes being trimmed from query string when querying. ([#6211](https://github.com/stashapp/stash/pull/6211)) +* **[0.29.2]** Page now redirects to list page when deleting an object in a new browser tab. ([#6203](https://github.com/stashapp/stash/pull/6203)) +* **[0.29.2]** Related groups can now be scraped when scraping a scene. ([#6228](https://github.com/stashapp/stash/pull/6228)) +* **[0.29.2]** Fixed panic when a scraper configuration contains an unknown field. ([#6220](https://github.com/stashapp/stash/pull/6220)) +* **[0.29.2]** Fixed panic when using `stash_box_index` input in scrape API calls. ([#6201](https://github.com/stashapp/stash/pull/6201)) +* **[0.29.1]** Fixed password with special characters not allowing login. ([#6163](https://github.com/stashapp/stash/pull/6163)) +* **[0.29.1]** Fixed layout issues using column direction for image wall. ([#6168](https://github.com/stashapp/stash/pull/6168)) +* **[0.29.1]** Fixed layout issues for scene list table. ([#6169](https://github.com/stashapp/stash/pull/6169)) +* **[0.29.1]** Fixed UI loop when sorting by random without seed using URL. ([#6167](https://github.com/stashapp/stash/pull/6167)) +* Fixed ordering studios by tag count returning error. ([#5776](https://github.com/stashapp/stash/pull/5776)) +* Fixed error when submitting fingerprints for scenes that have been deleted. ([#5799](https://github.com/stashapp/stash/pull/5799)) +* Fixed errors when scraping groups. ([#5793](https://github.com/stashapp/stash/pull/5793), [#5974](https://github.com/stashapp/stash/pull/5974)) +* Fixed UI crash when viewing a gallery in the Performer details page. ([#5824](https://github.com/stashapp/stash/pull/5824)) +* Fixed scraped performer stash ID being saved when cancelling scrape operation. ([#5839](https://github.com/stashapp/stash/pull/5839)) +* Fixed groups not transferring when merging tags. ([#6127](https://github.com/stashapp/stash/pull/6127)) +* Fixed URLs and stash IDs not transferring during scene merge operation. ([#6151](https://github.com/stashapp/stash/pull/6151), [#6152](https://github.com/stashapp/stash/pull/6152)) +* Fixed empty exclusion patterns being applied when scanning and cleaning. ([#6023](https://github.com/stashapp/stash/pull/6023)) +* Fixed login page being included in browser history. ([#5747](https://github.com/stashapp/stash/pull/5747)) +* Fixed gallery card resizing while scrubbing. ([#5844](https://github.com/stashapp/stash/pull/5844)) +* Fixed incorrectly positioned scene markers in the scene player timeline. ([#5801](https://github.com/stashapp/stash/pull/5801), [#5804](https://github.com/stashapp/stash/pull/5804)) +* Fixed incorrect marker colours in the scene player timeline. ([#6141](https://github.com/stashapp/stash/pull/6141)) +* Fixed custom fields not being displayed in Performer page with `Compact Expanded Details` enabled. ([#5833](https://github.com/stashapp/stash/pull/5833)) +* Fixed issue in tagger where creating a parent studio would not map it to the other results. ([#5810](https://github.com/stashapp/stash/pull/5810), [#5996](https://github.com/stashapp/stash/pull/5996)) +* Fixed generation options not being respected when generating using the Tasks page. ([#6139](https://github.com/stashapp/stash/pull/6139)) +* Related tags are now ordered by name. ([#5945](https://github.com/stashapp/stash/pull/5945)) +* Fixed error message not being displayed when failing at startup. ([#5798](https://github.com/stashapp/stash/pull/5798)) +* Fixed incorrect paths in confirm step of the setup wizard. ([#6138](https://github.com/stashapp/stash/pull/6138)) +* Fixed values being lost when navigating back from the confirmation step of the setup wizard. ([#6138](https://github.com/stashapp/stash/pull/6138)) +* Fixed incorrect paths generated in HLS when using a reverse proxy prefix. ([#5791](https://github.com/stashapp/stash/pull/5791)) +* Fixed marker preview being deleted when modifying a marker with a duration. ([#5800](https://github.com/stashapp/stash/pull/5800)) +* Fixed marker end seconds not being included in import/export. ([#5777](https://github.com/stashapp/stash/pull/5777)) +* Fixed parent tags missing in export if including dependencies. ([#5780](https://github.com/stashapp/stash/pull/5780)) +* Add short hash of basename when generating export file names to prevent the same filename being generated. ([#5780](https://github.com/stashapp/stash/pull/5780)) +* Fixed invalid studio and performer links in the tagger view. ([#5876](https://github.com/stashapp/stash/pull/5876)) +* Fixed clickable area for tag links. ([#6129](https://github.com/stashapp/stash/pull/6129)) +* ffmpeg hardware encoding checks now timeout after 1 second to prevent startup hangs. ([#6154](https://github.com/stashapp/stash/pull/6154)) \ No newline at end of file diff --git a/ui/v2.5/src/docs/en/Changelog/v0300.md b/ui/v2.5/src/docs/en/Changelog/v0300.md new file mode 100644 index 000000000..128be4cf7 --- /dev/null +++ b/ui/v2.5/src/docs/en/Changelog/v0300.md @@ -0,0 +1,35 @@ +### ✨ New Features +* Added SFW content mode option to settings and setup wizard. ([#6262](https://github.com/stashapp/stash/pull/6262)) +* Added stash-ids to Tags. ([#6255](https://github.com/stashapp/stash/pull/6255)) +* Logs can now be compressed after reaching a configurable size. ([#5696](https://github.com/stashapp/stash/pull/5696)) +* Added ability to edit multiple studios at once. ([#6238](https://github.com/stashapp/stash/pull/6238)) +* Added ability to edit multiple scene markers at once. ([#6239](https://github.com/stashapp/stash/pull/6239)) +* Added support for multiple Studio URLs. ([#6223](https://github.com/stashapp/stash/pull/6223)) +* Added option to add markers to front page. ([#6065](https://github.com/stashapp/stash/pull/6065)) +* Added duration filter to scene list sidebar. ([#6264](https://github.com/stashapp/stash/pull/6264)) +* Added experimental support for JPEG XL images. ([#6184](https://github.com/stashapp/stash/pull/6184)) + +### 🎨 Improvements +* Added performer age slider to scene filter sidebar. ([#6267](https://github.com/stashapp/stash/pull/6267)) +* Added markers option to scene filter sidebar. ([#6270](https://github.com/stashapp/stash/pull/6270)) +* Selected stash-box is now remembered in the scene tagger view. ([#6192](https://github.com/stashapp/stash/pull/6192)) +* Added hardware encoding support for Rockchip RKMPP devices. ([#6182](https://github.com/stashapp/stash/pull/6182)) +* stash now uses the Media Session API when playing scenes. ([#6298](https://github.com/stashapp/stash/pull/6298)) +* Added `inputURL` and `inputHostname` fields to scraper specs. ([#6250](https://github.com/stashapp/stash/pull/6250)) +* Added extra studio fields to scraper specs. ([#6249](https://github.com/stashapp/stash/pull/6249)) +* Added o-count to studio cards and details page. ([#5982](https://github.com/stashapp/stash/pull/5982)) +* Added o-count to group cards. ([#6122](https://github.com/stashapp/stash/pull/6122)) +* Added options to filter and sort groups by o-count. ([#6122](https://github.com/stashapp/stash/pull/6122)) +* Added o-count to performer details page. ([#6171](https://github.com/stashapp/stash/pull/6171)) +* Added option to sort by total scene direction for performers, studios and tags. ([#6172](https://github.com/stashapp/stash/pull/6172)) +* Added option to sort scenes by Performer age. ([#6009](https://github.com/stashapp/stash/pull/6009)) +* Added option to sort scenes by Studio. ([#6155](https://github.com/stashapp/stash/pull/6155)) +* Added option to show external links on Performer cards. ([#6153](https://github.com/stashapp/stash/pull/6153)) +* Added keyboard shortcuts to generate scene screenshot at current time (`c c`) and to regenerate default screenshot (`c d`). ([#5984](https://github.com/stashapp/stash/pull/5984)) + +### 🐛 Bug fixes +* stash-ids are now set when creating new objects from the scrape dialog. ([#6269](https://github.com/stashapp/stash/pull/6269)) +* partial dates are now correctly handled when scraping scenes. ([#6305](https://github.com/stashapp/stash/pull/6305)) +* Fixed external player not loading on Android when a scene title has special characters. ([#6297](https://github.com/stashapp/stash/pull/6297)) +* Fixed Macos version check pointing to incorrect location. ([#6289](https://github.com/stashapp/stash/pull/6289)) +* stash will no longer try to generate marker previews where a marker start is set after the end of a scene's duration. ([#6290](https://github.com/stashapp/stash/pull/6290)) \ No newline at end of file diff --git a/ui/v2.5/src/docs/en/Manual/Captions.md b/ui/v2.5/src/docs/en/Manual/Captions.md index e52fc54bb..df2bee8bc 100644 --- a/ui/v2.5/src/docs/en/Manual/Captions.md +++ b/ui/v2.5/src/docs/en/Manual/Captions.md @@ -2,15 +2,17 @@ Stash supports captioning with SRT and VTT files. -These files need to be named as follows: +Captions will only be detected if they are located in the same folder as the corresponding scene file. + +Ensure the caption files follow these naming conventions: ## Scene -- {scene_name}.{language_code}.ext -- {scene_name}.ext +- {scene_file_name}.{language_code}.ext +- {scene_file_name}.ext Where `{language_code}` is defined by the [ISO-6399-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (2 letters) standard and `ext` is the file extension. Captions files without a language code will be labeled as Unknown in the video player but will work fine. Scenes with captions can be filtered with the `captions` criterion. -**Note:** If the caption file was added after the scene was initially added during scan you will need to run a Selective Scan task for it to show up. +**Note:** If the caption file was added after the scene was initially added during scan, you will need to run a Selective Scan task for it to show up. diff --git a/ui/v2.5/src/docs/en/Manual/Configuration.md b/ui/v2.5/src/docs/en/Manual/Configuration.md index 9b0469114..d7c1b4804 100644 --- a/ui/v2.5/src/docs/en/Manual/Configuration.md +++ b/ui/v2.5/src/docs/en/Manual/Configuration.md @@ -2,7 +2,13 @@ ## Library -This section allows you to add and remove directories from your library list. Files in these directories will be included when scanning. Files that are outside of these directories will be removed when running the Clean task. +This section enables you to add or remove directories that will be discoverable by Stash. The directories you add will be utilized for scanning new files and for updating their locations in Stash database. + +You can configure these directories to apply specifically to: + +- **Videos** +- **Images** +- **Both** > **⚠️ Note:** Don't forget to click `Save` after updating these directories! diff --git a/ui/v2.5/src/docs/en/Manual/Contributing.md b/ui/v2.5/src/docs/en/Manual/Contributing.md index 9e55dbd6d..2d62dde08 100644 --- a/ui/v2.5/src/docs/en/Manual/Contributing.md +++ b/ui/v2.5/src/docs/en/Manual/Contributing.md @@ -26,4 +26,4 @@ We welcome ideas for future improvements and features, and bug reports help ever ## Providing support -Offering support for new users on [Discord](https://discord.gg/2TsNFKt) is also welcomed. +Offering support for new users on our [Community forum](https://discourse.stashapp.cc/) and [Discord](https://discord.gg/2TsNFKt) is also welcomed. diff --git a/ui/v2.5/src/docs/en/Manual/Help.md b/ui/v2.5/src/docs/en/Manual/Help.md index f5d1d69e5..c9c4ab9d3 100644 --- a/ui/v2.5/src/docs/en/Manual/Help.md +++ b/ui/v2.5/src/docs/en/Manual/Help.md @@ -1,5 +1,7 @@ # Where to get further help +Join our [Community forum](https://discourse.stashapp.cc/). + Join our [Discord](https://discord.gg/2TsNFKt). The [Stash-Docs](https://docs.stashapp.cc) covers some areas not covered in the in-app help. diff --git a/ui/v2.5/src/docs/en/Manual/Images.md b/ui/v2.5/src/docs/en/Manual/Images.md index 7b384596b..e5733fc2e 100644 --- a/ui/v2.5/src/docs/en/Manual/Images.md +++ b/ui/v2.5/src/docs/en/Manual/Images.md @@ -13,6 +13,8 @@ For best results, images in zip file should be stored without compression (copy, If a filename of an image in the gallery zip file ends with `cover.jpg`, it will be treated like a cover and presented first in the gallery view page and as a gallery cover in the gallery list view. If more than one images match the name the first one found in natural sort order is selected. +You can also manually select any image from a gallery as its cover. On the gallery details page, select the desired cover image, and then select **Set as Cover** in the ⋯ menu. + ## Image clips/gifs Images can also be clips/gifs. These are meant to be short video loops. Right now they are not possible in zipfiles. To declare video files to be images, there are two ways: diff --git a/ui/v2.5/src/docs/en/Manual/Interface.md b/ui/v2.5/src/docs/en/Manual/Interface.md index 0f5fc23c4..cf5911405 100644 --- a/ui/v2.5/src/docs/en/Manual/Interface.md +++ b/ui/v2.5/src/docs/en/Manual/Interface.md @@ -4,6 +4,15 @@ Setting the language affects the formatting of numbers and dates. +## SFW Content Mode + +SFW Content Mode is used to indicate that the content being managed is _not_ adult content. + +When SFW Content Mode is enabled, the following changes are made to the UI: +- default performer images are changed to less adult-oriented images +- certain adult-specific metadata fields are hidden (e.g. performer genital fields) +- `O`-Counter is replaced with `Like`-counter + ## Scene/Marker Wall Preview Type The Scene Wall and Marker pages display scene preview videos (mp4) by default. This can be changed to animated image (webp) or static image. @@ -30,9 +39,9 @@ By default, when a scene has a resume point, the scene player will automatically ## Custom CSS -The stash UI can be customised using custom CSS. See [here](https://docs.stashapp.cc/user-interface-ui/custom-css-snippets) for a community-curated set of CSS snippets to customise your UI. +The stash UI can be customised using custom CSS. See [here](https://docs.stashapp.cc/themes/custom-css-snippets/) for a community-curated set of CSS snippets to customise your UI. -[Stash Plex Theme](https://docs.stashapp.cc/user-interface-ui/themes/plex) is a community created theme inspired by the popular Plex interface. +There is also a [collection of community-created themes](https://docs.stashapp.cc/themes/list/#browse-themes) available. ## Custom Javascript diff --git a/ui/v2.5/src/docs/en/Manual/KeyboardShortcuts.md b/ui/v2.5/src/docs/en/Manual/KeyboardShortcuts.md index 870de61b5..69006d429 100644 --- a/ui/v2.5/src/docs/en/Manual/KeyboardShortcuts.md +++ b/ui/v2.5/src/docs/en/Manual/KeyboardShortcuts.md @@ -30,6 +30,7 @@ | `v g` | Set view to grid | | `v l` | Set view to list | | `v w` | Set view to wall | +| `v t` | Set view to tagger | | `+` | Increase zoom slider | | `-` | Decrease zoom slider | | `←` | Previous page of results | @@ -67,6 +68,9 @@ | `r 0` | Unset rating (stars) | | `r {0-9} {0-9}` | Set rating (decimal - `00` for `10.0`) | | ``r ` `` | Unset rating (decimal) | +| Cover generation || +| `c c` | Generate screenshot at current time | +| `c d` | Generate default screenshot | | Playback || | `p n` | Play next scene in queue | | `p p` | Play previous scene in queue | diff --git a/ui/v2.5/src/docs/en/Manual/Plugins.md b/ui/v2.5/src/docs/en/Manual/Plugins.md index 47b87cf01..cd24e0d4a 100644 --- a/ui/v2.5/src/docs/en/Manual/Plugins.md +++ b/ui/v2.5/src/docs/en/Manual/Plugins.md @@ -1,6 +1,7 @@ # Plugins Stash supports plugins that can do the following: + - perform custom tasks when triggered by the user from the Tasks page - perform custom tasks when triggered from specific events - add custom CSS to the UI @@ -14,7 +15,7 @@ Plugin tasks can be implemented using embedded Javascript, or by calling an exte Plugins can be installed and managed from the `Settings > Plugins` page. -Scrapers are installed using the `Available Plugins` section. This section allows configuring sources from which to install plugins. The `Community (stable)` source is configured by default. This source contains plugins for the current _stable_ version of stash. +Plugins are installed using the `Available Plugins` section. This section allows configuring sources from which to install plugins. The `Community (stable)` source is configured by default. This source contains plugins for the current _stable_ version of stash. These are the plugin sources maintained by the stashapp organisation: @@ -64,8 +65,11 @@ Plugins provide tasks which can be run from the Tasks page. The basic structure of a plugin configuration file is as follows: -``` -name: +```yaml +name: +# optional list of dependencies to be included +# "#" is is part of the config - do not remove +# requires: description: version: url: @@ -120,6 +124,8 @@ tasks: The `name`, `description`, `version` and `url` fields are displayed on the plugins page. +`# requires` will make the plugin manager select plugins matching the specified IDs to be automatically installed as dependencies. Only works with plugins within the same index. + The `exec`, `interface`, `errLog` and `tasks` fields are used only for plugins with tasks. The `settings` field is used to display plugin settings on the plugins page. Plugin settings can also be set using the graphql mutation `configurePlugin` - the settings set this way do _not_ need to be specified in the `settings` field unless they are to be displayed in the stock plugin settings UI. diff --git a/ui/v2.5/src/docs/en/Manual/ScraperDevelopment.md b/ui/v2.5/src/docs/en/Manual/ScraperDevelopment.md index 0ee1c0880..1f52028f8 100644 --- a/ui/v2.5/src/docs/en/Manual/ScraperDevelopment.md +++ b/ui/v2.5/src/docs/en/Manual/ScraperDevelopment.md @@ -325,10 +325,58 @@ Alternatively, an attribute value may be set to a fixed value, rather than scrap ```yaml performer: - Gender: + Gender: fixed: Female ``` +### Input URL placeholders + +The `{inputURL}` and `{inputHostname}` placeholders can be used in both `fixed` values and `selector` expressions to access information about the original URL that was used to scrape the content. + +#### {inputURL} + +The `{inputURL}` placeholder provides access to the full URL. This is useful when you want to return or reference the source URL as part of the scraped data. + +For example: + +```yaml +scene: + URL: + fixed: "{inputURL}" + Title: + selector: //h1[@class="title"] +``` + +When scraping from `https://example.com/scene/12345`, the `{inputURL}` placeholder will be replaced with `https://example.com/scene/12345`. + +#### {inputHostname} + +The `{inputHostname}` placeholder extracts just the hostname from the URL. This is useful when you need to reference the domain without manually parsing the URL. + +For example: + +```yaml +scene: + Studio: + fixed: "{inputHostname}" + Details: + selector: //div[@data-domain="{inputHostname}"]//p[@class="description"] +``` + +When scraping from `https://example.com/scene/12345`, the `{inputHostname}` placeholder will be replaced with `example.com`. + +These placeholders can also be used within selectors for more advanced use cases: + +```yaml +scene: + Details: + selector: //div[@data-url="{inputURL}"]//p[@class="description"] + Site: + selector: //div[@data-host="{inputHostname}"]//span[@class="site-name"] +``` + +> **Note:** These placeholders represent the actual URL used to fetch the content, after any URL replacements have been applied. + ### Common fragments The `common` field is used to configure selector fragments that can be referenced in the selector strings. These are key-value pairs where the key is the string to reference the fragment, and the value is the string that the fragment will be replaced with. For example: @@ -691,7 +739,11 @@ xPathScrapers: URL: $performer/@href Studio: Name: $studio - URL: $studio/@href + URL: $studio/@href + Details: //div[@class="studioDescription"] + Aliases: //div[@class="studioAliases"]/span + Tags: + Name: //div[@class="studioTags"]/a ``` See also [#333](https://github.com/stashapp/stash/pull/333) for more examples. @@ -774,6 +826,11 @@ jsonScrapers: Name: data.performers.#.name Studio: Name: data.site.name + URL: data.site.url + Details: data.site.description + Aliases: data.site.aliases + Tags: + Name: data.site.tags.#.name Tags: Name: data.tags.#.tag @@ -791,6 +848,11 @@ jsonScrapers: Name: $data.performers.#.name Studio: Name: $data.site.name + URL: $data.site.url + Details: $data.site.description + Aliases: $data.site.aliases + Tags: + Name: $data.site.tags.#.name Tags: Name: $data.tags.#.tag driver: @@ -907,7 +969,10 @@ URLs ### Studio ``` +Aliases +Details Name +Tags (see Tag fields) URL ``` diff --git a/ui/v2.5/src/docs/en/Manual/UIPluginApi.md b/ui/v2.5/src/docs/en/Manual/UIPluginApi.md index 4453dfb10..67d837ed7 100644 --- a/ui/v2.5/src/docs/en/Manual/UIPluginApi.md +++ b/ui/v2.5/src/docs/en/Manual/UIPluginApi.md @@ -23,6 +23,7 @@ This namespace contains the generated graphql client interface. This is a low-le ### `libraries` `libraries` provides access to the following UI libraries: + - `ReactRouterDOM` - `Bootstrap` - `Apollo` @@ -66,7 +67,7 @@ This namespace contains all of the components available to plugins. These includ ### `utils` -This namespace provides access to the `NavUtils` and `StashService` namespaces. It also provides access to the `loadComponents` method. +This namespace provides access to the `NavUtils` , `StashService` and `InteractiveUtils` namespaces. It also provides access to the `loadComponents` method. #### `PluginApi.utils.loadComponents` @@ -80,9 +81,76 @@ In general, `PluginApi.hooks.useLoadComponents` hook should be used instead. Returns a `Promise` that resolves when all of the components have been loaded. +#### `PluginApi.utils.InteractiveUtils` +This namespace provides access to `interactiveClientProvider` and `getPlayer` + - `getPlayer` returns the current `videojs` player object + - `interactiveClientProvider` takes `IInteractiveClientProvider` which allows a developer to hook into the lifecycle of funscripts. +```ts + export interface IDeviceSettings { + connectionKey: string; + scriptOffset: number; + estimatedServerTimeOffset?: number; + useStashHostedFunscript?: boolean; + [key: string]: unknown; +} + +export interface IInteractiveClientProviderOptions { + handyKey: string; + scriptOffset: number; + defaultClientProvider?: IInteractiveClientProvider; + stashConfig?: GQL.ConfigDataFragment; +} +export interface IInteractiveClientProvider { + (options: IInteractiveClientProviderOptions): IInteractiveClient; +} + +/** + * Interface that is used for InteractiveProvider + */ +export interface IInteractiveClient { + connect(): Promise; + handyKey: string; + uploadScript: (funscriptPath: string, apiKey?: string) => Promise; + sync(): Promise; + configure(config: Partial): Promise; + play(position: number): Promise; + pause(): Promise; + ensurePlaying(position: number): Promise; + setLooping(looping: boolean): Promise; + readonly connected: boolean; + readonly playing: boolean; +} + +``` +##### Example +For instance say I wanted to add extra logging when `IInteractiveClient.connect()` is called. +In my plugin you would install your own client provider as seen below + +```ts +InteractiveUtils.interactiveClientProvider = ( + opts +) => { + if (!opts.defaultClientProvider) { + throw new Error('invalid setup'); + } + + const client = opts.defaultClientProvider(opts); + const connect = client.connect; + client.connect = async () => { + console.log('patching connect method'); + return connect.call(client); + }; + + return client; +}; + +``` + + ### `hooks` This namespace provides access to the following core utility hooks: + - `useGalleryLightbox` - `useLightbox` - `useSpriteInfo` @@ -153,8 +221,8 @@ Returns `void`. - `CompressedPerformerDetailsPanel` - `ConstantSetting` - `CountrySelect` -- `CustomFields` - `CustomFieldInput` +- `CustomFields` - `DateInput` - `DetailImage` - `ExternalLinkButtons` @@ -169,6 +237,9 @@ Returns `void`. - `GalleryIDSelect` - `GallerySelect` - `GallerySelect.sort` +- `GroupIDSelect` +- `GroupSelect` +- `GroupSelect.sort` - `HeaderImage` - `HoverPopover` - `Icon` @@ -176,11 +247,12 @@ Returns `void`. - `ImageInput` - `LightboxLink` - `LoadingIndicator` +- `MainNavBar.MenuItems` +- `MainNavBar.UtilityItems` - `ModalSetting` -- `GroupIDSelect` -- `GroupSelect` -- `GroupSelect.sort` - `NumberSetting` +- `Pagination` +- `PaginationIndex` - `PerformerAppearsWithPanel` - `PerformerCard` - `PerformerCard.Details` @@ -190,16 +262,17 @@ Returns `void`. - `PerformerCard.Title` - `PerformerDetailsPanel` - `PerformerDetailsPanel.DetailGroup` -- `PerformerIDSelect` -- `PerformerPage` -- `PerformerSelect` -- `PerformerSelect.sort` - `PerformerGalleriesPanel` - `PerformerGroupsPanel` - `PerformerHeaderImage` +- `PerformerIDSelect` - `PerformerImagesPanel` +- `PerformerPage` - `PerformerScenesPanel` +- `PerformerSelect` +- `PerformerSelect.sort` - `PluginRoutes` +- `PluginSettings` - `RatingNumber` - `RatingStars` - `RatingSystem` @@ -208,18 +281,20 @@ Returns `void`. - `SceneCard.Image` - `SceneCard.Overlays` - `SceneCard.Popovers` +- `SceneFileInfoPanel` - `SceneIDSelect` - `ScenePage` -- `ScenePage.Tabs` - `ScenePage.TabContent` +- `ScenePage.Tabs` - `ScenePlayer` - `SceneSelect` - `SceneSelect.sort` - `SelectSetting` - `Setting` +- `SettingGroup` - `SettingModal` -- `StringSetting` - `StringListSetting` +- `StringSetting` - `StudioIDSelect` - `StudioSelect` - `StudioSelect.sort` @@ -231,15 +306,11 @@ Returns `void`. - `TagCard.Overlays` - `TagCard.Popovers` - `TagCard.Title` -- `TagLink` -- `TabTitleCounter` - `TagIDSelect` +- `TagLink` - `TagSelect` - `TagSelect.sort` - `TruncatedText` -- `PluginSettings` -- `Setting` -- `SettingGroup` ### `PluginApi.Event` @@ -248,3 +319,5 @@ Allows plugins to listen for Stash's events. ```js PluginApi.Event.addEventListener("stash:location", (e) => console.log("Page Changed", e.detail.data.location.pathname)) ``` + + diff --git a/ui/v2.5/src/docs/en/ReleaseNotes/index.ts b/ui/v2.5/src/docs/en/ReleaseNotes/index.ts index 8e2f503d4..78e5e4b37 100644 --- a/ui/v2.5/src/docs/en/ReleaseNotes/index.ts +++ b/ui/v2.5/src/docs/en/ReleaseNotes/index.ts @@ -4,6 +4,7 @@ import v0240 from "./v0240.md"; import v0250 from "./v0250.md"; import v0260 from "./v0260.md"; import v0270 from "./v0270.md"; +import v0290 from "./v0290.md"; export interface IReleaseNotes { // handle should be in the form of YYYYMMDD @@ -13,6 +14,11 @@ export interface IReleaseNotes { } export const releaseNotes: IReleaseNotes[] = [ + { + date: 20251026, + version: "v0.29.0", + content: v0290, + }, { date: 20240826, version: "v0.27.0", diff --git a/ui/v2.5/src/docs/en/ReleaseNotes/v0290.md b/ui/v2.5/src/docs/en/ReleaseNotes/v0290.md new file mode 100644 index 000000000..6dfe0b209 --- /dev/null +++ b/ui/v2.5/src/docs/en/ReleaseNotes/v0290.md @@ -0,0 +1,5 @@ +The Scenes page and related scene list views have been updated with a filter sidebar and a toolbar for filtering and other actions. This design is intended to be applied to other query pages in the following release. The design will be refined based on user feedback. + +You can help steer the direction of this design by providing feedback in the [forum thread](https://discourse.stashapp.cc/t/query-page-redesign-feedback-thread-0-29/3935). + +Old userscripts and plugins that intercept GraphQL with content-type `application/json` will stop working, as gqlenc uses the updated content-type `application/graphql-response+json` \ No newline at end of file diff --git a/ui/v2.5/src/hooks/Config.tsx b/ui/v2.5/src/hooks/Config.tsx index 0b00d0dc5..65ad7122a 100644 --- a/ui/v2.5/src/hooks/Config.tsx +++ b/ui/v2.5/src/hooks/Config.tsx @@ -2,14 +2,28 @@ import React from "react"; import * as GQL from "src/core/generated-graphql"; export interface IContext { - configuration?: GQL.ConfigDataFragment; - loading?: boolean; + configuration: GQL.ConfigDataFragment; } -export const ConfigurationContext = React.createContext({}); +export const ConfigurationContext = React.createContext(null); + +export const useConfigurationContext = () => { + const context = React.useContext(ConfigurationContext); + + if (context === null) { + throw new Error( + "useConfigurationContext must be used within a ConfigurationProvider" + ); + } + + return context; +}; + +export const useConfigurationContextOptional = () => { + return React.useContext(ConfigurationContext); +}; export const ConfigurationProvider: React.FC = ({ - loading, configuration, children, }) => { @@ -17,7 +31,6 @@ export const ConfigurationProvider: React.FC = ({ {children} diff --git a/ui/v2.5/src/hooks/Interactive/context.tsx b/ui/v2.5/src/hooks/Interactive/context.tsx index a42f0aa7b..ccdc948b4 100644 --- a/ui/v2.5/src/hooks/Interactive/context.tsx +++ b/ui/v2.5/src/hooks/Interactive/context.tsx @@ -1,7 +1,11 @@ import React, { useCallback, useContext, useEffect, useState } from "react"; -import { ConfigurationContext } from "../Config"; +import { useConfigurationContext } from "../Config"; import { useLocalForage } from "../LocalForage"; import { Interactive as InteractiveAPI } from "./interactive"; +import InteractiveUtils, { + IInteractiveClient, + IInteractiveClientProvider, +} from "./utils"; export enum ConnectionState { Missing, @@ -34,7 +38,7 @@ export function connectionStateLabel(s: ConnectionState) { } export interface IState { - interactive: InteractiveAPI; + interactive: IInteractiveClient; state: ConnectionState; serverOffset: number; initialised: boolean; @@ -69,13 +73,20 @@ interface IInteractiveState { lastSyncTime: number; } +export const defaultInteractiveClientProvider: IInteractiveClientProvider = ({ + handyKey, + scriptOffset, +}): IInteractiveClient => { + return new InteractiveAPI(handyKey, scriptOffset); +}; + export const InteractiveProvider: React.FC = ({ children }) => { const [{ data: config }, setConfig] = useLocalForage( LOCAL_FORAGE_KEY, { serverOffset: 0, lastSyncTime: 0 } ); - const { configuration: stashConfig } = React.useContext(ConfigurationContext); + const { configuration: stashConfig } = useConfigurationContext(); const [state, setState] = useState(ConnectionState.Missing); const [handyKey, setHandyKey] = useState(undefined); @@ -85,7 +96,22 @@ export const InteractiveProvider: React.FC = ({ children }) => { const [scriptOffset, setScriptOffset] = useState(0); const [useStashHostedFunscript, setUseStashHostedFunscript] = useState(false); - const [interactive] = useState(new InteractiveAPI("", 0)); + + const resolveInteractiveClient = useCallback(() => { + const interactiveClientProvider = + InteractiveUtils.interactiveClientProvider ?? + defaultInteractiveClientProvider; + + return interactiveClientProvider({ + handyKey: "", + scriptOffset: 0, + defaultClientProvider: defaultInteractiveClientProvider, + stashConfig, + }); + }, [stashConfig]); + + // fetch client provider from PluginApi if not found use default provider + const [interactive] = useState(resolveInteractiveClient); const [initialised, setInitialised] = useState(false); const [error, setError] = useState(); @@ -104,7 +130,9 @@ export const InteractiveProvider: React.FC = ({ children }) => { } if (config?.serverOffset) { - interactive.setServerTimeOffset(config.serverOffset); + await interactive.configure({ + estimatedServerTimeOffset: config.serverOffset, + }); setState(ConnectionState.Connecting); try { await interactive.connect(); @@ -138,13 +166,17 @@ export const InteractiveProvider: React.FC = ({ children }) => { const oldKey = interactive.handyKey; - interactive.handyKey = handyKey ?? ""; - interactive.scriptOffset = scriptOffset; - interactive.useStashHostedFunscript = useStashHostedFunscript; - - if (oldKey !== interactive.handyKey && interactive.handyKey) { - initialise(); - } + interactive + .configure({ + connectionKey: handyKey ?? "", + offset: scriptOffset, + useStashHostedFunscript, + }) + .then(() => { + if (oldKey !== interactive.handyKey && interactive.handyKey) { + initialise(); + } + }); }, [ handyKey, scriptOffset, @@ -171,7 +203,7 @@ export const InteractiveProvider: React.FC = ({ children }) => { const uploadScript = useCallback( async (funscriptPath: string) => { - interactive.pause(); + await interactive.pause(); if ( !interactive.handyKey || !funscriptPath || diff --git a/ui/v2.5/src/hooks/Interactive/interactive.ts b/ui/v2.5/src/hooks/Interactive/interactive.ts index ef34bd2ef..4ca59b25b 100644 --- a/ui/v2.5/src/hooks/Interactive/interactive.ts +++ b/ui/v2.5/src/hooks/Interactive/interactive.ts @@ -5,6 +5,7 @@ import { CsvUploadResponse, HandyFirmwareStatus, } from "thehandy/lib/types"; +import { IDeviceSettings } from "./utils"; interface IFunscript { actions: Array; @@ -108,6 +109,13 @@ export class Interactive { this._playing = false; } + get connected() { + return this._connected; + } + get playing() { + return this._playing; + } + async connect() { const connected = await this._handy.getConnected(); if (!connected) { @@ -180,6 +188,15 @@ export class Interactive { this._handy.estimatedServerTimeOffset = offset; } + async configure(config: Partial) { + this._scriptOffset = config.scriptOffset ?? this._scriptOffset; + this.handyKey = config.connectionKey ?? this.handyKey; + this._handy.estimatedServerTimeOffset = + config.estimatedServerTimeOffset ?? this._handy.estimatedServerTimeOffset; + this.useStashHostedFunscript = + config.useStashHostedFunscript ?? this.useStashHostedFunscript; + } + async play(position: number) { if (!this._connected) { return; diff --git a/ui/v2.5/src/hooks/Interactive/utils.ts b/ui/v2.5/src/hooks/Interactive/utils.ts new file mode 100644 index 000000000..c1d066e86 --- /dev/null +++ b/ui/v2.5/src/hooks/Interactive/utils.ts @@ -0,0 +1,51 @@ +import { getPlayer } from "src/components/ScenePlayer/util"; +import type { VideoJsPlayer } from "video.js"; +import * as GQL from "src/core/generated-graphql"; + +export interface IDeviceSettings { + connectionKey: string; + scriptOffset: number; + estimatedServerTimeOffset?: number; + useStashHostedFunscript?: boolean; + [key: string]: unknown; +} + +export interface IInteractiveClientProviderOptions { + handyKey: string; + scriptOffset: number; + defaultClientProvider?: IInteractiveClientProvider; + stashConfig?: GQL.ConfigDataFragment; +} +export interface IInteractiveClientProvider { + (options: IInteractiveClientProviderOptions): IInteractiveClient; +} + +/** + * Interface that is used for InteractiveProvider + */ +export interface IInteractiveClient { + connect(): Promise; + handyKey: string; + uploadScript: (funscriptPath: string, apiKey?: string) => Promise; + sync(): Promise; + configure(config: Partial): Promise; + play(position: number): Promise; + pause(): Promise; + ensurePlaying(position: number): Promise; + setLooping(looping: boolean): Promise; + readonly connected: boolean; + readonly playing: boolean; +} + +export interface IInteractiveUtils { + getPlayer: () => VideoJsPlayer | undefined; + interactiveClientProvider: IInteractiveClientProvider | undefined; +} +const InteractiveUtils = { + // hook to allow to customize the interactive client + interactiveClientProvider: undefined, + // returns the active player + getPlayer, +}; + +export default InteractiveUtils; diff --git a/ui/v2.5/src/hooks/Lightbox/Lightbox.tsx b/ui/v2.5/src/hooks/Lightbox/Lightbox.tsx index 0af1e835b..f0f057d86 100644 --- a/ui/v2.5/src/hooks/Lightbox/Lightbox.tsx +++ b/ui/v2.5/src/hooks/Lightbox/Lightbox.tsx @@ -19,7 +19,7 @@ import usePageVisibility from "../PageVisibility"; import { useToast } from "../Toast"; import { FormattedMessage, useIntl } from "react-intl"; import { LightboxImage } from "./LightboxImage"; -import { ConfigurationContext } from "../Config"; +import { useConfigurationContext } from "../Config"; import { Link } from "react-router-dom"; import { OCounterButton } from "src/components/Scenes/SceneDetails/OCounterButton"; import { @@ -44,11 +44,13 @@ import { faSearchMinus, faTimes, faBars, + faImages, } from "@fortawesome/free-solid-svg-icons"; import { RatingSystem } from "src/components/Shared/Rating/RatingSystem"; import { useDebounce } from "../debounce"; import { isVideo } from "src/utils/visualFile"; import { imageTitle } from "src/core/files"; +import { galleryTitle } from "src/core/galleries"; const CLASSNAME = "Lightbox"; const CLASSNAME_HEADER = `${CLASSNAME}-header`; @@ -62,6 +64,8 @@ const CLASSNAME_OPTIONS_INLINE = `${CLASSNAME_OPTIONS}-inline`; const CLASSNAME_RIGHT = `${CLASSNAME_HEADER}-right`; const CLASSNAME_FOOTER = `${CLASSNAME}-footer`; const CLASSNAME_FOOTER_LEFT = `${CLASSNAME_FOOTER}-left`; +const CLASSNAME_FOOTER_CENTER = `${CLASSNAME_FOOTER}-center`; +const CLASSNAME_FOOTER_RIGHT = `${CLASSNAME_FOOTER}-right`; const CLASSNAME_DISPLAY = `${CLASSNAME}-display`; const CLASSNAME_CAROUSEL = `${CLASSNAME}-carousel`; const CLASSNAME_INSTANT = `${CLASSNAME_CAROUSEL}-instant`; @@ -150,7 +154,7 @@ export const LightboxComponent: React.FC = ({ const Toast = useToast(); const intl = useIntl(); - const { configuration: config } = React.useContext(ConfigurationContext); + const { configuration: config } = useConfigurationContext(); const [interfaceLocalForage, setInterfaceLocalForage] = useInterfaceLocalForage(); @@ -451,6 +455,7 @@ export const LightboxComponent: React.FC = ({ React.createElement(image.paths.preview != "" ? "video" : "img", { loop: image.paths.preview != "", autoPlay: image.paths.preview != "", + playsInline: image.paths.preview != "", src: image.paths.preview != "" ? image.paths.preview ?? "" @@ -933,14 +938,30 @@ export const LightboxComponent: React.FC = ({ )}
      -
      +
      {currentImage && ( - close()}> - {title ?? ""} - + <> + close()} + > + {title ?? ""} + + {currentImage.galleries?.length ? ( + close()} + > + + {galleryTitle(currentImage.galleries[0])} + + ) : null} + )}
      -
      +
      ); diff --git a/ui/v2.5/src/hooks/Lightbox/lightbox.scss b/ui/v2.5/src/hooks/Lightbox/lightbox.scss index b12de3cf9..95a5fbc42 100644 --- a/ui/v2.5/src/hooks/Lightbox/lightbox.scss +++ b/ui/v2.5/src/hooks/Lightbox/lightbox.scss @@ -105,10 +105,25 @@ padding-left: 1em; } + &-center { + display: flex; + flex-direction: column; + justify-content: center; + padding-left: 1em; + text-align: center; + } + a { color: $text-color; - font-weight: bold; text-decoration: none; + + .fa-icon { + margin-right: 0.5rem; + } + + &.image-link { + font-weight: bold; + } } } diff --git a/ui/v2.5/src/hooks/Lightbox/types.ts b/ui/v2.5/src/hooks/Lightbox/types.ts index 56c9d6b71..58cdc8434 100644 --- a/ui/v2.5/src/hooks/Lightbox/types.ts +++ b/ui/v2.5/src/hooks/Lightbox/types.ts @@ -14,6 +14,17 @@ interface IFiles { video_codec?: GQL.Maybe; } +interface IWithPath { + path: string; +} + +export interface IGallery { + id: string; + title?: GQL.Maybe; + files?: GQL.Maybe; + folder?: GQL.Maybe; +} + export interface ILightboxImage { id?: string; title?: GQL.Maybe; @@ -21,6 +32,7 @@ export interface ILightboxImage { o_counter?: GQL.Maybe; paths: IImagePaths; visual_files?: IFiles[]; + galleries?: GQL.Maybe; } export interface IChapter { diff --git a/ui/v2.5/src/hooks/useTableColumns.ts b/ui/v2.5/src/hooks/useTableColumns.ts index 09d5357d2..ed6380bdb 100644 --- a/ui/v2.5/src/hooks/useTableColumns.ts +++ b/ui/v2.5/src/hooks/useTableColumns.ts @@ -1,6 +1,5 @@ -import { useContext } from "react"; import { useConfigureUI } from "src/core/StashService"; -import { ConfigurationContext } from "src/hooks/Config"; +import { useConfigurationContext } from "src/hooks/Config"; import { useToast } from "./Toast"; export const useTableColumns = ( @@ -9,7 +8,7 @@ export const useTableColumns = ( ) => { const Toast = useToast(); - const { configuration } = useContext(ConfigurationContext); + const { configuration } = useConfigurationContext(); const [saveUI] = useConfigureUI(); const ui = configuration?.ui; diff --git a/ui/v2.5/src/index.scss b/ui/v2.5/src/index.scss index 9393397ed..74599eb34 100755 --- a/ui/v2.5/src/index.scss +++ b/ui/v2.5/src/index.scss @@ -1,12 +1,16 @@ // variables required by other scss files // this is calculated from the existing height -// TODO: we should set this explicitly in the navbar $navbar-height: 48.75px; +$sticky-detail-header-height: 50px; + +$sidebar-width: 250px; + @import "styles/theme"; @import "styles/range"; @import "styles/scrollbars"; +@import "sfw-mode.scss"; @import "src/components/Changelog/styles.scss"; @import "src/components/Galleries/styles.scss"; @import "src/components/Help/styles.scss"; @@ -55,7 +59,7 @@ body { @include media-breakpoint-down(xs) { @media (orientation: portrait) { - padding: 1rem 0 $navbar-height; + padding: 0.5rem 0 $navbar-height; } } } @@ -85,10 +89,10 @@ dd { .sticky.detail-header { display: block; - min-height: 50px; + min-height: $sticky-detail-header-height; padding: unset; position: fixed; - top: 3.3rem; + top: $navbar-height; z-index: 10; @media (max-width: 576px) { @@ -692,35 +696,48 @@ div.dropdown-menu { .badge { margin: unset; - // stylelint-disable declaration-no-important - white-space: normal !important; + white-space: normal; } } .tag-item { + align-items: center; background-color: $muted-gray; color: $dark-text; + display: inline-flex; font-size: 12px; font-weight: 400; line-height: 16px; margin: 5px; padding: 2px 6px; + // if link, move padding to link to make full tag clickable + &.tag-link { + padding: 0; + + a { + padding: 2px 6px; + } + } + &:hover { cursor: pointer; } + .search-term svg { + margin-left: 0; + } + .btn { background: none; border: none; bottom: 2px; color: $dark-text; font-size: 12px; - line-height: 1rem; + line-height: 16px; margin-right: -0.5rem; opacity: 0.5; padding: 0 0.5rem; - position: relative; &:active, &:hover { @@ -1025,6 +1042,9 @@ div.dropdown-menu { top: auto; } } + @include media-breakpoint-up(xl) { + height: $navbar-height; + } .navbar-toggler { padding: 0.5em 0; @@ -1408,3 +1428,8 @@ select { overflow-y: auto; padding-right: 1.5rem; } + +// Fix descenders clipping in line-height #6047 +h3 .TruncatedText { + line-height: 1.5; +} diff --git a/ui/v2.5/src/locales/bg-BG.json b/ui/v2.5/src/locales/bg-BG.json new file mode 100644 index 000000000..65f57dee2 --- /dev/null +++ b/ui/v2.5/src/locales/bg-BG.json @@ -0,0 +1,402 @@ +{ + "actions": { + "add": "Добави", + "add_directory": "Добави Директория", + "add_entity": "Добави {entityType}", + "add_manual_date": "Добави дата ръчно", + "add_sub_groups": "Добави Подгрупа", + "add_o": "Добави О", + "add_play": "Добави Гледане", + "add_to_entity": "Добави към {entityType}", + "allow": "Позволи", + "allow_temporarily": "Позволи временно", + "anonymise": "Анонимизирай", + "apply": "Приложи", + "auto_tag": "Автоматично Тагване", + "backup": "Резервно копие", + "browse_for_image": "Преглеждане за картина…", + "cancel": "Отмяна", + "choose_date": "Избери дата", + "clean": "Изчисти", + "clean_generated": "Изчисти генерирани файлове", + "clear": "Изчисти", + "clear_back_image": "Изчисти задна картина", + "clear_date_data": "Изчисти дата на данни", + "clear_front_image": "Изчисти предна картина", + "clear_image": "Изичисти картина", + "close": "Затвори", + "confirm": "Потвърди", + "continue": "Продължи", + "copy_to_clipboard": "Копиране в буфера", + "create": "Създай", + "create_chapters": "Създай Глава", + "create_entity": "Създай {entityType}", + "create_marker": "Създай Маркер", + "create_parent_studio": "Създай родителско студио", + "created_entity": "Създаден {entity_type}: {entity_name}", + "customise": "Персонализирай", + "delete": "Изтрий", + "delete_entity": "Изтрий {entityType}", + "delete_file": "Изтрий файла", + "delete_file_and_funscript": "Изтрий файл (и funscript)", + "delete_generated_supporting_files": "Изтрий генерирани поддържащи файлове", + "disable": "Изключи", + "disallow": "Забрани", + "download": "Свали", + "download_anonymised": "Свали анонимизирана", + "download_backup": "Свали резевно копие", + "edit": "Редакция", + "edit_entity": "Редакция {entityType}", + "enable": "Активирай", + "encoding_image": "Кодиране на картина…", + "export": "Експортиране", + "export_all": "Експортирай всичко…", + "reshuffle": "Пренареди", + "assign_stashid_to_parent_studio": "Присвояване на Stash ID към съществуващо родителско студио и актуализиране на метаданните", + "find": "Намери", + "finish": "Приключи", + "from_file": "От файл…", + "from_url": "От URL…", + "full_export": "Пълен експорт", + "full_import": "Пълен Импорт", + "generate": "Генерирай", + "generate_thumb_default": "Генерирай тъмбнайл по подразбиране", + "generate_thumb_from_current": "Генерирай тъмбнайл от сегашният кадър", + "hash_migration": "миграция на хеш", + "hide": "Скрий", + "hide_configuration": "Скрий конфигурация", + "identify": "Индентифицирай", + "ignore": "Игнорирай", + "import": "Импорт…", + "import_from_file": "Импорт от файл", + "load": "Зареди", + "load_filter": "Зареди филтър", + "logout": "Изход", + "make_primary": "Направи Основен", + "merge": "Слей", + "merge_from": "Слей от", + "merge_into": "Слей към", + "migrate_blobs": "Мигрирай Блобове", + "migrate_scene_screenshots": "Мигрирай Скрийншоти от Сцени", + "next_action": "Следващ", + "not_running": "не върви", + "open_in_external_player": "Отвори в външет плейер", + "open_random": "Отвори Случайно", + "optimise_database": "Оптимизирай База Данни", + "overwrite": "Презапиши", + "play": "Пусни", + "play_random": "Пусни Случайно", + "play_selected": "Пусни избраните", + "preview": "Преглеждане", + "previous_action": "Назад", + "reassign": "Презадай", + "refresh": "Опресни", + "reload": "Презареди", + "reload_plugins": "Презареди плъгините", + "reload_scrapers": "Презареди търкачите", + "remove": "Премахни", + "remove_date": "Премахни дата", + "remove_from_containing_group": "Премахни от Група", + "remove_from_gallery": "Премахни от Галерия", + "rename_gen_files": "Преименувай генериран файл", + "rescan": "Пресканирай", + "reset_play_duration": "Нулирай период на пускане", + "reset_resume_time": "Нулирай преме за възтановяване", + "reset_cover": "Възтанови Първоначална Корица", + "running": "върви", + "save": "Запази", + "save_delete_settings": "Изполвай тези настройки по подразвиране при изтриване", + "save_filter": "Запази филтър", + "scan": "Сканирай", + "scrape": "Изтъркай", + "scrape_query": "Изтъркай със заявка", + "scrape_scene_fragment": "Изтъркай по частица", + "scrape_with": "Изтъркай чрез…", + "search": "Търси", + "select_all": "Избери Всичко", + "select_entity": "Избери {entityType}", + "select_folders": "Избери папки", + "select_none": "Избери Нищо", + "selective_auto_tag": "Избирателно Автоматично Тагване", + "selective_clean": "Избирателно Почистване", + "selective_scan": "Избирателно Сканиране", + "set_as_default": "Сложи по подразбиране", + "set_back_image": "Задна картина…", + "set_cover": "Сложи Като Корица", + "set_front_image": "Предна Картина…", + "set_image": "Сложи картина…", + "show": "Покажи", + "show_configuration": "Покажи Конфигурация", + "show_results": "Покажи резултат", + "show_count_results": "Покажи {count} резултати", + "sidebar": { + "close": "Затвори странично меню", + "open": "Отвори странично меню", + "toggle": "Превключи странично меню" + }, + "skip": "Пропусни", + "split": "Раздели", + "stop": "Спри", + "submit": "Подай", + "submit_stash_box": "Подай към Stash-Box", + "submit_update": "Подай обноваване", + "swap": "Подмени", + "tasks": { + "clean_confirm_message": "Сигурен ли си че искаш да Изчистиш? Това ще изтрие иформацията от база данни и генерирано съдържание за всички сцени и галерий който не мога да бъдат намерени на файловата система.", + "dry_mode_selected": "Избрано е Сухо Пускане. Нищо няма да бъде изтрито на истина, са ще бъде записано в логовете.", + "import_warning": "Сигурен ли си че искаш да импортираш? Това ще изтрие базата данни и че вкара на ново твоите експортирани метаданни." + }, + "temp_disable": "Спри временно…", + "temp_enable": "Включи временно…", + "unset": "Премахни", + "use_default": "Използвай на стойностите по подразбиране", + "view_history": "Виж история", + "view_random": "Виж Случайно" + }, + "actions_name": "Действия", + "age": "Години", + "age_on_date": "{age} по време на продукция", + "aliases": "Псевдоними", + "all": "всички", + "also_known_as": "Също така познат/а като", + "appears_with": "Има Участия Със", + "ascending": "Възходящ", + "audio_codec": "Аудио Кодек", + "average_resolution": "Средностатистическа Резолюция", + "between_and": "и", + "birth_year": "Година на раждане", + "birthdate": "Дата на раждане", + "bitrate": "Бит Рейт", + "blobs_storage_type": { + "database": "База Данни", + "filesystem": "Файлова Система" + }, + "captions": "Субтитри", + "career_length": "Подължителност на Кариера", + "chapters": "Глави", + "circumcised": "Образан", + "circumcised_types": { + "CUT": "Обрязан", + "UNCUT": "Необрязан" + }, + "component_tagger": { + "config": { + "active_instance": "Активни инстанции на stash-box:", + "blacklist_desc": "Предмети от черният списък са изключени от заяки. Забележи че те са regular expressions и не гледа главни и малки букви. Някой символи трябва да пъдат escape-нати със наклонка: {chars_require_escape}", + "blacklist_label": "Черен списък", + "errors": { + "blacklist_duplicate": "Дубликирани предмети от черния списък" + }, + "mark_organized_desc": "Веднага отбележи сцена като Организирана след като се натисне бутон Запази.", + "mark_organized_label": "Отбележи като Организирана на запазване", + "query_mode_auto": "Автоматично", + "query_mode_auto_desc": "Използа метаданни ако съществиват, или име на файл", + "query_mode_dir": "Папка", + "query_mode_dir_desc": "Използва само папката която съдържа видео файла", + "query_mode_filename": "Име на файл", + "query_mode_filename_desc": "Използва само име на файл", + "query_mode_label": "Мод на Заявки", + "query_mode_metadata": "Мета данни", + "query_mode_metadata_desc": "Използва само мета данни", + "query_mode_path": "Път", + "query_mode_path_desc": "Използва целият път на файла", + "set_cover_desc": "Замени корицата на сцената ако се намери такава.", + "set_cover_label": "Заложи картина за корица на сцена", + "set_tag_desc": "Закачи тагове към сцената, или чрез презаписване или чрез сливане със съществуващите тагове на сцената.", + "set_tag_label": "Задай тагове", + "show_male_desc": "Превключи дали мъжки изпълнители ще въдат предоставени за тагване.", + "show_male_label": "Покажи мъжки изпълнители", + "source": "Източник" + }, + "noun_query": "Заявка", + "results": { + "duration_off": "Продължителност не съвпада с поне {number} сек.", + "duration_unknown": "Неизвестна продължителност", + "fp_matches": "Продължителността съвпада", + "fp_matches_multi": "Продължителността съвпада {matchCount}/{durationsLength} отпечатъци", + "hash_matches": "{hash_type} съвпада", + "match_failed_already_tagged": "Сцената вече има тагове", + "match_failed_no_result": "Няма намерени резултати", + "match_success": "Счената е успешно тагната", + "phash_matches": "{count} PHashes съвпадат", + "unnamed": "Неименуван" + }, + "verb_match_fp": "Сравни Отпечатъци", + "verb_matched": "Сравнени", + "verb_scrape_all": "Изтъркай Всичко", + "verb_submit_fp": "Подай {fpCount, plural, one{# Отпечатък} other{# Отпечатъци}}", + "verb_toggle_unmatched": "{toggle} несъвпадаци сцени" + }, + "config": { + "about": { + "build_hash": "Хеш на билда:", + "build_time": "Време на билда:", + "check_for_new_version": "Проверка за нова версия", + "latest_version": "Последна Версия", + "latest_version_build_hash": "Хеш на билда на Последна Версия:", + "new_version_notice": "[НОВО]", + "release_date": "Дана за издаване:", + "stash_discord": "Присъедини се към нашият {url} канал", + "stash_home": "Stash home на {url}", + "stash_open_collective": "Подкрепи ни чрез {url}", + "stash_wiki": "Stash {url} страница", + "version": "Версия" + }, + "advanced_mode": "Мод за Напреднали", + "application_paths": { + "heading": "Пътища на Апликация" + }, + "categories": { + "about": "Относно", + "changelog": "Списък на промените", + "interface": "Интерфейс", + "logs": "Дневници", + "metadata_providers": "Доставчици на Мета данни", + "plugins": "Приставки", + "scraping": "Търкане", + "security": "Сигурност", + "services": "Услуги", + "system": "Система", + "tasks": "Задачи", + "tools": "Иструменти" + }, + "dlna": { + "allow_temp_ip": "Позволи {tempIP}", + "allowed_ip_addresses": "Позволени IP адреси", + "allowed_ip_temporarily": "Позволени IP временно", + "default_ip_whitelist": "Основен IP Бъл списък", + "default_ip_whitelist_desc": "Основени IP адреси позволени да достигат DLNA. Изполвай {wildcard} за да позволиш всички IP адреси.", + "disabled_dlna_temporarily": "Временно изключено DLNA", + "disallowed_ip": "Непозволени IP", + "enabled_by_default": "Включено по подразвиране", + "enabled_dlna_temporarily": "Временно включено DLNA", + "network_interfaces": "Интерфейси", + "network_interfaces_desc": "Интерфейси да се достъпн DLNA сървъра. Празен лист ще ползва всички интерфейси. Изисква DLNA рестрат след промяна.", + "recent_ip_addresses": "Скорошни IP адреси", + "server_display_name": "Име за Покаване на Сървъра", + "server_display_name_desc": "Име за покаване на DLNA сървъра. По подразбиране {server_name} ако е празно.", + "server_port": "Порт на Сървъра", + "server_port_desc": "Порт на който да върви DLNA сървъра. Изисква рестарт на DLNA след промяна.", + "successfully_cancelled_temporary_behaviour": "Успешно отказано временно поведение", + "until_restart": "до рестартиране", + "video_sort_order": "Ред на Видеа по подразбиране", + "video_sort_order_desc": "Ред по който да реди видеа по подразбиране." + }, + "general": { + "auth": { + "api_key": "API ключ", + "api_key_desc": "API ключ за външни системи. Нужен само когато име/парола са настроени. Името трябва да бъде запазене преди генерация на API ключ.", + "authentication": "Идентификация", + "clear_api_key": "Изчисти API ключ", + "credentials": { + "description": "Удостоверителни данни за контрол на достъпа до stash.", + "heading": "Удостоверителни данни" + }, + "generate_api_key": "Генерирай API ключ", + "log_file": "Лог файл", + "log_file_desc": "Път към файла за извод на лог. Празен за да спре извод на лог. Изисква рестарт.", + "log_http": "Логвай http достъп", + "log_http_desc": "Логва http достъп на терминала. Изисква рестарт.", + "log_to_terminal": "Лог към терминал", + "log_to_terminal_desc": "Логва към терминал заедно с към файл. Винаги истина ако логване към файл е изключено. Изискава рестарт.", + "maximum_session_age": "Максимална Продължителност на Сесия", + "maximum_session_age_desc": "Максимално време на бездействие, преди сесията за вход да изтече, в секунди. Изисква рестартиране.", + "password": "Парола", + "password_desc": "Парола за достъп до Stash. Остави празно за да изключи достъп чрез потребител", + "stash-box_integration": "Stash-box интеграция", + "username": "Потребителско име", + "username_desc": "Потребителско име за достъп до Stash. Остави празно за да изключи достъп чрез потребител", + "log_file_max_size": "Максимален размер на файла", + "log_file_max_size_desc": "Максимален размер в мегабайти на лог файла преди компресиране. 0 MB означава деактивирано. Изисква рестартиране." + }, + "backup_directory_path": { + "description": "Местоположение на папка за резрвни SQLite бази данни", + "heading": "Път към Папка за Резервни Данни" + }, + "blobs_path": { + "description": "Къде във файловата система да се пазят бинарни данни. Позва се само ако се ползва Файлова система за блоб пазене. ВНИМАНИЕ: промяната ще изисква ръчно местене на съществуващи данни.", + "heading": "Път до файловата система за двоични данни" + } + }, + "ui": { + "custom_locales": { + "option_label": "Персонализирана локализация е активирана" + }, + "delete_options": { + "description": "Настройки по подразбиране при триене на картини, галерий и сцени.", + "heading": "Изтриване на настройки", + "options": { + "delete_file": "Изтриване на файлове по подразбиране", + "delete_generated_supporting_files": "Изтриване на генерираните поддържащи файлове по подразбиране" + } + }, + "desktop_integration": { + "desktop_integration": "Десктоп Интеграция", + "notifications_enabled": "Включване на известяването", + "send_desktop_notifications_for_events": "Изпащане на десктоп известявания за събития", + "skip_opening_browser": "Пропускане на отваряне на браузер", + "skip_opening_browser_on_startup": "Пропускане на автоматично отваряне на броузер по време на стартиране" + }, + "detail": { + "compact_expanded_details": { + "description": "Когато е включена, тази настройка ще предосвати разширени детайли запавайки компактна презентация", + "heading": "Компактни разширени детайли" + }, + "enable_background_image": { + "description": "Покажи фонова картина на станицата с детайли.", + "heading": "Включи фонова картина" + }, + "heading": "Станица с детайли", + "show_all_details": { + "description": "Когато е включена, всичкото съдържание ще бъде показано по подразбиране и всеки детайл ще бъде в собствена колона", + "heading": "Покажи всички детайли" + } + }, + "editing": { + "disable_dropdown_create": { + "description": "Премахни възможноста да се създават нови обекти от падащият селектор", + "heading": "Изключи падащо създаване" + }, + "heading": "Редактиране", + "max_options_shown": { + "label": "Максимален брой неща който се показват в падащ селектор" + }, + "rating_system": { + "star_precision": { + "label": "Точност на звездния рейтинг", + "options": { + "full": "Цели", + "half": "Половинки", + "quarter": "Четвъртинки", + "tenth": "Десетици" + } + }, + "type": { + "label": "Тип система за рейтинг", + "options": { + "decimal": "Десетична", + "stars": "Звезди" + } + } + } + }, + "funscript_offset": { + "description": "Време за разминаване в милисекунди за пускане на интерактивни скриптове.", + "heading": "Funscript разминаване (ms)" + }, + "handy_connection": { + "connect": "Свързване", + "server_offset": { + "heading": "Сървърно разминаване" + }, + "status": { + "heading": "Статус на връзка с Handy" + }, + "sync": "Синхронизиране" + }, + "handy_connection_key": { + "description": "Handy connection key за ползване със интерактивни сцени. Слагането на този ключ ще позволи на Stash да сподели иформация за текущата сцена със handyfeeling.com" + } + } + } +} diff --git a/ui/v2.5/src/locales/ca-ES.json b/ui/v2.5/src/locales/ca-ES.json index 9ad457bc1..3c2452671 100644 --- a/ui/v2.5/src/locales/ca-ES.json +++ b/ui/v2.5/src/locales/ca-ES.json @@ -136,7 +136,8 @@ "add_play": "Agregar reproduir", "add_to_entity": "Afegir a {entityType}", "create_entity": "Crear {entityType}", - "add_sub_groups": "Afegeix subgrups" + "add_sub_groups": "Afegeix subgrups", + "remove_from_containing_group": "Suprimeix del grup" }, "appears_with": "Apareix amb", "career_length": "Durada de la carrera", diff --git a/ui/v2.5/src/locales/cs-CZ.json b/ui/v2.5/src/locales/cs-CZ.json index 622e57706..a518e1d4d 100644 --- a/ui/v2.5/src/locales/cs-CZ.json +++ b/ui/v2.5/src/locales/cs-CZ.json @@ -6,15 +6,15 @@ "add_to_entity": "Přidat do {entityType}", "allow": "Povolit", "allow_temporarily": "Povolit dočasně", - "apply": "Potvrdit", + "apply": "Použít", "auto_tag": "Auto Tag", "backup": "Záloha", "browse_for_image": "Vybrat obrázek…", "cancel": "Zrušit", "clean": "Vyčistit", "clear": "Vyčistit", - "clear_back_image": "Vymazat zadní obrázek", - "clear_front_image": "Vymazat přední obrázek", + "clear_back_image": "Vymazat obrázek zadní strany", + "clear_front_image": "Vymazat obrázek přední strany", "clear_image": "Vymazat obrázek", "close": "Zavřít", "confirm": "Potvrdit", @@ -106,9 +106,9 @@ "submit_update": "Publikovat aktualizaci", "swap": "Prohodit", "tasks": { - "clean_confirm_message": "Jste si jistý, že chcete vyčistit databázi? Tato operace vymaže informace z databáze a generovaný obsah pro všechny scény a galerie, které se již nenacházejí v souborovém systému.", + "clean_confirm_message": "Chcete doopravdy provést vyčištění databáze? Tato operace vymaže informace z databáze a generovaný obsah pro všechny scény a galerie, které se již nenacházejí v souborovém systému.", "dry_mode_selected": "Vybrán \"Dry Mode\". Nic nebude smazáno, pouze logováno.", - "import_warning": "Jste si jisti, že chcete importovat? Tato operace smaže databázi a znovu importuje z Vašich exportovaných metadat." + "import_warning": "Chcete doopravdy provést import? Tato operace smaže databázi a znovu naimportuje Vaše exportovaná metadata." }, "temp_disable": "Zakázat dočasně…", "temp_enable": "Povolit dočasně…", @@ -129,9 +129,9 @@ "assign_stashid_to_parent_studio": "Přiřaď Stash ID k existujícímu nadřazenému studiu a aktualizuj metadata", "choose_date": "Vyberte datum", "create_chapters": "Vytvořit kapitolu", - "clear_date_data": "Vymazat data datumu", + "clear_date_data": "Vymazat informace o datumech", "reload": "Načíst znovu", - "clean_generated": "Vyčistěte vygenerované soubory", + "clean_generated": "Vyčistit vygenerované soubory", "remove_date": "Odstranit datum", "add_manual_date": "Přidat datum ručně", "add_play": "Přidat přehrávání", @@ -139,9 +139,19 @@ "reset_cover": "Obnovit výchozí obal", "add_sub_groups": "Přidat podskupinu", "set_cover": "Nastavit jako obal", - "remove_from_containing_group": "Odebrat ze skupiny", + "remove_from_containing_group": "Odstranit ze skupiny", "reset_resume_time": "Obnovit čas pokračování", - "reset_play_duration": "Obnovit dobu přehrávání" + "reset_play_duration": "Obnovit dobu přehrávání", + "sidebar": { + "close": "Zavřít postranní panel", + "open": "Zobrazit postranní panel", + "toggle": "Boční panel" + }, + "play": "Přehrát", + "show_results": "Zobrazit výsledky", + "show_count_results": "Zobrazit {count} výsledků", + "load": "Načíst", + "load_filter": "Načíst filtr" }, "actions_name": "Akce", "age": "Věk", @@ -283,7 +293,9 @@ "password_desc": "Heslo pro přístup do aplikace. Ponechte prázdné pro vypnutí autentizace", "stash-box_integration": "Stash-box integrace", "username": "Přihlašovací jméno", - "username_desc": "Přihlašovací jméno pro přístup do aplikace. Ponechte prázdné pro vypnutí autentizace" + "username_desc": "Přihlašovací jméno pro přístup do aplikace. Ponechte prázdné pro vypnutí autentizace", + "log_file_max_size": "Maximální velikost logu", + "log_file_max_size_desc": "Maximální velikost logu v megabytech před kompresí. 0MB pro deaktivaci. Vyžaduje restart." }, "backup_directory_path": { "description": "Adresář umístění záloh databáze SQLite", @@ -333,7 +345,7 @@ "description": "Cesta ke spustitelnému souboru pythonu (nejen ke složce). Používá se pro script scrappery a pluginy. Pokud je prázdné, python bude vyřešen z prostředí", "heading": "Cesta k Pythonu" }, - "scraper_user_agent": "Scraper User Agent", + "scraper_user_agent": "User Agent Scraperu", "scraper_user_agent_desc": "User-Agent řetězec používaný při scrapování http požadavků", "scrapers_path": { "description": "Adresář konfiguračních souborů scraperů", @@ -435,7 +447,9 @@ "endpoint": "Koncový bod", "graphql_endpoint": "Koncový bod GraphQL", "name": "Název", - "title": "Stash-box Endpointy" + "title": "Stash-box Endpointy", + "max_requests_per_minute": "Maximální počet dotazů za minutu", + "max_requests_per_minute_description": "Používá základní hodnotu {defaultValue} pokud je nastaven na 0" }, "system": { "transcoding": "Překódování" @@ -561,7 +575,9 @@ "whitespace_chars": "Whitespace znaky", "whitespace_chars_desc": "Tyto znaky v názvu budou nahrazeny prázdným znakem (mezerou)" }, - "scene_tools": "Nástroje pro scény" + "scene_tools": "Nástroje pro scény", + "graphql_playground": "GraphQL hřiště", + "heading": "Nástroje" }, "ui": { "abbreviate_counters": { @@ -710,7 +726,7 @@ "heading": "Automaticky spustit video při přehrávání vybraného" }, "continue_playlist_default": { - "description": "Přehrát následující scénu na seznamu při skončení vida", + "description": "Přehrát následující scénu na seznamu při skončení videa", "heading": "(Výchozí nastavení) Pokračovat v playlistu" }, "show_scrubber": "Zobrazit Scrubber", @@ -786,6 +802,18 @@ "use_stash_hosted_funscript": { "description": "Je-li povoleno, budou funscripty poskytovány přímo ze Stash do vašeho zařízení Handy bez použití serveru Handy třetí strany. Vyžaduje, aby byl Stash dostupný z vašeho zařízení Handy a vygenerovaný API klíč, pokud má stash nakonfigurované údaje.", "heading": "Funscripty podávejte přímo" + }, + "sfw_mode": { + "description": "Zapněte zda použáváte stash k ukládání SFW obsahu. Schová nebo změní některé aspekty uživatelského rozhraní související s obsahem pro dospělé.", + "heading": "Režim obsahu SFW" + }, + "performer_list": { + "heading": "List účinkujicích", + "options": { + "show_links_on_grid_card": { + "heading": "Zobrazit odkazy na mřížce karet účinkujicích" + } + } } }, "advanced_mode": "Pokročilý mód" @@ -840,12 +868,12 @@ "developmentVersion": "Vývojářská verze", "dialogs": { "delete_alert": "Následující {count, plural, one {{singularEntity}} other {{pluralEntity}}} budou permanentně smazány:", - "delete_confirm": "Jste si jisti, že chcete smazat {entityName}?", - "delete_entity_desc": "{count, plural, one {Jste si jisti, že checete smazat toto {singularEntity}? Pokud není soubor rovněž smazán, tato {singularEntity} bude znovu přidána při příštím skenování.} other {Jste si jisti, že chcete smazat tyto {pluralEntity}? Pokud nejsou soubory rovněž smazány, tyto {pluralEntity} budou znovu přidány při příštím skenování.}}", + "delete_confirm": "Chcete doopravdy smazat {entityName}?", + "delete_entity_desc": "{count, plural, one {Doopravdy chcete smazat {singularEntity}? Pokud nebude smazán i soubor, {singularEntity} bude znovu přidán při příštím skenování.} other {Doopravdy chcete smazat tyto {pluralEntity}? Pokud nebudou smazány i soubory, tyto {pluralEntity} budou znovu přidány při příštím skenování.}}", "delete_entity_title": "{count, plural, one {Smazat {singularEntity}} other {Smazat {pluralEntity}}}", "delete_galleries_extra": "…navíc všechny obrazové soubory, které nejsou připojeny k žádné jiné galerii.", "delete_gallery_files": "Smazat složku galerie/zip soubor a jakékoliv obrázky nenapojené na jinou galerii.", - "delete_object_desc": "Jste si jisti, že chcete smazat {count, plural, one {tuto {singularEntity}} other {tyto {pluralEntity}}}?", + "delete_object_desc": "Doopravdy chcete smazat {count, plural, one {{singularEntity}} other {tyto {pluralEntity}}}?", "delete_object_overflow": "…a {count} other {count, plural, one {{singularEntity}} other {{pluralEntity}}}.", "delete_object_title": "Smazat {count, plural, one {{singularEntity}} other {{pluralEntity}}}", "dont_show_until_updated": "Skrýt do příští aktualizace", @@ -878,7 +906,6 @@ "destination": "Cíl", "source": "Zdroj" }, - "overwrite_filter_confirm": "JSte si jisti, že chcete přepsat aktuálně uložený dotaz {entityName}?", "scene_gen": { "force_transcodes": "Vynutit generování Transkódu", "force_transcodes_tooltip": "Ve výchozím nastavení, transkódy jsou generovány pouze tehdy, když video soubor není podporován prohlížečem. V případě aktivování, transkódy budou generovány i v ostatních případech.", @@ -946,7 +973,10 @@ "clear_o_history_confirm": "Opravdu chcete vymazat historii O?", "clear_play_history_confirm": "Opravdu chcete vymazat historii přehrávání?", "delete_entity_simple_desc": "{count, plural, one {Opravdu chcete smazat tuto {singularEntity}?} other {Opravdu chcete smazat tyto {pluralEntity}?}}", - "performers_found": "{count} nalezených účinkujících" + "performers_found": "{count} nalezených účinkujících", + "overwrite_filter_warning": "Uložený filtr \"{entityName}\" bude přepsán.", + "set_default_filter_confirm": "Chcete doopravdy nastavit tento filtr jako výchozí?", + "clear_o_history_confirm_sfw": "Opravdu chcete vymazat historii lajků?" }, "chapters": "Kapitoly", "circumcised": "Obřezán", @@ -1012,7 +1042,8 @@ "grid": "Mřížka", "tagger": "Tagger", "wall": "Stěna", - "unknown": "Neznámý" + "unknown": "Neznámý", + "label_current": "Mód zobrazení: {current}" }, "effect_filters": { "aspect": "Aspekt", @@ -1132,7 +1163,7 @@ "setup": { "paths": { "where_can_stash_store_its_generated_content_description": "Aby Stash mohl poskytovat miniatury, náhledy a sprity generuje Stash obrázky a videa. To zahrnuje také transkódování pro nepodporované formáty souborů. Ve výchozím nastavení Stash vytvoří generated adresář v adresáři obsahujícím váš konfigurační soubor. Pokud chcete změnit, kam se budou tato generovaná media ukládat, zadejte prosím absolutní nebo relativní (k aktuálnímu pracovnímu adresáři) cestu. Stash vytvoří tento adresář, pokud ještě neexistuje.", - "where_is_your_porn_located_description": "Přidejte adresáře obsahující vaše porno videa a obrázky. Stash použije tyto adresáře k vyhledání videí a obrázků během skenování.", + "where_is_your_porn_located_description": "Přidejte adresáře obsahující váše videa a obrázky. Stash použije tyto adresáře k vyhledání videí a obrázků během skenování.", "where_can_stash_store_blobs_description": "Kam může Stash ukládat binární data jako jsou obaly scén, účinkující, studia a obrázky tagů, buď v databázi nebo v souborovém systému. Ve výchozím nastavení bude tato data ukládat do souborového systému v podadresáři blobs v adresáři obsahujícím váš konfigurační soubor. Pokud to chcete změnit, zadejte prosím absolutní nebo relativní (k aktuálnímu pracovnímu adresáři) cestu. Stash vytvoří tento adresář, pokud ještě neexistuje.", "path_to_cache_directory_empty_for_default": "cesta k adresáři mezipaměti (ve výchozím nastavení prázdné)", "path_to_generated_directory_empty_for_default": "cesta k adresáři vygenerovaných souborů (ve výchozím nastavení prázdné)", @@ -1141,16 +1172,19 @@ "where_can_stash_store_its_generated_content": "Kam může Stash ukládat svůj vygenerovaný obsah?", "where_can_stash_store_its_database_warning": "VAROVÁNÍ: Uložení databáze na jiný systém, než ze kterého se spouští Stash (např. uložení databáze na NAS při spuštění serveru Stash na jiném počítači), nepodporováno! SQLite není určen pro použití v síti a pokus o to může velmi snadno způsobit poškození celé vaší databáze.", "database_filename_empty_for_default": "název souboru databáze (ve výchozím nastavení prázdné)", - "description": "Dále musíme určit, kde najdeme vaši sbírku porna a kam uložit databázi Stash, vygenerované soubory a soubory mezipaměti. Tato nastavení lze v případě potřeby později změnit.", + "description": "Dále musíme určit, kde najdeme vaši sbírku obsahu a kam uložit databázi Stash, vygenerované soubory a soubory mezipaměti. Tato nastavení lze v případě potřeby později změnit.", "path_to_blobs_directory_empty_for_default": "cesta k adresáři blobů (ve výchozím nastavení prázdné)", "stash_alert": "Nebyla vybrána žádná cesta knihovny. Žádné médium nebude možné naskenovat do Stash. Jste si jisti?", - "where_is_your_porn_located": "Kde se nachází vaše porno?", + "where_is_your_porn_located": "Kde se nachází váš obsah?", "where_can_stash_store_cache_files_description": "Aby některé funkce, jako je živé transkódování HLS/DASH, fungovaly, vyžaduje Stash adresář mezipaměti pro dočasné soubory. Ve výchozím nastavení Stash vytvoří adresář mezipaměť v adresáři obsahujícím váš konfigurační soubor. Pokud to chcete změnit, zadejte prosím absolutní nebo relativní (k aktuálnímu pracovnímu adresáři) cestu. Stash vytvoří tento adresář, pokud ještě neexistuje.", "where_can_stash_store_its_database": "Kde může Stash uložit svou databázi?", "where_can_stash_store_blobs": "Kde může Stash ukládat binární data databáze?", "where_can_stash_store_blobs_description_addendum": "Případně můžete tato data uložit do databáze. Poznámka: Tím se zvětší velikost souboru databáze a prodlouží se doba migrace databáze.", - "where_can_stash_store_its_database_description": "Stash používá databázi SQLite k ukládání metadat porna. Ve výchozím nastavení bude tento soubor vytvořen jako stash-go.sqlite v adresáři obsahujícím váš konfigurační soubor. Pokud to chcete změnit, zadejte prosím absolutní nebo relativní (k aktuálnímu pracovnímu adresáři) název souboru.", - "store_blobs_in_database": "Uložte bloby do databáze" + "where_can_stash_store_its_database_description": "Stash používá databázi SQLite k ukládání metadat obsahu. Ve výchozím nastavení bude tento soubor vytvořen jako stash-go.sqlite v adresáři obsahujícím váš konfigurační soubor. Pokud to chcete změnit, zadejte prosím absolutní nebo relativní (k aktuálnímu pracovnímu adresáři) název souboru.", + "store_blobs_in_database": "Uložte bloby do databáze", + "sfw_content_settings": "Používáte stash k SFW obsahu?", + "sfw_content_settings_description": "Stash lze použít ke správě SFW obsahu, jako jsou fotografie, umění, komiksy a další. Povolení této možnosti upraví některé vlastnosti uživatelského rozhraní tak, aby byly vhodnější pro SFW obsah.", + "use_sfw_content_mode": "Použít režim obsahu SFW" }, "stash_setup_wizard": "Průvodce nastavením Stash", "success": { @@ -1261,7 +1295,7 @@ "syncing": "Probíhá synchronizace se serverem", "uploading": "Nahrávání skriptu" }, - "hasMarkers": "Má značky", + "hasMarkers": "Značky", "height_cm": "Výška (cm)", "include_sub_studios": "Zahrnout dceřiná studia", "interactive": "Interaktivní", @@ -1294,7 +1328,6 @@ "o_count": "Počet O" }, "megabits_per_second": "{value} mbps", - "o_counter": "O-Počítadlo", "none": "Žádný", "pagination": { "last": "Poslední", @@ -1315,7 +1348,9 @@ "saved_filters": "Uložené filtry", "update_filter": "Aktualizovat filtr", "edit_filter": "Upravit filtr", - "name": "Filtr" + "name": "Filtr", + "more_filter_criteria": "+{count} navíc", + "search_term": "Hledaný výraz" }, "ethnicity": "Etnická příslušnost", "existing_value": "Existujicí hodnota", @@ -1336,7 +1371,7 @@ }, "hair_color": "Barva vlasů", "help": "Pomoc", - "hasChapters": "Má kapitoly", + "hasChapters": "Kapitoly", "height": "Výška", "ignore_auto_tag": "Ignoruj automatické tagování", "instagram": "Instragram", @@ -1522,5 +1557,17 @@ }, "age_on_date": "{age} během produkce", "sort_name": "Seřadit jména", - "eta": "Přibližný čas dokončení" + "eta": "Přibližný čas dokončení", + "login": { + "password": "Heslo", + "invalid_credentials": "Neplatné uživatelské jméno nebo heslo", + "login": "Přihlášení", + "username": "Uživatelské jméno", + "internal_error": "Neočekávaná interní chyba. Podívej se do logu pro více detailů" + }, + "last_o_at_sfw": "Poslední lajk", + "o_count_sfw": "Lajky", + "o_history_sfw": "Historie lajků", + "odate_recorded_no_sfw": "Žádný datum lajku nebyl zaznamenán", + "scenes_duration": "Trvání scény" } diff --git a/ui/v2.5/src/locales/da-DK.json b/ui/v2.5/src/locales/da-DK.json index 033f1896e..54cc89938 100644 --- a/ui/v2.5/src/locales/da-DK.json +++ b/ui/v2.5/src/locales/da-DK.json @@ -821,7 +821,6 @@ "destination": "Destination", "source": "Kilde" }, - "overwrite_filter_confirm": "Er du sikker på, at du vil overskrive eksisterende gemte forespørgsel {entityName}?", "scene_gen": { "force_transcodes": "Tving omkodningsgenerering", "force_transcodes_tooltip": "Som standard genereres omkoder kun, når videofilen ikke understøttes i browseren. Når det er aktiveret, genereres omkoder, selv når videofilen ser ud til at være understøttet i browseren.", @@ -1033,7 +1032,6 @@ "name": "Navn", "new": "Ny", "none": "Ingen", - "o_counter": "O-tæller", "operations": "Operationer", "organized": "Organiseret", "pagination": { diff --git a/ui/v2.5/src/locales/de-DE.json b/ui/v2.5/src/locales/de-DE.json index df7d089db..3354d4085 100644 --- a/ui/v2.5/src/locales/de-DE.json +++ b/ui/v2.5/src/locales/de-DE.json @@ -141,7 +141,17 @@ "remove_from_containing_group": "Von Gruppe entfernen", "reset_play_duration": "Spieldauer zurücksetzten", "reset_resume_time": "Fortschritt zurücksetzten", - "add_sub_groups": "Untergruppen hinzufügen" + "add_sub_groups": "Untergruppen hinzufügen", + "play": "Abspielen", + "sidebar": { + "toggle": "Seitenleiste umschalten", + "close": "Seitenleiste schließen", + "open": "Seitenleiste öffnen" + }, + "show_count_results": "Zeige {count} Ergebnisse", + "show_results": "Ergebnisse anzeigen", + "load_filter": "Filter laden", + "load": "Laden" }, "actions_name": "Aktionen", "age": "Alter", @@ -294,7 +304,9 @@ "password_desc": "Passwort für den Zugriff auf Stash. Feld leer lassen, um Benutzerauthentifizierung zu deaktivieren", "stash-box_integration": "Stash-box Einbindung", "username": "Benutzername", - "username_desc": "Benutzername für den Zugriff auf Stash. Feld leer lassen, um Benutzerauthentifizierung zu deaktivieren" + "username_desc": "Benutzername für den Zugriff auf Stash. Feld leer lassen, um Benutzerauthentifizierung zu deaktivieren", + "log_file_max_size": "Maximale Log Größe", + "log_file_max_size_desc": "Maximale Größe, in Megabytes, von den Log Files bevor es komprimiert wird. 0MB ist deaktiviert. Benötigt Neustart." }, "backup_directory_path": { "description": "Verzeichnisspeicherort für SQLite-Datenbankdateisicherungen", @@ -446,7 +458,9 @@ "endpoint": "Endpunkt", "graphql_endpoint": "GraphQL-Endpunkt", "name": "Name", - "title": "Stash-Box-Endpunkte" + "title": "Stash-Box-Endpunkte", + "max_requests_per_minute": "Max requests pro Minute", + "max_requests_per_minute_description": "Verwendet default Wert {defaultValue} wenn auf 0 gesetzt" }, "system": { "transcoding": "Transcodierung" @@ -572,7 +586,9 @@ "whitespace_chars": "Zwischenraumzeichen", "whitespace_chars_desc": "Diese Zeichen werden im Titel durch Zwischenraumzeichen ersetzt" }, - "scene_tools": "Szenen-Tools" + "scene_tools": "Szenen-Tools", + "heading": "Werkzeuge", + "graphql_playground": "GraphQL-Spielplatz" }, "ui": { "abbreviate_counters": { @@ -737,7 +753,8 @@ }, "show_ab_loop_controls": "Die Steuerungselemente des AB-Loop-Plugins anzeigen", "disable_mobile_media_auto_rotate": "Deaktiviere das automatische Drehen von Vollbildmedien auf Mobilgeräten", - "enable_chromecast": "Chromecast aktivieren" + "enable_chromecast": "Chromecast aktivieren", + "show_range_markers": "Zeige Range der Markierungen" } }, "scene_wall": { @@ -796,6 +813,18 @@ "use_stash_hosted_funscript": { "description": "Wenn aktiviert, werden Funscripts direkt von Stash an dein Handy-Gerät gesendet, ohne Handy-Server von Drittanbietern zu verwenden. Erfordert, dass Stash von deinem Handy-Gerät aus zugänglich ist und ein API-Schlüssel generiert wurde, falls Stash mit Zugangsdaten konfiguriert ist.", "heading": "Funscripts direkt bereitstellen" + }, + "performer_list": { + "options": { + "show_links_on_grid_card": { + "heading": "Zeige den Link auf der Darsteller Gitterkarte" + } + }, + "heading": "Darsteller Liste" + }, + "sfw_mode": { + "description": "Aktivieren wenn man Stash für das speichern von SFW content benutzt. Versteckt oder Ändernt ein paar NFSW eigenschaften des UI.", + "heading": "SFW Content Modus" } }, "advanced_mode": "Fortgeschrittener Modus" @@ -905,7 +934,6 @@ "destination": "Ziel", "source": "Quelle" }, - "overwrite_filter_confirm": "Möchten Sie die vorhandene gespeicherte Anfrage {entityName} wirklich überschreiben?", "reassign_entity_title": "{count, plural, one {Weise {singularEntity} neu zu} other {Weise {pluralEntity} neu zu}}}", "reassign_files": { "destination": "Neu zuweisen an" @@ -958,7 +986,10 @@ "unsaved_changes": "Nicht gespeicherte Änderungen. Bist du sicher dass du die Seite verlassen willst?", "clear_play_history_confirm": "Bist du sicher, dass du den Wiedergabeverlauf löschen möchtest?", "performers_found": "{count} Darsteller:innen gefunden", - "clear_o_history_confirm": "Möchten Sie wirklich den O-Verlauf löschen?" + "clear_o_history_confirm": "Möchten Sie wirklich den O-Verlauf löschen?", + "overwrite_filter_warning": "Der gespeicherte Filter \"{entityName}\" wird überschrieben.", + "set_default_filter_confirm": "Sind Sie sicher, dass Sie diesen Filter als Standard festlegen möchten?", + "clear_o_history_confirm_sfw": "Bist du dir sicher das du den Verlauf löschen willst?" }, "dimensions": "Maße", "director": "Regisseur", @@ -968,7 +999,8 @@ "list": "Liste", "tagger": "Tagger", "unknown": "Unbekannt", - "wall": "Wand" + "wall": "Wand", + "label_current": "Anzeigemodus: {current}" }, "donate": "Spenden", "dupe_check": { @@ -1115,7 +1147,7 @@ "interactive_speed": "Interaktive Geschwindigkeit", "performer_card": { "age": "{age} {years_old}", - "age_context": "{age} {years_old} in dieser Szene" + "age_context": "{age} {years_old} bei der Produktion" }, "phash": "PHashwert", "play_count": "Anzahl Wiedergaben", @@ -1129,7 +1161,6 @@ "name": "Name", "new": "Neu", "none": "Keiner", - "o_counter": "O-Zähler", "operations": "Operationen", "organized": "Organisiert", "pagination": { @@ -1218,7 +1249,9 @@ "edit_filter": "Filter editieren", "name": "Filter", "saved_filters": "Gespeicherte Filter", - "update_filter": "Filter aktualisieren" + "update_filter": "Filter aktualisieren", + "more_filter_criteria": "+{count} mehr", + "search_term": "Suchbegriff" }, "second": "Sekunde", "seconds": "Sekunden", @@ -1283,7 +1316,8 @@ "where_is_your_porn_located": "Wo finden wir deine Porno-Kollektion?", "where_is_your_porn_located_description": "Füge Ordner hinzu in denen sich deine Porno-Videos und -Bilder befinden. Stash wird diese Ordner nutzen, um Videos und Bilder in das System einzupflegen.", "path_to_blobs_directory_empty_for_default": "Pfad zum Verzeichnis der blobs (standardmäßig leer)", - "store_blobs_in_database": "blobs in der Datenbank speichern" + "store_blobs_in_database": "blobs in der Datenbank speichern", + "sfw_content_settings": "Benutzt du stash auch für SFW Inhalte?" }, "stash_setup_wizard": "Einrichtungshelfer für Stash", "success": { @@ -1484,7 +1518,9 @@ "custom_fields": { "title": "Benutzerdefinierte Felder", "value": "Wert", - "field": "Feld" + "field": "Feld", + "criteria_format_string": "{criterion} (custom field) {modifierString} {valueString}", + "criteria_format_string_others": "{criterion} (custom field) {modifierString} {valueString} (+{others} others)" }, "distance": "Distanz", "group_count": "Gruppenanzahl", @@ -1517,5 +1553,19 @@ "tag_sub_tag_tooltip": "Hat Untertags", "include_sub_groups": "Untergruppen einbeziehen", "studio_and_parent": "Studio & Mutterstudio", - "eta": "Edited to add" + "eta": "Edited to add", + "login": { + "login": "Login", + "internal_error": "Unvorhergesehener interner Fehler. Weitere Details in den Logs", + "password": "Passwort", + "invalid_credentials": "Ungültiger Nutzername oder Passwort", + "username": "Benutzername" + }, + "age_on_date": "bei Produktion", + "sort_name": "Namen sortieren", + "scenes_duration": "Szenen Dauer", + "last_o_at_sfw": "Letztes mal ein Gefällt mir gegeben am", + "o_count_sfw": "Gefällt mir", + "o_history_sfw": "Gefällt mir Verlauf", + "odate_recorded_no_sfw": "Kein Gefällt mir Datum vermerkt" } diff --git a/ui/v2.5/src/locales/en-GB.json b/ui/v2.5/src/locales/en-GB.json index b69e5a763..28d16e486 100644 --- a/ui/v2.5/src/locales/en-GB.json +++ b/ui/v2.5/src/locales/en-GB.json @@ -68,6 +68,8 @@ "ignore": "Ignore", "import": "Import…", "import_from_file": "Import from file", + "load": "Load", + "load_filter": "Load filter", "logout": "Log out", "make_primary": "Make Primary", "merge": "Merge", @@ -81,6 +83,7 @@ "open_random": "Open Random", "optimise_database": "Optimise Database", "overwrite": "Overwrite", + "play": "Play", "play_random": "Play Random", "play_selected": "Play selected", "preview": "Preview", @@ -124,9 +127,12 @@ "set_image": "Set image…", "show": "Show", "show_configuration": "Show Configuration", + "show_results": "Show results", + "show_count_results": "Show {count} results", "sidebar": { "close": "Close sidebar", - "open": "Open sidebar" + "open": "Open sidebar", + "toggle": "Toggle sidebar" }, "skip": "Skip", "split": "Split", @@ -295,6 +301,8 @@ "log_http_desc": "Logs http access to the terminal. Requires restart.", "log_to_terminal": "Log to terminal", "log_to_terminal_desc": "Logs to the terminal in addition to a file. Always true if file logging is disabled. Requires restart.", + "log_file_max_size": "Maximum log size", + "log_file_max_size_desc": "Maximum size in megabytes of the log file before it is compressed. 0MB is disabled. Requires restart.", "maximum_session_age": "Maximum Session Age", "maximum_session_age_desc": "Maximum idle time before a login session is expired, in seconds. Requires restart.", "password": "Password", @@ -307,6 +315,10 @@ "description": "Directory location for SQLite database file backups", "heading": "Backup Directory Path" }, + "delete_trash_path": { + "description": "Path where deleted files will be moved to instead of being permanently deleted. Leave empty to permanently delete files.", + "heading": "Trash Path" + }, "blobs_path": { "description": "Where in the filesystem to store binary data. Applicable only when using the Filesystem blob storage type. WARNING: changing this requires manually moving existing data.", "heading": "Binary data filesystem path" @@ -565,6 +577,8 @@ "set_name_date_details_from_metadata_if_present": "Set name, date, details from embedded file metadata" }, "tools": { + "graphql_playground": "GraphQL playground", + "heading": "Tools", "scene_duplicate_checker": "Scene Duplicate Checker", "scene_filename_parser": { "add_field": "Add Field", @@ -776,6 +790,10 @@ "description": "Number of times to attempt to scroll before moving to the next/previous item. Only applies for Pan Y scroll mode.", "heading": "Scroll attempts before transition" }, + "sfw_mode": { + "description": "Enable if using stash to store SFW content. Hides or changes some adult-content-related aspects of the UI.", + "heading": "SFW Content Mode" + }, "show_tag_card_on_hover": { "description": "Show tag card when hovering tag badges", "heading": "Tag card tooltips" @@ -793,6 +811,14 @@ } } }, + "performer_list": { + "heading": "Performer list", + "options": { + "show_links_on_grid_card": { + "heading": "Display links on performer grid cards" + } + } + }, "tag_panel": { "heading": "Tag view", "options": { @@ -881,9 +907,11 @@ "developmentVersion": "Development Version", "dialogs": { "clear_o_history_confirm": "Are you sure you want to clear the O history?", + "clear_o_history_confirm_sfw": "Are you sure you want to clear the like history?", "clear_play_history_confirm": "Are you sure you want to clear the play history?", "create_new_entity": "Create new {entity}", "delete_alert": "The following {count, plural, one {{singularEntity}} other {{pluralEntity}}} will be deleted permanently:", + "delete_alert_to_trash": "The following {count, plural, one {{singularEntity}} other {{pluralEntity}}} will be moved to trash:", "delete_confirm": "Are you sure you want to delete {entityName}?", "delete_entity_desc": "{count, plural, one {Are you sure you want to delete this {singularEntity}? Unless the file is also deleted, this {singularEntity} will be re-added when scan is performed.} other {Are you sure you want to delete these {pluralEntity}? Unless the files are also deleted, these {pluralEntity} will be re-added when scan is performed.}}", "delete_entity_simple_desc": "{count, plural, one {Are you sure you want to delete this {singularEntity}?} other {Are you sure you want to delete these {pluralEntity}?}}", @@ -1118,8 +1146,8 @@ "syncing": "Syncing with server", "uploading": "Uploading script" }, - "hasChapters": "Has Chapters", - "hasMarkers": "Has Markers", + "hasChapters": "Chapters", + "hasMarkers": "Markers", "height": "Height", "height_cm": "Height (cm)", "help": "Help", @@ -1142,6 +1170,7 @@ "interactive_speed": "Interactive Speed", "isMissing": "Is Missing", "last_o_at": "Last O At", + "last_o_at_sfw": "Last Like At", "last_played_at": "Last Played At", "library": "Library", "loading": { @@ -1182,9 +1211,11 @@ "new": "New", "none": "None", "o_count": "O Count", - "o_counter": "O-Counter", + "o_count_sfw": "Likes", "o_history": "O History", + "o_history_sfw": "Like History", "odate_recorded_no": "No O Date Recorded", + "odate_recorded_no_sfw": "No Like Date Recorded", "operations": "Operations", "organized": "Organised", "orientation": "Orientation", @@ -1300,6 +1331,7 @@ "sceneTagger": "Scene Tagger", "scene_code": "Studio Code", "scene_count": "Scene Count", + "scenes_duration": "Scene Duration", "scene_created_at": "Scene Created At", "scene_date": "Date of Scene", "scene_id": "Scene ID", @@ -1311,7 +1343,9 @@ "edit_filter": "Edit Filter", "name": "Filter", "saved_filters": "Saved filters", - "update_filter": "Update Filter" + "search_term": "Search term", + "update_filter": "Update Filter", + "more_filter_criteria": "+{count} more" }, "second": "Second", "seconds": "Seconds", @@ -1358,25 +1392,28 @@ }, "paths": { "database_filename_empty_for_default": "database filename (empty for default)", - "description": "Next up, we need to determine where to find your porn collection, and where to store the Stash database, generated files and cache files. These settings can be changed later if needed.", + "description": "Next up, we need to determine where to find your content, and where to store the Stash database, generated files and cache files. These settings can be changed later if needed.", "path_to_blobs_directory_empty_for_default": "path to blobs directory (empty for default)", "path_to_cache_directory_empty_for_default": "path to cache directory (empty for default)", "path_to_generated_directory_empty_for_default": "path to generated directory (empty for default)", "set_up_your_paths": "Set up your paths", + "sfw_content_settings": "Using stash for SFW content?", + "sfw_content_settings_description": "stash can be used to manage SFW content such as photography, art, comics, and more. Enabling this option will adjust some UI behaviour to be more appropriate for SFW content.", "stash_alert": "No library paths have been selected. No media will be able to be scanned into Stash. Are you sure?", "store_blobs_in_database": "Store blobs in database", + "use_sfw_content_mode": "Use SFW content mode", "where_can_stash_store_blobs": "Where can Stash store database binary data?", "where_can_stash_store_blobs_description": "Stash can store binary data such as scene covers, performer, studio and tag images either in the database or in the filesystem. By default, it will store this data in the filesystem in the subdirectory blobs within the directory containing your config file. If you want to change this, please enter an absolute or relative (to the current working directory) path. Stash will create this directory if it does not already exist.", "where_can_stash_store_blobs_description_addendum": "Alternatively, you can store this data in the database. Note: This will increase the size of your database file, and will increase database migration times.", "where_can_stash_store_cache_files": "Where can Stash store cache files?", "where_can_stash_store_cache_files_description": "In order for some functionality like HLS/DASH live transcoding to function, Stash requires a cache directory for temporary files. By default, Stash will create a cache directory within the directory containing your config file. If you want to change this, please enter an absolute or relative (to the current working directory) path. Stash will create this directory if it does not already exist.", "where_can_stash_store_its_database": "Where can Stash store its database?", - "where_can_stash_store_its_database_description": "Stash uses an SQLite database to store your porn metadata. By default, this will be created as stash-go.sqlite in the directory containing your config file. If you want to change this, please enter an absolute or relative (to the current working directory) filename.", + "where_can_stash_store_its_database_description": "Stash uses an SQLite database to store your content metadata. By default, this will be created as stash-go.sqlite in the directory containing your config file. If you want to change this, please enter an absolute or relative (to the current working directory) filename.", "where_can_stash_store_its_database_warning": "WARNING: storing the database on a different system to where Stash is run from (e.g. storing the database on a NAS while running the Stash server on another computer) is unsupported! SQLite is not intended for use across a network, and attempting to do so can very easily cause your entire database to become corrupted.", "where_can_stash_store_its_generated_content": "Where can Stash store its generated content?", "where_can_stash_store_its_generated_content_description": "In order to provide thumbnails, previews and sprites, Stash generates images and videos. This also includes transcodes for unsupported file formats. By default, Stash will create a generated directory within the directory containing your config file. If you want to change where this generated media will be stored, please enter an absolute or relative (to the current working directory) path. Stash will create this directory if it does not already exist.", - "where_is_your_porn_located": "Where is your porn located?", - "where_is_your_porn_located_description": "Add directories containing your porn videos and images. Stash will use these directories to find videos and images during scanning." + "where_is_your_porn_located": "Where is your content located?", + "where_is_your_porn_located_description": "Add directories containing your videos and images. Stash will use these directories to find videos and images during scanning." }, "stash_setup_wizard": "Stash Setup Wizard", "success": { diff --git a/ui/v2.5/src/locales/en-US.json b/ui/v2.5/src/locales/en-US.json index 1f4f31fc5..7d730601c 100644 --- a/ui/v2.5/src/locales/en-US.json +++ b/ui/v2.5/src/locales/en-US.json @@ -1,13 +1,9 @@ { "actions": { + "anonymise": "Anonymize", + "download_anonymised": "Download anonymized", "customise": "Customize", - "add_sub_groups": "Add Sub-Groups", - "add": "Add", - "add_directory": "Add Directory", - "add_entity": "Add {entityType}", - "add_manual_date": "Add manual date", - "add_o": "Add O", - "add_play": "Add play" + "optimise_database": "Optimize Database" }, "config": { "tools": { @@ -26,5 +22,10 @@ "favourite": "Favorite", "hair_color": "Hair Color", "organized": "Organized", - "performer_favorite": "Performer Favorited" + "performer_favorite": "Performer Favorited", + "component_tagger": { + "config": { + "mark_organized_label": "Mark as Organized on save" + } + } } diff --git a/ui/v2.5/src/locales/es-ES.json b/ui/v2.5/src/locales/es-ES.json index d9585f46e..ce3a38b0a 100644 --- a/ui/v2.5/src/locales/es-ES.json +++ b/ui/v2.5/src/locales/es-ES.json @@ -138,7 +138,20 @@ "view_history": "Ver historial", "add_sub_groups": "Añadir subgrupos", "remove_from_containing_group": "Eliminar del grupo", - "reset_play_duration": "Reiniciar la duración de la reproducción" + "reset_play_duration": "Reiniciar la duración de la reproducción", + "load": "Cargar", + "load_filter": "Cargar el filtro", + "play": "Reproducir", + "reset_resume_time": "Restablecer el tiempo de reanudación", + "reset_cover": "Restaurar portada por defecto", + "set_cover": "Establecer como portada", + "show_results": "Mostrar resultados", + "show_count_results": "Mostrar {count} resultados", + "sidebar": { + "close": "Cerrar barra lateral", + "open": "Abrir barra lateral", + "toggle": "Alternar barra lateral" + } }, "actions_name": "Acciones", "age": "Edad", @@ -182,7 +195,10 @@ "show_male_label": "Mostrar actores", "source": "Fuente", "mark_organized_desc": "Marcar la escena como organizada tras pulsar el botón de Guardar.", - "mark_organized_label": "Marcar como organizado al guardar" + "mark_organized_label": "Marcar como organizado al guardar", + "errors": { + "blacklist_duplicate": "Elemento duplicado en la lista negra" + } }, "noun_query": "Consulta", "results": { @@ -282,7 +298,9 @@ "password_desc": "Contraseña para acceder a Stash. Dejar en blanco para deshabilitar la exigencia de identificación para acceder a la aplicación", "stash-box_integration": "Integración Stash-box", "username": "Usuario", - "username_desc": "Usuario para acceder a Stash. Dejar en blanco para deshabilitar la exigencia de identificación para acceder a la aplicación" + "username_desc": "Usuario para acceder a Stash. Dejar en blanco para deshabilitar la exigencia de identificación para acceder a la aplicación", + "log_file_max_size": "Tamaño máximo del registro", + "log_file_max_size_desc": "Tamaño máximo en megabytes del archivo de registro antes de comprimirlo. 0 MB está desactivado. Requiere reiniciar." }, "backup_directory_path": { "description": "Ubicación del directorio para copias de seguridad de archivos de bases de datos SQLite", @@ -434,7 +452,9 @@ "endpoint": "Terminal de red", "graphql_endpoint": "Terminal de red GraphQL", "name": "Nombre", - "title": "Terminal de red Stash-box" + "title": "Terminal de red Stash-box", + "max_requests_per_minute": "Máximas peticiones por minuto", + "max_requests_per_minute_description": "Utiliza el valor predeterminado {defaultValue} si se establece en 0" }, "system": { "transcoding": "Transcodificación" @@ -486,7 +506,7 @@ "heading": "Identificar", "identifying_from_paths": "Identificación de las escenas que se encuentren en las siguientes rutas", "identifying_scenes": "Identificando {num} {scene}", - "include_male_performers": "Incluir actores (varones)", + "include_male_performers": "Incluir actores varones", "set_cover_images": "Selección automática de carátula de escena", "set_organized": "Marcar escena como \"clasificada\"", "source": "Fuente", @@ -560,7 +580,9 @@ "whitespace_chars": "Espacios en blanco", "whitespace_chars_desc": "Estos caracteres se reemplazarán en el título por espacios en blanco" }, - "scene_tools": "Herramientas de escenas" + "scene_tools": "Herramientas de escenas", + "graphql_playground": "Entorno de pruebas de GraphQL", + "heading": "Herramientas" }, "ui": { "abbreviate_counters": { @@ -725,7 +747,8 @@ "heading": "Etiqueta de VR" }, "enable_chromecast": "Habilitar Chromecast", - "show_ab_loop_controls": "Mostrar controles del plugin de bucle AB" + "show_ab_loop_controls": "Mostrar controles del plugin de bucle AB", + "show_range_markers": "Mostrar marcadores de rango" } }, "scene_wall": { @@ -784,6 +807,18 @@ "heading": "Mostrar contenido de subetiquetas" } } + }, + "sfw_mode": { + "heading": "Modo de contenido SFW", + "description": "Actívelo si utiliza Stash para almacenar contenido SFW. Oculta o modifica algunos aspectos de la interfaz de usuario relacionados con contenido para adultos." + }, + "performer_list": { + "heading": "Lista de actores", + "options": { + "show_links_on_grid_card": { + "heading": "Mostrar enlaces en las tarjetas de la cuadrícula de actores" + } + } } }, "advanced_mode": "Modo avanzado" @@ -874,7 +909,6 @@ "destination": "Destino", "source": "Fuente" }, - "overwrite_filter_confirm": "¿Estás seguro de sobreescribir la consulta guardada {entityName}?", "scene_gen": { "force_transcodes": "Forzar generación de transcodificación", "force_transcodes_tooltip": "Por defecto las transcodificaciones son solo generadas cuando el archivo de vídeo no es soportado por el navegador. Cuando están habilitadas, las transcodificaciones se generarán incluso cuando el fichero de vídeo sea soportado por el navegador.", @@ -884,7 +918,7 @@ "marker_image_previews": "Vistas previas de marcadores en formato de imagen animada", "marker_image_previews_tooltip": "Generar también vistas previas animadas (webp), solo requeridas cuando el tipo de vista previa de la pared de escenas/marcadores está configurado como Imagen Animada. Al navegar, consumen menos CPU que las vistas previas de video, pero se generan además de ellas y son archivos más grandes.", "marker_screenshots": "Capturas de pantalla de marcadores", - "marker_screenshots_tooltip": "Imágenes estáticas JPG de marcadores, solo requeridas si el tipo de vista previa seleccionada por defecto es \"Imagen estática\".", + "marker_screenshots_tooltip": "Imágenes estáticas JPG de marcadores", "markers": "Vistas previas de marcadores", "markers_tooltip": "Vídeos de 20 segundos de duración que comienzan a partir del tiempo seleccionado.", "override_preview_generation_options": "Sobrescribir opciones para la generación de vistas previas", @@ -943,7 +977,10 @@ "destination": "Reasignar a" }, "delete_entity_simple_desc": "{count, plural, one {¿Estás seguro de que quieres eliminar esta {singularEntity}?} other {¿Estás seguro de que quieres eliminar estas {pluralEntity}?}}", - "reassign_entity_title": "{count, plural, one {Reasignar {singularEntity}} other {Reasignar {pluralEntity}}}" + "reassign_entity_title": "{count, plural, one {Reasignar {singularEntity}} other {Reasignar {pluralEntity}}}", + "clear_o_history_confirm_sfw": "¿Estás seguro de que quieres borrar el historial de «Me gusta»?", + "overwrite_filter_warning": "El filtro guardado \"{entityName}\" se sobrescribirá.", + "set_default_filter_confirm": "¿Estás seguro de que deseas establecer este filtro como predeterminado?" }, "dimensions": "Dimensiones", "director": "Director", @@ -952,7 +989,8 @@ "list": "Lista", "tagger": "Etiquetadora", "unknown": "Desconocido/a", - "wall": "Muro" + "wall": "Muro", + "label_current": "Modo de visualización: {current}" }, "donate": "Donar", "dupe_check": { @@ -1040,7 +1078,7 @@ "uploading": "Subiendo script", "error": "Error al conectar con Handy" }, - "hasMarkers": "Tiene marcadores", + "hasMarkers": "Marcadores", "height": "Estatura", "help": "Ayuda", "ignore_auto_tag": "Ignorar Etiquetado Automático", @@ -1070,21 +1108,20 @@ "interactive_speed": "Velocidad interactiva", "performer_card": { "age": "{age} {years_old}", - "age_context": "{age} {years_old} en esta escena" + "age_context": "{age} {years_old} durante la producción" }, "phash": "Función de hash perceptual", "stream": "Transmisión", "video_codec": "Códec de vídeo", "play_count": "Contador de reproducciones", "play_duration": "Tiempo de reproducción", - "o_count": "Contador de pajas" + "o_count": "Contador de orgasmos" }, "megabits_per_second": "{value} megabits por segundo (mbps)", "metadata": "Metadatos", "name": "Nombre", "new": "Añadir", "none": "Ninguno/a", - "o_counter": "Contador “P”", "operations": "Acciones", "organized": "Clasificadas", "pagination": { @@ -1159,7 +1196,9 @@ "name": "Filtro", "saved_filters": "Filtros guardados", "update_filter": "Actualizar filtro", - "edit_filter": "Editar filtro" + "edit_filter": "Editar filtro", + "search_term": "Término de búsqueda", + "more_filter_criteria": "+{count} más" }, "seconds": "Segundos", "settings": "Preferencias", @@ -1181,7 +1220,9 @@ "errors": { "something_went_wrong": "¡OH NO! ¡Algo ha ido mal!", "something_went_wrong_description": "Si sospechas que puede haber un error con los datos aportados, por favor, haz clic en volver para arreglarlos. De lo contrario, abre una incidencia en {githubLink} o busca ayuda en {discordLink}.", - "something_went_wrong_while_setting_up_your_system": "Algo ha salido mal mientras configurábamos tu entorno. Éste es el mensaje de error recibido: {error}" + "something_went_wrong_while_setting_up_your_system": "Algo ha salido mal mientras configurábamos tu entorno. Éste es el mensaje de error recibido: {error}", + "unable_to_retrieve_system_status": "No se puede recuperar el estado del sistema: {error}", + "unexpected_error": "Se ha producido un error inesperado: {error}" }, "folder": { "file_path": "Ruta relativa del fichero", @@ -1203,7 +1244,7 @@ }, "paths": { "database_filename_empty_for_default": "nombre para el archivo de la base de datos (en blanco para usar opción por defecto)", - "description": "A continuación necesitamos saber dónde se encuentra tu colección de porno, y dónde guardar la base de datos de Stash y los ficheros multimedia de soporte generados. Estos ajustes se pueden modificar posteriormente.", + "description": "A continuación necesitamos saber dónde se encuentra tu contenido, y dónde guardar la base de datos de Stash y los ficheros multimedia de soporte generados. Estos ajustes se pueden modificar posteriormente.", "path_to_generated_directory_empty_for_default": "ruta al directorio de ficheros multimedia generados (dejar en blanco para usar opción por defecto)", "set_up_your_paths": "Selecciona tus rutas", "stash_alert": "No se han seleccionado rutas para tu biblioteca. Ningún fichero multimedia podrá ser seleccionado para su inclusión en Stash. ¿Estás seguro?", @@ -1211,8 +1252,8 @@ "where_can_stash_store_its_database_description": "Stash emplea una base de datos SQLite para almacenar los metadatos de tu colección. Por defecto será creada como stash-go.sqlite en el directorio en el que se encuentra tu archivo de configuración. Si quieres cambiar esto, por favor, introduce un nombre de archivo con ruta absoluta o relativa al directorio de trabajo actual.", "where_can_stash_store_its_generated_content": "¿Dónde guarda Stash los ficheros multimedia de soporte generados?", "where_can_stash_store_its_generated_content_description": "Para poder ofrecerte miniaturas, vistas previas y conjuntos de imágenes animadas, Stash genera imágenes y vídeos. Esto incluye también transcodificaciones para formatos de vídeo no soportados. Por defecto, Stash creará el directorio generated en el directorio que contiene tu archivo de configuración. Si quieres cambiar dónde se almacenarán estos archivos generados, por favor, introduce una ruta absoluta o relativa (al directorio de trabajo actual). Stash creará este directorio si no existe.", - "where_is_your_porn_located": "¿Dónde guardas el porno?", - "where_is_your_porn_located_description": "Añade los directorios que contienen tus imágenes y vídeos porno. Stash usará estos directorios para buscar imágenes y vídeos durante el escaneo.", + "where_is_your_porn_located": "¿Dónde guardas tu contenido?", + "where_is_your_porn_located_description": "Añade los directorios que contienen tus imágenes y vídeos. Stash usará estos directorios para buscar imágenes y vídeos durante el escaneo.", "path_to_cache_directory_empty_for_default": "ruta al directorio de la caché (dejar en blanco para usar el directorio por defecto)", "store_blobs_in_database": "Almacenar blobs en la base de datos", "path_to_blobs_directory_empty_for_default": "ruta al directorio con los blobs (dejar en blanco para el valor por defecto)", @@ -1221,7 +1262,10 @@ "where_can_stash_store_its_database_warning": "ADVERTENCIA: ¡almacenar la base de datos en un sistema diferente al que Stash se ejecuta (por ejemplo, almacenar la base de datos en un NAS mientras se ejecuta el servidor Stash en otro equipo) no es compatible! SQLite no está diseñado para su uso a través de una red e intentar hacerlo puede corromper fácilmente toda tu base de datos.", "where_can_stash_store_blobs": "¿Dónde puede Stash guardar los datos binarios de la base de datos?", "where_can_stash_store_blobs_description": "Stash puede almacenar datos binarios como portadas de escenas, imágenes de intérpretes, estudios y etiquetas ya sea en la base de datos o en el sistema de archivos. Por defecto, almacenará estos datos en el sistema de archivos en el subdirectorio blobs dentro del directorio que contiene tu archivo de configuración. Si deseas cambiar esto, por favor ingresa una ruta absoluta o relativa (respecto al directorio de trabajo actual). Stash creará este directorio si aún no existe.", - "where_can_stash_store_cache_files_description": "Para que algunas funciones como la transcodificación en vivo de HLS/DASH funcionen, Stash requiere un directorio de caché para archivos temporales. Por defecto, Stash creará un directorio cache dentro del directorio que contiene tu archivo de configuración. Si deseas cambiar esto, por favor ingresa una ruta absoluta o relativa (respecto al directorio de trabajo actual). Stash creará este directorio si aún no existe." + "where_can_stash_store_cache_files_description": "Para que algunas funciones como la transcodificación en vivo de HLS/DASH funcionen, Stash requiere un directorio de caché para archivos temporales. Por defecto, Stash creará un directorio cache dentro del directorio que contiene tu archivo de configuración. Si deseas cambiar esto, por favor ingresa una ruta absoluta o relativa (respecto al directorio de trabajo actual). Stash creará este directorio si aún no existe.", + "sfw_content_settings": "¿Usar Stash para contenido SFW?", + "sfw_content_settings_description": "Stash se puede utilizar para gestionar contenido SFW, como fotografía, arte, cómics y mucho más. Al habilitar esta opción, se ajustará el comportamiento de la interfaz de usuario para que sea más adecuado para el contenido SFW.", + "use_sfw_content_mode": "Utilizar el modo de contenido SFW" }, "stash_setup_wizard": "Asistente de configuración de Stash", "success": { @@ -1271,7 +1315,7 @@ "scenes_duration": "Duración de las escenas", "scenes_size": "Tamaño de las escenas", "total_play_count": "Contador total de reproducciones", - "total_o_count": "Total de pajas", + "total_o_count": "Total de orgasmos", "total_play_duration": "Tiempo total de reproducciones", "scenes_played": "Escenas reproducidas" }, @@ -1342,7 +1386,7 @@ } }, "file_count": "Conteo de archivos", - "hasChapters": "Tiene capítulos", + "hasChapters": "Capítulos", "index_of_total": "{index} de {total}", "last_played_at": "Última reproducción el", "package_manager": { @@ -1382,8 +1426,8 @@ "date_format": "YYYY-MM-DD", "datetime_format": "YYYY-MM-DD HH:MM", "disambiguation": "Disambiguación", - "o_count": "Contador de pajas", - "o_history": "Historial de pajas", + "o_count": "Contador de orgasmos", + "o_history": "Historial de orgasmos", "orientation": "Orientación", "penis_length_cm": "Longitud del pene (cm)", "play_count": "Contador de reproducciones", @@ -1434,7 +1478,7 @@ "saved_filter": "Filtro guardado" } }, - "last_o_at": "Última paja a las", + "last_o_at": "Último orgasmo a las", "parent_studio": "Estudio principal", "primary_file": "Archivo principal", "recently_added_objects": "{objects} añadidas recientemente", @@ -1465,14 +1509,15 @@ "blank": "${path} no puede estar vacío", "date_invalid_form": "${path} tiene que tener el formato YYYY-MM-DD", "required": "${path} es un campo requerido", - "unique": "${path} tiene que ser único" + "unique": "${path} tiene que ser único", + "end_time_before_start_time": "El tiempo de finalización debe ser mayor o igual que el tiempo de inicio" }, "subsidiary_studio_count": "Número de estudios secundarios", "tag_parent_tooltip": "Tiene etiquetas primarias", "tag_sub_tag_tooltip": "Tiene sub-etiquetas", "time": "Hora", "type": "Tipo", - "odate_recorded_no": "No hay registro de pajas grabado", + "odate_recorded_no": "No hay registro de orgasmos grabado", "urls": "URLs", "zip_file_count": "Números de archivos zip", "unknown_date": "Fecha desconocida", @@ -1487,7 +1532,9 @@ "custom_fields": { "field": "Campo", "value": "Valor", - "title": "Campos personalizados" + "title": "Campos personalizados", + "criteria_format_string": "{criterion} (custom field) {modifierString} {valueString}", + "criteria_format_string_others": "{criterion} (custom field) {modifierString} {valueString} (+{others} others)" }, "sub_group_count": "Recuento de subgrupos", "sub_group_of": "Subgrupo de {parent}", @@ -1497,9 +1544,30 @@ "any": "Cualquiera", "any_of": "Cualquiera de", "none": "Ninguno", - "only": "Solamente" + "only": "Solo" }, "include_sub_group_content": "Incluir contenido de subgrupos", "include_sub_groups": "Incluir subgrupos", - "eta": "Tiempo estimado" + "eta": "Tiempo estimado", + "containing_group": "Grupo contenedor", + "containing_group_count": "Contador del grupo contenedor", + "containing_groups": "Grupo de contenedores", + "login": { + "username": "Nombre de usuario", + "password": "Contraseña", + "invalid_credentials": "Nombre de usuario o contraseña incorrecto", + "login": "Iniciar sesión", + "internal_error": "Error interno inesperado. Consulte los registros para obtener más detalles" + }, + "age_on_date": "{age} durante la producción", + "include_sub_studio_content": "Incluir contenido de subestudios", + "include_sub_tag_content": "Incluir contenido de subetiquetas", + "last_o_at_sfw": "Último «Me gusta» en", + "sort_name": "Ordenar por nombre", + "o_count_sfw": "Me gusta", + "o_history_sfw": "Historial de Me gusta", + "odate_recorded_no_sfw": "Sin fecha de Me gusta registrada", + "scenes_duration": "Duración de la escena", + "sub_group_order": "Orden de subgrupo", + "time_end": "Hora de finalización" } diff --git a/ui/v2.5/src/locales/et-EE.json b/ui/v2.5/src/locales/et-EE.json index 0a6173691..ec377065e 100644 --- a/ui/v2.5/src/locales/et-EE.json +++ b/ui/v2.5/src/locales/et-EE.json @@ -141,7 +141,17 @@ "add_play": "Lisa mängimine", "clear_date_data": "Eemalda kuupäeva andmed", "view_history": "Vaata ajalugu", - "remove_from_containing_group": "Eemalda Grupist" + "remove_from_containing_group": "Eemalda Grupist", + "sidebar": { + "open": "Ava külgriba", + "close": "Sulge külgriba", + "toggle": "Lülita külgriba sisse/välja" + }, + "play": "Esita", + "show_results": "Näita tulemusi", + "show_count_results": "Näita {count} tulemust", + "load": "Lae", + "load_filter": "Lae filter" }, "actions_name": "Tegevused", "age": "Vanus", @@ -289,7 +299,9 @@ "password_desc": "Parool Stashi pääsemiseks. Jäta tühjaks, kui soovid sisselogimise keelata", "stash-box_integration": "Stash-kasti integratsioon", "username": "Kasutajanimi", - "username_desc": "Kasutajanimi Stashi pääsemiseks. Jäta tühjaks, kui soovid sisselogimise keelata" + "username_desc": "Kasutajanimi Stashi pääsemiseks. Jäta tühjaks, kui soovid sisselogimise keelata", + "log_file_max_size": "Maksimaalne logi suurus", + "log_file_max_size_desc": "Maksimaalne logifaili suurus megabaitides enne tihendamist. 0MB on väljalülitatud. Nõuab taaskäivitust." }, "backup_directory_path": { "description": "Failitee SQLite andmebaasi varundusfailide jaoks", @@ -441,7 +453,9 @@ "endpoint": "Lõpp-punkt", "graphql_endpoint": "GraphQL lõpp-punkt", "name": "Nimi", - "title": "Stash-kasti Lõpp-punktid" + "title": "Stash-kasti Lõpp-punktid", + "max_requests_per_minute": "Maksimaalne arv päringuid minutis", + "max_requests_per_minute_description": "Kasutab vaikimisi väärtust {defaultValue}, kui on 0" }, "system": { "transcoding": "Ümbertöötlemine" @@ -567,7 +581,9 @@ "whitespace_chars": "Tühikumärgid", "whitespace_chars_desc": "Need märgid asendatakse pealkirjas tühikutega" }, - "scene_tools": "Stseeni Tööriistad" + "scene_tools": "Stseeni Tööriistad", + "graphql_playground": "GraphQL mänguplats", + "heading": "Tööriistad" }, "ui": { "abbreviate_counters": { @@ -732,7 +748,8 @@ "vr_tag": { "description": "VR-nupp kuvatakse ainult selle sildiga stseenide puhul.", "heading": "VR Silt" - } + }, + "show_range_markers": "Näita Vahemiku Märke" } }, "scene_wall": { @@ -791,6 +808,18 @@ "heading": "Kompaktselt laiendatud detailid" }, "heading": "Detailide Leht" + }, + "performer_list": { + "heading": "Näitlejate nimekiri", + "options": { + "show_links_on_grid_card": { + "heading": "Kuva linke näitlejate ruudustiku kaartidel" + } + } + }, + "sfw_mode": { + "description": "Luba, kui kasutad stashi SFW sisu jaoks. Peidab või muudab kasutajaliidese mõningaid täiskasvanutele mõeldud sisuga seotud aspekte.", + "heading": "SFW Sisu Režiim" } }, "advanced_mode": "Täpsem Režiim" @@ -900,7 +929,6 @@ "destination": "Sihtkoht", "source": "Allikas" }, - "overwrite_filter_confirm": "Oled kindel, et tahad üle kirjutada juba eksisteerivat päringut {entityName}?", "reassign_entity_title": "{count, plural, one {Määra Ümber {singularEntity}} other {Määra Ümber {pluralEntity}-d/id}}", "reassign_files": { "destination": "Määra Ümber" @@ -953,7 +981,10 @@ "unsaved_changes": "Salvestamata muudatused. Kas soovid kindlasti lahkuda?", "performers_found": "Leiti {count} esinejat", "clear_o_history_confirm": "Kas oled kindel, et soovid puhastada O ajaloo?", - "clear_play_history_confirm": "Kas oled kindel, et soovid puhastada vaatamise ajaloo?" + "clear_play_history_confirm": "Kas oled kindel, et soovid puhastada vaatamise ajaloo?", + "set_default_filter_confirm": "Kas oled kindel, et soovid määrata seda filtrit vaikimisi valikuks?", + "overwrite_filter_warning": "Salvestatud filter \"{entityName}\" kirjutatakse üle.", + "clear_o_history_confirm_sfw": "Kas oled kindel, et tahad meeldimiste ajalugu tühjendada?" }, "dimensions": "Dimensioonid", "director": "Režissöör", @@ -963,7 +994,8 @@ "list": "Nimekiri", "tagger": "Sildistaja", "unknown": "Teadmata", - "wall": "Sein" + "wall": "Sein", + "label_current": "Kuvarežiim: {current}" }, "donate": "Anneta", "dupe_check": { @@ -1047,7 +1079,7 @@ "filters": "Filtrid", "folder": "Kaust", "framerate": "Kaadrisagedus", - "frames_per_second": "{value} fps", + "frames_per_second": "{value} kaadrit sekundis", "front_page": { "types": { "premade_filter": "Eelsätestatud Filter", @@ -1076,8 +1108,8 @@ "syncing": "Serveriga sünkroniseerimine", "uploading": "Skripti üleslaadimine" }, - "hasChapters": "Sisaldab Episoode", - "hasMarkers": "On Markereid", + "hasChapters": "Peatükid", + "hasMarkers": "Markerid", "height": "Pikkus", "height_cm": "Pikkus (cm)", "help": "Abi", @@ -1110,7 +1142,7 @@ "interactive_speed": "Interaktiivne kiirus", "performer_card": { "age": "{age} {years_old}", - "age_context": "{age} selles stseenis {years_old}" + "age_context": "{age} {years_old} filmimisel" }, "phash": "PHash", "play_count": "Esituste Arv", @@ -1124,7 +1156,6 @@ "name": "Nimi", "new": "Uus", "none": "Puudub", - "o_counter": "O-Loendur", "operations": "Operatsioonid", "organized": "Organiseeritud", "pagination": { @@ -1210,7 +1241,9 @@ "edit_filter": "Muuda Filtrit", "name": "Filter", "saved_filters": "Salvestatud filtrid", - "update_filter": "Uuenda Filtrit" + "update_filter": "Uuenda Filtrit", + "more_filter_criteria": "+{count} rohkem", + "search_term": "Otsi sõnet" }, "second": "Sekund", "seconds": "Sekundit", @@ -1257,7 +1290,7 @@ }, "paths": { "database_filename_empty_for_default": "andmebaasi failinimi (vaikimisi tühi)", - "description": "Järgmisena peame kindlaks määrama, kust leida su pornokogu ja kuhu salvestada stashi andmebaas, genereeritud failid ja cache. Neid sätteid saab hiljem vajadusel muuta.", + "description": "Järgmisena peame kindlaks määrama, kust leida su sisu ja kuhu salvestada stashi andmebaas, genereeritud failid ja cache. Neid sätteid saab hiljem vajadusel muuta.", "path_to_cache_directory_empty_for_default": "tee cache kaustani (tühi vaikeseadeks)", "path_to_generated_directory_empty_for_default": "genereeritud kataloogi tee (vaikimisi tühi)", "set_up_your_paths": "Seadista oma failiteed", @@ -1268,14 +1301,17 @@ "where_can_stash_store_cache_files": "Kus saab Stash hoida cache faile?", "where_can_stash_store_cache_files_description": "Mõne funktsionaalsuse, nagu HLS/DASH reaalas transkodeerimine, töötamiseks vajab Stash cache kausta ajutiste failide jaoks. Vaikimisi loob Stash cache kausta mis asub konfiguratsioonifailiga samas kaustas. Kui tahad seda muuta, palun sisesta absoluutne või relatiivne (töökaustaga) tee. Stash loob selle kausta kui seda juba ei eksisteeri.", "where_can_stash_store_its_database": "Kuhu saab Stash oma andmebaasi salvestada?", - "where_can_stash_store_its_database_description": "Stash kasutab su porno metaandmete salvestamiseks SQLite'i andmebaasi. Vaikimisi luuakse see konfiguratsioonifaili sisaldavasse kataloogi kui stash-go.sqlite. Kui soovid seda muuta, sisesta absoluutne või suhteline failinimi (praeguse töökataloogi suhtes).", + "where_can_stash_store_its_database_description": "Stash kasutab su sisu metaandmete salvestamiseks SQLite'i andmebaasi. Vaikimisi luuakse see konfiguratsioonifaili sisaldavasse kataloogi kui stash-go.sqlite. Kui soovid seda muuta, sisesta absoluutne või suhteline failinimi (praeguse töökataloogi suhtes).", "where_can_stash_store_its_database_warning": "HOIATUS: hoides andmebaasi erineval süsteemil kui millel Stash jookseb (nt hoides andmebaasi NASil kui Stash jookseb teisel arvutil) on mitte toetatud! SQLite ei ole mõeldud kasutamiseks üle võrgu ja selle proovimine võib väga kergesti viia andmebaasi korrupeerumiseni.", "where_can_stash_store_its_generated_content": "Kus saab Stash oma genereeritud sisu salvestada?", "where_can_stash_store_its_generated_content_description": "Pisipiltide, eelvaadete ja spraitide pakkumiseks loob Stash pilte ja videoid. See hõlmab ka toetamata failivormingute ümbertöötlemist. Vaikimisi loob Stash konfiguratsioonifaili sisaldavas kaustas genereeritud kausta. Kui soovid muuta seda, kus see loodud meedium salvestatakse, sisesta absoluutne või suhteline failitee (praeguse töökataloogi suhtes). Stash loob selle kausta, kui seda veel pole.", - "where_is_your_porn_located": "Kus su porno asub?", - "where_is_your_porn_located_description": "Lisage oma pornovideoid ja pilte sisaldavad kataloogid. Stash kasutab neid katalooge skanimise ajal videote ja piltide otsimiseks.", + "where_is_your_porn_located": "Kus su sisu asub?", + "where_is_your_porn_located_description": "Lisage oma videoid ja pilte sisaldavad kataloogid. Stash kasutab neid katalooge skanimise ajal videote ja piltide otsimiseks.", "path_to_blobs_directory_empty_for_default": "blobsi kataloogi tee (vaikimisi tühi)", - "store_blobs_in_database": "Salvesta blobid andmebaasi" + "store_blobs_in_database": "Salvesta blobid andmebaasi", + "sfw_content_settings": "Kasutad stashi SFW sisu jaoks?", + "sfw_content_settings_description": "stashi saab kasutada SFW-sisu, näiteks fotograafia, kunsti, koomiksite ja muu haldamiseks. Selle valiku lubamine muudab kasutajaliidese käitumist SFW-sisu jaoks sobivamaks.", + "use_sfw_content_mode": "Kasuta SFW sisu režiimi" }, "stash_setup_wizard": "Stashi Ülessättimise Viisard", "success": { @@ -1515,7 +1551,23 @@ "custom_fields": { "field": "Väli", "title": "Kohandatud Väli", - "value": "Väärtus" + "value": "Väärtus", + "criteria_format_string_others": "{criterion} (kohandatud väli) {modifierString} {valueString} (+{others} teist)", + "criteria_format_string": "{criterion} (kohandatud väli) {modifierString} {valueString}" }, - "eta": "ETA" + "eta": "ETA", + "login": { + "username": "Kasutajanimi", + "password": "Parool", + "internal_error": "Ootamatu sisemine viga. Vaata logisid rohkemate detailide jaoks", + "invalid_credentials": "Vale kasutajanimi või parool", + "login": "Logi Sisse" + }, + "age_on_date": "{age} filmimisel", + "sort_name": "Sorteeritud Nimi", + "scenes_duration": "Stseeni Pikkus", + "last_o_at_sfw": "Viimane Meeldimine", + "o_count_sfw": "Meeldimisi", + "o_history_sfw": "Meeldimiste Ajalugu", + "odate_recorded_no_sfw": "Meeldimise Kuupäeva Pole Salvestatud" } diff --git a/ui/v2.5/src/locales/fa-IR.json b/ui/v2.5/src/locales/fa-IR.json index ed9914f98..25a57a44c 100644 --- a/ui/v2.5/src/locales/fa-IR.json +++ b/ui/v2.5/src/locales/fa-IR.json @@ -5,6 +5,31 @@ "add_entity": "افزودن {entityType}", "add_to_entity": "اضافه‌کردن به {entityType}", "allow": "اجازه دادن", - "allow_temporarily": "به طور موقت اجازه دهید" + "allow_temporarily": "موقتا اجازه دهید", + "add_sub_groups": "افزودن زیرگروه", + "browse_for_image": "پیدا کردن عکس…", + "cancel": "لغو", + "choose_date": "انتخاب تاریخ", + "clean": "پاکسازی", + "create_entity": "ایجاد {entityType}", + "add_manual_date": "افزودن دستی تاریخ", + "add_play": "افزودن نمایش", + "apply": "اعمال", + "backup": "پشتیبان گیری", + "auto_tag": "تگ زدن خودکار", + "clear_front_image": "پاک کردن عکس جلویی", + "clean_generated": "پاکسازی فایل های تولید شده", + "clear": "پاک کردن", + "clear_back_image": "پاک کردن عکس پشتی", + "clear_date_data": "پاک کردن دیتای تاریخ", + "clear_image": "پاک کردن عکس", + "close": "بستن", + "confirm": "تایید", + "continue": "ادامه", + "copy_to_clipboard": "کپی به کلیپبورد", + "create": "ایجاد", + "create_parent_studio": "ایجاد استادیو والد", + "anonymise": "بی نام کردن", + "create_chapters": "ایجاد فصل" } } diff --git a/ui/v2.5/src/locales/fi-FI.json b/ui/v2.5/src/locales/fi-FI.json index f90e06076..2256d8e5d 100644 --- a/ui/v2.5/src/locales/fi-FI.json +++ b/ui/v2.5/src/locales/fi-FI.json @@ -141,7 +141,17 @@ "add_sub_groups": "Lisää aliryhmiä", "migrate_blobs": "Siirrä blobit", "migrate_scene_screenshots": "Siirrä kohtauksen kuvakaappaukset", - "reset_play_duration": "Nollaa toiston kesto" + "reset_play_duration": "Nollaa toiston kesto", + "load": "Ladataan", + "load_filter": "Lataa filtteri", + "play": "Toista", + "show_results": "Näytä tulokset", + "show_count_results": "Näytä {count} tulosta", + "sidebar": { + "close": "Sulje sivupalkki", + "open": "Avaa sivupalkki", + "toggle": "näytä/piilota sivupalkki" + } }, "actions_name": "Toiminnot", "age": "Ikä", @@ -367,10 +377,12 @@ }, "transcode": { "output_args": { - "desc": "Edistynyt: Lisäargumentit, jotka välitetään ffmpegille ennen tuloskenttää videota luotaessa." + "desc": "Edistynyt: Lisäargumentit, jotka välitetään ffmpegille ennen tuloskenttää videota luotaessa.", + "heading": "FFmpeg:n muunnoksen ulostuloparametrit" }, "input_args": { - "desc": "Edistynyt: Lisäargumentit, jotka välitetään ffmpegille ennen syöttökenttää videota luotaessa." + "desc": "Edistynyt: Lisäargumentit, jotka välitetään ffmpegille ennen syöttökenttää videota luotaessa.", + "heading": "FFmpeg:n muunnoksen syöteparametrit" } }, "ffmpeg_path": { @@ -383,10 +395,12 @@ }, "live_transcode": { "input_args": { - "desc": "Edistynyt: Lisäargumentit, jotka välitetään ffmpegille ennen syöttökenttää, kun videota muutetaan livenä." + "desc": "Edistynyt: Lisäargumentit, jotka välitetään ffmpegille ennen syöttökenttää, kun videota muutetaan livenä.", + "heading": "FFmpeg:n live-muunnoksen syöteparametrit" }, "output_args": { - "desc": "Edistynyt: Lisäargumentit, jotka siirretään ffmpegille ennen lähtökenttää, kun videota muutetaan livenä." + "desc": "Edistynyt: Lisäargumentit, jotka siirretään ffmpegille ennen lähtökenttää, kun videota muutetaan livenä.", + "heading": "FFmpeg:n live-muunnoksen ulostuloparametrit" } } }, @@ -405,7 +419,8 @@ "funscript_heatmap_draw_range_desc": "Piirrä liikealue generoidun lämpökartan y-akselille. Olemassa olevat lämpökartat on luotava uudelleen vaihtamisen jälkeen.", "funscript_heatmap_draw_range": "Sisällytä alue luotuihin lämpökarttoihin", "gallery_cover_regex_desc": "Regexp käytetään kuvaamaan gallerian kansikuvaa", - "gallery_cover_regex_label": "Gallerian kansikuvio" + "gallery_cover_regex_label": "Gallerian kansikuvio", + "heatmap_generation": "Funscript-lämpökarttageneraattori" }, "library": { "exclusions": "Poisjättäminen", @@ -435,7 +450,9 @@ "endpoint": "Päätepiste", "graphql_endpoint": "GraphQL päätepiste", "name": "Nimi", - "title": "Stash-box päätepisteet" + "title": "Stash-box päätepisteet", + "max_requests_per_minute": "Enimmäispyynnöt minuutissa", + "max_requests_per_minute_description": "Käyttää oletusarvoa {defaultValue}, jos se on asetettu 0:ksi" }, "system": { "transcoding": "Transkoodaus" @@ -491,14 +508,21 @@ "sources": "Lähteet", "strategy": "Strategia", "skip_multiple_matches": "Ohita vastaavat, joilla on useampi kuin yksi tulos", - "skip_multiple_matches_tooltip": "Jos tämä ei ole otettu käyttöön ja palautetaan useampi kuin yksi tulos, yksi valitaan satunnaisesti vastaamaan" + "skip_multiple_matches_tooltip": "Jos tämä ei ole otettu käyttöön ja palautetaan useampi kuin yksi tulos, yksi valitaan satunnaisesti vastaamaan", + "skip_single_name_performers": "Ohita yksinimiset esiintyjät ilman tarkennusta", + "skip_single_name_performers_tooltip": "Jos tämä ei ole käytössä, usein geneeriset esiintyjät kuten Samantha tai Olga yhdistetään", + "tag_skipped_matches": "Merkitse ohitetut osumat seuraavalla", + "tag_skipped_matches_tooltip": "Luo tunniste, kuten 'Tunnista: Useita osumia', jota voit suodattaa Scene Tagger -näkymässä ja valita oikean osuman käsin", + "tag_skipped_performer_tooltip": "Luo tunniste, kuten 'Identify: Single Name Performer', jota voit suodattaa Scene Tagger -näkymässä ja valita, miten haluat käsitellä näitä esiintyjiä", + "tag_skipped_performers": "Merkitse ohitetut esiintyjät seuraavalla" }, "import_from_exported_json": "Tuo viedystä JSON -tiedoista, jotka ovat samassa kansiossa kuin metadata. Pyyhkii olemassaolevan tietokannan.", "incremental_import": "Lisäävä tuonti valitusta zip -tiedostosta.", "job_queue": "Tehtäväjono", "maintenance": "Ylläpito", "migrate_blobs": { - "delete_old": "Poista vanhat tiedot" + "delete_old": "Poista vanhat tiedot", + "description": "Siirrä blobit nykyiseen blob-tallennusjärjestelmään. Tämä siirto tulisi suorittaa blob-tallennusjärjestelmän vaihdon jälkeen. Vanhojen tietojen poistaminen siirron jälkeen on valinnainen." }, "migrate_hash_files": "Käytetään kun muutetaan generoitua tiedoston nimeämistiivistettä jo generoitujen tiedostojen uudelleennimeämiseen uuteen muotoon.", "migrations": "Migraatiot", @@ -516,12 +540,26 @@ "previews_desc": "Kohtauksien esikatselut ja pienoiskuvat", "blob_files": "Blob-tiedostot", "description": "Poistaa luodut tiedostot ilman vastaavaa tietokantatietuetta.", - "image_thumbnails": "Kuvien pikkukuvat" + "image_thumbnails": "Kuvien pikkukuvat", + "image_thumbnails_desc": "Kuvien pikkukuvat ja pätkät", + "sprites": "Kohtauksien sprite-kuvat", + "transcodes": "Kohtauksien muunnokset" }, "anonymising_database": "Anonymisoidaan tietokantaa", "anonymise_database": "Tekee kopion tietokannasta varmuuskopioiden hakemistoon anonymisoimalla kaikki arkaluontoiset tiedot. Tämä voidaan sitten tarjota muille vianmääritys- ja viankorjaustarkoituksiin. Alkuperäistä tietokantaa ei ole muokattu. Anonymisoitu tietokanta käyttää tiedostonimimuotoa {filename_format}.", "generate_sprites_during_scan_tooltip": "Videosoittimen alla näkyvät kuvat navigoinnin helpottamiseksi.", - "generate_video_covers_during_scan": "Luo kohtausten kannet" + "generate_video_covers_during_scan": "Luo kohtausten kannet", + "generate_clip_previews_during_scan": "Luo esikatselukuvat kuvaklippejä varten", + "generate_sprites_during_scan": "Luo pyyhkijän kuvasarjat", + "migrate_scene_screenshots": { + "delete_files": "Poista näyttötallenteiden tiedostot", + "description": "Siirrä kohtauksen näyttökuvat uuteen blob-tallennusjärjestelmään. Tämä siirto tulisi suorittaa olemassa olevan järjestelmän päivittämisen jälkeen versioon 0.20. Vanhojen näyttökuvien poistaminen siirron jälkeen on valinnainen.", + "overwrite_existing": "Korvaa olemassa olevat blobit näyttötallennetiedoilla" + }, + "optimise_database": "Yritä parantaa suorituskykyä analysoimalla ja koko tietokantatiedoston uudelleen rakentamalla.", + "optimise_database_warning": "Varoitus: tämän tehtävän ollessa käynnissä kaikki tietokantaa muokkaavat toiminnot epäonnistuvat, ja tietokannan koosta riippuen suoritus voi kestää useita minuutteja. Tarvitset lisäksi vähintään yhtä paljon vapaata levytilaa kuin tietokantasi koko on, mutta 1,5-kertainen määrä on suositeltavaa.", + "rescan": "Uudelleenskannaa tiedostot", + "rescan_tooltip": "Uudelleenskannaa kaikki tiedostot polussa. Käytetään tiedoston metatietojen pakolliseen päivitykseen ja zip-tiedostojen uudelleenskannaukseen." }, "tools": { "scene_duplicate_checker": "Kohtauksien kaksoiskappaleiden tarkistus", @@ -533,9 +571,16 @@ "ignore_organized": "Jätä järjestellyt kohtaukset huomiotta", "ignored_words": "Huomiotta jätetyt sanat", "matches_with": "Täsmää seuraavan kanssa {i}", - "whitespace_chars_desc": "Nämä merkit korvataan välilyönnillä otsikossa" + "whitespace_chars_desc": "Nämä merkit korvataan välilyönnillä otsikossa", + "escape_chars": "Käytä \\ merkin edessä, kun haluat käsitellä merkin kirjaimellisena merkkinä", + "filename_pattern": "Tiedostonimen malli", + "select_parser_recipe": "Valitse jäsentämisen ohjeistus, joka määrittää tiedon purkamisen ja käsittelyn", + "title": "Kohteen tiedostonimen jäsentäjä", + "whitespace_chars": "välilyöntimerkit" }, - "scene_tools": "Kohtauksen työkalut" + "scene_tools": "Kohtauksen työkalut", + "graphql_playground": "GraphQL-kokeiluympäristö", + "heading": "Työkalut" }, "ui": { "basic_settings": "Perusasetukset", @@ -551,7 +596,8 @@ }, "custom_locales": { "heading": "Mukautettu lokalisointi", - "option_label": "Mukautettu lokalisointi käytössä" + "option_label": "Mukautettu lokalisointi käytössä", + "description": "Ylikirjoita yksittäisiä paikallisia merkkijonoja. Katso https://github.com/stashapp/stash/blob/develop/ui/v2.5/src/locales/en-GB.json master-lista. Sivun lataus on tehtävä uudelleen, jotta muutokset tulevat voimaan." }, "delete_options": { "description": "Oletusasetukset kun poistetaan kuvia, gallerioita ja kohtauksia.", @@ -580,7 +626,8 @@ "options": { "full": "Kokonainen", "half": "Puolikas", - "quarter": "Neljäsosa" + "quarter": "Neljäsosa", + "tenth": "Kymmenes" } }, "type": { @@ -590,6 +637,9 @@ "stars": "Tähdet" } } + }, + "max_options_shown": { + "label": "Valintavalikoissa näytettävien kohteiden enimmäismäärä" } }, "funscript_offset": { @@ -687,13 +737,33 @@ } } }, - "title": "Käyttöliittymä" + "title": "Käyttöliittymä", + "abbreviate_counters": { + "description": "Lyhennä lukujen esitystapaa korteissa ja yksityiskohtien näkymissä, esimerkiksi luku \"1831\" esitetään muodossa \"1,8K\".", + "heading": "Lukujen esitysmuodon lyhentäminen" + }, + "detail": { + "compact_expanded_details": { + "description": "Kun tämä asetus on otettu käyttöön, se näyttää laajennetut tiedot säilyttäen samalla kompaktin esityksen.", + "heading": "Tiivistetyt laajennetut tiedot" + }, + "enable_background_image": { + "description": "Näytä taustakuva yksityiskohtasivulla.", + "heading": "Ota taustakuva käyttöön" + }, + "heading": "Lisätietosivu", + "show_all_details": { + "description": "Kun tämä on otettu käyttöön, kaikki sisällön tiedot näytetään oletuksena ja jokainen tietoelementti mahtuu yhden sarakkeen alle.", + "heading": "Näytä kaikki tiedot" + } + } }, "advanced_mode": "Edistynyt tila", "plugins": { "installed_plugins": "Asennetut lisäosat", "available_plugins": "Saatavilla olevat liitännäiset", - "hooks": "Koukut" + "hooks": "Koukut", + "triggers_on": "Aktivoituu kun" } }, "configuration": "Konfiguraatio", @@ -784,7 +854,6 @@ "destination": "Kohde", "source": "Lähde" }, - "overwrite_filter_confirm": "Haluatko varmasti ylikirjoittaa jo olemassaolevan {entityName}?", "scene_gen": { "force_transcodes": "Pakota transkoodaus", "force_transcodes_tooltip": "Oletuksena transkoodaus tehdään vain, mikäli selain ei tue videotiedostoa. Jos tämä valinta on päällä, transkoodaus tehdään vaikka selain näyttäisi tukevan videotiedostoa.", @@ -793,7 +862,7 @@ "marker_image_previews": "Animoidut merkkien esikatselukuvat", "marker_image_previews_tooltip": "Animoidut merkkien WebP esikatselut, vaaditaan vain jos esikatselun tyypiksi on valittu Animoitu kuva.", "marker_screenshots": "Merkkien esikatselukuvat", - "marker_screenshots_tooltip": "Merkkien staattinen JPG -kuva, vaadittu vain jos esikatselutyypiksi on asetettu staattinen kuva.", + "marker_screenshots_tooltip": "Staattiset JPG-kuvat merkintöihin", "markers": "Merkkien esikatselut", "markers_tooltip": "20 sekunnin video jokaisen aikakoodin alusta.", "override_preview_generation_options": "Ohita Esikatselun generoinnin asetukset", @@ -942,7 +1011,7 @@ "interactive_speed": "Interaktiivinen nopeus", "performer_card": { "age": "{age} {years_old}", - "age_context": "{age} {years_old} tässä kohtauksessa" + "age_context": "{age} {years_old} tuotantovaiheessa" }, "phash": "PHash", "play_count": "Toistokerrat", @@ -955,7 +1024,6 @@ "name": "Nimi", "new": "Uusi", "none": "Ei mitään", - "o_counter": "O-Laskuri", "operations": "Operaatiot", "organized": "Järjestelty", "pagination": { diff --git a/ui/v2.5/src/locales/fr-FR.json b/ui/v2.5/src/locales/fr-FR.json index 3e9e74648..94780b647 100644 --- a/ui/v2.5/src/locales/fr-FR.json +++ b/ui/v2.5/src/locales/fr-FR.json @@ -141,7 +141,17 @@ "reset_resume_time": "Réinitialiser le temps de reprise", "set_cover": "Définir comme vignette", "remove_from_containing_group": "Supprimer du groupe", - "add_sub_groups": "Ajouter des groupes affiliés" + "add_sub_groups": "Ajouter des groupes affiliés", + "sidebar": { + "close": "Fermer la barre latérale", + "open": "Ouvrir la barre latérale", + "toggle": "Barre latérale" + }, + "show_count_results": "Afficher {count} résultats", + "show_results": "Afficher les résultats", + "play": "Lecture", + "load": "Charger", + "load_filter": "Charger un filtre" }, "actions_name": "Actions", "age": "Âge", @@ -295,7 +305,9 @@ "password_desc": "Mot de passe pour accéder à Stash. Laisser vide pour désactiver l'authentification utilisateur", "stash-box_integration": "Intégration de Stash-Box", "username": "Nom d'utilisateur", - "username_desc": "Nom d'utilisateur pour accéder à Stash. Laisser vide pour désactiver l'authentification utilisateur" + "username_desc": "Nom d'utilisateur pour accéder à Stash. Laisser vide pour désactiver l'authentification utilisateur", + "log_file_max_size": "Taille maximale du journal", + "log_file_max_size_desc": "Taille maximale en mégaoctets du fichier journal avant compression. 0 Mo est désactivé. Nécessite un redémarrage." }, "backup_directory_path": { "description": "Emplacement de sauvegarde des bases de données SQLite", @@ -447,7 +459,9 @@ "endpoint": "Point de terminaison", "graphql_endpoint": "Point de terminaison GraphQL", "name": "Nom", - "title": "Points de terminaison Stash-Box" + "title": "Points de terminaison Stash-Box", + "max_requests_per_minute": "Requêtes maximales par minute", + "max_requests_per_minute_description": "Utiliser la valeur par défaut de {defaultValue} si définie à 0" }, "system": { "transcoding": "Transcodage" @@ -573,7 +587,9 @@ "whitespace_chars": "Caractères d'espacement", "whitespace_chars_desc": "Ces caractères seront remplacés par un espace dans le titre" }, - "scene_tools": "Outils de scène" + "scene_tools": "Outils de scène", + "heading": "Outils", + "graphql_playground": "Implémentation GraphQL" }, "ui": { "abbreviate_counters": { @@ -798,6 +814,18 @@ "use_stash_hosted_funscript": { "description": "Activée, les scripts interactifs sont transmis directement de Stash à votre dispositif Handy sans recourir au serveur Handy de tierce partie. Nécessite que Stash soit accessible depuis votre dispositif Handy, et qu'une clé API soit générée si Stash a des informations d'identification configurées.", "heading": "Transmettre directement les funscripts" + }, + "performer_list": { + "heading": "Liste de performeurs", + "options": { + "show_links_on_grid_card": { + "heading": "Afficher les liens sur les fiches des performeurs" + } + } + }, + "sfw_mode": { + "description": "Activez cette option si vous utilisez Stash pour stocker du contenu SFW. Masque ou modifie certains aspects de l'interface utilisateur liés au contenu pour adultes.", + "heading": "Mode contenu SFW" } }, "advanced_mode": "Mode avancé" @@ -907,7 +935,6 @@ "destination": "Destination", "source": "Source" }, - "overwrite_filter_confirm": "Êtes-vous sûr de vouloir remplacer la requête sauvegardée existante {entityName} ?", "performers_found": "{count} performeurs trouvés", "reassign_entity_title": "{count, plural, one {Réaffecté {singularEntity}} other {Réaffectés {pluralEntity}}}", "reassign_files": { @@ -960,7 +987,10 @@ "set_image_url_title": "URL de l'image", "unsaved_changes": "Modifications non sauvegardées. Vous êtes sûr de vouloir quitter ?", "clear_o_history_confirm": "Êtes-vous sûr de vouloir effacer l'historique des O ?", - "clear_play_history_confirm": "Êtes-vous sûr de vouloir effacer l'historique de lecture ?" + "clear_play_history_confirm": "Êtes-vous sûr de vouloir effacer l'historique de lecture ?", + "overwrite_filter_warning": "Le filtre enregistré \"{entityName}\" sera remplacé.", + "set_default_filter_confirm": "Êtes-vous sûr de vouloir définir ce filtre par défaut ?", + "clear_o_history_confirm_sfw": "Êtes-vous sûr de vouloir effacer l'historique des \"J'aime\" ?" }, "dimensions": "Dimensions", "director": "Réalisateur", @@ -970,7 +1000,8 @@ "list": "Liste", "tagger": "Étiqueteuse", "unknown": "Inconnu", - "wall": "Mur" + "wall": "Mur", + "label_current": "Mode d'affichage : {current}" }, "donate": "Faire un don", "dupe_check": { @@ -1083,8 +1114,8 @@ "syncing": "Synchronisation avec le serveur", "uploading": "Script de chargement" }, - "hasChapters": "A des chapitres", - "hasMarkers": "Dispose de marqueurs", + "hasChapters": "Chapitres", + "hasMarkers": "Marqueurs", "height": "Taille", "height_cm": "Taille (cm)", "help": "Aide", @@ -1114,7 +1145,7 @@ "audio_codec": "Codec audio", "checksum": "Somme de contrôle", "downloaded_from": "Téléchargé depuis", - "hash": "Hachage", + "hash": "Empreinte", "interactive_speed": "Vitesse interactive", "performer_card": { "age": "{age} {years_old}", @@ -1132,7 +1163,6 @@ "name": "Nom", "new": "Nouveau", "none": "Aucun", - "o_counter": "O-Compteur", "operations": "Opérations", "organized": "Organisé", "pagination": { @@ -1222,7 +1252,9 @@ "edit_filter": "Modifier le filtre", "name": "Filtre", "saved_filters": "Filtres sauvegardés", - "update_filter": "Filtre actualisé" + "update_filter": "Filtre actualisé", + "more_filter_criteria": "+{count} de plus", + "search_term": "Terme recherché" }, "second": "Deuxième", "seconds": "Secondes", @@ -1269,7 +1301,7 @@ }, "paths": { "database_filename_empty_for_default": "Nom de fichier de la base de données (vide par défaut)", - "description": "Ensuite, nous devons déterminer où trouver votre collection pornographique, et où stocker la base de données Stash, les fichiers générés et les fichiers cache. Ces paramètres peuvent être modifiés ultérieurement si nécessaire.", + "description": "Ensuite, nous devons déterminer où trouver votre contenu, et où stocker la base de données Stash, les fichiers générés et les fichiers cache. Ces paramètres peuvent être modifiés ultérieurement si nécessaire.", "path_to_blobs_directory_empty_for_default": "chemin vers le répertoire des blobs (vide par défaut)", "path_to_cache_directory_empty_for_default": "chemin du répertoire du cache (vide par défaut)", "path_to_generated_directory_empty_for_default": "Chemin vers le répertoire généré (vide par défaut)", @@ -1282,12 +1314,15 @@ "where_can_stash_store_cache_files": "Où Stash peut-il stocker les fichiers cache ?", "where_can_stash_store_cache_files_description": "Pour que certaines fonctionnalités telles que le transcodage en temps réel HLS/DASH puissent fonctionner, Stash a besoin d'un répertoire de cache pour les fichiers temporaires. Par défaut, Stash créera un sous-répertoire cache dans le répertoire contenant votre fichier de configuration. Si vous souhaitez le modifier, merci de saisir un chemin absolu ou relatif (par rapport au répertoire de travail actuel). Stash créera ce sous-répertoire s'il n'existe pas déjà.", "where_can_stash_store_its_database": "Où Stash peut-il stocker sa base de données ?", - "where_can_stash_store_its_database_description": "Stash utilise une base de données SQLite pour stocker vos métadonnées pornographiques. Par défaut, cette base sera créée en tant que stash-go.sqlite dans le répertoire contenant votre fichier de configuration. Si vous souhaitez modifier cela, saisissez un nom de fichier absolu ou relatif ( vers le répertoire de travail actuel).", + "where_can_stash_store_its_database_description": "Stash utilise une base de données SQLite pour stocker vos métadonnées de contenu. Par défaut, cette base sera créée en tant que stash-go.sqlite dans le répertoire contenant votre fichier de configuration. Si vous souhaitez modifier cela, saisissez un nom de fichier absolu ou relatif ( vers le répertoire de travail actuel).", "where_can_stash_store_its_database_warning": "AVERTISSEMENT : Le stockage de la base de données sur un système différent de celui à partir duquel Stash est exécuté (par exemple, le stockage de la base de données sur un NAS tout en exécutant le serveur Stash sur un autre ordinateur) est non pris en charge ! SQLite n'est pas conçu pour être utilisé sur un réseau, et toute tentative de le faire peut très facilement entraîner la corruption de l'ensemble de votre base de données.", "where_can_stash_store_its_generated_content": "Où Stash peut-il stocker son contenu généré ?", "where_can_stash_store_its_generated_content_description": "Afin de produire les vignettes, aperçus et sprites, Stash génère des images et des vidéos. Cela inclut également les transcodes pour les formats de fichiers non pris en charge. Par défaut, Stash crée un répertoire generated dans le répertoire contenant votre fichier de configuration. Si vous souhaitez modifier l'emplacement où seront stockés les médias générés, veuillez saisir un chemin absolu ou relatif ( vers le répertoire de travail actuel). Stash créera ce répertoire s'il n'existe pas déjà.", - "where_is_your_porn_located": "Où se trouve votre porno ?", - "where_is_your_porn_located_description": "Ajoutez des répertoires contenant vos vidéos et images pornographiques. Stash utilisera ces répertoires pour rechercher les vidéos et les images lors de l'analyse." + "where_is_your_porn_located": "Où se trouve votre contenu ?", + "where_is_your_porn_located_description": "Ajoutez des répertoires contenant vos vidéos et images. Stash utilisera ces répertoires pour rechercher les vidéos et les images lors de l'analyse.", + "sfw_content_settings": "Utiliser Stash pour du contenu SFW ?", + "sfw_content_settings_description": "Stash peut être utilisé pour gérer du contenu SFW tel que des photographies, des illustrations, des bandes dessinées, et plus. L'activation de cette option modifiera certains comportements de l'interface utilisateur pour les rendre plus appropriés au contenu SFW.", + "use_sfw_content_mode": "Utiliser le mode de contenu SFW" }, "stash_setup_wizard": "Assistant de configuration de Stash", "success": { @@ -1478,13 +1513,13 @@ "last_o_at": "Dernier O le", "o_count": "Nombre d'O", "o_history": "Historique d'O", - "odate_recorded_no": "Aucune date d'O enregistrée", + "odate_recorded_no": "Aucun O daté enregistré", "subsidiary_studio_count": "Nombre de studios affiliés", "tag_sub_tag_tooltip": "A des étiquettes affiliées", "time": "Temps", "photographer": "Photographe", "play_history": "Historique de Lecture", - "playdate_recorded_no": "Aucune date de lecture enregistrée", + "playdate_recorded_no": "Aucune lecture datée enregistrée", "plays": "{value} lectures", "unknown_date": "Date inconnue", "history": "Historique", @@ -1522,5 +1557,17 @@ }, "eta": "TAE", "sort_name": "Nom de tri", - "age_on_date": "{age} à la production" + "age_on_date": "{age} à la production", + "login": { + "password": "Mot de passe", + "invalid_credentials": "Nom d'utilisateur ou mot de passe incorrect", + "internal_error": "Erreur interne inattendue. Consulter le journal pour plus de détails", + "login": "Identification", + "username": "Nom d'utilisateur" + }, + "scenes_duration": "Durée de la scène", + "last_o_at_sfw": "Dernier J'aime", + "o_count_sfw": "J'aime", + "odate_recorded_no_sfw": "Aucun “J’aime” daté enregistré", + "o_history_sfw": "Historique des \"J’aime\"" } diff --git a/ui/v2.5/src/locales/hr-HR.json b/ui/v2.5/src/locales/hr-HR.json index dbd8deab3..70a5a49fe 100644 --- a/ui/v2.5/src/locales/hr-HR.json +++ b/ui/v2.5/src/locales/hr-HR.json @@ -91,11 +91,198 @@ "swap": "Zamijeni", "tasks": { "clean_confirm_message": "Jeste li sigurni da želite započeti čišćenje? Ovaj će postupak obrisati podatke iz baze podataka i sav generirani sadržaj za sve scene i galerije čije su izvorne datoteke obrisane.", - "dry_mode_selected": "Odabran je probni način rada. Ništa neće biti obrisano, datoteke koje više ne postoje će se samo zapisati u konzolu." + "dry_mode_selected": "Odabran je probni način rada. Ništa neće biti obrisano, datoteke koje više ne postoje će se samo zapisati u konzolu.", + "import_warning": "Da li ste sigurni da želite uvesti? Ovo će izbrisati bazu podataka i ponovno je uvesti iz vaših izvezenih metapodataka." }, "temp_disable": "Privremeno isključi…", "temp_enable": "Privremeno uključi…", "use_default": "Koristi zadane vrijednosti", - "view_random": "Vidi nasumično" + "view_random": "Vidi nasumično", + "add_manual_date": "Dodaj ručni datum", + "add_sub_groups": "Dodaj podgrupu", + "add_o": "Dodaj O", + "add_play": "Dodaj reproduciranje", + "anonymise": "Anonimiziraj", + "assign_stashid_to_parent_studio": "Dodijeli Stash ID na postojeći matični studio i ažuriraj metapodatke", + "choose_date": "Odaberi datum", + "clean_generated": "Očisti generirane datoteke", + "clear_back_image": "Obriši stražnju sliku", + "clear_date_data": "Očisti podatke o datumu", + "clear_front_image": "Očisti prednju sliku", + "copy_to_clipboard": "Kopiraj u međuspremnik", + "create_chapters": "Stvori poglavlje", + "create_parent_studio": "Napravi matični studio", + "customise": "Prilagodi", + "delete_file_and_funscript": "Izbriši datoteku (i funscript)", + "disable": "Onemogući", + "download_anonymised": "Preuzmi anonimno", + "enable": "Omogući", + "encoding_image": "Kodiranje slike…", + "hash_migration": "migracija hash-a", + "load": "Učitaj", + "load_filter": "Učitaj filter", + "make_primary": "Učini Primarnim", + "migrate_blobs": "Spoji Blobs", + "migrate_scene_screenshots": "Migriraj Snimke Zaslona Scene", + "optimise_database": "Optimiziraj Bazu Podataka", + "overwrite": "Prebriši", + "play": "Pokreni", + "reassign": "Preraspodjeli", + "reload": "Ponovno Učitaj", + "reload_scrapers": "Ponovno učitaj scraper-e", + "remove_date": "Ukloni datum", + "remove_from_containing_group": "Ukloni iz Grupe", + "reset_play_duration": "Resetiraj duljinu reprodukcije", + "reset_resume_time": "Resetiraj vrijeme nastavka", + "reset_cover": "Vrati Zadanu Naslovnicu", + "reshuffle": "Promješaj", + "set_back_image": "Stražnja slika…", + "set_cover": "Postavi kao Naslovnicu", + "set_front_image": "Prednja slika…", + "show_results": "Prikaži rezultate", + "show_count_results": "Prikaži {count} rezultata", + "sidebar": { + "close": "Zatvori bočnu traku", + "open": "Otvori bočnu traku", + "toggle": "Uključi/Isključi bočnu traku" + }, + "view_history": "Vidi povijest" + }, + "actions_name": "Radnje", + "age": "Dob", + "age_on_date": "{age} u produkciji", + "aliases": "Pseudonimi", + "all": "sve", + "also_known_as": "Također poznat kao", + "appears_with": "Pojavljuje se sa", + "ascending": "Uzlazno", + "audio_codec": "Audio Kodek", + "average_resolution": "Prosječna Rezolucija", + "between_and": "i", + "birth_year": "Godina Rođenja", + "birthdate": "Datum rođenja", + "bitrate": "Brzina Prijenosa Podataka", + "blobs_storage_type": { + "database": "Baza podataka", + "filesystem": "Datotečni sustav" + }, + "captions": "Natpisi", + "career_length": "Duljina Karijere", + "chapters": "Poglavlja", + "circumcised": "Obrezan", + "circumcised_types": { + "CUT": "Izrezan", + "UNCUT": "Neizrezan" + }, + "component_tagger": { + "config": { + "active_instance": "Aktivna stash-box instanca:", + "blacklist_desc": "Stavke crne liste isključene su iz upita. Imajte na umu da su to regularni izrazi i da nisu osjetljivi na velika i mala slova. Određeni znakovi moraju se izbjeći obrnutom kosom crtom: {chars_require_escape}", + "blacklist_label": "Crna Lista", + "errors": { + "blacklist_duplicate": "Duplikat stavke crne liste" + }, + "mark_organized_desc": "Odmah označi scenu kao Organiziranu nakon što je tipka Spremi stisnuta.", + "mark_organized_label": "Označi kao organizirano pri spremanju", + "query_mode_auto": "Automatski", + "query_mode_auto_desc": "Koristi metapodatke ako postoje, ili ime datoteke", + "query_mode_dir": "Dir", + "query_mode_dir_desc": "Koristi samo nadređeni direktorij video datoteke", + "query_mode_filename": "Ime datoteke", + "query_mode_filename_desc": "Koristi samo ime datoteke", + "query_mode_label": "Query Mod", + "query_mode_metadata": "Metapodaci", + "query_mode_metadata_desc": "Koristi samo metapodatke", + "query_mode_path": "Putanja", + "query_mode_path_desc": "Koristi cijelu putanju datoteke", + "set_cover_desc": "Zamijeni sliku naslovnice scene ako je pronađena.", + "set_cover_label": "Postavi sliku naslovnice scene", + "set_tag_desc": "Priložite oznake sceni, bilo prepisivanjem ili spajanjem s postojećim oznakama na sceni.", + "set_tag_label": "Postavi oznake", + "show_male_desc": "Uključi/isključi mogućnost označavanja muških izvođača.", + "show_male_label": "Prikaži muške izvođače", + "source": "Izvor" + }, + "noun_query": "Upit", + "results": { + "duration_unknown": "Trajanje nepoznato", + "fp_matches": "Trajanje se podudara", + "fp_matches_multi": "Trajanje odgovara otiscima {matchCount}/{durationsLength}", + "hash_matches": "{hash_type} se podudara", + "match_failed_already_tagged": "Scena već označena", + "match_failed_no_result": "Nisu pronađeni rezultati", + "match_success": "Scena uspješno označena", + "unnamed": "Neimenovano" + }, + "verb_matched": "Podudara se", + "verb_toggle_unmatched": "{toggle} neusklađene scene" + }, + "config": { + "about": { + "build_hash": "Izradi hash:", + "build_time": "Vrijeme izrade:", + "check_for_new_version": "Provjeri za novu verziju", + "latest_version": "Zadnja Verzija", + "latest_version_build_hash": "Izrađen Hash Zadnje Verzije:", + "new_version_notice": "[NOVO]", + "release_date": "Datum izdanja:", + "stash_discord": "Pridruži se našem {url} kanalu", + "stash_home": "Stash početna stranica na {url}", + "stash_open_collective": "Podrži nas kroz {url}", + "stash_wiki": "Stash {url} stranica", + "version": "Verzija" + }, + "advanced_mode": "Napredan Način", + "application_paths": { + "heading": "Putanje Aplikacije" + }, + "categories": { + "about": "O nama", + "changelog": "Zapisnik promjena", + "interface": "Sučelje", + "logs": "Zapisnici", + "metadata_providers": "Pružatelji Metapodataka", + "plugins": "Dodaci", + "security": "Sigurnost", + "services": "Usluge", + "system": "Sistem", + "tasks": "Zadaci", + "tools": "Alati" + }, + "dlna": { + "allow_temp_ip": "Dopusti {tempIP}", + "allowed_ip_addresses": "Dopuštene IP adrese", + "allowed_ip_temporarily": "Dopušten IP privremeno", + "default_ip_whitelist": "Zadana bijela lista IP adresa", + "default_ip_whitelist_desc": "Zadane IP adrese omogućuju pristup DLNA. Koristi {wildcard} za dopuštanje svih IP adresa.", + "disabled_dlna_temporarily": "Onemogućen DLNA privremeno", + "disallowed_ip": "Nedopušen IP", + "enabled_by_default": "Omogućeno prema zadanim postavkama", + "enabled_dlna_temporarily": "Omogućen DLNA privremeno", + "network_interfaces": "Sučelja", + "network_interfaces_desc": "Sučelja na kojima će se izložiti DLNA poslužitelj. Prazan popis rezultira pokretanjem na svim sučeljima. Zahtijeva ponovno pokretanje DLNA nakon promjene.", + "recent_ip_addresses": "Nedavne IP adrese", + "server_display_name": "Prikazni Naziv Poslužitelja", + "server_display_name_desc": "Prikazni naziv za DLNA poslužitelj. Zadano je {server_name} ako je prazno.", + "server_port": "Port Poslužitelja", + "server_port_desc": "Port na kojem će se pokretati DLNA poslužitelj. Zahtijeva ponovno pokretanje DLNA nakon promjene.", + "successfully_cancelled_temporary_behaviour": "Uspješno otkazano privremeno ponašanje", + "until_restart": "do ponovnog pokretanja", + "video_sort_order": "Zadani Redoslijed Sortiranja Videozapisa" + }, + "general": { + "auth": { + "api_key": "API Ključ", + "api_key_desc": "API ključ za vanjske sustave. Potreban je samo kada je konfigurirano korisničko ime/lozinka. Korisničko ime mora biti spremljeno prije generiranja API ključa.", + "authentication": "Autentifikacija", + "clear_api_key": "Obriši API ključ", + "credentials": { + "description": "Vjerodajnice za ograničavanje pristupa zalihama.", + "heading": "Vjerodajnice" + }, + "generate_api_key": "Generiraj API ključ", + "log_file": "Datoteka zapisnika" + } + } } } diff --git a/ui/v2.5/src/locales/hu-HU.json b/ui/v2.5/src/locales/hu-HU.json index be47f77a9..b35e4579e 100644 --- a/ui/v2.5/src/locales/hu-HU.json +++ b/ui/v2.5/src/locales/hu-HU.json @@ -503,7 +503,6 @@ "name": "Név", "new": "Új", "none": "Nincs", - "o_counter": "O-Számláló", "operations": "Műveletek", "organized": "Rendezve", "pagination": { diff --git a/ui/v2.5/src/locales/id-ID.json b/ui/v2.5/src/locales/id-ID.json index a7327508a..a1b4f43f2 100644 --- a/ui/v2.5/src/locales/id-ID.json +++ b/ui/v2.5/src/locales/id-ID.json @@ -3,7 +3,7 @@ "welcome_to_stash": "Selamat datang di Stash", "paths": { "where_is_your_porn_located": "Di mana lokasi porno Anda?", - "description": "Selanjutnya, kita perlu menentukan di mana lokasi koleksi porno Anda, dan di mana menyimpan pangkalan data Stash, berkas yang dihasilkan, dan berkas tembolok. Pengaturan ini dapat diubah nanti jika diperlukan." + "description": "Selanjutnya, kita perlu menentukan di mana lokasi koleksi bokep Anda, dan di mana menyimpan pangkalan data Stash, berkas yang dihasilkan, dan berkas tembolok. Pengaturan ini dapat diubah nanti jika diperlukan." }, "success": { "thanks_for_trying_stash": "Terima kasih sudah mencoba Stash!", @@ -29,7 +29,7 @@ "continue": "Lanjutkan", "copy_to_clipboard": "Salin ke papan klip", "create": "Buat", - "create_chapters": "Buat Bab", + "create_chapters": "Buat Bagian", "create_entity": "Buat {entityType}", "create_marker": "Buat Tanda", "create_parent_studio": "Buat studio induk", @@ -147,7 +147,23 @@ "use_default": "Gunakan bawaan", "view_random": "Lihat Acak", "unset": "Tidak disetel", - "view_history": "Lihat histori" + "view_history": "Lihat histori", + "reset_cover": "Pulihkan Sampul Bawaan", + "set_cover": "Atur sebagai Sampul", + "reset_resume_time": "Atur ulang waktu lanjut", + "reset_play_duration": "Atur ulang durasi putar", + "add_sub_groups": "Tambah Subgrup", + "remove_from_containing_group": "Hapus dari Grup", + "load": "Muat", + "load_filter": "Muat filter", + "play": "Mainkan", + "show_results": "Lihat hasil", + "show_count_results": "Lihat {count} hasil", + "sidebar": { + "close": "Tutup bilah samping", + "open": "Buka bilah samping", + "toggle": "Alihkan bilah samping" + } }, "circumcised_types": { "CUT": "Disunat", @@ -216,7 +232,7 @@ "query_mode_filename_desc": "Hanya menggunakan nama berkas", "query_mode_label": "Mode Kueri", "query_mode_metadata_desc": "Hanya menggunakan metadata", - "query_mode_path": "Jalur", + "query_mode_path": "Lokasi", "query_mode_path_desc": "Menggunakan seluruh jalur berkas", "set_cover_desc": "Ganti gambar adegan jika cover ditemukan.", "set_cover_label": "Tetapkan gambar cover adegan", @@ -224,7 +240,10 @@ "set_tag_desc": "Lampirkan tag ke adegan, baik dengan menimpa atau menggabungkan dengan tag yang sudah ada.", "show_male_desc": "Baeralih apakah pemain pria dapat diberi tag.", "show_male_label": "Tampilkan pemain pria", - "source": "Sumber" + "source": "Sumber", + "errors": { + "blacklist_duplicate": "Duplikat item daftar hitam" + } }, "results": { "duration_unknown": "Durasi tidak diketahui", @@ -280,7 +299,9 @@ "enabled_dlna_temporarily": "DLNA yang diaktifkan sementara", "network_interfaces_desc": "Antarmuka untuk mengekspos server DLNA. Daftar kosong menghasilkan berjalannya di semua antarmuka. Dibutuhkan mulai ulang DLNA setelah perubahan.", "recent_ip_addresses": "Alamat IP terbaru", - "server_display_name": "Nama Tampilan Server" + "server_display_name": "Nama Tampilan Server", + "server_port_desc": "Port untuk menjalankan server DLNA. Harus memulai ulang DLNA setelah diganti.", + "server_port": "Port Server" }, "general": { "logging": "Pencatatan", @@ -322,7 +343,8 @@ "gallery_ext_desc": "Daftar ekstensi berkas yang dibatasi koma yang akan diidentifikasi sebagai berkas zip galeri.", "gallery_ext_head": "Ekstensi zip galeri", "python_path": { - "heading": "Jalur Eksekusi Python" + "heading": "Jalur Eksekusi Python", + "description": "Lokasi executable Python (bukan hanya folder). Digunakan untuk skrip penggali data dan plugin. Jika kosong, Python akan diambil dari environment" }, "scraper_user_agent": "Agen Pengguna Penggali", "db_path_head": "Jalur Pangkalan Data", @@ -359,10 +381,72 @@ "blobs_path": { "description": "Dimana pada sistem berkas untuk menyimpan data biner. Hanya berlaku saat menggunakan jenis penyimpanan blob Sistem Berkas. PERINGATAN: mengubah ini memerlukan pemindahan data yang ada secara manual.", "heading": "Jalur sistem berkas data biner" - } + }, + "check_for_insecure_certificates": "Cek untuk sertifikat tidak aman", + "cache_location": "Direktori lokasi cache. Harus diisi jika streaming menggunakan HLS (seperti pada perangkat Apple) atau DASH.", + "calculate_md5_and_ohash_label": "Kalkulasi MD5 untuk video", + "cache_path_head": "Lokasi Cache", + "calculate_md5_and_ohash_desc": "Kalkulasi checksum MD5 untuk tambahan oshash. Jika diaktifkan akan memperlambat proses scan awal. Hash penamaan file harus diatur menjadi oshash untuk menonaktifkan kalkulasi MD5.", + "check_for_insecure_certificates_desc": "Beberapa situs menggunakan sertifikat ssl yang tidak aman. Jika dinonaktifkan, scraper akan mengabaikan sertifikat yang tidak aman dan akan melanjutkan scraping. Jika anda mendapatkan error saat scraping, nonaktifkan ini.", + "chrome_cdp_path": "Lokasi Chrome CDP", + "chrome_cdp_path_desc": "Lokasi file eksekutabel Chrome, atau alamat remote (dimulai dengan http:// atau https://, sebagai contoh http://localhost:9222/json/version) sebuah instansi Chrome.", + "ffmpeg": { + "live_transcode": { + "output_args": { + "desc": "Lanjutan: Argumen tambahan untuk ditambahkan pada ffmpeg sebelum isian output saat mentranscode video secara langsung.", + "heading": "Argumen untuk Output Transcode Langsung pada FFmpeg" + }, + "input_args": { + "desc": "Lanjutan: Argumen tambahan untuk diteruskan ke ffmpeg sebelum field input saat melakukan transcoding video langsung.", + "heading": "FFmpeg Live Transcode Input Args" + } + }, + "transcode": { + "input_args": { + "desc": "Lanjutan: Argumen tambahan untuk ditambahkann pada ffmpeg sebelum isian saat menghasilkan video.", + "heading": "Argumen Input Transcode FFmpeg" + }, + "output_args": { + "desc": "Lanjutan: Argumen tambahan untuk ditambahkan pada ffmpeg sebelum output saat menghasilkan video.", + "heading": "Argumen Output Transcode FFmpeg" + } + }, + "download_ffmpeg": { + "description": "Mengunduh FFmpeg ke dalam direktori konfigurasi dan mengosongkan lokasi ffmpeg serta ffprobe untuk diambil dari direktori konfigurasi.", + "heading": "Unduh FFmpeg" + }, + "ffmpeg_path": { + "description": "Lokasi ke executable ffmpeg (bukan hanya folder). Jika kosong, ffmpeg akan diambil dari environment melalui $PATH, direktori konfigurasi, atau dari $HOME/.stash", + "heading": "Lokasi Executable FFmpeg" + }, + "ffprobe_path": { + "description": "Lokasi executable ffprobe (bukan hanya folder). Jika kosong, ffprobe akan diambil dari environment melalui $PATH, direktori konfigurasi, atau dari $HOME/.stash", + "heading": "Lokasi Executable FFprobe" + }, + "hardware_acceleration": { + "desc": "Menggunakan perangkat keras yang tersedia untuk melakukan encoding video dalam transcoding langsung.", + "heading": "Encoding perangkat keras FFmpeg" + } + }, + "create_galleries_from_folders_label": "Buat galeri dari folder yang berisi gambar", + "directory_locations_to_your_content": "Lokasi direktori konten Anda", + "create_galleries_from_folders_desc": "Jika true, secara bawaan membuat galeri dari folder yang berisi gambar. Buat sebuah file bernama .forcegallery atau .nogallery di dalam folder untuk memaksa/mencegah hal ini.", + "excluded_image_gallery_patterns_desc": "Regexp file gambar dan galeri/lokasi yang akan dikecualikan dari Pemindaian dan ditambahkan ke Pembersihan", + "excluded_image_gallery_patterns_head": "Pola Gambar/Galeri yang Dikecualikan", + "excluded_video_patterns_desc": "Regexp file video/lokasi yang akan dikecualikan dari Pemindaian dan ditambahkan ke Pembersihan", + "excluded_video_patterns_head": "Pola Video yang Dikecualikan", + "generated_file_naming_hash_desc": "Gunakan MD5 atau oshash untuk penamaan file yang dihasilkan. Mengubah ini memerlukan semua adegan memiliki nilai MD5/oshash yang sesuai. Setelah mengubah nilai ini, file yang sudah dihasilkan perlu dimigrasikan atau dibuat ulang. Lihat halaman Tugas untuk migrasi.", + "image_ext_desc": "Daftar ekstensi file yang dipisahkan koma dan akan dikenali sebagai gambar.", + "plugins_path": { + "description": "Lokasi direktori file konfigurasi plugin", + "heading": "Lokasi Plugin" + }, + "video_ext_desc": "Daftar ekstensi file yang dipisahkan koma dan akan dikenali sebagai video." }, "library": { - "exclusions": "Pengecualian" + "exclusions": "Pengecualian", + "gallery_and_image_options": "Opsi Galeri dan Gambar", + "media_content_extensions": "Ekstensi konten media" }, "tasks": { "identify": { @@ -387,9 +471,11 @@ "markers": "Pratinjau Penanda", "image_thumbnails": "Keluku Gambar", "image_thumbnails_desc": "Keluku dan klip gambar", - "previews": "Pratinjau Adegan" + "previews": "Pratinjau Adegan", + "previews_desc": "Pratinjau adegan dan keluku" }, - "added_job_to_queue": "{operation_name} ditambahkan ke antrean tugas" + "added_job_to_queue": "{operation_name} ditambahkan ke antrean tugas", + "data_management": "Manajemen data" }, "ui": { "editing": { @@ -456,14 +542,16 @@ "supported_types": "Tipe yang didukung", "search_by_name": "Cari berdasarkan nama", "available_scrapers": "Penggali Tersedia", - "entity_scrapers": "Penggali {entityType}" + "entity_scrapers": "Penggali {entityType}", + "excluded_tag_patterns_head": "Pola Tag Terkecualikan" }, "stashbox": { "endpoint": "Titik akhir", "name": "Nama", "graphql_endpoint": "Titik akhir GraphQL", "title": "Titik Akhir Stash-box", - "api_key": "Kunci API" + "api_key": "Kunci API", + "max_requests_per_minute": "Maks permintaan per menit" }, "system": { "transcoding": "Transkode" @@ -472,6 +560,13 @@ "scene_filename_parser": { "filename": "Nama berkas" } + }, + "logs": { + "log_level": "Level Log" + }, + "plugins": { + "available_plugins": "Plugin Tersedia", + "installed_plugins": "Plugin Terinstal" } }, "criterion": { @@ -499,7 +594,8 @@ "options": "Opsi", "scroll_mode": { "zoom": "Perbesar" - } + }, + "page_header": "Halaman {page} / {total}" }, "merge": { "destination": "Destinasi", @@ -514,7 +610,9 @@ "video_previews": "Pratinjau" }, "scrape_results_existing": "Yang sudah ada", - "scrape_results_scraped": "Digali" + "scrape_results_scraped": "Digali", + "performers_found": "{count} pemain ditemukan", + "dont_show_until_updated": "Sembunyikan hingga pembaruan selanjutnya" }, "effect_filters": { "brightness": "Kecerahan", @@ -548,13 +646,16 @@ "uninstall": "Copot pemasangan", "update": "Perbarui", "version": "Versi", - "unknown": "" + "unknown": "", + "installed_version": "Versi Terpasang", + "latest_version": "Versi Terkini" }, "pagination": { "next": "Berikutnya", "previous": "Sebelumnya", "last": "Terakhir", - "first": "Pertama" + "first": "Pertama", + "current_total": "{current} dari {total}" }, "performer": "Pemain", "performers": "Pemain", @@ -650,15 +751,44 @@ }, "instagram": "Instagram", "interactive": "Interaktif", - "library": "Pustaka", + "library": "Koleksi", "loading": { "generic": "Memuat…" }, "tag": "Tag", - "o_counter": "Penghitung Crot", "operations": "Operasi", "organized": "Terorganisir", "orientation": "Orientasi", "all": "semua", - "ascending": "Urut naik" + "ascending": "Urut naik", + "age_on_date": "{age} saat produksi", + "performer_age": "Umur Pemain", + "performer_count": "Jumlah Pemain", + "performer_favorite": "Pemain Difavorit", + "performer_image": "Foto Pemain", + "performer_tagger": { + "add_new_performers": "Tambah Pemain Baru" + }, + "part_of": "Bagian dari {parent}", + "cover_image": "Foto Sampul", + "death_date": "Tanggal Kematian", + "death_year": "Tahun Kematian", + "last_o_at": "Terakhir Crot Pada", + "last_played_at": "Terakhir Dimainkan Pada", + "login": { + "username": "Nama Pengguna", + "password": "Kata Sandi", + "login": "Masuk", + "invalid_credentials": "Nama pengguna atau kata sandi salah" + }, + "marker_count": "Jumlah Penanda", + "media_info": { + "o_count": "Jumlah Crot", + "performer_card": { + "age": "{age} {years_old}", + "age_context": "{age} {years_old} saat produksi" + }, + "phash": "PHash" + }, + "o_count": "Jumlah Crot" } diff --git a/ui/v2.5/src/locales/index.ts b/ui/v2.5/src/locales/index.ts index 86c1a607e..0e699b8f7 100644 --- a/ui/v2.5/src/locales/index.ts +++ b/ui/v2.5/src/locales/index.ts @@ -2,6 +2,7 @@ import Countries from "i18n-iso-countries"; export const localeCountries = { af: () => import("i18n-iso-countries/langs/af.json"), + bg: () => import("i18n-iso-countries/langs/bg.json"), bn: () => import("i18n-iso-countries/langs/bn.json"), ca: () => import("i18n-iso-countries/langs/ca.json"), cs: () => import("i18n-iso-countries/langs/cs.json"), @@ -20,6 +21,7 @@ export const localeCountries = { it: () => import("i18n-iso-countries/langs/it.json"), ja: () => import("i18n-iso-countries/langs/ja.json"), ko: () => import("i18n-iso-countries/langs/ko.json"), + lt: () => import("i18n-iso-countries/langs/lt.json"), lv: () => import("i18n-iso-countries/langs/lv.json"), nb: () => import("i18n-iso-countries/langs/nb.json"), nl: () => import("i18n-iso-countries/langs/nl.json"), @@ -32,6 +34,7 @@ export const localeCountries = { sv: () => import("i18n-iso-countries/langs/sv.json"), th: () => import("i18n-iso-countries/langs/th.json"), tr: () => import("i18n-iso-countries/langs/tr.json"), + ur: () => import("i18n-iso-countries/langs/ur.json"), uk: () => import("i18n-iso-countries/langs/uk.json"), vi: () => import("i18n-iso-countries/langs/vi.json"), zh: () => import("i18n-iso-countries/langs/zh.json"), @@ -53,6 +56,7 @@ export async function registerCountry(locale: string) { export const localeLoader = { afZA: () => import("./af-ZA.json"), + bgBG: () => import("./bg-BG.json"), bnBD: () => import("./bn-BD.json"), caES: () => import("./ca-ES.json"), csCZ: () => import("./cs-CZ.json"), @@ -72,6 +76,7 @@ export const localeLoader = { itIT: () => import("./it-IT.json"), jaJP: () => import("./ja-JP.json"), koKR: () => import("./ko-KR.json"), + ltLT: () => import("./lt-LT.json"), lvLV: () => import("./lv-LV.json"), nbNO: () => import("./nb-NO.json"), // neNP: () => import("./ne-NP.json"), @@ -85,6 +90,7 @@ export const localeLoader = { svSE: () => import("./sv-SE.json"), thTH: () => import("./th-TH.json"), trTR: () => import("./tr-TR.json"), + urPK: () => import("./ur-PK.json"), ukUA: () => import("./uk-UA.json"), viVN: () => import("./vi-VN.json"), zhCN: () => import("./zh-CN.json"), diff --git a/ui/v2.5/src/locales/it-IT.json b/ui/v2.5/src/locales/it-IT.json index 98269f6d8..0735540d6 100644 --- a/ui/v2.5/src/locales/it-IT.json +++ b/ui/v2.5/src/locales/it-IT.json @@ -135,7 +135,8 @@ "optimise_database": "Ottimizza il Database", "reload": "Ricarica", "remove_date": "Rimuovi la data", - "view_history": "Visualizza cronologia" + "view_history": "Visualizza cronologia", + "add_sub_groups": "Aggiungi Sottogruppi" }, "actions_name": "Azioni", "age": "Età", @@ -744,7 +745,6 @@ "destination": "Destinazione", "source": "Origine" }, - "overwrite_filter_confirm": "Sei sicuro di voler sovrascrivere le esistenti query salvate {entityName}?", "reassign_entity_title": "{count, plural, one {Riassegna {singularEntity}} other {Riassegna {pluralEntity}}}", "reassign_files": { "destination": "Riassegna a" @@ -937,7 +937,6 @@ "name": "Nome", "new": "Nuovo", "none": "Nessuno/a", - "o_counter": "Contatore-O", "operations": "Operazioni", "organized": "Ordinato", "pagination": { diff --git a/ui/v2.5/src/locales/ja-JP.json b/ui/v2.5/src/locales/ja-JP.json index c8e95e595..0c5a8ef89 100644 --- a/ui/v2.5/src/locales/ja-JP.json +++ b/ui/v2.5/src/locales/ja-JP.json @@ -141,7 +141,15 @@ "set_cover": "カバーをセット", "view_history": "履歴を表示する", "reset_resume_time": "再開時間をリセットする", - "reset_cover": "標準カバーに復元" + "reset_cover": "標準カバーに復元", + "sidebar": { + "close": "サイドバーを閉じる", + "open": "サイドバーを開く", + "toggle": "サイドバーを切り替え" + }, + "play": "再生", + "show_results": "結果を表示", + "show_count_results": "{count}件の結果を表示" }, "actions_name": "操作", "age": "年齢", @@ -435,7 +443,8 @@ "endpoint": "エンドポイント", "graphql_endpoint": "GraphQL エンドポイント", "name": "名前", - "title": "Stash-box エンドポイント" + "title": "Stash-box エンドポイント", + "max_requests_per_minute": "1分あたりの最大リクエスト数" }, "system": { "transcoding": "トランスコード" @@ -718,8 +727,11 @@ "disable_mobile_media_auto_rotate": "モバイル機器でフル画面再生時の画面回転を無効化", "enable_chromecast": "クロームキャスト機能の有効化", "vr_tag": { - "heading": "VRタッグ" - } + "heading": "VRタッグ", + "description": "VRボタンはこのタグがついたシーンにのみ表示されます。" + }, + "show_ab_loop_controls": "ABループプラグインのコントロールを表示", + "show_range_markers": "範囲マーカーを表示" } }, "scene_wall": { @@ -779,6 +791,9 @@ "direction": "方向", "heading": "画像ウォール", "margin": "マージン (px単位)" + }, + "performer_list": { + "heading": "AV女優・男優リスト" } }, "advanced_mode": "高度なモード" @@ -796,7 +811,7 @@ }, "country": "国", "cover_image": "カバー画像", - "created_at": "作成者:", + "created_at": "作成日", "criterion": { "greater_than": "より大きい", "less_than": "より小さい", @@ -862,7 +877,8 @@ "label": "スクロールモード", "pan_y": "Yにパン", "zoom": "拡大" - } + }, + "page_header": "ページ {page} / {total}" }, "merge": { "destination": "宛先", @@ -873,7 +889,6 @@ "destination": "場所", "source": "ソース" }, - "overwrite_filter_confirm": "本当に保存されているクエリ「{entityName}」を上書きしてもよろしいですか?", "reassign_entity_title": "{count, plural, one {{singularEntity}を再割り当て} other {{pluralEntity}を再割り当て}}", "reassign_files": { "destination": "次に再割り当て:" @@ -911,7 +926,10 @@ "transcodes": "トランスコード", "transcodes_tooltip": "サポートされていない動画フォーマットをMP4に変換します", "video_previews": "プレビュー", - "video_previews_tooltip": "シーンにマウスカーソルを置いた時に再生されるビデオプレビュー" + "video_previews_tooltip": "シーンにマウスカーソルを置いた時に再生されるビデオプレビュー", + "clip_previews": "画像のプレビュー", + "covers": "シーンカバー", + "image_thumbnails": "サムネ画像" }, "scenes_found": "{count}シーンが見つかりました", "scrape_entity_query": "{entity_type}スクレイプクエリ", @@ -919,7 +937,9 @@ "scrape_results_existing": "存在します", "scrape_results_scraped": "スクレイプ済み", "set_image_url_title": "画像URL", - "unsaved_changes": "変更が保存されていません。本当に移動してよろしいですか?" + "unsaved_changes": "変更が保存されていません。本当に移動してよろしいですか?", + "clear_play_history_confirm": "再生履歴を本当に削除しますか?", + "performers_found": "{count}人の出演者が見つかりました" }, "dimensions": "寸法", "director": "監督", @@ -1059,7 +1079,6 @@ "name": "名前", "new": "新規作成", "none": "なし", - "o_counter": "発射カウンター", "operations": "オペレーション", "organized": "分類済み", "pagination": { @@ -1299,6 +1318,18 @@ "date_format": "YYYY -MM-DD", "datetime_format": "YYYY-MM-DD HH:MM", "criterion_modifier_values": { - "none": "ない" - } + "none": "ない", + "only": "のみ" + }, + "connection_monitor": { + "websocket_connection_failed": "WebSocket接続ができません:詳細はブラウザのコンソールを確認してください" + }, + "custom_fields": { + "field": "フィールド", + "title": "カスタムフィールド", + "value": "値" + }, + "distance": "距離", + "age_on_date": "撮影時の年齢 {age}歳", + "containing_group": "含まれるグループ" } diff --git a/ui/v2.5/src/locales/ko-KR.json b/ui/v2.5/src/locales/ko-KR.json index 60f942e82..15d285434 100644 --- a/ui/v2.5/src/locales/ko-KR.json +++ b/ui/v2.5/src/locales/ko-KR.json @@ -45,13 +45,13 @@ "from_url": "URL로 불러오기…", "full_export": "전부 내보내기", "full_import": "전부 불러오기", - "generate": "만들기", - "generate_thumb_default": "기본 썸네일 만들기", - "generate_thumb_from_current": "현재 화면으로 썸네일 만들기", + "generate": "생성", + "generate_thumb_default": "기본 썸네일 생성", + "generate_thumb_from_current": "현재 화면으로 썸네일 생성", "hash_migration": "해쉬 값 마이그레이션", "hide": "숨기기", "hide_configuration": "설정 숨기기", - "identify": "인증", + "identify": "식별", "ignore": "무시", "import": "불러오기…", "import_from_file": "파일 불러오기", @@ -65,7 +65,7 @@ "next_action": "다음", "not_running": "실행 중이 아님", "open_in_external_player": "외부 플레이어에서 열기", - "open_random": "랜덤 배우 정보 열기", + "open_random": "랜덤 열기", "overwrite": "덮어쓰기", "play_random": "랜덤 영상 재생", "play_selected": "선택된 영상 재생", @@ -104,7 +104,7 @@ "show": "보여주기", "show_configuration": "설정 보여주기", "skip": "건너뛰기", - "split": "나누기", + "split": "분할", "stop": "정지", "submit": "제출", "submit_stash_box": "Stash-Box에 제출하기", @@ -141,7 +141,17 @@ "reset_play_duration": "재생 시간 초기화", "reset_resume_time": "마지막 재생 위치 초기화", "add_sub_groups": "서브그룹 추가", - "remove_from_containing_group": "그룹에서 제거" + "remove_from_containing_group": "그룹에서 제거", + "sidebar": { + "close": "사이드바 닫기", + "open": "사이드바 열기", + "toggle": "사이드바 토글" + }, + "play": "재생", + "show_results": "결과 표시", + "show_count_results": "{count}개 결과 표시", + "load": "불러오기", + "load_filter": "필터 불러오기" }, "actions_name": "액션", "age": "나이", @@ -191,7 +201,10 @@ "show_male_label": "남성 배우 보여주기", "source": "출처", "mark_organized_desc": "저장 버튼을 클릭하면 곧바로 영상을 '정리됨' 상태로 만듭니다.", - "mark_organized_label": "저장 시 '정리됨' 상태로 만들기" + "mark_organized_label": "저장 시 '정리됨' 상태로 만들기", + "errors": { + "blacklist_duplicate": "블랙리스트 항목이 중복되었습니다" + } }, "noun_query": "쿼리", "results": { @@ -201,7 +214,7 @@ "fp_matches": "영상 길이가 일치함", "fp_matches_multi": "영상 길이가 {durationsLength}개 중 {matchCount}개의 식별값과 일치합니다", "hash_matches": "{hash_type}이 일치함", - "match_failed_already_tagged": "이미 태깅된 영상", + "match_failed_already_tagged": "이미 태그된 영상", "match_failed_no_result": "결과 없음", "match_success": "영상 태깅 성공", "phash_matches": "{count}개의 PHash가 일치함", @@ -306,7 +319,7 @@ "heading": "바이너리 데이터 저장 타입" }, "cache_location": "캐시 폴더 경로입니다. HLS(애플 기기 등)이나 DASH로 스트리밍할 때 필요합니다.", - "cache_path_head": "캐쉬 경로", + "cache_path_head": "캐시 경로", "calculate_md5_and_ohash_desc": "oshash 외에 MD5 체크섬도 계산합니다. 활성화하면 초기 스캔을 더 느리게 만들 것입니다. MD5 계산을 사용하지 않으려면 파일 이름 해쉬를 oshash로 설정해야 합니다.", "calculate_md5_and_ohash_label": "비디오 MD5 계산하기", "check_for_insecure_certificates": "안전하지 않은 자격증명 검사", @@ -419,7 +432,7 @@ }, "plugins": { "hooks": "후크", - "triggers_on": "트리거 켜기", + "triggers_on": "작동 조건", "available_plugins": "사용 가능한 플러그인", "installed_plugins": "설치된 플러그인" }, @@ -443,7 +456,9 @@ "endpoint": "엔드포인트", "graphql_endpoint": "GraphQL 엔드포인트", "name": "이름", - "title": "Stash-box 엔드포인트" + "title": "Stash-box 엔드포인트", + "max_requests_per_minute": "분당 최대 요청 수", + "max_requests_per_minute_description": "0으로 설정할 경우 기본값({defaultValue})을 사용합니다" }, "system": { "transcoding": "트랜스코딩" @@ -472,9 +487,9 @@ "generating_from_paths": "다음 경로에서 영상 생성 중", "generating_scenes": "{num}개의 {scene} 생성 중" }, - "generate_clip_previews_during_scan": "이미지 클립 미리보기 생성하기", + "generate_clip_previews_during_scan": "이미지 클립 미리보기 생성", "generate_desc": "이미지, 스프라이트, 비디오, vtt 등 파일을 생성합니다.", - "generate_phashes_during_scan": "컨텐츠 해시 값 생성", + "generate_phashes_during_scan": "해쉬 값 생성", "generate_phashes_during_scan_tooltip": "중복된 파일 확인과 영상 식별에 사용됩니다.", "generate_previews_during_scan": "움직이는 이미지 미리보기 생성", "generate_previews_during_scan_tooltip": "애니메이션(webp) 미리보기 또한 생성합니다. 영상/마커 월의 미리보기 유형이 '애니메이션 이미지'로 설정된 경우에만 필요합니다. '애니메이션 미리보기'는 '비디오 미리보기'보다 CPU를 덜 사용하지만, '비디오 미리보기'에 추가적으로 '애니메이션 미리보기'가 생성되기 때문에 파일 크기가 커집니다.", @@ -569,7 +584,9 @@ "whitespace_chars": "공백 문자", "whitespace_chars_desc": "이 문자들은 제목에서 공백으로 대체됩니다" }, - "scene_tools": "영상 도구" + "scene_tools": "영상 도구", + "heading": "도구", + "graphql_playground": "GraphQL 플레이그라운드" }, "ui": { "abbreviate_counters": { @@ -609,12 +626,12 @@ }, "editing": { "disable_dropdown_create": { - "description": "드랍다운 메뉴에서 새로운 오브젝트를 추가할 수 없도록 합니다", - "heading": "드랍다운 메뉴 비활성화" + "description": "선택창에서 새로운 오브젝트를 추가할 수 없도록 합니다", + "heading": "선택창 비활성화" }, "heading": "수정하기", "max_options_shown": { - "label": "Dropdown에 표시되는 최대 개수" + "label": "선택창에 표시되는 최대 개수" }, "rating_system": { "star_precision": { @@ -726,7 +743,7 @@ "description": "비디오가 끝나면 대기열에 있는 다음 영상을 재생합니다", "heading": "플레이리스트 이어보기" }, - "show_scrubber": "스크러버 보이기", + "show_scrubber": "스크러버 표시", "track_activity": "영상 재생 기록 활성화", "vr_tag": { "description": "VR 버튼은 이 태그를 가진 영상에서만 보여질 것입니다.", @@ -734,7 +751,8 @@ }, "enable_chromecast": "크롬캐스트 활성화", "disable_mobile_media_auto_rotate": "모바일 환경에서 전체화면 시 자동 방향 회전 비활성화", - "show_ab_loop_controls": "구간반복 기능 활성화" + "show_ab_loop_controls": "구간반복 기능 활성화", + "show_range_markers": "범위 마커 표시" } }, "scene_wall": { @@ -793,6 +811,14 @@ "description": "활성화되면, 모든 컨텐츠 세부사항이 기본값으로 보여지게 되고, 각각의 세부사항들이 하나의 열에 위아래로 정렬됩니다", "heading": "모든 세부사항 보여주기" } + }, + "performer_list": { + "heading": "배우 목록", + "options": { + "show_links_on_grid_card": { + "heading": "배우 그리드 카드에 링크 표시" + } + } } }, "advanced_mode": "고급 설정 모드" @@ -820,7 +846,7 @@ "criterion_modifier": { "between": "구간", "equals": "=", - "excludes": "포함하지 않음", + "excludes": "제외", "format_string": "{criterion} {modifierString} {valueString}", "greater_than": ">", "includes": "포함", @@ -834,7 +860,7 @@ "not_null": "값 존재함", "format_string_excludes": "{criterion} {modifierString} {valueString} ({excludedString} 제외)", "format_string_excludes_depth": "{criterion} {modifierString} {valueString} ({excludedString} 제외) (+{depth, plural, =-1 {all} other {{depth}}})", - "format_string_depth": "{criterion} {modifierString} {valueString} (+{depth, plural, =-1 {all} other {{depth}}})" + "format_string_depth": "{criterion} {modifierString} {valueString} (+{depth, plural, =-1 {all} other {{depth}}}수준)" }, "custom": "커스텀", "date": "날짜", @@ -897,7 +923,6 @@ "destination": "다른 태그와 합쳐질 태그", "source": "다른 태그로 합쳐질 태그" }, - "overwrite_filter_confirm": "정말 원래 저장되어 있었던 쿼리 {entityName}을 덮어쓰시겠습니까?", "reassign_entity_title": "{count, plural, one {{singularEntity} 재할당} other {{pluralEntity} 재할당}}", "scene_gen": { "clip_previews": "이미지 클립 미리보기", @@ -910,13 +935,13 @@ "marker_image_previews": "마커 움직이는 이미지 미리보기", "marker_image_previews_tooltip": "애니메이션(webp) 미리보기도 생성합니다. 영상/마커 월 미리보기 유형이 '애니메이션 이미지'로 설정된 경우에만 필요합니다. '비디오 미리보기'보다 CPU를 덜 사용하지만, '비디오 미리보기'에 추가적으로 생성되기 때문에 파일 크기가 커집니다.", "marker_screenshots": "마커 스크린샷", - "marker_screenshots_tooltip": "마커 JPG 이미지. 미리보기 유형이 이미지로 설정된 경우에만 필요합니다.", + "marker_screenshots_tooltip": "마커 고정 JPG 이미지", "markers": "마커 미리보기", "markers_tooltip": "주어진 시간 코드에서 시작하는 20초 짜리 비디오입니다.", "override_preview_generation_options": "미리보기 생성 옵션 재정의", "override_preview_generation_options_desc": "이 작업에 대한 미리보기 생성 옵션을 재정의합니다. 기본값은 '시스템' -> '미리보기 생성'에서 설정됩니다.", "overwrite": "기존 파일들 덮어쓰기", - "phash": "해시", + "phash": "해쉬", "preview_exclude_end_time_desc": "영상 미리보기에서 마지막 x 초를 제외합니다. 초 단위, 혹은 전체 영상 재생 길이 중 비율(예: 2%)로 나타낼 수 있습니다.", "preview_exclude_end_time_head": "마지막 영상 부분 제외", "preview_exclude_start_time_desc": "영상 미리보기에서 처음 x 초를 제외합니다. 초 단위, 혹은 전체 영상 재생 길이 중 비율(예: 2%)로 나타낼 수 있습니다.", @@ -955,7 +980,9 @@ }, "reassign_files": { "destination": "~으로 재지정" - } + }, + "overwrite_filter_warning": "저장된 필터 \"{entityName}\"은 덮어쓰기될 것입니다.", + "set_default_filter_confirm": "정말로 이 필터를 기본값으로 설정하시겠습니까?" }, "dimensions": "해상도", "director": "감독", @@ -965,12 +992,13 @@ "list": "목록", "tagger": "태거", "unknown": "알 수 없음", - "wall": "월 모드" + "wall": "월 모드", + "label_current": "디스플레이 모드: {current}" }, "donate": "후원", "dupe_check": { "description": "'정확' 이하의 수준에서는 계산이 오래 걸릴 수 있습니다. 낮은 정밀도 수준에서는 부정확한 결과가 함께 나올 수 있습니다.", - "duration_diff": "최대 영상 재생 시간 차이", + "duration_diff": "최대 영상 길이 차이", "duration_options": { "any": "상관 없음", "equal": "같음" @@ -1017,13 +1045,19 @@ }, "empty_server": "이 페이지에서 추천 영상들을 확인하려면 영상을 추가하세요.", "errors": { - "image_index_greater_than_zero": "이미지 인덱스는 0보다 커야 합니다", + "image_index_greater_than_zero": "이미지 번호는 0보다 커야 합니다", "lazy_component_error_help": "만약 최근에 Stash를 업그레이드했다면, 웹페이지를 새로고침하거나 브라우저 캐시를 삭제해주세요.", "something_went_wrong": "오류가 발생했습니다.", "header": "오류", "loading_type": "{type}을(를) 로딩하는 중 오류가 발생했습니다", "invalid_javascript_string": "유효하지 않은 자바스크립트 코드입니다: {error}", - "invalid_json_string": "유효하지 않은 JSON 문자열입니다: {error}" + "invalid_json_string": "유효하지 않은 JSON 문자열입니다: {error}", + "custom_fields": { + "field_name_required": "항목 이름이 필요합니다", + "field_name_whitespace": "항목 이름의 전후에 공백이 없어야 합니다", + "duplicate_field": "항목 이름은 중복될 수 없습니다", + "field_name_length": "항목 이름의 글자 수는 65글자보다 작아야 합니다" + } }, "ethnicity": "인종", "existing_value": "존재하는 값", @@ -1072,8 +1106,8 @@ "syncing": "서버와 동기화 중", "uploading": "스크립트 업로드 중" }, - "hasChapters": "챕터 유무", - "hasMarkers": "마커 유무", + "hasChapters": "챕터", + "hasMarkers": "마커", "height": "키", "height_cm": "키 (cm)", "help": "도움말", @@ -1092,7 +1126,8 @@ "last_played_at": "마지막 재생 날짜", "library": "라이브러리", "loading": { - "generic": "로드 중…" + "generic": "로드 중…", + "plugins": "플러그인 로딩 중…" }, "marker_count": "마커 개수", "markers": "마커", @@ -1105,11 +1140,11 @@ "interactive_speed": "인터랙티브 속도", "performer_card": { "age": "{age} {years_old}", - "age_context": "작품에서 {age} {years_old}" + "age_context": "제작 당시 {age} {years_old}" }, "phash": "PHash", - "play_count": "재생 횟수", - "play_duration": "재생 길이", + "play_count": "재생된 횟수", + "play_duration": "재생된 길이", "stream": "스트림", "video_codec": "비디오 코덱", "o_count": "싼 횟수" @@ -1119,7 +1154,6 @@ "name": "이름", "new": "새로 만들기", "none": "없음", - "o_counter": "싼 횟수", "operations": "작업", "organized": "정리됨", "pagination": { @@ -1163,21 +1197,21 @@ "network_error": "네트워크 오류", "no_results_found": "결과가 없습니다.", "number_of_performers_will_be_processed": "{performer_count}명의 배우들이 처리됩니다", - "performer_already_tagged": "이 배우에 이미 존재하는 태그입니다", + "performer_already_tagged": "배우가 이미 태그되어 있음", "performer_names_separated_by_comma": "배우 이름 (,으로 구분)", "performer_selection": "배우 선택", "performer_successfully_tagged": "배우 태깅에 성공했습니다:", "query_all_performers_in_the_database": "데이터베이스의 모든 배우", "refresh_tagged_performers": "태그된 배우 새로고침", - "refreshing_will_update_the_data": "새로고침하면 Stash-box 인스턴스에 있는 태그된 배우들의 데이터가 업데이트될 것입니다.", + "refreshing_will_update_the_data": "'새로고침'을 통해, Stash-box 인스턴스로부터 태그된 배우들의 데이터를 업데이트합니다.", "status_tagging_job_queued": "상태: 태그 작업 대기열 추가됨", "status_tagging_performers": "상태: 배우 태그 중", "tag_status": "태그 상태", "to_use_the_performer_tagger": "배우 태거를 사용하기 위해서는 stash-box 인스턴스가 설정되어야 합니다.", "untagged_performers": "태그되지 않은 배우", - "update_performer": "배우 수정", - "update_performers": "배우 수정", - "updating_untagged_performers_description": "태그가 지정되지 않은 배우를 업데이트하면, Stash ID가 없는 배우와 비교해본 뒤 메타데이터를 업데이트할 것입니다." + "update_performer": "배우 업데이트", + "update_performers": "배우 업데이트", + "updating_untagged_performers_description": "'태그되지 않은 배우 업데이트'를 통해, Stash ID가 없는 배우들에 대한 데이터를 찾아보고, 가능하다면 이를 이용해 배우를 업데이트합니다." }, "performer_tags": "배우 태그", "performers": "배우", @@ -1208,14 +1242,16 @@ "edit_filter": "필터 수정", "name": "필터", "saved_filters": "저장된 필터", - "update_filter": "필터 업데이트" + "update_filter": "필터 업데이트", + "more_filter_criteria": "외 {count} 개", + "search_term": "검색어" }, "second": "초", "seconds": "초", "settings": "설정", "setup": { "confirm": { - "almost_ready": "거의 설정을 완료했습니다. 아래 설정들을 확인해주세요. 틀린 내용이 있다면 이전으로 돌아가 변경할 수 있습니다. 내용이 모두 맞다면, '확인'을 눌러 시스템을 만드세요.", + "almost_ready": "거의 설정을 완료했습니다. 아래 설정들을 확인해주세요. 틀린 내용이 있다면 이전으로 돌아가 변경할 수 있습니다. 내용이 모두 맞다면, '확인'을 눌러 시스템을 생성하세요.", "blobs_directory": "바이너리 데이터 경로", "cache_directory": "캐시 파일 경로", "configuration_file_location": "설정 파일 위치:", @@ -1345,20 +1381,20 @@ "title": "제목", "toast": { "added_entity": "{singularEntity}을(를) 추가했습니다", - "added_generation_job_to_queue": "생성 작업을 대기열에 추가했습니다", + "added_generation_job_to_queue": "컨텐츠 생성 작업을 대기열에 추가했습니다", "created_entity": "{entity}를 생성했습니다", "default_filter_set": "기본 필터가 설정되었습니다", "delete_past_tense": "{count, plural, one {{singularEntity}} other {{pluralEntity}}}이(가) 삭제되었습니다", "generating_screenshot": "스크린샷을 생성하는 중…", "image_index_too_large": "오류: 이미지 번호가 갤러리의 이미지 개수보다 큽니다", - "merged_scenes": "영상들을 합쳤습니다", - "merged_tags": "병합된 태그", - "reassign_past_tense": "재할당된 파일", + "merged_scenes": "영상이 병합되었습니다", + "merged_tags": "태그가 병합되었습니다", + "reassign_past_tense": "파일이 재할당되었습니다", "removed_entity": "{singularEntity}을(를) 제거했습니다", "rescanning_entity": "{count, plural, one {{singularEntity}} other {{pluralEntity}}} 다시 스캔하는 중…", "saved_entity": "{entity}를 저장했습니다", "started_auto_tagging": "자동 태깅을 시작했습니다", - "started_generating": "생성을 시작했습니다", + "started_generating": "컨텐츠 생성을 시작했습니다", "started_importing": "불러오기를 시작했습니다", "updated_entity": "{entity}를 수정했습니다" }, @@ -1373,7 +1409,7 @@ "required": "${path}는 필수 항목입니다", "unique": "${path}은(는) 유일해야 합니다", "blank": "${path}를 빈 칸으로 둘 수 없습니다", - "end_time_before_start_time": "종료 시간은 시작 시간보다 크거나 같아야 합니다" + "end_time_before_start_time": "종료 시간은 시작 시간 이후여야 합니다" }, "videos": "비디오", "view_all": "모두 보기", @@ -1459,7 +1495,7 @@ "show_all": "모두 보여주기", "update": "업데이트", "selected_only": "선택된 것만", - "required_by": "{packages}로 인해 요구됨" + "required_by": "{packages}가 정상 동작하기 위해 설치되어야 함" }, "o_count": "싼 횟수", "orientation": "방향", @@ -1495,5 +1531,29 @@ "include_sub_studio_content": "서브스튜디오 컨텐츠 포함", "include_sub_tag_content": "서브태그 컨텐츠 포함", "time_end": "종료 시간", - "include_sub_groups": "서브그룹 포함" + "include_sub_groups": "서브그룹 포함", + "custom_fields": { + "value": "값", + "field": "항목", + "title": "커스텀 항목", + "criteria_format_string": "{criterion} (커스텀 항목) {modifierString} {valueString}", + "criteria_format_string_others": "{criterion} (커스텀 항목) {modifierString} {valueString} (+{others} 기타)" + }, + "login": { + "password": "비밀번호", + "invalid_credentials": "유효하지 않은 사용자 이름 또는 비밀번호입니다", + "login": "로그인", + "internal_error": "예상치 못한 내부 에러입니다. 로그에서 세부 사항을 확인하세요", + "username": "사용자 이름" + }, + "age_on_date": "제작 당시 {age}살", + "sort_name": "이름 (sort name)", + "criterion_modifier_values": { + "none": "값 없음", + "only": "해당 값만 존재", + "any": "값 존재", + "any_of": "해당 값 중 일부 포함" + }, + "eta": "예상 소요 시간", + "scenes_duration": "영상 길이" } diff --git a/ui/v2.5/src/locales/lt-LT.json b/ui/v2.5/src/locales/lt-LT.json new file mode 100644 index 000000000..0007adb26 --- /dev/null +++ b/ui/v2.5/src/locales/lt-LT.json @@ -0,0 +1,112 @@ +{ + "actions": { + "add": "Pridėti", + "add_directory": "Pridėti katalogą", + "add_entity": "Pridėti {entityType}", + "add_manual_date": "Įvesti datą rankini būdu", + "add_sub_groups": "Pridėti pogrupius", + "add_o": "Pridėti O", + "add_to_entity": "Pridėti prie {entityType}", + "allow": "Leisti", + "allow_temporarily": "Leisti laikinai", + "anonymise": "Anonimizuoti", + "apply": "Taikyti", + "assign_stashid_to_parent_studio": "Priskirti Stash ID esamai pagrindinei studijai ir atnaujinti metaduomenis", + "auto_tag": "Auto žymė", + "browse_for_image": "Ieškoti vaizdo…", + "cancel": "Atšaukti", + "choose_date": "Pasirinkti datą", + "clean": "Valyti", + "clean_generated": "Išvalyti sugeneruotus failus", + "clear": "Valyti", + "clear_date_data": "Valyti datos duomenis", + "clear_front_image": "Valyti priekinį vaizdą", + "clear_back_image": "Valyti galinį vaizdą", + "clear_image": "Valyti vaizdą", + "close": "Uždaryti", + "confirm": "Patvirtinti", + "continue": "Tęsti", + "copy_to_clipboard": "Kopijuoti į iškarpinę", + "create": "Sukurti", + "create_chapters": "Sukurti skyrių", + "create_entity": "Sukurti {entityType}", + "create_marker": "Sukurti žymeklį", + "create_parent_studio": "Sukurti pagrindinę studiją", + "created_entity": "Sukurtas {entity_type}: {entity_name}", + "customise": "Tinkinti", + "delete": "Ištrinti", + "delete_entity": "Ištrinti {entityType}", + "delete_file": "Ištrinti failą", + "delete_file_and_funscript": "Ištrinti failą (ir funscript)", + "delete_generated_supporting_files": "Ištrinti sugeneruotus pagalbinius failus", + "disable": "Išjungti", + "disallow": "Neleisti", + "download": "Atsisiųsti", + "download_anonymised": "Atsisiųsti anonimizuotą", + "download_backup": "Atsisiųsti atsarginę kopiją", + "edit": "Redaguoti", + "edit_entity": "Redaguoti {entityType}", + "enable": "Įjungti", + "encoding_image": "Koduojamas vaizdas…", + "export": "Eksportuoti", + "export_all": "Eksportuoti visus…", + "find": "Rasti", + "finish": "Baigti", + "from_file": "Iš failo…", + "from_url": "Iš URL…", + "full_export": "Pilnas eksportas", + "full_import": "Pilnas importas", + "generate": "Generuoti", + "generate_thumb_default": "Sugeneruoti numatytąją miniatiūrą", + "generate_thumb_from_current": "Sugeneruoti miniatiūrą iš dabartinio", + "hide": "Paslėpti", + "hide_configuration": "Paslėpti konfiguraciją", + "identify": "Atpažinti", + "ignore": "Ignoruoti", + "import": "Importuoti…", + "import_from_file": "Importuoti iš failo", + "load": "Krauti", + "load_filter": "Užkrauti filtrą", + "logout": "Atsijungti", + "make_primary": "Padaryti pirminiu", + "merge": "Sulieti", + "merge_from": "Sulieti iš", + "merge_into": "Sulieti į", + "next_action": "Kitas", + "not_running": "Nevykdomas", + "open_in_external_player": "Atidaryti išoriniame grotuve", + "open_random": "Atidaryti atsitiktinį", + "optimise_database": "Optimizuoti duomenų bazę", + "overwrite": "Perrašyti", + "play": "Groti", + "play_random": "Groti atsitiktinį", + "play_selected": "Groti pasirinktą", + "preview": "Peržiūra", + "previous_action": "Atgal", + "reassign": "Priskirti iš naujo", + "refresh": "Atnaujinti", + "reload": "Perkrauti", + "reload_plugins": "Perkrauti papildinius", + "reload_scrapers": "Perkrauti skreperius", + "remove": "Šalinti", + "remove_date": "Šalinti datą", + "remove_from_containing_group": "Šalinti iš grupės", + "remove_from_gallery": "Šalinti iš galerijos", + "rename_gen_files": "Pervadinti sugeneruotus failus", + "rescan": "Pakartotinai nuskaityti", + "reset_play_duration": "Atstatyti grojimo trukmę", + "reset_resume_time": "Atstatyti tęsimo laiką", + "reset_cover": "Atkurti numatytąjį viršelį", + "reshuffle": "Permaišyti", + "running": "Vykdoma", + "save": "Išsaugoti", + "save_delete_settings": "Naudoti šias parinktis kaip numatytąsias trinant", + "save_filter": "Išsaugoti filtrą", + "scan": "Skenuoti", + "search": "Ieškoti", + "select_all": "Pasirinkti visus", + "select_entity": "Pasirinkti {entityType}", + "select_folders": "Pasirinkti katalogus", + "select_none": "Atžymėti viską" + } +} diff --git a/ui/v2.5/src/locales/lv-LV.json b/ui/v2.5/src/locales/lv-LV.json index b90c34df2..e61f8f9ab 100644 --- a/ui/v2.5/src/locales/lv-LV.json +++ b/ui/v2.5/src/locales/lv-LV.json @@ -64,13 +64,13 @@ "add_sub_groups": "Pievienot apakšgrupas", "from_file": "No Faila…", "from_url": "No URL…", - "disallow": "Neatļaut", + "disallow": "Aizliegt", "download": "Lejupielādēt", "download_anonymised": "Lejupielādēt anonīmi", "download_backup": "Lejupielādēt Dublējumu", "edit": "Rediģēt", "edit_entity": "Rediģēt {entityType}", - "enable": "Iepējot", + "enable": "Iespējot", "encoding_image": "Konstruē bildi…", "export_all": "Eksportēt visu…", "find": "Atrast", @@ -80,7 +80,7 @@ "hide_configuration": "Paslēpt Konfigurāciju", "identify": "Identificēt", "ignore": "Ignorēt", - "import": "Importēt…", + "import": "Ievietot…", "hide": "Paslēpt", "make_primary": "Padarīt primāro", "merge_from": "Apvienot no", @@ -100,7 +100,7 @@ "reload_plugins": "Pārlādēt spraudņus", "refresh": "Atsvaidzināt", "disable": "Atspējot", - "export": "Eksportēt", + "export": "Izgūt", "logout": "Izrakstīties", "full_export": "Pilns Eksports", "full_import": "Pilns Imports", @@ -108,7 +108,17 @@ "generate_thumb_from_current": "Ģenerēt sīktēlu no pašreizējā", "import_from_file": "Importēt no faila", "merge": "Apvienot", - "migrate_scene_screenshots": "Migrēt Video Ekrānšāviņus" + "migrate_scene_screenshots": "Migrēt Video Ekrānšāviņus", + "save": "Saglabāt", + "search": "Meklēt", + "skip": "Izlaist", + "split": "Sadalīt", + "stop": "Apturēt", + "submit": "Iesniegt", + "remove": "Noņemt", + "rescan": "Skenēt pa jaunu", + "scan": "Skenēt", + "show": "Rādīt" }, "unknown_date": "Nezināms datums", "twitter": "Twitter", @@ -117,5 +127,54 @@ "zip_file_count": "Zip Failu Skaits", "weight_kg": "Svars (kg)", "weight": "Svars", - "years_old": "Gadus vecs" + "years_old": "Gadus vecs", + "component_tagger": { + "config": { + "query_mode_filename": "Datnes nosaukums", + "blacklist_label": "Melnais saraksts", + "query_mode_dir": "Mape", + "query_mode_metadata": "Metadati" + } + }, + "actions_name": "Darbības", + "age": "Vecums", + "aliases": "Aizstājvārdi", + "all": "visi", + "ascending": "Augošā secībā", + "between_and": "un", + "birthdate": "Dzimšanas datums", + "blobs_storage_type": { + "filesystem": "Datņsistēma", + "database": "Datubāze" + }, + "captions": "Subtitri", + "chapters": "Nodaļas", + "config": { + "categories": { + "security": "Drošība", + "tools": "Rīki", + "changelog": "Izmaiņu žurnāls", + "plugins": "Spraudņi" + }, + "general": { + "plugins_path": { + "description": "Ceļš uz spraudņu konfigurācijas mapi", + "heading": "Spraudņu mape" + } + }, + "plugins": { + "available_plugins": "Pieejamie spraudņi", + "installed_plugins": "Uzstādītie spraudņi" + }, + "tasks": { + "cleanup_desc": "Meklēt trūkstošos failus un noņemt tos no datubāzes. Šī darbība ir neatgriezeniska." + }, + "about": { + "check_for_new_version": "Pārbaudīt, vai pieejama jauna versija" + } + }, + "donate": "Ziedot", + "package_manager": { + "check_for_updates": "Pārbaudīt, vai pieejami atjauninājumi" + } } diff --git a/ui/v2.5/src/locales/nb-NO.json b/ui/v2.5/src/locales/nb-NO.json index 883b33b34..1eff0a044 100644 --- a/ui/v2.5/src/locales/nb-NO.json +++ b/ui/v2.5/src/locales/nb-NO.json @@ -5,7 +5,7 @@ "confirm": "Bekreft", "continue": "Fortsett", "close": "Lukk", - "reset_cover": "Tilbakestill Standard Omslag", + "reset_cover": "Tilbakestill Standard Forsidebilde", "remove": "Fjern", "running": "kjører", "submit_stash_box": "Send til Stash-Box", @@ -29,7 +29,7 @@ "save_delete_settings": "Bruk disse alternativene som standard når du sletter", "save_filter": "Lagre filter", "scan": "Skann", - "scrape": "Skrape", + "scrape": "Skrap", "create": "Opprett", "create_chapters": "Opprett Kapittel", "create_marker": "Opprett Markør", @@ -61,22 +61,22 @@ "created_entity": "Opprettet {entity_type}: {entity_name}", "merge_from": "Slå sammen fra", "clean_generated": "Rydd opp i genererte filer", - "clear": "Tøm", + "clear": "Fjern", "clear_back_image": "Fjern bakbilde", "clear_date_data": "Fjern dato data", "clear_image": "Fjern Bilde", "create_parent_studio": "Opprett foreldre studio", "customise": "Tilpass", - "disallow": "Ikke tillat", + "disallow": "Forby", "download_anonymised": "Last ned anonymisert", "export_all": "Eksporter alle…", - "full_export": "Full eksport", - "full_import": "Full Import", + "full_export": "Eksporter alle", + "full_import": "Importer alle", "hash_migration": "hash migrering", "make_primary": "Gjør til Primær", "previous_action": "Tilbake", "refresh": "Oppdater", - "reload": "Last på nytt", + "reload": "Last inn på nytt", "not_running": "Kjører ikke", "open_in_external_player": "Åpne i ekstern spiller", "remove_date": "Fjern dato", @@ -105,9 +105,9 @@ "view_history": "Visningshistorikk", "view_random": "Vis Tilfeldig", "migrate_blobs": "Migrer Blobs", - "migrate_scene_screenshots": "Migrer Scene Skjermbilder", - "reassign": "Omplasser", - "reload_plugins": "Last inn plugins på nytt", + "migrate_scene_screenshots": "Flytt Scene Skjermbilder", + "reassign": "Tilordne på nytt", + "reload_plugins": "Last inn programtillegg på nytt", "reload_scrapers": "Last inn skrapere på nytt", "scrape_scene_fragment": "Skrap etter fragment", "set_back_image": "Baksidebilde…", @@ -119,7 +119,7 @@ "cancel": "Avbryt", "apply": "Bruk", "assign_stashid_to_parent_studio": "Tildel Stash ID til eksisterende foreldre studio og oppdater metadata", - "add_to_entity": "Legg til til {entityType}", + "add_to_entity": "Legg til {entityType}", "add_entity": "Legg til {entityType}", "add_manual_date": "Legg til manuell dato", "add_directory": "Legg til mappe", @@ -138,10 +138,18 @@ "play_selected": "Spill av valgte", "rescan": "Skann på nytt", "reshuffle": "Stokk om", - "rename_gen_files": "Gi nytt navn til genererte filer", - "selective_auto_tag": "Selektiv Automatisk Tagging", + "rename_gen_files": "Gi genererte filer nytt navn", + "selective_auto_tag": "Selektiv Auto Tag", "set_image": "Velg bilde…", - "selective_clean": "Selektiv Rens" + "selective_clean": "Selektiv Fjerning", + "sidebar": { + "close": "lukk sidebar", + "open": "åpne sidebar", + "toggle": "Endre sidepanelet" + }, + "show_results": "Vis resultater", + "show_count_results": "Vis {count} resultater", + "play": "Spill av" }, "component_tagger": { "config": { @@ -175,8 +183,23 @@ "noun_query": "Forespørsel", "results": { "duration_off": "Varighet avviker fra forventet verdi med minst {number}s", - "duration_unknown": "Ukjent varighet" - } + "duration_unknown": "Ukjent varighet", + "phash_matches": "{count} PHash-er stemmer overens", + "unnamed": "Uten navn", + "hash_matches": "{hash_type} stemmer overens", + "match_failed_already_tagged": "Scenen er allerede tagget", + "match_failed_no_result": "Ingen resultater funnet", + "fp_found": "{fpCount, plural, =0 {Ingen nye fingeravtrykksmatch funnet} other {# nye fingeravtrykksmatch funnet}}", + "fp_matches": "Varighet stemmer overens", + "fp_matches_multi": "Varighet samsvarer med {matchCount} av {durationsLength} fingeravtrykk", + "match_success": "Scenen ble tagget vellykket" + }, + "verb_match_fp": "Match Fingeravtrykk", + "verb_matched": "Matchet", + "verb_scrape_all": "Skrap alle", + "verb_submit_fp": "Send inn {fpCount, plural, one{# Fingeravtrykk} andre{# Fingerprints}}", + "verb_toggle_config": "{toggle} {configuration}", + "verb_toggle_unmatched": "{toggle} vis scener uten treff" }, "config": { "dlna": { @@ -192,7 +215,14 @@ "allow_temp_ip": "Tillatt {tempIP}", "allowed_ip_addresses": "Tillatt IP adresser", "server_port": "Serverport", - "server_display_name": "Server Visningsnavn" + "server_display_name": "Server Visningsnavn", + "server_display_name_desc": "Visningsnavn for DLNA-serveren. Standard til {server_navn} hvis tom.", + "server_port_desc": "Port for å kjøre DLNA-serveren på. Krever omstart av DLNA etter endring.", + "until_restart": "frem til omstart", + "network_interfaces_desc": "Grensesnitt for å eksponere DLNA-server på. En tom liste resulterer i å kjøre på alle grensesnitt. Krever omstart av DLNA etter endring.", + "successfully_cancelled_temporary_behaviour": "Vellykket kansellert midlertidig oppførsel", + "video_sort_order_desc": "Rekkefølgen som videoer sorteres etter som standard.", + "video_sort_order": "Standard videosortering" }, "about": { "stash_open_collective": "Støtt oss gjennom {url}", @@ -203,7 +233,10 @@ "check_for_new_version": "Sjekk for ny versjon", "latest_version": "Siste versjon", "latest_version_build_hash": "Siste Versjon Build Hash:", - "build_time": "Kompileringstid:" + "build_time": "Kompileringstid:", + "stash_wiki": "stash {url} side", + "build_hash": "bygg hash:", + "stash_home": "Stash-startside på {url}" }, "advanced_mode": "Avansert Modus", "categories": { @@ -227,18 +260,533 @@ "log_file": "Log-fil", "generate_api_key": "Generer API-nøkkel", "log_to_terminal": "Log til terminal", - "password": "Passord" + "password": "Passord", + "log_http_desc": "Logger HTTP-tilgang til terminalen. Krever omstart.", + "authentication": "Autentisering", + "clear_api_key": "Fjern API-nøkkel", + "credentials": { + "description": "Brukernavn og passord for å sikre tilgang til Stash.", + "heading": "Påloggingsinformasjon" + }, + "log_file_desc": "Sti til filen hvor logg skal lagres. La feltet stå tomt for å deaktivere fillogging. Krever omstart.", + "log_http": "Logg HTTP-tilgang", + "log_to_terminal_desc": "Logger til terminalen i tillegg til en fil. Er alltid aktivert hvis fillogging er deaktivert. Krever omstart.", + "maximum_session_age": "Maksimal levetid for økt", + "maximum_session_age_desc": "Maksimal inaktiv tid før en innloggingsøkt utløper, i sekunder. Krever omstart.", + "password_desc": "Passord for å få tilgang til Stash. La stå tomt for å deaktivere brukergodkjenning", + "stash-box_integration": "ntegrasjon med Stash-box", + "username_desc": "Brukernavn for å få tilgang til Stash. La stå tomt for å deaktivere brukergodkjenning", + "api_key_desc": "API-nøkkel for eksterne systemer. Kun nødvendig når brukernavn/passord er konfigurert. Brukernavn må lagres før API-nøkkel kan genereres." }, "db_path_head": "Database filbane", "ffmpeg": { "download_ffmpeg": { - "heading": "Last ned FFmpeg" + "heading": "Last ned FFmpeg", + "description": "Laster ned FFmpeg til konfigurasjonsmappen og tilbakestiller ffmpeg- og ffprobe-banene til å bruke konfigurasjonsmappen i stedet." }, "hardware_acceleration": { - "heading": "FFmpeg maskinvare encoding" + "heading": "Maskinvareakselerert koding med FFmpeg", + "desc": "Bruker tilgjengelig maskinvare til å kode video for sanntids-transkoding." + }, + "ffmpeg_path": { + "description": "Bane til ffmpeg-programmet (ikke bare mappen). Hvis den er tom, vil ffmpeg bli funnet fra miljøet via $PATH, konfigurasjonsmappen eller fra $HOME/.stash", + "heading": "FFmpeg kjørbar filbane" + }, + "ffprobe_path": { + "heading": "FFmpeg kjørbar filbane", + "description": "Bane til ffprobe-kjørbar fil (ikke bare mappen). Hvis feltet er tomt, vil ffprobe bli hentet fra miljøet via $PATH, konfigurasjonsmappen eller fra $HOME/.stash" + }, + "live_transcode": { + "input_args": { + "heading": "FFmpeg sanntids-transkoding inndata-argumenter", + "desc": "Avansert: Ekstra argumenter som sendes til ffmpeg før inndatafeltet ved sanntids-transkoding av video." + }, + "output_args": { + "heading": "FFmpeg sanntids-transkoding utdata-argumenter", + "desc": "Avansert: Ekstra argumenter som sendes til ffmpeg før utdatafeltet ved sanntids-transkoding av video." + } + }, + "transcode": { + "input_args": { + "desc": "Avansert: Ekstra argumenter som sendes til ffmpeg før inndatafeltet ved generering av video.", + "heading": "FFmpeg transkoding inndata-argumenter" + }, + "output_args": { + "desc": "Avansert: Ekstra argumenter som sendes til ffmpeg før utdatafeltet ved generering av video.", + "heading": "FFmpeg transkoding utdata-argumenter" + } } }, - "database": "Database" + "database": "Database", + "backup_directory_path": { + "heading": "Sti til sikkerhetskopimappe", + "description": "Mappeplassering for sikkerhetskopier av SQLite-databasefilen" + }, + "blobs_storage": { + "description": "Hvor binærdata som scenecovers, bilder av skuespillere, studioer og tagger skal lagres. Etter at denne verdien endres, må eksisterende data migreres ved hjelp av oppgaven “Migrer blobs”. Se oppgavesiden for migrering.", + "heading": "Lagringstype for binærdata" + }, + "blobs_path": { + "description": "Hvor i filsystemet binærdata skal lagres. Gjelder kun når filsystem er valgt som lagringstype for blob-data. ADVARSEL: Endring av dette krever at eksisterende data flyttes manuelt.", + "heading": "Sti for lagring av binærdata" + }, + "cache_path_head": "Sti til hurtigbuffer", + "chrome_cdp_path": "Sti til Chrome CDP", + "cache_location": "Mappeplassering for hurtigbufferen. Påkrevd ved strømming med HLS (f.eks. på Apple-enheter) eller DASH.", + "calculate_md5_and_ohash_desc": "Beregn MD5-sjekksum i tillegg til oshash. Å aktivere dette vil gjøre innledende skanninger tregere. Filnavn-hash må være satt til oshash for å deaktivere MD5-beregning.", + "calculate_md5_and_ohash_label": "Beregn MD5 for videoer", + "check_for_insecure_certificates": "Sjekk etter usikre sertifikater", + "check_for_insecure_certificates_desc": "Noen nettsteder bruker usikre SSL-sertifikater. Når dette er avhuket, hopper skraperen over kontrollen av sertifikater og tillater skraping av slike nettsteder. Hvis du får en sertifikatfeil under skraping, fjern avhukingen her.", + "chrome_cdp_path_desc": "Filsti til Chrome-kjørbar fil, eller en ekstern adresse (som begynner med http:// eller https://, for eksempel http://localhost:9222/json/version) til en Chrome-instans.", + "create_galleries_from_folders_desc": "Hvis aktivert, opprettes gallerier automatisk fra mapper som inneholder bilder. Opprett en fil kalt .forcegallery eller .nogallery i en mappe for å henholdsvis tvinge eller hindre dette.", + "create_galleries_from_folders_label": "Lag gallerier automatisk fra bildemapper", + "directory_locations_to_your_content": "Stier til innholdskataloger", + "excluded_image_gallery_patterns_desc": "Regexps av bilde og galleri filer/filbaner å utelukke fra Scan og legge til Clean", + "excluded_video_patterns_desc": "Regexps av video filer/filbaner å utelukke fra Scan og legge til Clean", + "excluded_image_gallery_patterns_head": "Utelukkede Bilde-/Gallerimønstre", + "excluded_video_patterns_head": "Utelukkede Videomønstre", + "image_ext_head": "Bilde-filendelser", + "plugins_path": { + "description": "Mappestedsplassering for plugin-konfigurasjonsfiler", + "heading": "Plugin-bane" + }, + "scrapers_path": { + "heading": "Scraper-bane", + "description": "Mappestedsplassering for scraper-konfigurasjonsfiler" + }, + "scraping": "Scraping", + "logging": "Logging", + "maximum_transcode_size_head": "Maksimal transkodingsstørrelse", + "funscript_heatmap_draw_range": "Inkluder område i genererte varmekart", + "funscript_heatmap_draw_range_desc": "Tegn bevegelsesområde på y-aksen i det genererte varmekartet. Eksisterende varmekart må genereres på nytt etter endring.", + "generated_file_naming_hash_head": "Hash for generert filnavngivning", + "generated_path_head": "Generert bane", + "maximum_streaming_transcode_size_head": "Maksimal størrelse for strømmingstranskoding", + "maximum_transcode_size_desc": "Maksimal størrelse for genererte transkodinger", + "number_of_parallel_task_for_scan_generation_head": "Antall parallelle oppgaver for skanning/generering", + "scraper_user_agent_desc": "User-Agent-streng som brukes under HTTP-forespørsler for scraping", + "gallery_cover_regex_desc": "Regexp som brukes for å identifisere et bilde som galleriomslag", + "include_audio_desc": "Inkluderer lydstrøm ved generering av forhåndsvisninger.", + "include_audio_head": "Inkluder lyd", + "maximum_streaming_transcode_size_desc": "Maksimal størrelse for transkodede strømmer", + "metadata_path": { + "heading": "Metadatabane", + "description": "Mappestedsplassering som brukes ved full eksport eller import" + }, + "python_path": { + "description": "Bane til Python-kjørbar fil (ikke bare mappen). Brukes for skript-skapere og plugins. Hvis tomt, vil Python bli hentet fra miljøet", + "heading": "Python kjørbar filbane" + }, + "generated_file_naming_hash_desc": "Bruk MD5 eller oshash for generert filnavngivning. Endring av dette krever at alle scener har den aktuelle MD5/oshash-verdien fylt ut. Etter å ha endret denne verdien, må eksisterende genererte filer migreres eller genereres på nytt. Se Oppgaver-siden for migrering.", + "heatmap_generation": "Funscript-varmekartgenerering", + "number_of_parallel_task_for_scan_generation_desc": "Sett til 0 for automatisk deteksjon. Advarsel: Å kjøre flere oppgaver enn nødvendig for å oppnå 100 % CPU-utnyttelse vil redusere ytelsen og kan potensielt forårsake andre problemer.", + "sqlite_location": "Filplassering for SQLite-databasen (krever omstart). ADVARSEL: Å lagre databasen på et annet system enn der Stash-serveren kjører (f.eks. over nettverket) støttes ikke!", + "image_ext_desc": "Kommaseparert liste over filendelser som vil bli identifisert som bilder.", + "parallel_scan_head": "Parallell skanning/generering", + "video_ext_desc": "Kommaseparert liste over filendelser som vil bli identifisert som videoer.", + "gallery_cover_regex_label": "Mønster for galleriomslag", + "gallery_ext_desc": "Kommaseparert liste over filendelser som vil bli identifisert som galleri-zip-filer.", + "gallery_ext_head": "Galleri-zip-filendelser", + "generated_files_location": "Mappestedsplassering for de genererte filene (scene-markører, scene-forhåndsvisninger, sprites, osv.)", + "hashing": "Hashing", + "preview_generation": "Forhåndsvisningsgenerering", + "scraper_user_agent": "Scraper-brukeragent", + "video_ext_head": "Video-filendelser", + "video_head": "Video" + }, + "application_paths": { + "heading": "applikasjon baner" + }, + "tasks": { + "plugin_tasks": "Plugin-oppgaver", + "generate_thumbnails_during_scan": "Generer miniatyrbilder for bilder", + "identify": { + "source": "Kilde", + "tag_skipped_matches": "Tagg hoppet over treff med", + "and_create_missing": "og skape mangler", + "create_missing": "Lag mangler", + "description": "Angi automatisk scenemetadata ved hjelp av stash-box- og scraper-kilder.", + "field": "Felt", + "identifying_scenes": "Identifisering av {num} {scene}", + "include_male_performers": "Inkluder mannlige utøvere", + "set_cover_images": "Sett forsidebilder", + "tag_skipped_performers": "Tagg hoppet over utøvere med", + "default_options": "Standardalternativer", + "set_organized": "Sett organisert flagg", + "identifying_from_paths": "Identifisere scener fra følgende stier", + "tag_skipped_performer_tooltip": "Opprett en tagg som «Identifiser: Enkeltnavnsutøver» som du kan filtrere etter i scenetaggervisningen, og velg hvordan du vil håndtere disse utøverne", + "explicit_set_description": "Følgende alternativer vil bli brukt der de ikke overstyres i de kildespesifikke alternativene.", + "field_behaviour": "{strategi} {felt}", + "field_options": "Feltalternativer", + "heading": "Identifisere", + "skip_multiple_matches": "Hopp over treff som har mer enn ett resultat", + "skip_multiple_matches_tooltip": "Hvis dette ikke er aktivert og mer enn ett resultat returneres, vil ett bli tilfeldig valgt for å matche", + "skip_single_name_performers": "Hopp over utøvere med ett enkelt navn uten entydighet", + "skip_single_name_performers_tooltip": "Hvis dette ikke er aktivert, vil utøvere som ofte er generiske, som Samantha eller Olga, bli matchet", + "source_options": "{kilde} Alternativer", + "sources": "Kilder", + "strategy": "Strategi", + "tag_skipped_matches_tooltip": "Opprett en tagg som «Identifiser: Flere treff» som du kan filtrere etter i Scene Tagger-visningen og velge riktig treff manuelt" + }, + "rescan": "Skann filer på nytt", + "auto_tag": { + "auto_tagging_all_paths": "Automatisk tagging av alle stier", + "auto_tagging_paths": "Automatisk tagging av følgende stier" + }, + "auto_tag_based_on_filenames": "Automatisk tagging av innhold basert på filstier.", + "clean_generated": { + "blob_files": "Blob-filer", + "description": "Fjerner genererte filer uten en tilhørende databaseoppføring.", + "image_thumbnails": "Bildeminiatyrer", + "markers": "Markørforhåndsvisninger", + "previews": "Sceneforhåndsvisninger", + "sprites": "Scenesprites", + "transcodes": "Scenetranskodinger", + "image_thumbnails_desc": "Bildeminiatyrer og klipp", + "previews_desc": "Sceneforhåndsvisninger og miniatyrbilder" + }, + "dont_include_file_extension_as_part_of_the_title": "Ikke inkluder filtypen som en del av tittelen", + "generate_video_previews_during_scan": "Generer forhåndsvisninger", + "generated_content": "Generert innhold", + "import_from_exported_json": "Importer fra eksportert JSON i metadatakatalogen. Sletter den eksisterende databasen.", + "incremental_import": "Trinnvis import fra en levert eksport-zip-fil.", + "job_queue": "Oppgavekø", + "maintenance": "Vedlikehold", + "anonymising_database": "Anonymisering av database", + "backing_up_database": "Sikkerhetskopiering av database", + "generate_video_previews_during_scan_tooltip": "Generer forhåndsvisninger av videoer som spilles av når du holder musepekeren over en scene", + "added_job_to_queue": "La til {operation_name} i jobbkøen", + "anonymise_and_download": "Lager en anonymisert kopi av databasen og laster ned den resulterende filen.", + "anonymise_database": "Lager en kopi av databasen i backup-mappen, og anonymiserer all sensitiv informasjon. Denne kan deretter deles med andre for feilsøking og debugging. Den opprinnelige databasen blir ikke endret. Den anonymiserte databasen bruker filnavnformatet {filename_format}.", + "backup_database": "Utfører en sikkerhetskopi av databasen til backup-mappen, med filnavnformatet {filename_format}", + "cleanup_desc": "Sjekk etter manglende filer og fjern dem fra databasen. Dette er en destruktiv handling.", + "defaults_set": "Standardinnstillinger er satt og vil bli brukt når du klikker på {action}-knappen på Oppgaver-siden.", + "migrate_scene_screenshots": { + "description": "Migrer skjermbilder av scener til det nye blob-lagringssystemet. Denne migreringen bør kjøres etter at et eksisterende system er migrert til 0.20. Kan eventuelt slette de gamle skjermbildene etter migreringen.", + "delete_files": "Slett skjermbildefiler", + "overwrite_existing": "Overskriv eksisterende blobs med skjermbildedata" + }, + "data_management": "Databehandling", + "generate_previews_during_scan_tooltip": "Generer også animerte (webp) forhåndsvisninger, som bare er nødvendig når Forhåndsvisningstype for scene/markørvegg er satt til Animert bilde. Når du surfer, bruker de mindre CPU enn videoforhåndsvisningene, men genereres i tillegg til dem og er større filer.", + "generate_video_covers_during_scan": "Generer sceneomslag", + "optimise_database_warning": "Advarsel: Mens denne oppgaven kjører, vil alle operasjoner som endrer databasen mislykkes, og avhengig av databasestørrelsen kan det ta flere minutter å fullføre. Den krever også minst like mye ledig diskplass som databasen er stor, men 1,5 ganger anbefales.", + "auto_tagging": "Automatisk tagging", + "backup_and_download": "Utfører en sikkerhetskopi av databasen og laster ned den resulterende filen.", + "empty_queue": "Ingen oppgaver kjører for øyeblikket.", + "export_to_json": "Eksporterer databaseinnholdet til JSON-format i metadata-mappen.", + "generate": { + "generating_from_paths": "Genererer for scener fra følgende stier", + "generating_scenes": "Genererer for {num} {scene}" + }, + "generate_clip_previews_during_scan": "Generer forhåndsvisninger for bildeklipp", + "generate_desc": "Generer støttefiler for bilde, sprite, video, vtt og andre filer.", + "generate_phashes_during_scan": "perseptuelle", + "generate_phashes_during_scan_tooltip": "For deduplisering og sceneidentifikasjon.", + "generate_previews_during_scan": "Generer animerte bildeforhåndsvisninger", + "generate_sprites_during_scan": "Generer scrubber-sprites", + "generate_sprites_during_scan_tooltip": "Bildesettet som vises under videospilleren for enkel navigering.", + "migrate_blobs": { + "delete_old": "Slett gamle data", + "description": "Migrer blober til gjeldende blob-lagringssystem. Denne migreringen bør kjøres etter at blob-lagringssystemet er endret. Kan eventuelt slette gamle data etter migrering." + }, + "migrate_hash_files": "Brukes etter endring av den genererte filnavngivningshashen for å gi eksisterende genererte filer nytt navn til det nye hashformatet.", + "migrations": "Migrasjoner", + "only_dry_run": "Utfør kun en prøvekjøring. Ikke fjern noe", + "optimise_database": "Forsøk å forbedre ytelsen ved å analysere og deretter gjenoppbygge hele databasefilen.", + "rescan_tooltip": "Skann alle filer i banen på nytt. Brukes til å tvinge frem oppdatering av filmetadata og skanne zip-filer på nytt.", + "scan": { + "scanning_all_paths": "Skanner alle stier", + "scanning_paths": "Skanner følgende stier" + }, + "scan_for_content_desc": "Skann etter nytt innhold og legg det til i databasen.", + "set_name_date_details_from_metadata_if_present": "Angi navn, dato og detaljer fra innebygde filmetadata" + }, + "ui": { + "scene_player": { + "options": { + "vr_tag": { + "heading": "VR Tag", + "description": "VR-knappen vises bare for scener med denne taggen." + }, + "always_start_from_beginning": "Start alltid videoen fra begynnelsen", + "auto_start_video": "Autostart video", + "auto_start_video_on_play_selected": { + "description": "Start scenevideoer automatisk når du spiller av fra køen, eller spiller av valgte eller tilfeldige scener fra scenesiden", + "heading": "Start video automatisk når den valgte videoen spilles av" + }, + "continue_playlist_default": { + "description": "Spill av neste scene i køen når videoen er ferdig", + "heading": "Fortsett spilleliste som standard" + }, + "disable_mobile_media_auto_rotate": "Deaktiver automatisk rotasjon av fullskjermsmedier på mobil", + "enable_chromecast": "Aktiver Chromecast", + "show_ab_loop_controls": "Vis AB Loop-plugin-kontroller", + "show_scrubber": "Vis Scrubber", + "show_range_markers": "Vis avstandsmarkører", + "track_activity": "Aktiver Scene Play-logg" + }, + "heading": "Scenespiller" + }, + "tag_panel": { + "options": { + "show_child_tagged_content": { + "heading": "Vis subtag-innhold", + "description": "I tag-visningen kan du også vise innhold fra undertaggene" + } + }, + "heading": "Tag-visning" + }, + "editing": { + "heading": "Redigering", + "disable_dropdown_create": { + "heading": "Deaktiver oppretting av rullegardinmenyen", + "description": "Fjern muligheten til å opprette nye objekter fra rullegardinmenyene" + }, + "max_options_shown": { + "label": "Maksimalt antall elementer som skal vises i utvalgte rullegardinmenyer" + }, + "rating_system": { + "star_precision": { + "label": "Rangeringsstjernepresisjon", + "options": { + "full": "Full", + "half": "Halv", + "quarter": "Fjerdedel", + "tenth": "Tiende" + } + }, + "type": { + "label": "Rangeringssystemtype", + "options": { + "decimal": "Desimal", + "stars": "Stjerner" + } + } + } + }, + "interactive_options": "Interaktive alternativer", + "studio_panel": { + "options": { + "show_child_studio_content": { + "heading": "Vis innhold fra understudioer", + "description": "I studiovisningen kan du også vise innhold fra understudioene" + } + }, + "heading": "Studio utsikt" + }, + "abbreviate_counters": { + "heading": "Forkort tellere", + "description": "Forkort tellere i kort- og detaljvisningssider, for eksempel vil «1831» bli formatert til «1,8K»." + }, + "basic_settings": "Grunnleggende innstillinger", + "custom_css": { + "heading": "Egendefinert CSS", + "option_label": "Egendefinert CSS aktivert", + "description": "Siden må lastes inn på nytt for at endringene skal tre i kraft. Det er ingen garanti for kompatibilitet mellom tilpasset CSS og fremtidige utgivelser av Stash." + }, + "custom_javascript": { + "description": "Siden må lastes inn på nytt for at endringene skal tre i kraft. Det er ingen garanti for kompatibilitet mellom tilpasset Javascript og fremtidige versjoner av Stash.", + "heading": "Egendefinert Javascript", + "option_label": "Egendefinert Javascript aktivert" + }, + "custom_locales": { + "heading": "Tilpasset lokalisering", + "option_label": "Egendefinert lokalisering aktivert", + "description": "Overstyr individuelle språkstrenger. Se https://github.com/stashapp/stash/blob/develop/ui/v2.5/src/locales/en-GB.json for hovedlisten. Siden må lastes inn på nytt for at endringene skal tre i kraft." + }, + "delete_options": { + "description": "Standardinnstillinger ved sletting av bilder, gallerier og scener.", + "heading": "Slett alternativer", + "options": { + "delete_file": "Slett fil som standard", + "delete_generated_supporting_files": "Slett genererte støttefiler som standard" + } + }, + "desktop_integration": { + "desktop_integration": "Desktop-integrasjon", + "notifications_enabled": "Aktiver varsler", + "send_desktop_notifications_for_events": "Send skrivebordsvarsler for hendelser", + "skip_opening_browser": "Hopp over å åpne nettleseren", + "skip_opening_browser_on_startup": "Hopp over automatisk åpning av nettleser under oppstart" + }, + "detail": { + "compact_expanded_details": { + "heading": "Kompakte utvidede detaljer", + "description": "Når dette alternativet er aktivert, vil det presentere utvidede detaljer samtidig som presentasjonen blir kompakt" + }, + "enable_background_image": { + "description": "Vis bakgrunnsbilde på detaljsiden.", + "heading": "Aktiver bakgrunnsbilde" + }, + "heading": "Detaljside", + "show_all_details": { + "description": "Når den er aktivert, vises alle innholdsdetaljer som standard, og hvert detaljelement får plass under én kolonne", + "heading": "Vis alle detaljer" + } + }, + "funscript_offset": { + "heading": "Funksjonsskriptforskyvning (ms)", + "description": "Tidsforskyvning i millisekunder for avspilling av interaktive skript." + }, + "handy_connection": { + "connect": "Koble til", + "server_offset": { + "heading": "Serveroffset" + }, + "status": { + "heading": "Praktisk tilkoblingsstatus" + }, + "sync": "Synkroniser" + }, + "handy_connection_key": { + "heading": "Handy tilkoblingsnøkkel", + "description": "Praktisk tilkoblingsnøkkel for bruk for interaktive scener. Hvis du angir denne knappen, kan Stash dele informasjon om gjeldende scene med handyfeeling.com" + }, + "image_lightbox": { + "heading": "Bilde lysboks" + }, + "image_wall": { + "direction": "Retning", + "heading": "Bildevegg", + "margin": "Margin (piksler)" + }, + "images": { + "heading": "Bilder", + "options": { + "create_image_clips_from_videos": { + "description": "Når et bibliotek har deaktivert videoer, vil videofiler (filer som slutter på videoendelsen) skannes som bildeklipp.", + "heading": "Skann videoutvidelser som bildeklipp" + }, + "write_image_thumbnails": { + "heading": "Skriv miniatyrbilder", + "description": "Skriv miniatyrbilder av bilder til disk når de genereres på farten" + } + } + }, + "language": { + "heading": "Språk" + }, + "max_loop_duration": { + "description": "Maksimal scenevarighet der scenespilleren vil spille av videoen i loop - 0 for å deaktivere", + "heading": "Maksimal sløyfevarighet" + }, + "menu_items": { + "heading": "Menyelementer", + "description": "Vis eller skjul ulike typer innhold på navigasjonslinjen" + }, + "minimum_play_percent": { + "description": "Prosentandelen av tiden en scene må spilles av før avspillingstallene økes.", + "heading": "Minimum Spilleprosent" + }, + "performers": { + "options": { + "image_location": { + "heading": "Tilpasset utøverbildebane", + "description": "Tilpasset sti for standard utøverbilder. La stå tomt for å bruke innebygde standardinnstillinger" + } + } + }, + "preview_type": { + "heading": "Forhåndsvisningstype", + "options": { + "animated": "Animert bilde", + "static": "Statisk bilde", + "video": "Video" + }, + "description": "Standardalternativet er forhåndsvisninger av videoer (mp4). For mindre CPU-bruk når du surfer, kan du bruke forhåndsvisninger av animerte bilder (webp). Disse må imidlertid genereres i tillegg til forhåndsvisningene av videoer, og de er større filer." + }, + "scene_list": { + "heading": "Rutenettvisning", + "options": { + "show_studio_as_text": "Vis studiooverlegg som tekst" + } + }, + "scene_wall": { + "heading": "Scene-/markørvegg", + "options": { + "toggle_sound": "Aktiver lyd", + "display_title": "Vis tittel og tagger" + } + }, + "scroll_attempts_before_change": { + "heading": "Rullforsøk før overgang", + "description": "Antall forsøk på å bla før man går til neste/forrige element. Gjelder kun for Pan Y-rullemodus." + }, + "show_tag_card_on_hover": { + "description": "Vis tagkort når du holder musepekeren over tag-merkene", + "heading": "Verktøytips for tagkort" + }, + "slideshow_delay": { + "description": "Lysbildefremvisning er tilgjengelig i gallerier i veggvisningsmodus", + "heading": "Forsinkelse av lysbildefremvisning (sekunder)" + }, + "title": "Brukergrensesnitt", + "use_stash_hosted_funscript": { + "heading": "Server funscripts direkte", + "description": "Når dette er aktivert, vil funscripts bli servert direkte fra Stash til Handy-enheten din uten å bruke tredjeparts Handy-serveren. Krever at Stash er tilgjengelig fra Handy-enheten din, og at en API-nøkkel genereres hvis stash har konfigurert legitimasjon." + } + }, + "scraping": { + "available_scrapers": "Tilgjengelige scrapers", + "search_by_name": "Søk etter navn", + "supported_types": "Støttede typer", + "installed_scrapers": "Installerte scrapers", + "scraper": "Skraper", + "entity_scrapers": "{entityType} scrapers", + "excluded_tag_patterns_desc": "Regulære uttrykk for tag-navn som skal ekskluderes fra scraperesultater", + "scrapers": "Skrapere", + "entity_metadata": "{entityType} Metadata", + "excluded_tag_patterns_head": "Ekskluderte tag-mønstre", + "supported_urls": "URLs" + }, + "plugins": { + "installed_plugins": "Installerte plugins", + "hooks": "Hooks", + "triggers_on": "Utløsere aktivert", + "available_plugins": "Tilgjengelige plugins" + }, + "library": { + "media_content_extensions": "Filendelser for medieinnhold", + "gallery_and_image_options": "Galleri- og bildeinnstillinger", + "exclusions": "Eksklusjoner" + }, + "tools": { + "scene_duplicate_checker": "Sceneduplikatkontrollør", + "scene_filename_parser": { + "add_field": "Legg til felt", + "capitalize_title": "Bruk stor bokstav i tittelen", + "display_fields": "Vis felt", + "escape_chars": "Bruk \\ for å escape-tegn", + "filename": "Filnavn", + "ignore_organized": "Ignorer organiserte scener", + "ignored_words": "Ignorerte ord", + "matches_with": "Samsvarer med {i}", + "select_parser_recipe": "Velg parseroppskrift", + "title": "Scenefilnavnparser", + "whitespace_chars_desc": "Disse tegnene vil bli erstattet med mellomrom i tittelen", + "filename_pattern": "Filnavnmønster", + "whitespace_chars": "Mellomromstegn" + }, + "graphql_playground": "GraphQL lekeplass", + "heading": "Verktøy", + "scene_tools": "Sceneverktøy" + }, + "stashbox": { + "endpoint": "Endepunkt", + "description": "Stash-box muliggjør automatisk tagging av scener og utøvere basert på fingeravtrykk og filnavn.\nEndepunkt og API-nøkkel finnes på kontosiden din på Stash-box-instansen. Navn kreves når mer enn én instans legges til.", + "graphql_endpoint": "GraphQL-endepunkt", + "name": "Navn", + "add_instance": "Legg til Stash-box-instans", + "api_key": "API-nøkkel", + "max_requests_per_minute": "Maks forespørsler per minutt", + "max_requests_per_minute_description": "Bruker standardverdi på {defaultValue} hvis satt til 0", + "title": "Stash-box-endepunkter" + }, + "logs": { + "log_level": "Loggnivå" + }, + "system": { + "transcoding": "Transkoding" } }, "appears_with": "Opptrer med", @@ -265,5 +813,735 @@ "UNCUT": "Ikke omskåret" }, "birth_year": "Fødselsår", - "all": "alle" + "all": "alt", + "media_info": { + "performer_card": { + "age": "{alder} {år_gammel}", + "age_context": "{age} {years_old} ved produksjon" + }, + "video_codec": "Video Kodek", + "audio_codec": "Lydkodek", + "checksum": "Sjekksum", + "downloaded_from": "Lastet ned fra", + "hash": "Hash", + "interactive_speed": "Interaktiv hastighet", + "o_count": "0 Antall", + "phash": "PHash", + "play_count": "Avspilt", + "play_duration": "Spillevarighet", + "stream": "Strøm" + }, + "age_on_date": "{age} ved produksjon", + "search_filter": { + "update_filter": "Oppdater Filtre", + "saved_filters": "Lagrede filter", + "edit_filter": "Rediger filter", + "name": "Filter", + "more_filter_criteria": "+{tell} flere" + }, + "history": "Historie", + "play_count": "Antall Avspillinger", + "play_history": "Avspillinger", + "release_notes": "Utgivelsesnotater", + "scene": "Scene", + "path": "Sti", + "package_manager": { + "installed_version": "Installert versjon", + "required_by": "Kreves av {pakker}", + "add_source": "Legg til kilde", + "check_for_updates": "Se etter oppdateringer", + "confirm_delete_source": "Er du sikker på at du vil slette kilden {name} ({url})?", + "description": "Beskrivelse", + "edit_source": "Rediger Kilde", + "hide_unselected": "Skjul uvalgt", + "latest_version": "Siste versjon", + "no_packages": "Ingen pakker funnet", + "no_sources": "Ingen kilder er konfigurert", + "no_upgradable": "Ingen oppgraderbare pakker funnet", + "package": "Pakke", + "selected_only": "Kun valgte", + "show_all": "Vis alle", + "source": { + "local_path": { + "heading": "Lokal Sti", + "description": "Relativ sti til lagringspakker for denne kilden. Merk at endring av dette krever at pakkene flyttes manuelt." + }, + "name": "Navn", + "url": "Kilde URL" + }, + "uninstall": "Avinstallere", + "unknown": "", + "update": "Oppdatere", + "version": "Versjon", + "install": "Installere", + "confirm_uninstall": "Er du sikker på at du vil avinstallere {number} pakker?" + }, + "rating": "Vurdering", + "queue": "Kø", + "studio_tagger": { + "status_tagging_job_queued": "Status: Taggejobb i kø", + "batch_update_studios": "Batch Oppdater Studio", + "failed_to_save_studio": "Kunne ikke lagre studioet «{studio}»", + "add_new_studios": "Legg til nye studioer", + "batch_add_studios": "Batch Legg Til Studio", + "config": { + "edit_excluded_fields": "Rediger ekskluderte felt", + "excluded_fields": "Ekskluderte felt:", + "no_fields_are_excluded": "Ingen felt er ekskludert", + "no_instances_found": "Ingen forekomster funnet", + "these_fields_will_not_be_changed_when_updating_studios": "Disse feltene vil ikke bli endret når du oppdaterer studioer.", + "active_stash-box_instance": "Aktiv stash-box-instans:", + "create_parent_label": "Lag foreldrestudioer", + "create_parent_desc": "Opprett manglende foreldrestudioer, eller tagg og oppdater data/bilde for eksisterende foreldrestudioer med nøyaktige navnesamsvar" + }, + "create_or_tag_parent_studios": "Opprett manglende eller tagg eksisterende foreldrestudioer", + "current_page": "Gjeldende side", + "name_already_exists": "Navnet finnes allerede", + "network_error": "Nettverksfeil", + "no_results_found": "Ingen resultater funnet.", + "number_of_studios_will_be_processed": "{studio_count} studioer vil bli behandlet", + "query_all_studios_in_the_database": "Alle studioer i databasen", + "refreshing_will_update_the_data": "Oppdatering vil oppdatere dataene til alle taggede studioer fra stash-box-instansen.", + "studio_already_tagged": "Studio allerede merket", + "studio_names_separated_by_comma": "Studionavn atskilt med komma", + "studio_selection": "Studio utvalg", + "studio_successfully_tagged": "Studio er tagget", + "any_names_entered_will_be_queried": "Alle navn som legges inn vil bli spørt fra den eksterne Stash-Box-instansen og lagt til hvis de blir funnet. Bare eksakte treff vil bli ansett som treff.", + "refresh_tagged_studios": "Oppdater taggede studioer", + "status_tagging_studios": "Status: Merking av studioer", + "tag_status": "Tag status", + "to_use_the_studio_tagger": "For å bruke studio-taggeren må en stash-box-instans konfigureres.", + "untagged_studios": "Umerkede studioer", + "update_studio": "Oppdater Studio", + "update_studios": "Oppdater Studio", + "updating_untagged_studios_description": "Oppdatering av utaggede studioer vil prøve å matche alle studioer som mangler en stashid og oppdatere metadataene." + }, + "effect_filters": { + "blue": "Blå", + "name_transforms": "Forvandles", + "red": "Rød", + "aspect": "Aspekt", + "blur": "Uskarphet", + "brightness": "Lysstyrke", + "contrast": "Kontrast", + "gamma": "Gamma", + "green": "Grønn", + "hue": "Hue", + "rotate": "Rotere", + "rotate_left_and_scale": "Roter til venstre og skaler", + "rotate_right_and_scale": "Roter til høyre og skaler", + "saturation": "Metning", + "scale": "Skala", + "warmth": "Varme", + "reset_filters": "Tilbakestill filtre", + "reset_transforms": "Tilbakestill Transforms", + "name": "Filtre" + }, + "megabits_per_second": "{verdi} mbps", + "stats": { + "scenes_duration": "Varighet av scener", + "image_size": "Bildestørrelse", + "total_o_count": "Total O-telling", + "scenes_played": "Scener spilt", + "scenes_size": "Scenestørrelse", + "total_play_count": "Totale Avspillinger", + "total_play_duration": "Total Spilletid" + }, + "studio_depth": "Nivåer (tomt for alle)", + "custom_fields": { + "title": "Egendefinerte felt", + "criteria_format_string": "{kriterium} (egendefinert felt) {modifierString} {valueString}", + "value": "Verdi", + "criteria_format_string_others": "{kriterium} (egendefinert felt) {modifierString} {valueString} (+{andre} andre)", + "field": "Felt" + }, + "dialogs": { + "scene_gen": { + "marker_screenshots": "Marker skjermbilder", + "video_previews": "Forhåndsvisninger", + "video_previews_tooltip": "Videoforhåndsvisninger som spilles av når du holder musepekeren over en scene", + "covers": "Scenebilder", + "image_previews": "Forhåndsvisninger av animerte bilder", + "image_previews_tooltip": "Generer også animerte (webp) forhåndsvisninger, som bare er nødvendig når Forhåndsvisningstype for scene/markørvegg er satt til Animert bilde. Når du surfer, bruker de mindre CPU enn videoforhåndsvisningene, men genereres i tillegg til dem og er større filer.", + "image_thumbnails": "Miniatyrbilder", + "interactive_heatmap_speed": "Generer varmekart og hastigheter for interaktive scener", + "marker_image_previews": "Forhåndsvisning av animerte bilder for markører", + "marker_screenshots_tooltip": "Marker statiske JPG-bilder", + "markers": "Marker forhåndsvisning", + "markers_tooltip": "20 sekunders videoer som starter på den gitte tidskoden.", + "override_preview_generation_options": "Overstyr forhåndsvisningsgenereringsalternativer", + "override_preview_generation_options_desc": "Overstyr forhåndsvisningsgenereringsalternativer for denne operasjonen. Standardverdier angis i System -> Forhåndsvisningsgenerering.", + "overwrite": "Overskriv eksisterende filer", + "phash": "Perseptuelle hasher", + "phash_tooltip": "For deduplisering og sceneidentifikasjon", + "preview_exclude_end_time_head": "Ekskluder sluttid", + "preview_exclude_start_time_desc": "Ekskluder de første x sekundene fra sceneforhåndsvisninger. Dette kan være en verdi i sekunder, eller en prosentandel (f.eks. 2 %) av den totale scenevarigheten.", + "preview_exclude_start_time_head": "Ekskluder starttidspunkt", + "preview_generation_options": "Forhåndsvisningsgenereringsalternativer", + "preview_options": "Forhåndsvisningsalternativer", + "preview_preset_head": "Forhåndsinnstilling av koding", + "preview_seg_count_desc": "Antall segmenter i forhåndsvisningsfiler.", + "preview_seg_count_head": "Antall segmenter i forhåndsvisning", + "preview_seg_duration_desc": "Varigheten av hvert forhåndsvisningssegment, i sekunder.", + "preview_seg_duration_head": "Forhåndsvis segmentets varighet", + "sprites": "Scene Scrubber Sprites", + "sprites_tooltip": "Bildesettet som vises under videospilleren for enkel navigering.", + "transcodes": "Transkoder", + "force_transcodes": "Tving generering av transkode", + "marker_image_previews_tooltip": "Generer også animerte (webp) forhåndsvisninger, som bare er nødvendig når Forhåndsvisningstype for scene/markørvegg er satt til Animert bilde. Når du surfer, bruker de mindre CPU enn videoforhåndsvisningene, men genereres i tillegg til dem og er større filer.", + "force_transcodes_tooltip": "Som standard genereres transkoder bare når videofilen ikke støttes i nettleseren. Når dette er aktivert, genereres transkoder selv om videofilen ser ut til å være støttet i nettleseren.", + "preview_preset_desc": "Forhåndsinnstillingen regulerer størrelse, kvalitet og kodingstid for forhåndsvisningsgenerering. Forhåndsinnstillinger utover «treg» har avtagende avkastning og anbefales ikke.", + "preview_exclude_end_time_desc": "Ekskluder de siste x sekundene fra sceneforhåndsvisninger. Dette kan være en verdi i sekunder, eller en prosentandel (f.eks. 2 %) av den totale scenevarigheten.", + "clip_previews": "Forhåndsvisninger av bildeklipp", + "transcodes_tooltip": "MP4-transkoder vil bli forhåndsgenerert for alt innhold; nyttig for trege CPU-er, men krever mye mer diskplass" + }, + "scenes_found": "{count} scener funnet", + "scrape_results_scraped": "Skrapet", + "set_image_url_title": "Bilde-URL", + "lightbox": { + "scroll_mode": { + "label": "Rullemodus", + "pan_y": "Pan Y", + "zoom": "Zoom", + "description": "Hold Shift-tasten nede for å midlertidig bruke en annen modus." + }, + "delay": "Forsinkelse (sek)", + "display_mode": { + "fit_to_screen": "Tilpass til skjermen", + "label": "Visningsmodus", + "original": "Orginalt", + "fit_horizontally": "Passer horisontalt" + }, + "options": "Alternativer", + "reset_zoom_on_nav": "Tilbakestill zoomnivå når du bytter bilde", + "scale_up": { + "description": "Skaler mindre bilder opp for å fylle skjermen", + "label": "Skaler opp for å passe" + }, + "page_header": "Side {side} / {totalt}" + }, + "merge": { + "empty_results": "Verdiene i destinasjonsfeltet vil forbli uendret.", + "destination": "Destinasjon", + "source": "Kilde" + }, + "imagewall": { + "margin_desc": "Antall margpiksler rundt hvert bilde.", + "direction": { + "column": "Kolonne", + "description": "Kolonne- eller radbasert oppsett.", + "row": "Rad" + } + }, + "delete_confirm": "Er du sikker på at du vil slette {entityName}?", + "clear_o_history_confirm": "Er du sikker på at du vil slette O-historikken?", + "clear_play_history_confirm": "Er du sikker på at du vil slette avspillingshistorikken?", + "create_new_entity": "Opprett ny {entity}", + "delete_entity_simple_desc": "{count, plural, one {Er du sikker på at du vil slette denne {singularEntity}?} other {Er du sikker på at du vil slette disse {pluralEntity}?}}", + "delete_entity_title": "{antall, flertall, én {Slett {entallEntitet}} annet {Slett {flertallEntitet}}}", + "delete_galleries_extra": "... pluss eventuelle bildefiler som ikke er knyttet til noe annet galleri.", + "delete_object_desc": "Er du sikker på at du vil slette {count, plural, one {this {singularEntity}} other {these {pluralEntity}}}?", + "delete_object_overflow": "…og {count} other {count, flertall, one {{singularEntity}} other {{pluralEntity}}}.", + "delete_object_title": "Slett {count, flertall, én {{singularEntity}} annen {{pluralEntity}}}", + "dont_show_until_updated": "Ikke vis før neste oppdatering", + "export_include_related_objects": "Inkluder relaterte objekter i eksporten", + "export_title": "Eksport", + "merge_tags": { + "destination": "Destinasjon", + "source": "Kilde" + }, + "performers_found": "{count} utøvere funnet", + "reassign_entity_title": "{antall, flertall, én {Reassign {singularEntity}} annen {Reassign {pluralEntity}}}", + "reassign_files": { + "destination": "Tilordne på nytt til" + }, + "scrape_entity_query": "Skrapeforespørsel fra {entity_type}", + "scrape_entity_title": "{entity_type} Skrape Resultater", + "scrape_results_existing": "Eksisterende", + "delete_entity_desc": "{count, plural, one {Er du sikker på at du vil slette denne {singularEntity}? Med mindre filen også slettes, vil denne {singularEntity} bli lagt til på nytt når skanningen utføres.} other {Er du sikker på at du vil slette disse {pluralEntity}? Med mindre filene også slettes, vil disse {pluralEntity} bli lagt til på nytt når skanningen utføres.}}", + "delete_gallery_files": "Slett gallerimappen/zip-filen og alle bilder som ikke er knyttet til noe annet galleri.", + "edit_entity_title": "Rediger {count, flertall, én {{singularEntity}} annen {{pluralEntity}}}", + "delete_alert": "Følgende {count, plural, one {{singularEntity}} other {{pluralEntity}}} vil bli slettet permanent:", + "overwrite_filter_warning": "Det lagrede filteret «{entityName}» vil bli overskrevet.", + "unsaved_changes": "Ulagrede endringer. Er du sikker på at du vil avslutte?", + "set_default_filter_confirm": "Er du sikker på at du vil angi dette filteret som standard?" + }, + "director": "Regissør", + "display_mode": { + "unknown": "Ukjent", + "wall": "Vegg", + "tagger": "Tagger", + "list": "Liste", + "label_current": "Visningsmodus: {gjeldende}", + "grid": "Rutenett" + }, + "distance": "Lengde", + "dupe_check": { + "only_select_matching_codecs": "Velg bare hvis alle kodeker samsvarer i duplikatgruppen", + "options": { + "exact": "Nøyaktig", + "high": "Høy", + "low": "Lav", + "medium": "Medium" + }, + "search_accuracy_label": "Søkenøyaktighet", + "duration_diff": "Maksimal varighetsforskjell", + "duration_options": { + "equal": "Lik", + "any": "Noen" + }, + "select_none": "Velg Ingen", + "select_oldest": "Velg den eldste filen i duplikatgruppen", + "select_options": "Velg Alternativer…", + "select_youngest": "Velg den yngste filen i duplikatgruppen", + "title": "Dupliserte scener", + "description": "Nivåer under «Nøyaktig» kan ta lengre tid å beregne. Falske positive resultater kan også returneres ved lavere nøyaktighetsnivåer.", + "found_sets": "{setCount, flertall, one{# sett med duplikater funnet.} other {# sett med duplikater funnet.}}", + "select_all_but_largest_file": "Velg alle filer i hver dupliserte gruppe, unntatt den største filen", + "select_all_but_largest_resolution": "Velg alle filer i hver dupliserte gruppe, unntatt filen med høyest oppløsning" + }, + "duplicated_phash": "Duplisert (pHash)", + "errors": { + "invalid_javascript_string": "Ugyldig javascript-kode: {error}", + "custom_fields": { + "duplicate_field": "Feltnavnet må være unikt", + "field_name_length": "Feltnavnet må inneholde færre enn 65 tegn", + "field_name_required": "Feltnavn er obligatorisk", + "field_name_whitespace": "Feltnavnet kan ikke ha innledende eller etterfølgende mellomrom" + }, + "header": "Feil", + "invalid_json_string": "Ugyldig JSON-streng: {error}", + "loading_type": "Feil ved lasting av {type}", + "something_went_wrong": "Noe gikk galt.", + "image_index_greater_than_zero": "Bildeindeksen må være større enn 0", + "lazy_component_error_help": "Hvis du nylig har oppgradert Stash, må du laste inn siden på nytt eller tømme nettleserens hurtigbuffer." + }, + "file_info": "Filinformasjon", + "group_scene_number": "Scenenummer", + "groups": "Grupper", + "image_index": "Bilde #", + "last_o_at": "Siste O Kl", + "library": "Bibliotek", + "penis": "Penis", + "part_of": "En del av {forelder}", + "performer_tagger": { + "batch_update_performers": "Batch Oppdater Skuespillere", + "config": { + "active_stash-box_instance": "Aktiv stash-box-instans:", + "edit_excluded_fields": "Rediger Ekskluderte Felt", + "no_fields_are_excluded": "Ingen felt er ekskludert", + "no_instances_found": "Ingen forekomster funnet", + "excluded_fields": "Ekskluderte felt:", + "these_fields_will_not_be_changed_when_updating_performers": "Disse feltene vil ikke bli endret når skuespillerne oppdateres." + }, + "network_error": "Nettverksfeil", + "performer_already_tagged": "Skuespilleren er allerede tagget", + "number_of_performers_will_be_processed": "{skuespiller_antall} skuespillere vil bli behandlet", + "performer_names_separated_by_comma": "Skuespillernavn atskilt med komma", + "batch_add_performers": "Batch Legg Til Skuespillere", + "current_page": "Gjeldende side", + "failed_to_save_performer": "Kunne ikke lagre skuespillere «{skuespiller}»", + "name_already_exists": "Navnet finnes allerede", + "no_results_found": "Ingen resultater funnet.", + "performer_selection": "Utvalg av skuespillere", + "performer_successfully_tagged": "Skuespiller er tagget:", + "query_all_performers_in_the_database": "Alle skuespillere i databasen", + "refresh_tagged_performers": "Oppdater taggede skuespillere", + "status_tagging_job_queued": "Status: Taggejobb i kø", + "status_tagging_performers": "Status: Tagger skuespillere", + "tag_status": "Tagging Status", + "to_use_the_performer_tagger": "For å bruke skuespiller-taggeren må en stash-box-instans konfigureres.", + "untagged_performers": "Utaggede skuespillere", + "update_performer": "Oppdater Skuespiller", + "update_performers": "Oppdater Skuespillere", + "add_new_performers": "Legg til ny skuespiller", + "updating_untagged_performers_description": "Oppdatering av utaggede skuespillere vil forsøke å matche skuespillere som mangler en stashid og oppdatere metadataene.", + "refreshing_will_update_the_data": "Oppdatering vil oppdatere dataene til alle taggede skuespillere fra stash-box-instansen.", + "any_names_entered_will_be_queried": "Alle navn som legges inn vil bli spørt fra den eksterne Stash-Box-instansen og lagt til hvis de blir funnet. Bare eksakte treff vil bli ansett som treff." + }, + "setup": { + "welcome_specific_config": { + "next_step": "Når du er klar til å fortsette med å sette opp et nytt system, klikker du på Neste.", + "config_path": "Stash vil bruke følgende konfigurasjonsfilsti: {path}", + "unable_to_locate_specified_config": "Hvis du leser dette, fant ikke Stash konfigurasjonsfilen som er angitt på kommandolinjen eller i miljøet. Denne veiviseren vil veilede deg gjennom prosessen med å sette opp en ny konfigurasjon." + }, + "paths": { + "set_up_your_paths": "Sett opp dine veier", + "database_filename_empty_for_default": "databasefilnavn (tomt for standard)", + "description": "Deretter må vi finne ut hvor du finner pornosamlingen din, og hvor du skal lagre Stash-databasen, genererte filer og hurtigbufferfiler. Disse innstillingene kan endres senere om nødvendig.", + "path_to_generated_directory_empty_for_default": "sti til generert katalog (tom som standard)", + "stash_alert": "Ingen bibliotekstier er valgt. Ingen medier kan skannes inn i Stash. Er du sikker?", + "store_blobs_in_database": "Lagre blober i databasen", + "where_can_stash_store_blobs": "Hvor kan Stash lagre binære databasedata?", + "where_can_stash_store_blobs_description_addendum": "Alternativt kan du lagre disse dataene i databasen. Merk: Dette vil øke størrelsen på databasefilen din, og det vil øke migreringstiden for databasen.", + "where_can_stash_store_cache_files": "Hvor kan Stash lagre hurtigbufferfiler?", + "where_can_stash_store_its_database_description": "Stash bruker en SQLite-database for å lagre pornometadataene dine. Som standard opprettes dette som stash-go.sqlite i katalogen som inneholder konfigurasjonsfilen din. Hvis du vil endre dette, må du skrive inn et absolutt eller relativt (til gjeldende arbeidskatalog) filnavn.", + "where_can_stash_store_its_database_warning": "ADVARSEL: lagring av databasen på et annet system enn der Stash kjøres fra (f.eks. lagring av databasen på en NAS mens Stash-serveren kjøres på en annen datamaskin) er ikke støttet! SQLite er ikke ment for bruk på tvers av et nettverk, og forsøk på å gjøre det kan lett føre til at hele databasen blir ødelagt.", + "where_can_stash_store_its_generated_content": "Hvor kan Stash lagre det genererte innholdet?", + "where_is_your_porn_located": "Hvor ligger pornoen din?", + "where_is_your_porn_located_description": "Legg til kataloger som inneholder pornovideoene og bildene dine. Stash vil bruke disse katalogene til å finne videoer og bilder under skanning.", + "path_to_blobs_directory_empty_for_default": "sti til blobs-katalogen (tom som standard)", + "where_can_stash_store_its_database": "Hvor kan Stash lagre databasen sin?", + "where_can_stash_store_cache_files_description": "For at funksjonalitet som HLS/DASH live-transkoding skal fungere, krever Stash en hurtigbufferkatalog for midlertidige filer. Som standard oppretter Stash en cache-katalog i katalogen som inneholder konfigurasjonsfilen din. Hvis du vil endre dette, må du angi en absolutt eller relativ (til gjeldende arbeidskatalog) sti. Stash oppretter denne katalogen hvis den ikke allerede finnes.", + "where_can_stash_store_its_generated_content_description": "For å kunne tilby miniatyrbilder, forhåndsvisninger og sprites genererer Stash bilder og videoer. Dette inkluderer også transkoder for filformater som ikke støttes. Som standard vil Stash opprette en generert katalog i katalogen som inneholder konfigurasjonsfilen din. Hvis du vil endre hvor dette genererte mediet skal lagres, må du angi en absolutt eller relativ (til gjeldende arbeidskatalog) sti. Stash vil opprette denne katalogen hvis den ikke allerede finnes.", + "path_to_cache_directory_empty_for_default": "sti til hurtigbufferkatalog (tom som standard)", + "where_can_stash_store_blobs_description": "Stash kan lagre binære data som scenecovere, utøver, studio og tag-bilder enten i databasen eller i filsystemet. Som standard lagrer den disse dataene i filsystemet i underkatalogen blobs i katalogen som inneholder konfigurasjonsfilen din. Hvis du vil endre dette, må du angi en absolutt eller relativ (til gjeldende arbeidskatalog) sti. Stash vil opprette denne katalogen hvis den ikke allerede finnes." + }, + "creating": { + "creating_your_system": "Oppretter systemet ditt" + }, + "errors": { + "something_went_wrong_while_setting_up_your_system": "Noe gikk galt under oppsettet av systemet ditt. Her er feilen vi mottok: {feil}", + "unable_to_retrieve_system_status": "Kan ikke hente systemstatus: {feil}", + "something_went_wrong": "Å nei! Noe gikk galt!", + "unexpected_error": "Det oppsto en uventet feil: {feil}", + "something_went_wrong_description": "Hvis dette ser ut som et problem med inndataene dine, kan du klikke tilbake for å fikse dem. Ellers kan du rapportere en feil på {githubLink} eller søke hjelp på {discordLink}." + }, + "folder": { + "file_path": "Filbane", + "up_dir": "Opp en mappe" + }, + "github_repository": "Github-depot", + "migrate": { + "migration_failed": "Migrering mislyktes", + "migration_irreversible_warning": "Skjemamigreringsprosessen er ikke reversibel. Når migreringen er utført, vil databasen din være inkompatibel med tidligere versjoner av stash.", + "migration_notes": "Migrasjonsnotater", + "migration_required": "Migrering kreves", + "perform_schema_migration": "Utfør skjemamigrering", + "backup_database_path_leave_empty_to_disable_backup": "Sti til sikkerhetskopieringsdatabase (la stå tomt for å deaktivere sikkerhetskopiering):", + "migration_failed_error": "Følgende feil oppsto under migrering av databasen:", + "schema_too_old": "Din nåværende stash-database er skjemaversjon {databaseSchema} og må migreres til versjon {appSchema}. Denne versjonen av Stash vil ikke fungere uten at databasen migreres. Hvis du ikke ønsker å migrere, må du nedgradere til en versjon som samsvarer med databaseskjemaet ditt.", + "backup_recommended": "Det anbefales at du sikkerhetskopierer den eksisterende databasen din før du migrerer. Vi kan gjøre dette for deg ved å lage en kopi av databasen din til {defaultBackupPath}.", + "migrating_database": "Migrerer database", + "migration_failed_help": "Gjør nødvendige rettelser og prøv på nytt. Ellers kan du melde fra om en feil på {githubLink} eller søke hjelp på {discordLink}." + }, + "confirm": { + "almost_ready": "Vi er nesten klare til å fullføre konfigurasjonen. Vennligst bekreft følgende innstillinger. Du kan klikke tilbake for å endre noe som er feil. Hvis alt ser bra ut, klikker du på Bekreft for å opprette systemet ditt.", + "blobs_directory": "Binær datakatalog", + "blobs_use_database": "", + "cache_directory": "Cache-katalog", + "configuration_file_location": "konfigurasjonsfilplassering:", + "database_file_path": "Banen til databasefilen", + "generated_directory": "Generert katalog", + "nearly_there": "Nesten der!", + "stash_library_directories": "Stash bibliotekkataloger" + }, + "stash_setup_wizard": "Stash Setup Wizard", + "success": { + "download_ffmpeg": "Last ned ffmpeg", + "getting_help": "Får hjelp", + "help_links": "Hvis du støter på problemer eller har spørsmål eller forslag, kan du gjerne åpne en sak i {githubLink} eller spørre fellesskapet i {discordLink}.", + "next_config_step_one": "Du blir deretter tatt til konfigurasjonssiden. Denne siden lar deg tilpasse hvilke filer som skal inkluderes og ekskluderes, angi et brukernavn og passord for å beskytte systemet ditt, og en hel rekke andre alternativer.", + "next_config_step_two": "Når du er fornøyd med disse innstillingene, kan du begynne å skanne innholdet ditt inn i Stash ved å klikke på {localized_task}, deretter {localized_scan}.", + "open_collective": "Sjekk ut vår {open_collective_link} for å se hvordan du kan bidra til den fortsatte utviklingen av Stash.", + "support_us": "Støtt oss", + "thanks_for_trying_stash": "Takk for at du prøvde Stash!", + "your_system_has_been_created": "Suksess! Systemet ditt er opprettet!", + "in_app_manual_explained": "Du oppfordres til å sjekke ut manualen i appen, som du finner via ikonet øverst til høyre på skjermen. Det ser slik ut: {icon}", + "missing_ffmpeg": "Du mangler den nødvendige ffmpeg-binærfilen. Du kan laste den ned automatisk til konfigurasjonskatalogen din ved å merke av i boksen nedenfor. Alternativt kan du oppgi stier til ffmpeg- og ffprobe-binærfilene i systeminnstillingene. Disse binærfilene må være tilstede for at Stash skal fungere.", + "welcome_contrib": "Vi tar også imot bidrag i form av kode (feilrettinger, forbedringer og nye funksjoner), testing, feilrapporter, forbedrings- og funksjonsforespørsler og brukerstøtte. Detaljer finner du i bidragsdelen i appens brukerhåndbok." + }, + "welcome": { + "in_current_stash_directory": "I katalogen {path}:", + "in_the_current_working_directory": "I {path}, arbeidskatalogen, for øyeblikket:", + "in_the_current_working_directory_disabled": "I {path}, arbeidskatalogen:", + "next_step": "Når alt dette er avklart, og du er klar til å fortsette med å sette opp et nytt system, må du velge hvor du vil lagre konfigurasjonsfilen.", + "store_stash_config": "Hvor vil du lagre Stash-konfigurasjonen din?", + "unexpected_explained": "Hvis du får denne skjermen uventet, kan du prøve å starte Stash på nytt i riktig arbeidsmappe eller med -c-flagget.", + "in_the_current_working_directory_disabled_macos": "Støttes ikke når du kjører Stash.app,

      kjør stash-macos for å sette opp i arbeidskatalogen", + "config_path_logic_explained": "Stash prøver først å finne konfigurasjonsfilen sin (config.yml) fra gjeldende arbeidsmappe, og hvis den ikke finner den der, går den tilbake til {fallback_path}. Du kan også få Stash til å lese fra en spesifikk konfigurasjonsfil ved å kjøre den med alternativene -c '' eller --config ''.", + "unable_to_locate_config": "Hvis du leser dette, fant ikke Stash en eksisterende konfigurasjon. Denne veiviseren vil veilede deg gjennom prosessen med å sette opp en ny konfigurasjon." + }, + "welcome_to_stash": "Velkommen til Stash" + }, + "stashbox": { + "submission_successful": "Innlevering vellykket", + "go_review_draft": "Gå til {endpoint_name} for å se gjennom utkastet.", + "selected_stash_box": "Valgt Stash-Box-endepunkt", + "source": "Stash-Box-kilde", + "submission_failed": "Innsending mislyktes", + "submit_update": "Finnes allerede i {endpoint_name}" + }, + "performer_image": "Skuespiller Bilde", + "countables": { + "images": "{antall, flertall, ett {bilde} andre {bilder}}", + "files": "{antall, flertall, én {fil} andre {filer}}", + "galleries": "{antall, flertall, ett {galleri} andre {gallerier}}", + "markers": "{antall, flertall, én {markør} andre {markører}}", + "scenes": "{antall, flertall, én {Scene} andre {Scener}}", + "studios": "{antall, flertall, ett {studio} andre {studioer}}", + "tags": "{antall, flertall, én {Tag} andre {Tags}}", + "groups": "{antall, flertall, én {gruppe} andre {grupper}}", + "performers": "{antall, flertall, én {utøver} andre {utøvere}}" + }, + "sort_name": "Sorter Navn", + "include_sub_studios": "Inkluder datterselskapsstudioer", + "include_sub_tag_content": "Inkluder innhold i undertagger", + "include_sub_tags": "Inkluder undertagger", + "include_sub_studio_content": "Inkluder innhold fra understudioer", + "dimensions": "Dimensjoner", + "criterion_modifier_values": { + "any_of": "noen av", + "none": "Ingen", + "only": "Bare", + "any": "Hvilken som helst" + }, + "configuration": "Konfigurasjon", + "connection_monitor": { + "websocket_connection_failed": "Klarte ikke å opprette websocket-tilkobling: se nettleserkonsollen for detaljer", + "websocket_connection_reestablished": "Websocket-tilkoblingen er gjenopprettet" + }, + "containing_group": "Inneholder gruppe", + "containing_group_count": "Inneholder gruppeantall", + "containing_groups": "Inneholder grupper", + "country": "Land", + "cover_image": "Forsidebilde", + "created_at": "Opprettet", + "criterion": { + "greater_than": "Større enn", + "less_than": "Mindre enn", + "value": "Verdi" + }, + "criterion_modifier": { + "between": "mellom", + "equals": "Er", + "format_string": "{kriterium} {modifikatorString} {verdiString}", + "format_string_excludes": "{kriterium} {modifierString} {valueString} (ekskluderer {excludedString})", + "format_string_excludes_depth": "{kriterium} {modifierString} {valueString} (ekskluderer {excludedString}) (+{dybde, flertall, =-1 {all} andre {{dybde}}})", + "includes": "inkluderer", + "includes_all": "inkluderer alle", + "is_null": "er null", + "less_than": "er mindre enn", + "matches_regex": "samsvarer med regulært uttrykk", + "not_between": "ikke mellom", + "not_equals": "er ikke", + "greater_than": "er større enn", + "format_string_depth": "{kriterium} {modifierString} {valueString} (+{dybde, flertall, =-1 {all} other {{dybde}}})", + "excludes": "ekskluderer", + "not_matches_regex": "samsvarer ikke med regex", + "not_null": "er ikke null" + }, + "custom": "Tilpasset", + "date": "Dato", + "date_format": "ÅÅÅÅ-MM-DD", + "datetime_format": "ÅÅÅÅ-MM-DD TT:MM", + "death_date": "Dødsdato", + "death_year": "Dødsår", + "descending": "Synkende", + "description": "Beskrivelse", + "detail": "Detalj", + "details": "Detaljer", + "developmentVersion": "Utviklingsversjon", + "disambiguation": "Presisering", + "duration": "Varighet", + "ethnicity": "Etnisitet", + "existing_value": "eksisterende verdi", + "eye_color": "Øyefarge", + "fake_tits": "Falske pupper", + "false": "Falsk", + "favourite": "Favoritt", + "file_count": "Antall filer", + "file_mod_time": "Filendringstid", + "files": "Filer", + "files_amount": "{value} filer", + "filesize": "Filstørrelse", + "filter": "Filter", + "filter_name": "Filternavn", + "filters": "Filtre", + "folder": "Mappe", + "framerate": "Bildefrekvens", + "frames_per_second": "{verdi} fps", + "front_page": { + "types": { + "saved_filter": "Lagrede filter", + "premade_filter": "Forhåndslaget filter" + } + }, + "galleries": "Gallerier", + "gallery": "Galleri", + "gallery_count": "Antall Galleri", + "gender": "Kjønn", + "gender_types": { + "FEMALE": "Kvinne", + "INTERSEX": "Intersex", + "MALE": "Mann", + "NON_BINARY": "Ikke Binær", + "TRANSGENDER_MALE": "Transgender Mann", + "TRANSGENDER_FEMALE": "Transgender kvinne" + }, + "group": "Gruppe", + "group_count": "Gruppetall", + "handy_connection_status": { + "connecting": "Kobler til", + "disconnected": "Koblet fra", + "missing": "Mangler", + "ready": "Klar", + "syncing": "Synkroniserer med server", + "uploading": "Laster opp skript", + "error": "Feil ved tilkobling til Handy" + }, + "hasChapters": "Har Kapitler", + "hasMarkers": "Har Markører", + "height": "Høyde", + "height_cm": "Høyde (cm)", + "help": "Hjelp", + "ignore_auto_tag": "Ignorer Automatisk Tagging", + "image": "Bilde", + "image_count": "Antall Bilder", + "images": "Bilder", + "include_parent_tags": "Inkluder overordnede tagger", + "include_sub_groups": "Inkluder undergrupper", + "index_of_total": "{indeks} av {totalt}", + "instagram": "Instagram", + "interactive": "Interaktiv", + "interactive_speed": "Interaktiv hastighet", + "isMissing": "Mangler", + "last_played_at": "Sist Spilt", + "loading": { + "generic": "Laster inn …", + "plugins": "Laster inn plugins …" + }, + "login": { + "login": "Logg inn", + "username": "Brukernavn", + "password": "Passord", + "invalid_credentials": "Ugyldig brukernavn eller passord", + "internal_error": "Uventet intern feil. Se loggene for mer informasjon" + }, + "marker_count": "Antall markører", + "markers": "Markører", + "measurements": "Mål", + "metadata": "Metadata", + "name": "Navn", + "new": "Ny", + "none": "Ingen", + "o_history": "O Historie", + "odate_recorded_no": "Ingen O-dato registrert", + "operations": "Operasjoner", + "organized": "Organisert", + "orientation": "Orientering", + "pagination": { + "current_total": "{nåværende} av {totalt}", + "first": "Første", + "last": "Siste", + "next": "Neste", + "previous": "Tilbake" + }, + "parent_of": "Forelder til {barn}", + "parent_studio": "Foreldrestudio", + "parent_studios": "Foreldrestudio", + "parent_tag_count": "Antall foreldremerker", + "parent_tags": "Foreldre Tagger", + "penis_length_cm": "Penis Lengde (cm)", + "perceptual_similarity": "Perseptuell Likhet (pHash)", + "performer": "Skuespiller", + "performer_age": "Skuespiller Alder", + "performer_count": "Skuespiller Antall", + "performers": "Skuespillere", + "photographer": "Fotograf", + "piercings": "Piercinger", + "playdate_recorded_no": "Ingen avspillningsdatodato registrert", + "plays": "{verdi} avspillinger", + "primary_file": "Primær fil", + "primary_tag": "Primær Tag", + "random": "Tilfeldig", + "recently_added_objects": "Nylig lagt til {objekter}", + "recently_released_objects": "Nylig utgitte {objekter}", + "resolution": "Oppløsning", + "resume_time": "Gjenoppta tid", + "sceneTagger": "Scene Tagger", + "scene_code": "Studio Kode", + "scene_count": "Antall Scener", + "scene_created_at": "Scene opprettet", + "scene_date": "Dato for scenen", + "scene_id": "Scene-ID", + "scene_tags": "Scene Tagger", + "scene_updated_at": "Scene Oppdatert", + "scenes": "Scener", + "scenes_updated_at": "Scener Oppdatert", + "second": "Sekund", + "seconds": "Sekunder", + "settings": "Innstillinger", + "stash_id": "Stash ID", + "stash_id_endpoint": "Stash ID-sluttpunkt", + "stash_ids": "Stash-ID-er", + "statistics": "Statistikk", + "status": "Status: {statusTekst}", + "studio": "Studio", + "studio_and_parent": "Studio og foreldre", + "studio_count": "Antall Studio", + "donate": "Donere", + "file": "fil", + "empty_server": "Legg til noen scener på serveren din for å se anbefalinger på denne siden.", + "penis_length": "Penis Lengde", + "performer_favorite": "Favoritt Skuespiller", + "eta": "ETA", + "performer_tags": "Skuespiller Tagger", + "play_duration": "Spillevarighet", + "hair_color": "Hårfarge", + "include_sub_group_content": "Inkluder innhold i undergrupper", + "o_count": "O Antall", + "toast": { + "merged_tags": "Sammenslåtte tagger", + "generating_screenshot": "Genererer skjermbilde …", + "added_generation_job_to_queue": "Lagt til genereringsjobb i køen", + "created_entity": "Opprettet {entity}", + "default_filter_set": "Standard filtersett", + "delete_past_tense": "Slettet {count, flertall, en {{singularEntity}} annen {{pluralEntity}}}", + "image_index_too_large": "Feil: Bildeindeksen er større enn antallet bilder i galleriet", + "merged_scenes": "Sammenslåtte scener", + "rescanning_entity": "Skanner på nytt {count, flertall, én {{singularEntity}} annen {{pluralEntity}}}…", + "saved_entity": "Lagret {entity}", + "started_generating": "Begynte å generere", + "started_importing": "Begynte å importere", + "updated_entity": "Oppdatert {entity}", + "started_auto_tagging": "Startet automatisk merking", + "removed_entity": "Fjernet {count, flertall, én {{singularEntity}} annen {{pluralEntity}}}", + "added_entity": "Lagt til {count, flertall, én {{singularEntity}} annen {{pluralEntity}}}", + "reassign_past_tense": "Filen er tildelt på nytt" + }, + "time_end": "Sluttid", + "sub_tags": "Undertagger", + "tag_count": "Antall Tagger", + "total": "Total", + "updated_at": "Oppdatert", + "url": "URL", + "urls": "URLs", + "validation": { + "blank": "${path} må ikke være tomt", + "end_time_before_start_time": "Sluttiden må være større enn eller lik starttiden", + "required": "${path} er et obligatorisk felt", + "unique": "${path} må være unik", + "date_invalid_form": "${path} må være i formatet ÅÅÅÅ-MM-DD" + }, + "video_codec": "Videokodek", + "videos": "Videoer", + "view_all": "Vis Alle", + "weight": "Vekt", + "weight_kg": "Vekt (kg)", + "studio_tags": "Studio Tagger", + "studios": "Studioer", + "sub_group_count": "Antall undergrupper", + "sub_group_of": "Undergruppe av {forelder}", + "sub_group_order": "Undergruppeordre", + "sub_groups": "Undergrupper", + "sub_tag_count": "Antall undertagger", + "sub_tag_of": "Undertagg av {parent}", + "subsidiary_studio_count": "Antall datterselskaper i studioer", + "subsidiary_studios": "Datterselskapsstudioer", + "synopsis": "Synopsis", + "tag": "Tag", + "tag_sub_tag_tooltip": "Har under-tagger", + "tags": "Tagger", + "tattoos": "Tatoveringer", + "time": "Tid", + "title": "Tittel", + "true": "Sant", + "twitter": "X", + "type": "Type", + "unknown_date": "Ukjent dato", + "years_old": "år gammel", + "zip_file_count": "Antall zip-filer", + "tag_parent_tooltip": "Har foreldretagger", + "sub_group": "Undergruppe" } diff --git a/ui/v2.5/src/locales/nl-NL.json b/ui/v2.5/src/locales/nl-NL.json index ceaf2ab27..fea685a1e 100644 --- a/ui/v2.5/src/locales/nl-NL.json +++ b/ui/v2.5/src/locales/nl-NL.json @@ -141,7 +141,17 @@ "make_primary": "Als primair aanduiden", "reload": "Herladen", "copy_to_clipboard": "Kopiëren naar klembord", - "swap": "Omwisselen" + "swap": "Omwisselen", + "sidebar": { + "close": "Sluit zijbalk", + "open": "Open zijbalk", + "toggle": "Schakelaar Zijbalk" + }, + "show_results": "Resultaat tonen", + "show_count_results": "{count} resultaten tonen", + "play": "Afspelen", + "load_filter": "Laad filter", + "load": "Laden" }, "actions_name": "Acties", "age": "Leeftijd", @@ -179,7 +189,10 @@ "show_male_label": "Mannen tonen", "source": "Bron", "mark_organized_label": "Markeren als geordend na opslaan", - "mark_organized_desc": "Markeer een scène als geordend na klikken op opslaan." + "mark_organized_desc": "Markeer een scène als geordend na klikken op opslaan.", + "errors": { + "blacklist_duplicate": "Dubbel zwarte lijst item" + } }, "noun_query": "Zoekvraag", "results": { @@ -279,7 +292,9 @@ "password_desc": "Wachtwoord om je verzameling te openen. Laat leeg om inloggen uit te schakelen", "stash-box_integration": "Stash-boxintegratie", "username": "Gebruikersnaam", - "username_desc": "Gebruikersnaam om je verzameling te openen. Laat leeg om inloggen uit te schakelen" + "username_desc": "Gebruikersnaam om je verzameling te openen. Laat leeg om inloggen uit te schakelen", + "log_file_max_size": "Maximale loggrootte", + "log_file_max_size_desc": "Maximale grootte in megabytes van het logbestand voordat het wordt gecomprimeerd. 0 MB is uitgeschakeld. Vereist herstart." }, "cache_location": "Locatie van de cachemap. Vereist als je streamt via HLS (zoals op Apple apparaten) of DASH.", "cache_path_head": "Cache pad", @@ -343,12 +358,59 @@ "database": "Database", "ffmpeg": { "download_ffmpeg": { - "heading": "Download FFmpeg" + "heading": "FFmpeg downloaden", + "description": "Downloadt FFmpeg naar de configuratiemap en wist de ffmpeg- en ffprobe-paden zodat deze uit de configuratiemap kunnen worden opgehaald." }, "hardware_acceleration": { - "heading": "FFmpeg hardwarecodering" + "heading": "FFmpeg hardwarecodering", + "desc": "Gebruikt beschikbare hardware om video te coderen voor live transcodering." + }, + "ffmpeg_path": { + "heading": "FFmpeg uitvoerbaar pad", + "description": "Pad naar het uitvoerbare bestand van ffmpeg (niet alleen de map). Indien leeg, wordt ffmpeg vanuit de omgeving opgelost via $PATH, de configuratiemap of vanuit $HOME/.stash" + }, + "ffprobe_path": { + "heading": "FFprobe uitvoerbaar pad", + "description": "Pad naar het uitvoerbare bestand ffprobe (niet alleen de map). Indien leeg, wordt ffprobe vanuit de omgeving opgelost via $PATH, de configuratiemap of vanuit $HOME/.stash" + }, + "live_transcode": { + "input_args": { + "desc": "Geavanceerd: Extra argumenten om door te geven aan ffmpeg vóór het invoerveld bij het live transcoderen van video.", + "heading": "FFmpeg Live Transcode Invoer Argumenten" + }, + "output_args": { + "desc": "Geavanceerd: Extra argumenten om door te geven aan ffmpeg vóór het uitvoerveld bij het live transcoderen van video.", + "heading": "FFmpeg Live Transcode Uitvoer Argumenten" + } + }, + "transcode": { + "input_args": { + "desc": "Geavanceerd: Extra argumenten om door te geven aan ffmpeg vóór het invoerveld bij het genereren van video.", + "heading": "FFmpeg Transcode Invoer Argumenten" + }, + "output_args": { + "heading": "FFmpeg Transcode Uitvoer Argumenten", + "desc": "Geavanceerd: Extra argumenten die aan ffmpeg moeten worden doorgegeven vóór het uitvoerveld bij het genereren van video." + } } - } + }, + "blobs_storage": { + "heading": "Type binaire gegevensopslag", + "description": "Waar binaire gegevens zoals scènecovers, performer-, studio- en tagafbeeldingen worden opgeslagen. Nadat u deze waarde hebt gewijzigd, moeten de bestaande gegevens worden gemigreerd met behulp van de taken Blobs migreren. Zie de pagina Taken voor meer informatie over migratie." + }, + "blobs_path": { + "description": "Locatie in het bestandssysteem waar binaire gegevens worden opgeslagen. Alleen van toepassing bij gebruik van het Bestandssysteem blob-opslagtype. WAARSCHUWING: om dit te wijzigen, moeten bestaande gegevens handmatig worden verplaatst.", + "heading": "Pad naar binair gegevensbestandssysteem" + }, + "heatmap_generation": "Funscript Heatmap Generatie", + "gallery_cover_regex_desc": "Regexp gebruikt om een afbeelding te identificeren als galerijomslag", + "plugins_path": { + "description": "Map locatie van plugin-configuratiebestanden", + "heading": "Plugin Pad" + }, + "gallery_cover_regex_label": "Galerie omslagpatroon", + "funscript_heatmap_draw_range": "Bereik opnemen in gegenereerde heatmaps", + "funscript_heatmap_draw_range_desc": "Teken het bewegingsbereik op de y-as van de gegenereerde heatmap. Bestaande heatmaps moeten na wijziging opnieuw worden gegenereerd." }, "library": { "exclusions": "Uitzonderingen", @@ -360,7 +422,9 @@ }, "plugins": { "hooks": "Triggers", - "triggers_on": "Reageert op" + "triggers_on": "Reageert op", + "available_plugins": "Beschikbare Plugins", + "installed_plugins": "Geïnstalleerde Plugins" }, "scraping": { "entity_metadata": "{entityType} Metadata", @@ -371,7 +435,9 @@ "scrapers": "Schrapers", "search_by_name": "Zoek op naam", "supported_types": "Ondersteunde types", - "supported_urls": "URL's" + "supported_urls": "URL's", + "installed_scrapers": "Geïnstalleerde Schrapers", + "available_scrapers": "Beschikbare schrapers" }, "stashbox": { "add_instance": "Voeg stash-box instance toe", @@ -380,7 +446,9 @@ "endpoint": "Eindpunt", "graphql_endpoint": "GraphQL eindpunt", "name": "Naam", - "title": "Stash-box Eindpunten" + "title": "Stash-box Eindpunten", + "max_requests_per_minute_description": "Gebruikt de standaardwaarde van {defaultValue} als deze is ingesteld op 0", + "max_requests_per_minute": "Max aanvragen per minuut" }, "system": { "transcoding": "Transcoderen" @@ -434,7 +502,8 @@ "source": "Bron", "source_options": "{source} Opties", "sources": "Bronnen", - "strategy": "Strategie" + "strategy": "Strategie", + "skip_multiple_matches": "Sla overeenkomsten met meer dan één resultaat over" }, "import_from_exported_json": "Import van geëxporteerde JSON in de map metadata. Maakt de bestaande database leeg.", "incremental_import": "Incrementele import uit een meegeleverde export zip-bestand.", @@ -449,7 +518,30 @@ "scanning_paths": "Scannen van de volgende paden" }, "scan_for_content_desc": "Scan naar nieuwe inhoud en voeg deze toe aan de database.", - "set_name_date_details_from_metadata_if_present": "Stel de naam, datum, details in vanuit Embedded File Metadata" + "set_name_date_details_from_metadata_if_present": "Stel de naam, datum, details in vanuit Embedded File Metadata", + "clean_generated": { + "blob_files": "Blob bestanden", + "image_thumbnails_desc": "Afbeeldingsminiaturen en clips", + "markers": "Markeer Voorbeelden", + "previews": "Scene Voorbeelden", + "sprites": "Scène Sprites", + "transcodes": "Scène Transcoderingen", + "description": "Verwijdert gegenereerde bestanden zonder bijbehorende database-invoer.", + "previews_desc": "Scene voorbeelden en afbeeldingsminiaturen", + "image_thumbnails": "Afbeeldingsminiaturen" + }, + "anonymising_database": "Anonimiseer database", + "anonymise_database": "Maakt een kopie van de database naar de backups-map, waarbij alle gevoelige gegevens anoniem worden gemaakt. Deze kan vervolgens aan anderen worden verstrekt voor probleemoplossing en debugging. De originele database wordt niet gewijzigd. De geanonimiseerde database gebruikt de bestandsnaamindeling {filename_format}.", + "anonymise_and_download": "Maakt een geanonimiseerde kopie van de database en downloadt het resulterende bestand.", + "generate_clip_previews_during_scan": "Genereer voorbeelden van Afbeelingsfragmenten", + "migrate_blobs": { + "delete_old": "Verwijder oude gegevens" + }, + "migrate_scene_screenshots": { + "delete_files": "Verwijder screenshotbestanden" + }, + "generate_sprites_during_scan_tooltip": "De set afbeeldingen die onder de videospeler worden weergegeven voor eenvoudige navigatie.", + "generate_video_covers_during_scan": "Scène-covers genereren" }, "tools": { "scene_duplicate_checker": "Scène Duplicator Checker", @@ -468,7 +560,9 @@ "whitespace_chars": "WhiteSpace-tekens", "whitespace_chars_desc": "Deze tekens worden vervangen door witruimte in de titel" }, - "scene_tools": "Scene gereedschap" + "scene_tools": "Scene gereedschap", + "graphql_playground": "GraphQL speeltuin", + "heading": "Hulpmiddelen" }, "ui": { "basic_settings": "Basis instellingen", @@ -497,11 +591,27 @@ "description": "Verwijder de mogelijkheid om nieuwe objecten te maken uit de dropdown menu", "heading": "Schakel het maken van dropdowns uit" }, - "heading": "Aanpassen" + "heading": "Aanpassen", + "rating_system": { + "type": { + "options": { + "decimal": "Decimaal", + "stars": "Sterren" + } + }, + "star_precision": { + "options": { + "full": "Vol", + "half": "Half", + "quarter": "Kwart", + "tenth": "Tiende" + } + } + } }, "funscript_offset": { "description": "Time Offset in milliseconden voor het afspelen van interactieve scripts.", - "heading": "Funscript Offset (ms)" + "heading": "" }, "handy_connection": { "connect": "Connecteer", @@ -515,7 +625,7 @@ }, "handy_connection_key": { "description": "Handy connection key om te gebruiken voor interactieve scènes. Instellen van deze sleutel staat Stash toe om uw huidige scène-informatie met HandyFeeling.com te delen", - "heading": "Handy Connection Key" + "heading": "" }, "image_lightbox": { "heading": "Afbeelding Lightbox" @@ -575,7 +685,9 @@ "continue_playlist_default": { "description": "Speel de volgende scène in de wachtrij wanneer video is voltooid", "heading": "Ga Standaard door met de afspeellijst" - } + }, + "always_start_from_beginning": "Start video altijd vanaf het begin", + "enable_chromecast": "Chromecast inschakelen" } }, "scene_wall": { @@ -593,7 +705,29 @@ "description": "Diavoorstelling is beschikbaar in galerijen in de muurweergavemodus", "heading": "Diavoorstellingsvertraging (in seconden)" }, - "title": "Gebruikers interface" + "title": "Gebruikers interface", + "custom_javascript": { + "heading": "Aangepaste JavaScript", + "option_label": "Aangepaste JavaScript ingeschakeld" + }, + "custom_locales": { + "heading": "Aangepaste lokalisatie", + "option_label": "Aangepaste lokalisatie ingeschakeld" + }, + "detail": { + "enable_background_image": { + "description": "Achtergrondfoto op detailscherm weergeven.", + "heading": "Achtergrondfoto inschakelen" + }, + "heading": "Detailscherm", + "show_all_details": { + "heading": "Alle details weergeven" + } + }, + "image_wall": { + "margin": "Marge (pixels)", + "direction": "Richting" + } }, "advanced_mode": "Geavanceerde modus" }, @@ -602,11 +736,11 @@ "files": "{count, plural, one {Bestand} other {Bestanden}}", "galleries": "{count, plural, one {Galerij} other {Galerijen}}", "images": "{count, plural, one {Afbeelding} other {Afbeeldingen}}", - "markers": "{count, plural, one {Marker} other {Markers}}", - "performers": "{count, plural, one {Performer} other {Performers}}", - "scenes": "{count, plural, one {Scene} other {Scenes}}", - "studios": "{count, plural, one {Studio} other {Studios}}", - "tags": "{count, plural, one {Tag} other {Tags}}" + "markers": "", + "performers": "", + "scenes": "", + "studios": "", + "tags": "" }, "country": "Land", "cover_image": "Cover afbeelding", @@ -678,7 +812,6 @@ "destination": "Bestemming", "source": "Afkomst" }, - "overwrite_filter_confirm": "Weet u zeker dat u de bestaande opgeslagen zoekopdracht {entityName} wilt overschrijven?", "scene_gen": { "force_transcodes": "Genereren van transcode forceren", "force_transcodes_tooltip": "Standaard worden transcodes alleen gegenereerd als het videobestand niet wordt ondersteund in de browser. Indien ingeschakeld, worden transcodes gegenereerd, zelfs als het videobestand in de browser lijkt te worden ondersteund.", @@ -707,12 +840,14 @@ "preview_seg_count_head": "Aantal segmenten in voorbeeld", "preview_seg_duration_desc": "Duur van elk voorbeeldsegment, in seconden.", "preview_seg_duration_head": "Voorbeeld Segment Duur", - "sprites": "Scene Scrubber Sprites", + "sprites": "Scène Scrubber Sprites", "sprites_tooltip": "De set afbeeldingen die onder de videospeler worden weergegeven voor eenvoudige navigatie.", "transcodes": "Transcoderingen", "transcodes_tooltip": "MP4-conversies van niet-ondersteunde video-indelingen", "video_previews": "Voorbeelden", - "video_previews_tooltip": "Videovoorbeelden die worden afgespeeld wanneer u over een scène beweegt" + "video_previews_tooltip": "Videovoorbeelden die worden afgespeeld wanneer u over een scène beweegt", + "covers": "Scène-covers", + "image_thumbnails": "Afbeeldingsminiaturen" }, "scenes_found": "{count} scenes gevonden", "scrape_entity_query": "{entity_type} Schraper Query", @@ -720,7 +855,18 @@ "scrape_results_existing": "Bestaande", "scrape_results_scraped": "Geschraapt", "set_image_url_title": "Afbeelding URL", - "unsaved_changes": "Niet-opgeslagen wijzigingen gaan verloren. Weet je zeker dat je wilt vertrekken?" + "unsaved_changes": "Niet-opgeslagen wijzigingen gaan verloren. Weet je zeker dat je wilt vertrekken?", + "merge": { + "destination": "Bestemming", + "source": "Bron" + }, + "performers_found": "{count} artiesten gevonden", + "imagewall": { + "direction": { + "column": "Kolom", + "row": "Rij" + } + } }, "dimensions": "Dimensies", "director": "Regisseur", @@ -742,7 +888,11 @@ "medium": "Medium" }, "search_accuracy_label": "Zoek accuraatheid", - "title": "Dubbele Scènes" + "title": "Dubbele Scènes", + "duration_options": { + "equal": "Gelijk" + }, + "select_none": "Niets selecteren" }, "duplicated_phash": "Gedupliceerd (phash)", "duration": "Looptijd", @@ -783,11 +933,11 @@ "filter_name": "Filter Naam", "filters": "Filters", "framerate": "Frame snelheid", - "frames_per_second": "{value} frames per seconde", + "frames_per_second": "{value} fps", "front_page": { "types": { "premade_filter": "Vooraf gemaakte filter", - "saved_filter": "Opgeslagen Filter" + "saved_filter": "Opgeslagen filter" } }, "galleries": "Galerijen", @@ -798,11 +948,11 @@ "FEMALE": "Vrouw", "INTERSEX": "Intersex", "MALE": "Man", - "NON_BINARY": "Non-Binar", + "NON_BINARY": "Non-binair", "TRANSGENDER_FEMALE": "Transgender Vrouw", "TRANSGENDER_MALE": "Transgender Man" }, - "hair_color": "Haar kleur", + "hair_color": "Haarkleur", "handy_connection_status": { "connecting": "Verbinden", "disconnected": "Verbinding verbroken", @@ -812,7 +962,7 @@ "syncing": "Synchroniseren met server", "uploading": "Script uploaden" }, - "hasMarkers": "Heeft Markeringen", + "hasMarkers": "Markeringen", "height": "Hoogte", "help": "Help", "ignore_auto_tag": "Negeer automatische tag", @@ -828,7 +978,8 @@ "isMissing": "Is Missende", "library": "Bibliotheek", "loading": { - "generic": "Laden…" + "generic": "Laden…", + "plugins": "Plugins laden…" }, "marker_count": "Marker Aantal", "markers": "Markeringen", @@ -841,18 +992,17 @@ "interactive_speed": "Interactieve snelheid", "performer_card": { "age": "{age} {years_old}", - "age_context": "{age} {years_old} in deze scène" + "age_context": "{age} {years_old} bij productie" }, "phash": "PHash", "stream": "Stream", "video_codec": "Video Codec" }, - "megabits_per_second": "{value} megabits per seconde", + "megabits_per_second": "{value} mbps", "metadata": "Metadata", "name": "Naam", "new": "Nieuw", "none": "Geen", - "o_counter": "O-Teller", "operations": "Operaties", "organized": "Georganiseerd", "pagination": { @@ -950,7 +1100,7 @@ }, "paths": { "database_filename_empty_for_default": "database bestandsnaam (leeg als standaard)", - "description": "Vervolgens moeten we bepalen waar we je pornocollectie kunnen vinden, waar we de stash-database en gegenereerde bestanden kunnen opslaan. Deze instellingen kunnen indien nodig later worden gewijzigd.", + "description": "Vervolgens moeten we bepalen waar we je collectie kunnen vinden, waar we de stash-database en gegenereerde bestanden kunnen opslaan. Deze instellingen kunnen indien nodig later worden gewijzigd.", "path_to_generated_directory_empty_for_default": "pad naar gegenereerde map (standaard leeg)", "set_up_your_paths": "Stel je paden in", "stash_alert": "Er zijn geen bibliotheekpaden geselecteerd. Er kan dan geen media worden gescand in Stash. Weet je zeker dat?", @@ -959,7 +1109,7 @@ "where_can_stash_store_its_generated_content": "Waar kan Stash de gegenereerde inhoud opslaan?", "where_can_stash_store_its_generated_content_description": "Om thumbnails, previews en sprites aan te bieden, genereert Stash afbeeldingen en video's. Dit omvat ook transcodes voor niet-ondersteunde bestandsindelingen. Standaard zal Stash een generated directory aanmaken in de directory die uw configuratiebestand bevat. Als u wilt wijzigen waar deze gegenereerde media wordt opgeslagen, voert u een absoluut of relatief (ten opzichte van de huidige werkmap) pad in. Stash maakt deze map aan als deze nog niet bestaat.", "where_is_your_porn_located": "Waar staat je porno?", - "where_is_your_porn_located_description": "Voeg mappen toe die uw pornovideo's en afbeeldingen bevatten. Stash gebruikt deze mappen om video's en afbeeldingen te vinden tijdens het scannen." + "where_is_your_porn_located_description": "Voeg mappen toe die uw video's en afbeeldingen bevatten. Stash gebruikt deze mappen om video's en afbeeldingen te vinden tijdens het scannen." }, "stash_setup_wizard": "Stash-installatiewizard", "success": { @@ -996,7 +1146,8 @@ "stats": { "image_size": "Afbeelding groote", "scenes_duration": "Scene duur", - "scenes_size": "Scene groote" + "scenes_size": "Scene groote", + "scenes_played": "Scènes gespeeld" }, "status": "Status: {statusText}", "studio": "Studio", @@ -1048,5 +1199,78 @@ "circumcised_types": { "CUT": "Ja", "UNCUT": "Nee" - } + }, + "folder": "Folder", + "hasChapters": "Hoofdstukken", + "image_index": "Afbeelding #", + "include_sub_groups": "Inclusief subgroepen", + "index_of_total": "{index} van {total}", + "orientation": "Oriëntatie", + "group": "Groep", + "group_count": "Aantal groepen", + "height_cm": "Lengte (cm)", + "history": "Geschiedenis", + "groups": "Groepen", + "file_count": "Aantal bestanden", + "files_amount": "{value} bestanden", + "include_sub_group_content": "Inclusief subgroep inhoud", + "login": { + "username": "Gebruikersnaam", + "password": "Wachtwoord", + "login": "Login", + "invalid_credentials": "Ongeldige gebruikersnaam of wachtwoord" + }, + "group_scene_number": "Scènenummer", + "include_sub_studio_content": "Inclusief substudio inhoud", + "last_played_at": "Laatst gespeeld op", + "include_sub_tag_content": "Inclusief sub-tag inhoud", + "age_on_date": "{age} tijdens productie", + "studio_tagger": { + "query_all_studios_in_the_database": "Alle studio's in de database", + "current_page": "Huidige pagina", + "status_tagging_job_queued": "Status: Tagging-taak in de wachtrij", + "config": { + "no_instances_found": "Geen gevallen gevonden", + "these_fields_will_not_be_changed_when_updating_studios": "Deze velden worden niet gewijzigd bij het updaten van studio's." + }, + "failed_to_save_studio": "Opslaan van studio “{studio}” mislukt", + "name_already_exists": "Naam bestaat reeds", + "network_error": "Netwerkfout", + "no_results_found": "Geen resultaten gevonden.", + "number_of_studios_will_be_processed": "{studio_count} studio's worden verwerkt", + "refresh_tagged_studios": "Vernieuwen getagde studio's", + "refreshing_will_update_the_data": "Vernieuwen zal de gegevens van alle getagde studio's van de stash-box bijwerken.", + "create_or_tag_parent_studios": "Maak ontbrekende of label bestaande moederstudio's" + }, + "zip_file_count": "Aantal Zipbestanden", + "unknown_date": "Onbekende datum", + "urls": "URL's", + "date_format": "JJJJ-MM-DD", + "description": "Omschrijving", + "distance": "Afstand", + "package_manager": { + "description": "Omschrijving", + "install": "Installeer", + "package": "Pakket", + "source": { + "name": "Naam" + }, + "uninstall": "Verwijderen", + "unknown": "", + "update": "Updaten", + "version": "Versie" + }, + "penis": "Penis", + "photographer": "Fotograaf", + "second": "Seconde", + "statistics": "Statistieken", + "time": "Tijd", + "criterion_modifier_values": { + "none": "Geen" + }, + "custom_fields": { + "field": "Veld", + "value": "Waarde" + }, + "datetime_format": "YYYY-MM-DD HH:MM" } diff --git a/ui/v2.5/src/locales/nn-NO.json b/ui/v2.5/src/locales/nn-NO.json index 81d94cf8e..995336e58 100644 --- a/ui/v2.5/src/locales/nn-NO.json +++ b/ui/v2.5/src/locales/nn-NO.json @@ -102,7 +102,13 @@ "performers_found": "Fann {count} utøvarar", "delete_entity_title": "{count, plural, one {Slett {singularEntity}} other {Slett {pluralEntity}}}", "scenes_found": "Fann {count} scener", - "dont_show_until_updated": "Ikkje vis før neste oppdatering" + "dont_show_until_updated": "Ikkje vis før neste oppdatering", + "imagewall": { + "direction": { + "column": "Kolonne", + "row": "Rad" + } + } }, "date": "Dato", "bitrate": "Bitrate", @@ -143,6 +149,9 @@ } } } + }, + "images": { + "heading": "Bilete" } }, "about": { @@ -199,7 +208,6 @@ "last": "Siste" }, "o_count": "Tal på O", - "o_counter": "O-teljar", "organized": "Organisert", "playdate_recorded_no": "Ingen avspelingsdato er registrert", "play_duration": "Avspelingslengd", @@ -229,5 +237,16 @@ "sub_group": "Undergruppe", "sub_group_count": "Tal på undergrupper", "sub_group_of": "Undergruppe av {parent}", - "sub_group_order": "Undergruppesortert" + "sub_group_order": "Undergruppesortert", + "groups": "Grupper", + "performers": "Utøvarar", + "studios": "Studio", + "image": "Bilete", + "images": "Bilete", + "scene": "Scene", + "group": "Gruppe", + "galleries": "Galleri", + "scenes": "Scener", + "studio": "Studio", + "performer": "Utøvar" } diff --git a/ui/v2.5/src/locales/pl-PL.json b/ui/v2.5/src/locales/pl-PL.json index 794497801..413460800 100644 --- a/ui/v2.5/src/locales/pl-PL.json +++ b/ui/v2.5/src/locales/pl-PL.json @@ -141,7 +141,9 @@ "remove_from_containing_group": "Usuń z grupy", "reset_cover": "Przywróć domyślną okładkę", "add_sub_groups": "Dodaj podgrupy", - "view_history": "Zobacz historię" + "view_history": "Zobacz historię", + "play": "Odtwarzaj", + "show_results": "Pokaż wyniki" }, "actions_name": "Działania", "age": "Wiek", @@ -346,6 +348,9 @@ "desc": "Zaawansowane: Dodatkowe argumenty do przekazania do FFmpeg przed polem wyjściowym podczas generowania wideo.", "heading": "Argumenty wyjścia dla transkodowania z użyciem FFmpeg" } + }, + "download_ffmpeg": { + "heading": "Pobierz FFmpeg" } }, "funscript_heatmap_draw_range": "Bierz pod uwagę zakres dla wygenerowanych heatmap", @@ -832,7 +837,6 @@ "destination": "Cel", "source": "Źródło" }, - "overwrite_filter_confirm": "Czy na pewno chcesz nadpisać istniejące zapisane zapytanie {entityName}?", "reassign_entity_title": "Przypisz {count, plural, one {{singularEntity}} other {{pluralEntity}}}", "reassign_files": { "destination": "Przypisz ponownie do" @@ -1032,7 +1036,6 @@ "name": "Nazwa", "new": "Dodaj", "none": "Brak", - "o_counter": "O-Licznik", "operations": "Operacje", "organized": "Uporządkowany", "pagination": { diff --git a/ui/v2.5/src/locales/pt-BR.json b/ui/v2.5/src/locales/pt-BR.json index b759122d7..eb183b234 100644 --- a/ui/v2.5/src/locales/pt-BR.json +++ b/ui/v2.5/src/locales/pt-BR.json @@ -689,7 +689,6 @@ "destination": "Destino", "source": "Fonte" }, - "overwrite_filter_confirm": "Tem certeza de que deseja sobrescrever a consulta salva existente {entityName}?", "scene_gen": { "force_transcodes": "Forçar geração de transcodificação", "force_transcodes_tooltip": "Por padrão, transcodificações são geradas apenas quando o arquivo de vídeo não é suportado pelo navegador. Quando ativado, transcodificações serão geradas mesmo quando o vídeo parecer ser suportado no navegador.", @@ -865,7 +864,6 @@ "name": "Nome", "new": "Novo", "none": "Nenhum", - "o_counter": "O-contador", "operations": "Operações", "organized": "Organizado", "pagination": { diff --git a/ui/v2.5/src/locales/ro-RO.json b/ui/v2.5/src/locales/ro-RO.json index f3fc389ba..1b4375207 100644 --- a/ui/v2.5/src/locales/ro-RO.json +++ b/ui/v2.5/src/locales/ro-RO.json @@ -88,7 +88,8 @@ "submit_update": "Trimite actualizare", "tasks": { "clean_confirm_message": "Ești sigur că vrei să cureți? Acest lucru va șterge informațiile din baza de date și conținutul generat pentru toate scenele și galeriile care nu se mai găsesc în sistemul de fișiere.", - "import_warning": "Ești sigur că vrei să imporți? Asta va șterge baza de date si va reimporta din metadatele tale exporatate." + "import_warning": "Ești sigur că vrei să imporți? Asta va șterge baza de date si va reimporta din metadatele tale exporatate.", + "dry_mode_selected": "\"Modul uscat\" selectat. Nu se va șterge nimic, doar se va loga." }, "temp_disable": "Dezactivează temporar…", "temp_enable": "Activează temporar…", @@ -131,7 +132,18 @@ "reshuffle": "Reamestecă", "scrape_query": "Extrage date", "scrape_scene_fragment": "Extrage fragment cu fragment", - "scrape_with": "Extrage cu…" + "scrape_with": "Extrage cu…", + "selective_clean": "Curățare selectivă", + "selective_scan": "Scanare selectivă", + "set_cover": "Setează ca fundal", + "swap": "Schimbă", + "unset": "Nesetat", + "view_history": "Vezi istoric", + "sidebar": { + "close": "Închide bara laterală", + "open": "Deschide bara laterală" + }, + "split": "Împarte" }, "actions_name": "Acțiuni", "age": "Vârstă", @@ -162,16 +174,27 @@ "set_tag_label": "Setați etichete", "show_male_desc": "Comutați dacă interpreții de sex masculin vor fi disponibili pentru etichetare.", "show_male_label": "Arată interpreți de sex masculin", - "source": "Sursă" + "source": "Sursă", + "query_mode_metadata": "Date meta", + "mark_organized_label": "Marchează ca Organizat la salvare", + "errors": { + "blacklist_duplicate": "Lucru de pe lista neagră duplicat" + }, + "mark_organized_desc": "Marchează scena ca Organizată imediat după ce butonul de Salvare este apăsat.", + "query_mode_label": "Mod de căutare", + "blacklist_desc": "Lucrurile din lista neagră sunt excluse din căutări. De reținut, căutările sunt expresii si diferențiază între litere mari și mici. Înaintea anumitor caractere, trebuie pus caracterul backslash: {chars_require_escape}" }, "results": { "duration_unknown": "Durată necunoscută", "match_failed_already_tagged": "Scena este deja etichetată", "match_failed_no_result": "Nu s-au găsit rezultate", "match_success": "Scena a fost etichetată cu succes", - "unnamed": "Fără denumire" + "unnamed": "Fără denumire", + "fp_matches": "Durația este aceeași", + "duration_off": "Durația diferă cu cel puțin {number}s" }, - "verb_toggle_config": "{toggle} {configuration}" + "verb_toggle_config": "{toggle} {configuration}", + "noun_query": "Căutare" }, "config": { "about": { @@ -253,7 +276,6 @@ "created_at": "Creat La", "dialogs": { "delete_confirm": "Ești sigur ca vrei să ștergi {entityName}?", - "overwrite_filter_confirm": "Sunteți sigur că doriți să suprascrieți interogarea salvată existentă {entityName}?", "scene_gen": { "force_transcodes_tooltip": "În mod implicit, transcodurile sunt generate numai atunci când fișierul video nu este acceptat în browser. Atunci când este activată, transcodurile vor fi generate chiar și atunci când fișierul video pare a fi acceptat în browser.", "image_previews": "Imagini animate de previzualizare", @@ -372,7 +394,6 @@ "metadata": "Metadate", "name": "Nume", "new": "Nou", - "o_counter": "O-Contor", "operations": "Operațiuni", "organized": "Organizat", "pagination": { @@ -495,5 +516,21 @@ "view_all": "Vezi Toate", "weight": "Greutate", "years_old": "ani", - "containing_group": "Grup aparținător" + "containing_group": "Grup aparținător", + "aliases": "Porecle", + "appears_with": "Apare cu", + "audio_codec": "Codec Audio", + "between_and": "și", + "blobs_storage_type": { + "database": "Bază de date", + "filesystem": "Sistem de fișiere" + }, + "captions": "Subtitrări", + "chapters": "Capitole", + "circumcised_types": { + "CUT": "Circumcis", + "UNCUT": "Necircumcis" + }, + "circumcised": "Circumcizie", + "age_on_date": "{age} la producție" } diff --git a/ui/v2.5/src/locales/ru-RU.json b/ui/v2.5/src/locales/ru-RU.json index b5e6d8dcf..9b1d790d2 100644 --- a/ui/v2.5/src/locales/ru-RU.json +++ b/ui/v2.5/src/locales/ru-RU.json @@ -128,7 +128,7 @@ "assign_stashid_to_parent_studio": "Присвоить Stash ID для текущей родительской студии и обновить метаданные", "add_manual_date": "Добавить дату вручную", "add_o": "Добавить О", - "add_play": "Добавить проигрывание", + "add_play": "Добавить воспроизведение", "choose_date": "Выбрать дату", "clean_generated": "Очистить сгенерированные файлы", "clear_date_data": "Очистить информацию о дате", @@ -139,7 +139,19 @@ "reset_cover": "Восстановить обложку по умолчанию", "set_cover": "Установить как обложку", "add_sub_groups": "Добавить подгруппы", - "remove_from_containing_group": "Удалить из группы" + "remove_from_containing_group": "Удалить из группы", + "reset_play_duration": "Сбросить время воспроизведения", + "reset_resume_time": "Сбросить точку продолжения", + "show_results": "Показать результаты", + "sidebar": { + "toggle": "Показать/скрыть боковую панель", + "open": "Открыть панель", + "close": "Закрыть панель" + }, + "show_count_results": "Показать {count} результат(ов)", + "play": "Воспроизвести", + "load": "Загрузить", + "load_filter": "Загрузить фильтр" }, "actions_name": "Действия", "age": "Возраст", @@ -183,7 +195,10 @@ "show_male_label": "Показывать актеров мужского пола", "source": "Источник", "mark_organized_label": "Отметить как Организованную при сохранении", - "mark_organized_desc": "Сразу же отметить сцену как Организованную после нажатия кнопки Сохранить." + "mark_organized_desc": "Сразу же отметить сцену как Организованную после нажатия кнопки Сохранить.", + "errors": { + "blacklist_duplicate": "Дублировать элемент чёрного списка" + } }, "noun_query": "Запрос", "results": { @@ -435,7 +450,9 @@ "endpoint": "Конечная точка", "graphql_endpoint": "Конечная точка GraphQL", "name": "Имя", - "title": "Конечные точки Stash-box" + "title": "Конечные точки Stash-box", + "max_requests_per_minute": "Максимальное количество запросов в минуту", + "max_requests_per_minute_description": "Использует значение по умолчанию {defaultValue}, если задано 0" }, "system": { "transcoding": "Транскодирование" @@ -541,7 +558,8 @@ "sprites": "Спрайты Сцен", "transcodes": "Транскоды Сцен" }, - "rescan": "Пересканировать файлы" + "rescan": "Пересканировать файлы", + "rescan_tooltip": "Повторно просканировать все файлы в пути. Используется для обновления метаданных и сканирования ZIP-файлов." }, "tools": { "scene_duplicate_checker": "Проверка сцен на дубликаты", @@ -560,7 +578,9 @@ "whitespace_chars": "Символы пробелов", "whitespace_chars_desc": "Эти символы будут заменены пробелами в названии" }, - "scene_tools": "Инструменты видео" + "scene_tools": "Инструменты видео", + "graphql_playground": "Песочница GraphQL", + "heading": "Инструменты" }, "ui": { "abbreviate_counters": { @@ -694,7 +714,7 @@ } }, "scene_list": { - "heading": "Сетка", + "heading": "Сеточный вид", "options": { "show_studio_as_text": "Отображать названия студии как текст" } @@ -720,7 +740,8 @@ "description": "Кнопка VR будет показана только для сцен с данным тегом.", "heading": "Тег VR" }, - "disable_mobile_media_auto_rotate": "Отключить автоповорот в полноэкранном режиме на мобильных устройствах" + "disable_mobile_media_auto_rotate": "Отключить автоповорот в полноэкранном режиме на мобильных устройствах", + "show_range_markers": "Показать маркеры диапазона" } }, "scene_wall": { @@ -883,7 +904,6 @@ "destination": "Назначение", "source": "Источник" }, - "overwrite_filter_confirm": "Вы уверены, что хотите перезаписать существующий сохраненный запрос {entityName}?", "reassign_entity_title": "{count, plural, one {Переназначить {singularEntity}} other {Переназначить {pluralEntity}}}", "reassign_files": { "destination": "Переназначить на" @@ -944,7 +964,9 @@ }, "clear_play_history_confirm": "Вы уверены, что хотите удалить историю просмотра?", "performers_found": "{count} исполнителей найдено", - "clear_o_history_confirm": "Вы уверены, что хотите очистить историю О?" + "clear_o_history_confirm": "Вы уверены, что хотите очистить историю О?", + "overwrite_filter_warning": "Сохранённый фильтр «{entityName}» будет перезаписан.", + "set_default_filter_confirm": "Вы уверены, что хотите установить этот фильтр по умолчанию?" }, "dimensions": "Размер", "director": "Режиссер", @@ -954,7 +976,8 @@ "list": "Список", "tagger": "Теггер", "unknown": "Неизвестный", - "wall": "Стена" + "wall": "Стена", + "label_current": "Режим отображения: {current}" }, "donate": "Пожертвование", "dupe_check": { @@ -1070,7 +1093,8 @@ "last_played_at": "Воспроизводился в последний раз", "library": "Библиотека", "loading": { - "generic": "Загрузка…" + "generic": "Загрузка…", + "plugins": "Загрузка плагинов…" }, "marker_count": "Количество маркеров", "markers": "Маркеры", @@ -1097,14 +1121,14 @@ "name": "Имя", "new": "Новый", "none": "Отсутствует", - "o_counter": "О-Счетчик", "operations": "Операции", "organized": "Организован", "pagination": { "first": "Первая", "last": "Последняя", "next": "Следующая", - "previous": "Предыдущий" + "previous": "Предыдущий", + "current_total": "{current} из {total}" }, "parent_of": "Родитель {children}", "parent_studios": "Родительские студии", @@ -1182,7 +1206,9 @@ "name": "Фильтр", "saved_filters": "Сохраненные фильтры", "update_filter": "Обновить фильтр", - "edit_filter": "Изменить фильтр" + "edit_filter": "Изменить фильтр", + "more_filter_criteria": "+ещё {count}", + "search_term": "Поисковый запрос" }, "seconds": "Секунды", "settings": "Настройки", @@ -1204,7 +1230,9 @@ "errors": { "something_went_wrong": "О, нет! Что-то пошло не так!", "something_went_wrong_description": "Если это похоже на проблему с вашими входными данными, нажмите «Назад», чтобы исправить их. В противном случае сообщите об ошибке на {githubLink} или обратитесь за помощью в {discordLink}.", - "something_went_wrong_while_setting_up_your_system": "Что-то пошло не так при настройке вашей системы. Мы получили следующую ошибку: {error}" + "something_went_wrong_while_setting_up_your_system": "Что-то пошло не так при настройке вашей системы. Мы получили следующую ошибку: {error}", + "unexpected_error": "Произошла непредвиденная ошибка: {error}", + "unable_to_retrieve_system_status": "Не удалось получить статус системы: {error}" }, "folder": { "file_path": "Путь файла", @@ -1432,7 +1460,15 @@ "image_index_greater_than_zero": "Индекс изображения должен быть больше 0", "header": "Ошибка", "loading_type": "Ошибка загрузки {type}", - "something_went_wrong": "Что-то пошло по пизде." + "something_went_wrong": "Что-то пошло по пизде.", + "custom_fields": { + "field_name_length": "Имя поля должно содержать меньше 65 символов", + "field_name_required": "Имя поля обязательно", + "field_name_whitespace": "Имя поля не должно начинаться или заканчиваться пробелом", + "duplicate_field": "Имя поля должно быть уникальным" + }, + "invalid_javascript_string": "Недопустимый код JavaScript: {error}", + "invalid_json_string": "Недопустимая JSON-строка: {error}" }, "date_format": "ГГГГ-ММ-ДД", "datetime_format": "ГГГГ-ММ-ДД ЧЧ:ММ", @@ -1451,7 +1487,8 @@ "date_invalid_form": "${path} должен быть в формате ГГГГ-ММ-ДД", "blank": "${path} не должен быть пустым", "required": "${path} обязательное поле", - "unique": "${path} должен быть уникальным" + "unique": "${path} должен быть уникальным", + "end_time_before_start_time": "Время окончания должно быть больше или равно времени начала" }, "unknown_date": "Неизвестная дата", "urls": "URLы", @@ -1471,5 +1508,43 @@ "age_on_date": "{age} на момент съемки", "sub_group_count": "Кол-во подгрупп", "sub_group": "Подгруппа", - "studio_tags": "Теги студии" + "studio_tags": "Теги студии", + "criterion_modifier_values": { + "any": "Любой", + "any_of": "Любой из", + "none": "Отсутствует", + "only": "Только" + }, + "containing_groups": "Группы, в которые входит объект", + "custom_fields": { + "criteria_format_string": "criterion} (пользовательское поле) {modifierString} {valueString}", + "criteria_format_string_others": "{criterion} (пользовательское поле) {modifierString} {valueString} (и ещё {others})", + "field": "Поле", + "title": "Настраиваемые поля", + "value": "Значение" + }, + "containing_group": "Содержащая группа", + "containing_group_count": "Количество содержащих групп", + "time_end": "Время окончания", + "eta": "Ожидаемое время завершения", + "login": { + "username": "Имя пользователя", + "password": "Пароль", + "login": "Логин", + "internal_error": "Произошла внутренняя ошибка. Подробности смотрите в логах.", + "invalid_credentials": "Неверное имя пользователя или пароль" + }, + "groups": "Группы", + "include_sub_tag_content": "Учитывать содержимое вложенных тегов", + "sort_name": "Сортировать по имени", + "include_sub_group_content": "Включать содержимое подгрупп", + "include_sub_studio_content": "Включить данные дочерних студий", + "group": "Группа", + "group_count": "Количество групп", + "group_scene_number": "Номер сцены", + "include_sub_groups": "Включать подгруппы", + "studio_count": "Количество студий", + "sub_group_of": "Входит в группу {parent}", + "sub_group_order": "Сортировка подгрупп", + "sub_groups": "Подгруппы" } diff --git a/ui/v2.5/src/locales/sv-SE.json b/ui/v2.5/src/locales/sv-SE.json index 2180a77f2..71ba3e99f 100644 --- a/ui/v2.5/src/locales/sv-SE.json +++ b/ui/v2.5/src/locales/sv-SE.json @@ -141,7 +141,17 @@ "add_sub_groups": "Lägg Till Undergrupper", "remove_from_containing_group": "Ta bort från Grupp", "reset_resume_time": "Återställ återupptagningstid", - "set_cover": "Välj som Omslag" + "set_cover": "Välj som Omslag", + "play": "Spela", + "show_count_results": "Visa {count} resultat", + "sidebar": { + "toggle": "Ändra sidolisten", + "close": "Stäng sidolisten", + "open": "Öppna sidolisten" + }, + "show_results": "Visa resultat", + "load": "Ladda", + "load_filter": "Ladda filter" }, "actions_name": "Handlingar", "age": "Ålder", @@ -447,7 +457,9 @@ "endpoint": "Adress", "graphql_endpoint": "GraphQL-adress", "name": "Namn", - "title": "Stash-box Adresser" + "title": "Stash-box Adresser", + "max_requests_per_minute": "Högsta antal förfrågningar per minut", + "max_requests_per_minute_description": "Använder standardvärdet {defaultValue} om detta är 0" }, "system": { "transcoding": "Omkodning" @@ -573,7 +585,9 @@ "whitespace_chars": "Blankstegstecken", "whitespace_chars_desc": "Dessa tecken kommer ersättas med blanksteg i titeln" }, - "scene_tools": "Scenverktyg" + "scene_tools": "Scenverktyg", + "graphql_playground": "GraphQL lekplats", + "heading": "Verktyg" }, "ui": { "abbreviate_counters": { @@ -798,6 +812,14 @@ "use_stash_hosted_funscript": { "description": "När aktiverat kommer funscripts att skickas direkt från Stash till din Handy-enhet utan att använda tredjeparts Handy-servern. Kräver att Stash kan nås från din Handy-enhet och att en API-nyckel är genererad om stash har lösenord aktiverat.", "heading": "Skicka funscripts direkt" + }, + "performer_list": { + "heading": "Lista av stjärnor", + "options": { + "show_links_on_grid_card": { + "heading": "Visa länkar på stjärnors kort" + } + } } }, "advanced_mode": "Avancerat Läge" @@ -907,7 +929,6 @@ "destination": "Mål", "source": "Källa" }, - "overwrite_filter_confirm": "Är du säker på att du vill skriva över existerande sökning {entityName}?", "performers_found": "{count} stjärnor hittade", "reassign_entity_title": "{count, plural, one {Omplacera {singularEntity}} other {Omplacera {pluralEntity}}}", "reassign_files": { @@ -960,7 +981,9 @@ "set_image_url_title": "URL till bild", "unsaved_changes": "Osparade ändringar. Är du säker att du vill lämna?", "clear_o_history_confirm": "Är du säker på att du vill radera O-historiken?", - "clear_play_history_confirm": "Är du säker på att du vill radera uppspelningshistoriken?" + "clear_play_history_confirm": "Är du säker på att du vill radera uppspelningshistoriken?", + "overwrite_filter_warning": "Sparat filter \"{entityName}\" kommer skrivas över.", + "set_default_filter_confirm": "Är du säker att du vill ställa in detta filter som standard?" }, "dimensions": "Mått", "director": "Regissör", @@ -970,7 +993,8 @@ "list": "Lista", "tagger": "Taggaren", "unknown": "Okänd", - "wall": "Vägg" + "wall": "Vägg", + "label_current": "Visningsläge: {current}" }, "donate": "Donera", "dupe_check": { @@ -1083,8 +1107,8 @@ "syncing": "Synkar med server", "uploading": "Laddar upp skript" }, - "hasChapters": "Har Kapitel", - "hasMarkers": "Har Markörer", + "hasChapters": "Kapitel", + "hasMarkers": "Markörer", "height": "Längd", "height_cm": "Längd (cm)", "help": "Hjälp", @@ -1118,7 +1142,7 @@ "interactive_speed": "Interaktiv Hastighet", "performer_card": { "age": "{age} {years_old}", - "age_context": "{age} {years_old} i den här scenen" + "age_context": "{age} {years_old} vid produktion" }, "phash": "PHash", "play_count": "Visningar", @@ -1132,7 +1156,6 @@ "name": "Namn", "new": "Ny", "none": "Ingen", - "o_counter": "O-räknare", "operations": "Operationer", "organized": "Organiserad", "pagination": { @@ -1222,7 +1245,9 @@ "edit_filter": "Ändra Filter", "name": "Filter", "saved_filters": "Sparade filter", - "update_filter": "Uppdatera filter" + "update_filter": "Uppdatera filter", + "more_filter_criteria": "+{count} fler", + "search_term": "Sökterm" }, "second": "Sekund", "seconds": "Sekunder", @@ -1516,8 +1541,19 @@ "custom_fields": { "field": "Fält", "title": "Skäddarsydda Fält", - "value": "Värde" + "value": "Värde", + "criteria_format_string": "{criterion} (eget fält) {modifierString} {valueString}", + "criteria_format_string_others": "{criterion} (eget fält) {modifierString} {valueString} (+{others} andra)" }, "eta": "Uppskattad återstående tid", - "sort_name": "Sorteringsnamn" + "sort_name": "Sorteringsnamn", + "login": { + "username": "Användarnamn", + "password": "Lösenord", + "internal_error": "Oväntad internt fel. Se loggen för mer information", + "login": "Inlogg", + "invalid_credentials": "Ogiltigt användarnamn eller lösenord" + }, + "age_on_date": "{age} vid produktion", + "scenes_duration": "Scen Speltid" } diff --git a/ui/v2.5/src/locales/th-TH.json b/ui/v2.5/src/locales/th-TH.json index 0376e880d..9467a0832 100644 --- a/ui/v2.5/src/locales/th-TH.json +++ b/ui/v2.5/src/locales/th-TH.json @@ -1078,7 +1078,6 @@ "destination": "ปลายทาง", "source": "ต้นทาง" }, - "overwrite_filter_confirm": "คุณแน่ใจว่าต้องการเขียนทับเงื่อนไขการค้นหา{entityName}ใช่หรือไม่?", "reassign_files": { "destination": "ย้ายไปที่" }, @@ -1303,7 +1302,6 @@ "name": "ชื่อเรื่อง", "new": "เพิ่ม", "none": "ไม่มี", - "o_counter": "O-Counter", "o_history": "ประวัติ O", "organized": "จัดระเบียบแล้ว", "disambiguation": "แก้ความกำกวม", diff --git a/ui/v2.5/src/locales/tr-TR.json b/ui/v2.5/src/locales/tr-TR.json index 8bd6f874c..d220e4f6e 100644 --- a/ui/v2.5/src/locales/tr-TR.json +++ b/ui/v2.5/src/locales/tr-TR.json @@ -137,11 +137,24 @@ "assign_stashid_to_parent_studio": "Mevcut ana stüdyoya Stash ID atayın ve üstverileri güncelleyin", "download_anonymised": "Anonim olarak indir", "add_manual_date": "Elle tarih ekle", - "reset_resume_time": "Devam etme süresini sıfırla" + "reset_resume_time": "Devam etme süresini sıfırla", + "split": "Ayır", + "swap": "Değiştir", + "encoding_image": "Resim kodlanıyor…", + "sidebar": { + "close": "Kenar çubuğunu kapat", + "open": "Kenar çubuğunu aç", + "toggle": "Kenar çubuğunu aç/kapat" + }, + "play": "Oynat", + "show_results": "Sonuçları göster", + "show_count_results": "{count} sonucu göster", + "load": "Yükle", + "load_filter": "Filtre yükle" }, "actions_name": "Eylemler", "age": "Yaş", - "aliases": "Takma isimler", + "aliases": "Diğer Adlar", "all": "tümü", "also_known_as": "Diğer adıyla", "ascending": "Artan", @@ -152,7 +165,7 @@ "career_length": "Kariyer Uzunluğu", "component_tagger": { "config": { - "active_instance": "Aktif stash-box:", + "active_instance": "Aktif stash-box oturumu:", "blacklist_desc": "Kara listeye alınan kelimeler sorguya eklenmez. Sözkonusu kelimeler kurallı ifadelerdir (regex) ve büyük-küçük harf ayrımına duyarlı değillerdir. Belirli karakterler ters bölü işaretiyle ayrılmalıdır: {chars_require_escape}", "blacklist_label": "Kara liste", "query_mode_auto": "Otomatik", @@ -228,7 +241,7 @@ "system": "Sistem", "tasks": "Görevler", "tools": "Araçlar", - "changelog": "Sürüm Notları" + "changelog": "Değişiklik Günlüğü" }, "dlna": { "allow_temp_ip": "{tempIP} IP adresine izin ver", @@ -287,13 +300,13 @@ "create_galleries_from_folders_desc": "Seçili ise resim içeren dizinlerden galeriler oluşturur.", "create_galleries_from_folders_label": "Resim içeren dizinlerden galeri oluştur", "db_path_head": "Veritabanı Yolu", - "directory_locations_to_your_content": "İçeriğiniz için dizin lokasyonları", + "directory_locations_to_your_content": "İçeriğiniz için dizin konumları", "excluded_image_gallery_patterns_desc": "Tarama ve Temizleme işlemine eklenmeyecek Resim ve Galeri dosyaları/dosya konumları için kurallı ifadeler (Regexp)", "excluded_image_gallery_patterns_head": "Dışta tutulan Resim/Galeri Kuralları", "excluded_video_patterns_desc": "Tarama ve Temizleme işlemine eklenmeyecek Video dosyaları/dosya konumları için kurallı ifadeler (Regexp)", "excluded_video_patterns_head": "Dışta tutulan Video Kuralları", "gallery_ext_desc": "Galeri ZIP dosyaları olarak tanımlanacak dosya uzantıları listesi (virgülle ayrılmış).", - "gallery_ext_head": "Galeri ZIP dosya Uzantıları", + "gallery_ext_head": "Galeri ZIP Uzantıları", "generated_file_naming_hash_desc": "Oluşturulacak dosya isimleri için MD5 veya oshash kullanın. Bu değeri değiştirmek, tüm sahneler için MD5/oshash hesaplaması gerektirir. Bu değeri değiştirdikten sonra mevcut tüm ek dosyalar yeniden oluşturulacak veya yer değiştirecektir. Yer değiştirme işlemleri için Görevler sayfasını ziyaret edin.", "generated_file_naming_hash_head": "Oluşturulan dosya adı imzası", "generated_files_location": "Oluşturulan ek dosyalar için dizin konumu (yer işaretleri, sahne önizlemeler, küçük resimler vb.)", @@ -323,7 +336,7 @@ "heading": "Veri Toplayıcı Yolu" }, "scraping": "Veri Toplama", - "sqlite_location": "SQLite veritabanı için dizin konumu (değiştirirseniz yeniden başlatma gerekir)", + "sqlite_location": "SQLite veritabanı için dosya konumu (yeniden başlatma gerektirir). UYARI: Veritabanını, Stash sunucusunun çalıştığı sistemden farklı bir sistemde (yani ağ üzerinden) depolamak desteklenmemektedir!", "video_ext_desc": "Video olarak işlem görecek dosya uzantı listesi (virgülle ayrılmış).", "video_ext_head": "Video Uzantıları", "video_head": "Video", @@ -386,12 +399,14 @@ "python_path": { "heading": "Python Yürütülebilir Yolu", "description": "Python yürütülebilir dosyasının yolu (yalnızca klasörün değil). Komut dosyası veri kazıyıcılar ve eklentiler için kullanılır. Boşsa, python ortamdan çözümlenecektir" - } + }, + "heatmap_generation": "Funscript Isı Haritası Oluşturma", + "funscript_heatmap_draw_range_desc": "Oluşturulan ısı haritasının y ekseninde hareket aralığını çizin. Değişiklik yapıldıktan sonra mevcut ısı haritalarının yeniden oluşturulması gerekecektir." }, "library": { "exclusions": "Dışta Tutulanlar", "gallery_and_image_options": "Galeri ve Resim seçenekleri", - "media_content_extensions": "Medya içerik uzantıları" + "media_content_extensions": "Medya İçeriği Uzantıları" }, "logs": { "log_level": "Kayıt Tutma Seviyesi" @@ -422,7 +437,9 @@ "endpoint": "Bağlantı Noktası", "graphql_endpoint": "GraphQL bağlantı noktası", "name": "Ad", - "title": "Stash-box Bağlantı Noktaları" + "title": "Stash-box Bağlantı Noktaları", + "max_requests_per_minute": "Dakika başına maksimum istek", + "max_requests_per_minute_description": "0 olarak ayarlanırsa, varsayılan değer olan {defaultValue} kullanılır" }, "system": { "transcoding": "Video Dönüştürme" @@ -515,7 +532,8 @@ "anonymise_and_download": "Veritabanının anonimleştirilmiş bir kopyasını oluşturur ve elde edilen dosyayı indirir.", "anonymise_database": "Tüm hassas verileri anonimleştirerek veritabanının bir kopyasını yedekler dizinine alır. Bu daha sonra sorun giderme ve hata ayıklama amacıyla başkalarına sağlanabilir. Orijinal veritabanı değiştirilmez. Anonimleştirilmiş veritabanı {filename_format} dosya adı biçimini kullanır.", "migrate_scene_screenshots": { - "delete_files": "Ekran görüntülerini sil" + "delete_files": "Ekran görüntülerini sil", + "overwrite_existing": "Mevcut blob'ları ekran görüntüsü verileriyle üzerine yaz" }, "rescan_tooltip": "Yoldaki her dosyayı yeniden tarayın. Dosya üstverilerini güncellemeyi zorlamak ve zip dosyalarını yeniden taramak için kullanılır.", "generate_clip_previews_during_scan": "Resim klipleri için önizlemeler oluştur" @@ -537,7 +555,9 @@ "whitespace_chars": "Boşluk karakterleri", "whitespace_chars_desc": "Bu karakterler başlıkta boşluk karakteri ile değiştirilecektir" }, - "scene_tools": "Sahne Araçları" + "scene_tools": "Sahne Araçları", + "graphql_playground": "GraphQL oyun alanı", + "heading": "Araçlar" }, "ui": { "basic_settings": "Temel Seçenekler", @@ -580,7 +600,7 @@ "half": "Yarım", "quarter": "Çeyrek", "tenth": "Onda bir", - "full": "Dolu" + "full": "Tam" }, "label": "Derecelendirme Yıldızı Hassasiyeti" } @@ -605,7 +625,8 @@ "heading": "Resim önizlemelerini kaydet" }, "create_image_clips_from_videos": { - "heading": "Video Uzantılarını Resim Klibi Olarak Tara" + "heading": "Video Uzantılarını Resim Klibi Olarak Tara", + "description": "Bir kütüphanede videolar devre dışı bırakıldığında, video dosyaları (video uzantısı ile biten dosyalar) Resim Klibi olarak taranacaktır." } } }, @@ -618,7 +639,7 @@ "heading": "Maksimum döngü süresi" }, "menu_items": { - "description": "Gezinti çubuğunda farklı türdeki içerikleri göster veya gizle", + "description": "Gezinti çubuğunda farklı içerik türlerini göster veya gizle", "heading": "Menü Öğeleri" }, "performers": { @@ -645,7 +666,7 @@ } }, "scene_player": { - "heading": "Sahne Oynatıcısı", + "heading": "Sahne Oynatıcı", "options": { "auto_start_video": "Videoları otomatik başlat", "auto_start_video_on_play_selected": { @@ -664,7 +685,9 @@ "track_activity": "Sahne Oynatma Geçmişi'ni etkinleştir", "enable_chromecast": "Chromecast'i Etkinleştir", "show_ab_loop_controls": "AB Loop eklenti kontrollerini göster", - "show_scrubber": "Video İlerleme Çubuğunu Göster" + "show_scrubber": "Video İlerleme Çubuğunu Göster", + "disable_mobile_media_auto_rotate": "Mobil cihazlarda tam ekran medyanın otomatik döndürülmesini devre dışı bırak", + "show_range_markers": "Zaman İşaretleyicilerini Göster" } }, "scene_wall": { @@ -688,6 +711,10 @@ "show_all_details": { "heading": "Tüm ayrıntıları göster", "description": "Etkinleştirildiğinde, varsayılan olarak tüm içerik ayrıntıları gösterilecek ve her ayrıntı öğesi tek bir sütuna sığacak" + }, + "compact_expanded_details": { + "heading": "Kompakt genişletilmiş ayrıntılar", + "description": "Bu seçenek etkinleştirildiğinde, kompakt görünüm korunurken genişletilmiş ayrıntılar gösterilir" } }, "custom_javascript": { @@ -696,12 +723,12 @@ "description": "Değişikliklerin etkili olması için sayfanın yeniden yüklenmesi gerekir. Özel Javascript ile Stash'in gelecekteki sürümleri arasında uyumluluk garantisi yoktur." }, "custom_locales": { - "heading": "Özel yerelleştirme", + "heading": "Özel Yerelleştirme", "option_label": "Özel yerelleştirme etkin", "description": "Bireysel yerel ayar dizelerini geçersiz kılın. Ana liste için https://github.com/stashapp/stash/blob/develop/ui/v2.5/src/locales/en-GB.json adresine bakın. Değişikliklerin etkili olması için sayfanın yeniden yüklenmesi gerekir." }, "studio_panel": { - "heading": "Stüdyo görünümü", + "heading": "Stüdyo Görünümü", "options": { "show_child_studio_content": { "heading": "Alt stüdyo içeriğini görüntüle", @@ -716,7 +743,7 @@ "description": "Etiket görünümündeyken alt etiketlerdeki içeriği de görüntüleyin" } }, - "heading": "Etiket görünümü" + "heading": "Etiket Görünümü" }, "abbreviate_counters": { "heading": "Sayaçları kısalt", @@ -735,10 +762,20 @@ "connect": "Bağlan", "status": { "heading": "Handy Bağlantı Durumu" - } + }, + "server_offset": { + "heading": "Sunucu Zaman Farkı" + }, + "sync": "Senkronize et" }, "use_stash_hosted_funscript": { "heading": "Funscript'leri doğrudan sun" + }, + "show_tag_card_on_hover": { + "heading": "Etiket kartı araç ipuçları" + }, + "scroll_attempts_before_change": { + "heading": "Geçiş Öncesi Kaydırma Denemeleri" } }, "advanced_mode": "Gelişmiş Mod" @@ -829,7 +866,6 @@ "destination": "Hedef Noktası", "source": "Kaynak" }, - "overwrite_filter_confirm": "Kayıtlı {entityName} sorgusunun üzerine yazmak istediğinizden emin misiniz?", "scene_gen": { "force_transcodes": "Dönüştürülmüş video oluşturmayı zorla", "force_transcodes_tooltip": "Varsayılan olarak, video yalnızca video dosyası tarayıcı tarafından desteklenmediğinde dönüştürülür. Etkinleştirildiğinde, video dosyası tarayıcı tarafından destekleniyorsa bile video dönüştürülür.", @@ -839,7 +875,7 @@ "marker_image_previews": "İşaretleyici Hareketli Resim Önizlemeleri", "marker_image_previews_tooltip": "Hareketli Yer İmi WebP önizlemeleri, Önizleme Türü sadece Hareketli Resim olarak seçilmişse gereklidir.", "marker_screenshots": "İşaretleyici Ekran Görüntüleri", - "marker_screenshots_tooltip": "Yer İmi hareketsiz JPG resimleri, Önizleme Türü sadece Hareketsiz Resim olarak seçilmişse gereklidir.", + "marker_screenshots_tooltip": "Yer İmi hareketsiz JPG resimleri", "markers": "İşaretleyici Önizlemeleri", "markers_tooltip": "Belirlenen zamandan itibaren başlayan 20 saniyelik videolar.", "overwrite": "Varolan oluşturulmuş dosyaların üzerine yaz", @@ -877,7 +913,9 @@ "unsaved_changes": "Değişiklikler kaydedilmedi. Sayfadan ayrılmak istediğinize emin misiniz?", "clear_play_history_confirm": "Oynatma geçmişini temizlemek istediğinize emin misiniz?", "merge": { - "source": "Kaynak" + "source": "Kaynak", + "destination": "Hedef", + "empty_results": "Hedef alan değerleri değişmeyecektir." }, "dont_show_until_updated": "Sonraki güncellemeye kadar gösterme", "clear_o_history_confirm": "O geçmişini temizlemek istediğinize emin misiniz?", @@ -894,7 +932,8 @@ "reassign_files": { "destination": "Şuraya yeniden ata" }, - "reassign_entity_title": "{count, plural, one {Yeniden ata {singularEntity}} other {Yeniden ata {pluralEntity}}}" + "reassign_entity_title": "{count, plural, one {Yeniden ata {singularEntity}} other {Yeniden ata {pluralEntity}}}", + "set_default_filter_confirm": "Bu filtreyi varsayılan olarak ayarlamak istediğinize emin misiniz?" }, "dimensions": "Boyutlar", "director": "Yönetmen", @@ -903,7 +942,8 @@ "list": "Liste", "tagger": "Etiketleyici", "unknown": "Bilinmeyen", - "wall": "Duvar" + "wall": "Duvar", + "label_current": "Görüntüleme Modu: {current}" }, "donate": "Bağış Yap", "dupe_check": { @@ -918,7 +958,8 @@ "search_accuracy_label": "Arama Kesinliği", "title": "Yinelenen Sahneler", "duration_options": { - "equal": "Eşit" + "equal": "Eşit", + "any": "Herhangi" }, "duration_diff": "Maksimum Süre Farkı", "select_all_but_largest_file": "En büyük dosya hariç, yinelenen her gruptaki her dosyayı seç", @@ -981,11 +1022,12 @@ "include_sub_tags": "Alt etiketleri dahil et", "instagram": "Instagram", "interactive": "Etkileşimli", - "interactive_speed": "Etkileşim hızı", + "interactive_speed": "Etkileşimli Hız", "isMissing": "Eksik", "library": "Kütüphane", "loading": { - "generic": "Yükleniyor…" + "generic": "Yükleniyor…", + "plugins": "Eklentiler yükleniyor…" }, "marker_count": "İşaretleyici Sayısı", "markers": "İşaretleyiciler", @@ -995,7 +1037,7 @@ "checksum": "Sağlama Toplamı (checksum)", "downloaded_from": "İndirildiği Yer", "hash": "Dosya İmzası (Hash)", - "interactive_speed": "Etkileşim hızı", + "interactive_speed": "Etkileşimli Hız", "performer_card": { "age": "{age} {years_old}", "age_context": "Bu sahnede {age} {years_old}" @@ -1012,7 +1054,6 @@ "name": "Ad", "new": "Yeni", "none": "Hiçbiri", - "o_counter": "O-Sayacı", "operations": "İşlemler", "organized": "Düzenlendi", "pagination": { @@ -1049,7 +1090,8 @@ "name": "Filtre", "saved_filters": "Kaydedilmiş filtreler", "update_filter": "Filtreyi Güncelle", - "edit_filter": "Filtreyi Düzenle" + "edit_filter": "Filtreyi Düzenle", + "search_term": "Arama terimi" }, "seconds": "Saniye", "settings": "Ayarlar", @@ -1094,7 +1136,7 @@ }, "paths": { "database_filename_empty_for_default": "veritabanı adı (varsayılan için boş bırakın)", - "description": "Sırada porno koleksiyonunuzun hangi dizinde olduğunun, stash veritabanının ve oluşturulan ek dosyaların nereye kaydedileceğinin belirlenmesi var. Bu ayarları sonradan değiştirebilirsiniz.", + "description": "Sırada, porno koleksiyonunuzun nerede bulunacağını ve Stash veritabanının, oluşturulan dosyaların ve önbellek dosyalarının nerede depolanacağını belirlememiz gerekiyor. Bu ayarlar daha sonra gerekirse değiştirilebilir.", "path_to_generated_directory_empty_for_default": "oluşturulan ek dosyalar için dizin konumu (varsayılan için boş bırakın)", "set_up_your_paths": "Yollarınızı ayarlayın", "stash_alert": "Herhangi bir kütüphane konumu seçilmedi. Hiçbir medya Stash'e taranamayacak. Emin misiniz?", @@ -1109,7 +1151,8 @@ "path_to_cache_directory_empty_for_default": "önbellek dizini yolu (varsayılan için boş bırakın)", "store_blobs_in_database": "Blob'ları veritabanında depola", "path_to_blobs_directory_empty_for_default": "blobs dizini yolu (varsayılan için boş bırakın)", - "where_can_stash_store_cache_files_description": "Stash, HLS/DASH canlı video dönüştürme gibi bazı işlevlerin çalışabilmesi için geçici dosyalara yönelik bir önbellek dizini gerektirir. Varsayılan olarak, Stash yapılandırma dosyanızı içeren dizin içinde bir cache dizini oluşturacaktır. Bunu değiştirmek istiyorsanız, lütfen mutlak veya göreceli (geçerli çalışma dizinine) bir yol girin. Mevcut değilse, Stash bu dizini oluşturacaktır." + "where_can_stash_store_cache_files_description": "Stash, HLS/DASH canlı video dönüştürme gibi bazı işlevlerin çalışabilmesi için geçici dosyalara yönelik bir önbellek dizini gerektirir. Varsayılan olarak, Stash yapılandırma dosyanızı içeren dizin içinde bir cache dizini oluşturacaktır. Bunu değiştirmek istiyorsanız, lütfen mutlak veya göreceli (geçerli çalışma dizinine) bir yol girin. Mevcut değilse, Stash bu dizini oluşturacaktır.", + "where_can_stash_store_blobs_description_addendum": "Alternatif olarak bu verileri veritabanında saklayabilirsiniz. Not:Bu işlem veritabanınızın boyutunu artıracak ve veritabanı taşıma süresini uzatacaktır." }, "stash_setup_wizard": "Stash Kurulum Sihirbazı", "success": { @@ -1129,11 +1172,12 @@ "welcome": { "config_path_logic_explained": "Stash (config.yml) yapılandırma dosyasını ilk olarak mevcut dizinde bulmaya çalışır. Eğer bulamazsa, $HOME/.stash/config.yml dizinini (Windows işletim sistemi için %USERPROFILE%\\.stash\\config.yml dizini) araştırır. Öte yandan -c '' veya --config '' seçeneklerini kullanarak özelleştirilmiş bir yapılandırma dosyası da kullanabilirsiniz.", "in_current_stash_directory": "{path} yolunda:", - "in_the_current_working_directory": "Mevcut dizinde", + "in_the_current_working_directory": "", "next_step": "Eğer yeni bir sistem oluşturmak için hazırsanız, yapılandırma dosyasının nereye kaydedileceğini seçin ve Sonraki düğmesine basın.", "store_stash_config": "Stash yapılandırmasını nereye kaydetmek istiyorsunuz?", "unable_to_locate_config": "Eğer bunu okuyorsanız, Stash herhangi bir mevcut yapılandırma bulamamış demektir. Bu sihirbaz yeni bir yapılandırma sırasında size yol gösterecektir.", - "unexpected_explained": "Eğer beklenmedik bir şekilde bu ekranı gördüyseniz, Stash uygulamasını doğru dizinden başlatın veya başlatma komutuna -c değişkenini ekleyin." + "unexpected_explained": "Eğer beklenmedik bir şekilde bu ekranı gördüyseniz, Stash uygulamasını doğru dizinden başlatın veya başlatma komutuna -c değişkenini ekleyin.", + "in_the_current_working_directory_disabled": "{path} yolundaki çalışma dizini:" }, "welcome_specific_config": { "config_path": "Stash, yapılandırma dosyası için bu dizini kullanacak: {path}", @@ -1142,7 +1186,7 @@ }, "welcome_to_stash": "Stash uygulamasına hoşgeldiniz" }, - "stash_id": "Stash Kimliği (ID)", + "stash_id": "Stash Kimliği", "stash_ids": "Stash Kimliği", "stats": { "image_size": "Toplam resim boyutu", @@ -1182,7 +1226,8 @@ "started_importing": "İçe aktarma başladı", "updated_entity": "{entity} güncellendi", "merged_scenes": "Birleştirilmiş sahneler", - "reassign_past_tense": "Dosya yeniden atandı" + "reassign_past_tense": "Dosya yeniden atandı", + "removed_entity": "{count, plural, one {{singularEntity}} other {{pluralEntity}}} kaldırıldı" }, "total": "Toplam", "true": "Doğru", @@ -1207,7 +1252,9 @@ "edit_excluded_fields": "Hariç Tutulan Alanları Düzenle", "no_fields_are_excluded": "Hiçbir alan hariç tutulmadı", "create_parent_label": "Ana stüdyo oluştur", - "these_fields_will_not_be_changed_when_updating_studios": "Stüdyolar güncellenirken bu alanlar değişmeyecektir." + "these_fields_will_not_be_changed_when_updating_studios": "Stüdyolar güncellenirken bu alanlar değişmeyecektir.", + "active_stash-box_instance": "Aktif stash-box oturumu:", + "no_instances_found": "Oturum bulunamadı" }, "batch_update_studios": "Stüdyoları Toplu Güncelle", "failed_to_save_studio": "Stüdyo kaydedilemedi \"{studio}\"", @@ -1227,7 +1274,12 @@ "tag_status": "Etiket Durumu", "untagged_studios": "Etiketlenmemiş stüdyolar", "updating_untagged_studios_description": "Etiketlenmemiş stüdyoları güncellemek, stashid'si olmayan tüm stüdyoları eşleştirmeye ve üstverileri güncellemeye çalışacaktır.", - "name_already_exists": "Ad zaten mevcut" + "name_already_exists": "Ad zaten mevcut", + "status_tagging_job_queued": "Durum: Etiketleme işi sıraya alındı", + "any_names_entered_will_be_queried": "Girilen tüm isimler karşıdaki Stash-Box oturumundan sorgulanacak ve bulunursa eklenecektir. Yalnızca tam eşleşmeler bir eşleşme olarak kabul edilecektir.", + "refreshing_will_update_the_data": "Yenileme işlemi stash-box oturumundaki tüm etiketli stüdyoların verilerini güncelleyecektir.", + "to_use_the_studio_tagger": "Stüdyo etiketleyiciyi kullanmak için bir stash-box oturumunun yapılandırılması gerekir.", + "studio_names_separated_by_comma": "Virgülle ayrılmış stüdyo adları" }, "blobs_storage_type": { "database": "Veritabanı", @@ -1261,7 +1313,8 @@ "update": "Güncelle", "version": "Sürüm", "confirm_delete_source": "Kaynağı silmek istediğinize emin misiniz {name} ({url})?", - "required_by": "{packages} için gerekli" + "required_by": "{packages} için gerekli", + "confirm_uninstall": "{number} paketi kaldırmak istediğinize emin misiniz?" }, "penis": "Penis", "penis_length": "Penis Uzunluğu", @@ -1272,7 +1325,9 @@ "excluded_fields": "Hariç tutulan alanlar:", "edit_excluded_fields": "Hariç Tutulan Alanları Düzenle", "no_fields_are_excluded": "Hiçbir alan hariç tutulmadı", - "these_fields_will_not_be_changed_when_updating_performers": "Oyuncular güncellenirken bu alanlar değiştirilmeyecektir." + "these_fields_will_not_be_changed_when_updating_performers": "Oyuncular güncellenirken bu alanlar değiştirilmeyecektir.", + "active_stash-box_instance": "Aktif stash-box oturumu:", + "no_instances_found": "Oturum bulunamadı" }, "current_page": "Geçerli sayfa", "network_error": "Ağ Hatası", @@ -1294,7 +1349,9 @@ "updating_untagged_performers_description": "Etiketlenmemiş oyuncuları güncellemek, stashid'si olmayan tüm oyuncuları eşleştirmeye ve üstverileri güncellemeye çalışacaktır.", "add_new_performers": "Yeni Oyuncular Ekle", "refresh_tagged_performers": "Etiketlenmiş oyuncuları yenile", - "performer_already_tagged": "Oyuncu zaten etikelenmiş" + "performer_already_tagged": "Oyuncu zaten etikelenmiş", + "any_names_entered_will_be_queried": "Girilen tüm isimler karşıdaki Stash-Box oturumundan sorgulanacak ve bulunursa eklenecektir. Yalnızca tam eşleşmeler bir eşleşme olarak kabul edilecektir.", + "refreshing_will_update_the_data": "Yenileme işlemi stash-box oturumundaki tüm etiketli oyuncuların verisini güncelleyecektir." }, "photographer": "Fotoğrafçı", "play_count": "Oynatma Sayısı", @@ -1330,7 +1387,13 @@ "loading_type": "{type} yüklenirken hata oluştu", "something_went_wrong": "Bir şeyler ters gitti.", "lazy_component_error_help": "Stash'i yakın zamanda güncellediyseniz, lütfen sayfayı yeniden yükleyin ya da tarayıcınızın önbelleğini temizleyin.", - "invalid_json_string": "Geçersiz JSON dizesi: {error}" + "invalid_json_string": "Geçersiz JSON dizesi: {error}", + "custom_fields": { + "duplicate_field": "Alan adı benzersiz olmalıdır", + "field_name_required": "Alan adı gereklidir", + "field_name_whitespace": "Alan adının başında veya sonunda boşluk bulunamaz", + "field_name_length": "Alan adı 65 karakterden az olmalıdır" + } }, "sub_group_order": "Alt Grup Sırası", "validation": { @@ -1358,7 +1421,8 @@ "disconnected": "Bağlantı kesildi", "error": "Handy'e bağlanırken hata oluştu", "ready": "Hazır", - "uploading": "Komut dosyası yükleniyor" + "uploading": "Komut dosyası yükleniyor", + "syncing": "Sunucu ile senkronize ediliyor" }, "o_count": "O Sayısı", "o_history": "O Geçmişi", @@ -1381,7 +1445,9 @@ "zip_file_count": "Zip Dosyası Sayısı", "last_played_at": "Son Oynatma Tarihi", "criterion_modifier_values": { - "only": "Sadece" + "only": "Sadece", + "none": "Hiçbiri", + "any_of": "Herhangi biri" }, "history": "Geçmiş", "existing_value": "mevcut değer", @@ -1418,6 +1484,20 @@ "sub_group_of": "{parent} öğesinin alt grubu", "time_end": "Bitiş Zamanı", "custom_fields": { - "value": "Değer" - } + "value": "Değer", + "field": "Alan", + "title": "Özel Alanlar", + "criteria_format_string": "{criterion} (özel alan) {modifierString} {valueString}" + }, + "eta": "Tahmini Kalan Süre", + "login": { + "password": "Şifre", + "internal_error": "Beklenmeyen dahili hata. Daha fazla ayrıntı için günlüklere bakın", + "login": "Giriş Yap", + "username": "Kullanıcı Adı", + "invalid_credentials": "Geçersiz kullanıcı adı veya şifre" + }, + "age_on_date": "Videoda {age} yaşında", + "time": "Başlangıç Zamanı", + "disambiguation": "Ad Ayrımı" } diff --git a/ui/v2.5/src/locales/uk-UA.json b/ui/v2.5/src/locales/uk-UA.json index bbf0e426f..3ecac7c2e 100644 --- a/ui/v2.5/src/locales/uk-UA.json +++ b/ui/v2.5/src/locales/uk-UA.json @@ -141,7 +141,17 @@ "copy_to_clipboard": "Копіювати до буфера обміну", "set_back_image": "Зворотне зображення…", "set_front_image": "Переднє зображення…", - "unset": "Скинути" + "unset": "Скинути", + "load": "Завантажити", + "load_filter": "Завантажити фільтр", + "play": "Відтворити", + "show_results": "Висвітити вислід", + "show_count_results": "Висвітити {count} висліди", + "sidebar": { + "close": "Сховати бічну панель", + "open": "Розгорнути бічну панель", + "toggle": "Перемикнути бічну панель" + } }, "actions_name": "Дії", "age": "Вік", @@ -520,7 +530,9 @@ "title": "Парсер Імені Файлу Сцени" }, "scene_tools": "Інструменти Сцени", - "scene_duplicate_checker": "Перевірка сцен на дублікати" + "scene_duplicate_checker": "Перевірка сцен на дублікати", + "graphql_playground": "GraphQL ігровий майданчик", + "heading": "Начиння" }, "ui": { "scene_player": { @@ -543,7 +555,8 @@ "enable_chromecast": "Увімкнути Chromecast", "show_scrubber": "Показати скруббер", "track_activity": "Увімкнути історію відтворення сцен", - "auto_start_video": "Автозапуск відео" + "auto_start_video": "Автозапуск відео", + "show_range_markers": "Виявити Позначки Охоплення" }, "heading": "Плеєр сцени" }, @@ -697,7 +710,8 @@ "description": "За замовчуванням використовуються відео-прев’ю (mp4). Для меншого навантаження на CPU під час перегляду можна використовувати анімовані зображення (webp) як прев’ю. Однак їх потрібно генерувати додатково до відео-прев’ю, і вони займають більше місця на диску.", "options": { "animated": "Анімоване зображення", - "static": "Статичне зображення" + "static": "Статичне зображення", + "video": "Відео" }, "heading": "Тип попереднього перегляду" }, @@ -743,7 +757,15 @@ "toggle_sound": "Увімкнути звук" } }, - "title": "Користувацький інтерфейс" + "title": "Користувацький інтерфейс", + "performer_list": { + "heading": "Перелік виконавців", + "options": { + "show_links_on_grid_card": { + "heading": "Відображати посилання на картки виконавців" + } + } + } }, "plugins": { "hooks": "Хуки", @@ -774,7 +796,9 @@ "endpoint": "Кінцева точка", "name": "Назва", "graphql_endpoint": "Кінцева точка GraphQL", - "api_key": "API ключ" + "api_key": "API ключ", + "max_requests_per_minute": "Макс запитів у хвилину", + "max_requests_per_minute_description": "Викорситовує значення за замовчуванням {defaultValue} якщо встановлено в 0" }, "system": { "transcoding": "Транскодування" @@ -992,7 +1016,6 @@ "generic": "Завантаження…", "plugins": "Завантаження плагінів…" }, - "o_counter": "O-Лічильник", "performer_tagger": { "status_tagging_job_queued": "Статус: Задача проставлення міток в черзі", "number_of_performers_will_be_processed": "Будуть оброблені {performer_count} виконавців", @@ -1061,7 +1084,6 @@ "synopsis": "Синопсис", "dialogs": { "delete_gallery_files": "Видалити папку галереї/zip-файл та всі зображення, які не прив'язані до жодної іншої галереї.", - "overwrite_filter_confirm": "Ви впевнені, що хочете перезаписати існуючий збережений запит {entityName}?", "scene_gen": { "marker_image_previews_tooltip": "Також створюйте анімовані (webp) прев’ю, які необхідні лише тоді, коли тип прев’ю для стіни сцен/маркерів встановлено на Анімоване зображення. Під час перегляду вони споживають менше ресурсів CPU, ніж відео-прев’ю, але генеруються додатково до них і займають більше місця на диску.", "transcodes_tooltip": "MP4-транскоди будуть попередньо згенеровані для всього контенту; корисно для повільних процесорів, але вимагає набагато більше дискового простору", @@ -1275,7 +1297,12 @@ "not_equals": "не є", "greater_than": "більше ніж", "includes_all": "включає все", - "is_null": "є null" + "is_null": "є null", + "between": "поміж", + "excludes": "виключення", + "format_string_excludes": "{criterion} {modifierString} {valueString} (за виключенням {excludedString})", + "format_string_excludes_depth": "{criterion} {modifierString} {valueString} (за виключенням {excludedString}) (+{глибина, множина, =-1 {all} інші {{depth}}})", + "includes": "включно" }, "toast": { "rescanning_entity": "Повторне сканування {count, plural, one {{singularEntity}} other {{pluralEntity}}}…", @@ -1322,7 +1349,8 @@ "created_at": "Створено", "criterion": { "greater_than": "Більше ніж", - "less_than": "Менше ніж" + "less_than": "Менше ніж", + "value": "Значення" }, "containing_group": "Група, що містить", "cover_image": "Обкладинка зображення", @@ -1330,7 +1358,8 @@ "custom_fields": { "title": "Користувацькі поля", "field": "Поле", - "value": "Значення" + "value": "Значення", + "criteria_format_string": "{criterion} (своє поле) {modifierString} {valueString}" }, "death_date": "Дата смерті", "developmentVersion": "Розробницька версія", @@ -1417,5 +1446,8 @@ "plays": "{value} відтворень", "subsidiary_studios": "Дочірні студії", "subsidiary_studio_count": "Кількість дочірніх студій", - "age_on_date": "{age} років під час зйомок" + "age_on_date": "{age} років під час зйомок", + "configuration": "Обрис", + "country": "Країна", + "custom": "Свій" } diff --git a/ui/v2.5/src/locales/ur-PK.json b/ui/v2.5/src/locales/ur-PK.json new file mode 100644 index 000000000..9558feeaa --- /dev/null +++ b/ui/v2.5/src/locales/ur-PK.json @@ -0,0 +1,14 @@ +{ + "actions": { + "add": "شامل کریں", + "allow": "اجازت دیں", + "add_directory": "ڈکشنری میں شامل کریں", + "cancel": "منسوخ کریں", + "add_manual_date": "تاریخ شامل کریں", + "add_o": "مٹھ کی گنتئ بڑہاین", + "add_play": "پلۓ شامل کریں", + "allow_temporarily": "وقتئ اجازت دیں", + "anonymise": "بےنام کریں", + "apply": "لاگو کریں" + } +} diff --git a/ui/v2.5/src/locales/vi-VN.json b/ui/v2.5/src/locales/vi-VN.json index 72749ca64..25da90f0e 100644 --- a/ui/v2.5/src/locales/vi-VN.json +++ b/ui/v2.5/src/locales/vi-VN.json @@ -134,14 +134,24 @@ "clean_confirm_message": "Bạn có chắc chắn muốn làm sạch không? Thao tác này sẽ xóa thông tin cơ sở dữ liệu và nội dung đã tạo cho tất cả các cảnh và bộ sưu tập không còn tồn tại trong hệ thống tệp.", "import_warning": "Bạn có chắc chắn muốn nhập không? Thao tác này sẽ xóa cơ sở dữ liệu và nhập lại từ siêu dữ liệu đã xuất của bạn." }, - "temp_disable": "Tạm thời vô hiệu hóa…", - "temp_enable": "Tạm thời kích hoạt…", + "temp_disable": "Vô hiệu hóa tạm thời…", + "temp_enable": "Kích hoạt tạm thời…", "unset": "Bỏ thiết lập", - "use_default": "Dùng mặc định", + "use_default": "Dùng thiết lập mặc định", "view_history": "Xem lịch sử", "view_random": "Xem ngẫu nhiên", "set_front_image": "Ảnh trước…", - "select_entity": "Chọn {entityType}" + "select_entity": "Chọn {entityType}", + "play": "Phát", + "show_results": "Hiển thị kết quả", + "show_count_results": "Hiển thị {count} kết quả", + "sidebar": { + "toggle": "Bật thanh bên", + "open": "Mở thanh bên", + "close": "Đóng thanh bên" + }, + "load": "Nạp", + "load_filter": "Nạp bộ lọc" }, "actions_name": "Hành động", "age": "Tuổi", @@ -158,25 +168,886 @@ "bitrate": "Bit Rate", "blobs_storage_type": { "database": "Cơ sở dữ liệu", - "filesystem": "Files hệ thống" + "filesystem": "Tập tin hệ thống" }, "captions": "Tiêu đề", "career_length": "Tuổi nghề", - "chapters": "Chapters", + "chapters": "Chương", "circumcised_types": { "CUT": "Cắt", "UNCUT": "Không cắt" }, - "circumcised": "Cắt bao quy đầu", + "circumcised": "Đã cắt bao quy đầu", "component_tagger": { "config": { "blacklist_desc": "Các mục trong danh sách đen sẽ bị loại trừ khỏi các truy vấn. Lưu ý rằng chúng là các biểu thức chính quy và không phân biệt chữ hoa chữ thường. Một số ký tự cần phải được thoát bằng dấu gạch chéo ngược: {chars_require_escape}", "blacklist_label": "Danh sách đen", - "mark_organized_desc": "Ngay lập tức đánh dấu cảnh là Đã tổ chức sau khi nhấn nút Lưu.", + "mark_organized_desc": "Ngay lập tức đánh dấu cảnh là Đã sắp xếp sau khi nhấn nút Lưu.", "active_instance": "Phiên bản stash-box đang hoạt động:", - "mark_organized_label": "Đánh dấu là Đã tổ chức khi lưu.", + "mark_organized_label": "Đánh dấu là Đã sắp xếp khi lưu.", "query_mode_auto": "Tự động", - "query_mode_auto_desc": "Sử dụng siêu dữ liệu nếu có, hoặc tên tệp." + "query_mode_auto_desc": "Sử dụng siêu dữ liệu nếu có, hoặc tên tệp", + "query_mode_filename": "Tên tệp tin", + "query_mode_filename_desc": "Chỉ dùng tên tệp tin", + "query_mode_label": "Chế độ truy vấn", + "query_mode_path": "Đường dẫn", + "query_mode_path_desc": "Dùng toàn bộ đường dẫn tệp tin", + "set_cover_desc": "Thay thế bìa nền nếu đã được tìm thấy.", + "set_cover_label": "Đặt ảnh bìa nền", + "set_tag_label": "Đặt các thẻ", + "query_mode_dir_desc": "Chỉ dùng thư mục chính của file video", + "set_tag_desc": "Đính kèm các thẻ vào cảnh, bằng cách ghi đè hoặc ghép với các thẻ có sẵn trên cảnh.", + "source": "Nguồn", + "errors": { + "blacklist_duplicate": "Các mục bị trùng lặp trong danh sách đen" + }, + "query_mode_dir": "Danh sách", + "show_male_desc": "Chọn khi thẻ của nam diễn viên có sẵn để gán.", + "show_male_label": "Xem danh sách diễn viên nam", + "query_mode_metadata_desc": "Chỉ dùng dữ liệu mô tả", + "query_mode_metadata": "Thông tin mô tả" + }, + "noun_query": "Truy vấn", + "results": { + "duration_unknown": "Thời gian không xác định", + "fp_matches": "Thời lượng tương ứng", + "fp_matches_multi": "Thời lượng khớp {matchCount}/{durationsLength} dấu vân tay", + "hash_matches": "Khớp với {hash_type}", + "match_failed_already_tagged": "Phân cảnh đã được gắn thẻ", + "match_failed_no_result": "Không có kết quả được tìm thấy", + "match_success": "Phân cảnh đã được gán thẻ thành công", + "phash_matches": "Khớp với {count} PHashes", + "duration_off": "Thời gian tắt ít nhất {number} giây", + "fp_found": "{fpCount, plural, =0 {Không có dấu vết trùng khớp mới được tìm thấy} other {# dấu vết trùng khớp mới đã được tìm thấy}}", + "unnamed": "Chưa được đặt tên" + }, + "verb_match_fp": "Các dấu vân tay trùng khớp", + "verb_matched": "Trùng khớp", + "verb_scrape_all": "Loại bỏ tất cả", + "verb_toggle_config": "{toggle} {configuration}", + "verb_toggle_unmatched": "{toggle} phân cảnh không trùng khớp", + "verb_submit_fp": "Gửi {fpCount, plural, one{# Fingerprint} other{# Fingerprint}}" + }, + "config": { + "about": { + "new_version_notice": "[MỚI]", + "build_hash": "Mã băm bản xây dựng:", + "check_for_new_version": "Kiểm tra phiên bản mới", + "latest_version": "Phiên bản mới nhất", + "latest_version_build_hash": "Mã bản dựng mới nhất:", + "release_date": "Ngày phát hành:", + "stash_discord": "Tham gia vào kênh {url} của chúng tôi", + "stash_open_collective": "Giúp đỡ chúng tôi qua {url}", + "version": "Phiên bản", + "build_time": "Thời điểm tạo:", + "stash_wiki": "Trang {url} của Stash", + "stash_home": "Trang chủ Stash tại {url}" + }, + "application_paths": { + "heading": "Đường dẫn tới ứng dụng" + }, + "categories": { + "about": "Về", + "changelog": "Nhật ký thay đổi", + "interface": "Giao diện", + "logs": "Tập nhật ký", + "plugins": "Các phần bổ trợ", + "security": "Bảo mật", + "services": "Các dịch vụ", + "system": "Hệ thống", + "tasks": "Các công việc", + "tools": "Các công cụ", + "metadata_providers": "Các bên cung cấp thông tin dữ liệu", + "scraping": "Đang quét dữ liệu" + }, + "dlna": { + "allow_temp_ip": "Cho phép {tempIP}", + "allowed_ip_addresses": "Các địa chỉ IP được cho phép", + "default_ip_whitelist": "Danh sách các IP mặc định được cho phép", + "disabled_dlna_temporarily": "Vô hiệu DLNA tạm thời", + "disallowed_ip": "Các IP bị cấm", + "enabled_by_default": "Mặc định được kích hoạt", + "enabled_dlna_temporarily": "Kích hoạt DLNA tạm thời", + "network_interfaces": "Các giao diện", + "recent_ip_addresses": "Các địa chỉ IP gần đây", + "server_display_name": "Tên hiển thị của máy chủ", + "server_display_name_desc": "Tên hiển thị cho máy chủ DLNA. Mặc định là {server_name} nếu để trống.", + "server_port": "Cổng máy chủ", + "server_port_desc": "Cổng cho máy chủ DLNA dùng. Yêu cầu khởi động lại DLNA sau khi sửa đổi.", + "successfully_cancelled_temporary_behaviour": "Hủy bỏ hành vi tạm thời thành công", + "until_restart": "cho tới lúc khởi động lại", + "video_sort_order": "Thứ tự sắp xếp video mặc định", + "video_sort_order_desc": "Thứ tự sắp xếp các video mặc định.", + "allowed_ip_temporarily": "Các địa chỉ IP được cho phép tạm thời", + "default_ip_whitelist_desc": "Các địa chỉ IP mặc định được phép sử dụng DLNA. Dùng {wildcard} để cho phép tất cả các địa chỉ IP.", + "network_interfaces_desc": "Các giao diện để hiển thị máy chủ DLNA. Danh sách trống nghĩa là chạy trên mọi máy chủ. Yêu cần khởi động lại DLNA sau khi sửa đổi." + }, + "general": { + "auth": { + "api_key": "Khóa API", + "authentication": "Xác thực", + "clear_api_key": "Xóa khóa API", + "credentials": { + "heading": "Các thông tin xác thực", + "description": "Tài khoản/mật khẩu dùng để kiểm soát quyền truy cập Stash." + }, + "generate_api_key": "Tạo khóa API", + "log_file": "File nhật ký", + "log_file_desc": "Đường dẫn tới file lưu nhật ký. Để trống để vô hiệu lưu nhật ký vào file. Yêu cầu khởi động lại.", + "log_http": "Nhật ký truy cập HTTP", + "log_to_terminal": "Xuất nhật ký lên terminal", + "maximum_session_age": "Thời gian phiên tối đa", + "maximum_session_age_desc": "Thời gian chờ tối đa trước khi phiên đăng nhập hết hạn, tính bằng giây. Yêu cầu khởi động lại.", + "password": "Mật khẩu", + "password_desc": "Mật khẩu để truy cập Stash. Để trống để tắt xác thực người dùng", + "stash-box_integration": "Tích hợp Stash-box", + "username": "Tên người dùng", + "username_desc": "Tên người dùng để truy cập Stash. Để trống để tắt xác thực người dùng", + "log_http_desc": "Xuất nhật ký truy cập HTTP lên terminal. Yêu cầu khởi động lại.", + "api_key_desc": "Khóa API cho các hệ thống ngoài. Chỉ yêu cầu khóa khi tên người dùng / mật khẩu được thiết lập. Tên người dùng phải được lưu trước khi tạo khóa API.", + "log_to_terminal_desc": "Đẩy nhật ký lên terminal bên cạnh việc lưu vào file. Luôn bật nếu đang vô hiệu lưu vào file. Yêu cầu khởi động lại." + }, + "backup_directory_path": { + "heading": "Đường dẫn tới thư mục sao lưu", + "description": "Vị trí thư mục để sao lưu file dữ liệu SQLite" + }, + "blobs_path": { + "heading": "Đường dẫn tới hệ thống tập tin dữ liệu binary", + "description": "Chỗ nào trong hệ thống file để lưu dữ liệu binary. Chỉ áp dụng cho lựa chọn lưu trữ blob trong hệ thống tệp tin. CẢNH BÁO: thay đổi cài đặt này yêu cầu di chuyển thủ công các dữ liệu hiện tại." + }, + "blobs_storage": { + "heading": "Loại lưu trữ dữ liệu binary", + "description": "Chỗ nào để lưu trữ dữ liệu binary như bìa phân cảnh, người biểu diễn, studio và các nhãn ảnh. Sau khi thay đổi giá trị này, dữ liệu hiện tại phải được chuyển đổi bằng cách sử dụng các tác vụ Chuyển Đổi Các Blob. Xem trang Các Tác Vụ để chuyển đổi." + }, + "cache_location": "Vị trí thư mục cache. Yêu cầu dùng nếu đang truyền trực tiếp sử dụng HLS (như trên thiết bị Apple) hoặc DASH.", + "cache_path_head": "Đường dẫn cache", + "calculate_md5_and_ohash_desc": "Tính toán hàm băm MD5 bên cạnh oshash. Bật lên sẽ làm quá trình quét ban đầu diễn ra chậm hơn. Hàm băm tên file phải đặt về oshash để vô hiệu MD5.", + "calculate_md5_and_ohash_label": "Tính toán MD5 cho các video", + "check_for_insecure_certificates": "Kiểm tra các chứng chỉ không an toàn", + "check_for_insecure_certificates_desc": "Một số trang sử dụng chứng chỉ ssl không an toàn. Nếu bỏ tick, bộ thu thập sẽ bỏ qua quy trình kiểm tra tính an toàn của chứng chỉ và sẽ thu thập toàn bộ các trang đó. Nếu bạn gặp vấn đề về chứng chỉ khi thu thập dữ liệu thì hãy bỏ tick.", + "create_galleries_from_folders_desc": "Nếu bật, các thư mục chứa ảnh sẽ mặc định được tạo thành thư viện. Tạo một tệp có tên .forcegallery hoặc .nogallery trong thư mục để ép buộc hoặc ngăn việc tạo thư viện.", + "create_galleries_from_folders_label": "Tạo thư viện ảnh từ các thư mục chứa hình ảnh", + "database": "Cơ sở dữ liệu", + "db_path_head": "Vị trí tệp cơ sở dữ liệu", + "directory_locations_to_your_content": "Vị trí thư mục chứa nội dung của bạn", + "excluded_image_gallery_patterns_head": "Các mẫu tên ảnh/thư viện cần loại trừ", + "excluded_video_patterns_desc": "Biểu thức chính quy (regex) của các tệp video hoặc đường dẫn cần loại trừ khỏi quá trình Quét và thêm vào mục Dọn dẹp", + "excluded_video_patterns_head": "Các mẫu tên video cần loại trừ", + "ffmpeg": { + "download_ffmpeg": { + "heading": "Tải xuống FFmpeg", + "description": "Tải FFmpeg vào thư mục cấu hình và xóa đường dẫn ffmpeg và ffprobe hiện tại để sử dụng từ thư mục cấu hình." + }, + "ffmpeg_path": { + "heading": "Đường dẫn tệp FFmpeg", + "description": "Đường dẫn đến tệp ffmpeg (không chỉ là thư mục). Nếu để trống, hệ thống sẽ tự tìm ffmpeg từ biến môi trường $PATH, thư mục cấu hình, hoặc từ $HOME/.stash" + }, + "ffprobe_path": { + "description": "Đường dẫn đến tệp ffprobe (không chỉ là thư mục). Nếu để trống, hệ thống sẽ tự tìm ffprobe từ biến môi trường $PATH, thư mục cấu hình hoặc từ $HOME/.stash", + "heading": "Đường dẫn tệp FFprobe" + }, + "hardware_acceleration": { + "desc": "Sử dụng phần cứng hiện có để mã hóa video trong quá trình chuyển mã trực tiếp.", + "heading": "Mã hóa phần cứng bằng FFmpeg" + }, + "live_transcode": { + "output_args": { + "heading": "Tham số đầu ra cho chuyển mã trực tiếp bằng FFmpeg", + "desc": "Nâng cao: Các tham số bổ sung sẽ được truyền vào FFmpeg trước trường đầu ra khi chuyển mã video trực tiếp." + }, + "input_args": { + "desc": "Nâng cao: Các tham số bổ sung sẽ được truyền vào FFmpeg trước trường đầu vào khi chuyển mã video trực tiếp.", + "heading": "Tham số đầu vào cho chuyển mã trực tiếp bằng FFmpeg" + } + }, + "transcode": { + "input_args": { + "desc": "Nâng cao: Các tham số bổ sung sẽ được truyền vào FFmpeg trước trường đầu vào khi tạo video.", + "heading": "Tham số đầu vào khi chuyển mã bằng FFmpeg" + }, + "output_args": { + "heading": "Tham số đầu ra khi chuyển mã bằng FFmpeg", + "desc": "Nâng cao: Các tham số bổ sung sẽ được truyền vào FFmpeg trước trường đầu ra khi tạo video." + } + } + }, + "funscript_heatmap_draw_range": "Bao gồm khoảng giá trị trong các bản đồ nhiệt được tạo ra", + "gallery_cover_regex_desc": "Biểu thức chính quy dùng để nhận diện ảnh bìa của thư viện", + "gallery_cover_regex_label": "Mẫu tên file ảnh dùng làm bìa thư viện", + "gallery_ext_desc": "Danh sách phần mở rộng tệp (file extensions), phân cách bằng dấu phẩy, sẽ được nhận diện là tệp thư viện dạng nén (zip).", + "gallery_ext_head": "Phần mở rộng tệp thư viện nén", + "generated_file_naming_hash_head": "Mã băm dùng để đặt tên cho các tệp được tạo ra", + "generated_files_location": "Vị trí thư mục lưu trữ các tệp được tạo (dấu cảnh, ảnh xem trước cảnh, ảnh sprite, v.v.)", + "generated_path_head": "Thư mục lưu trữ các tệp sinh ra tự động", + "hashing": "Băm (tạo mã băm)", + "heatmap_generation": "Tạo bản đồ nhiệt từ Funscript", + "image_ext_desc": "Danh sách phần mở rộng tệp được nhận diện là hình ảnh, ngăn cách bằng dấu phẩy.", + "image_ext_head": "Đuôi file ảnh", + "include_audio_desc": "Bao gồm luồng âm thanh khi tạo bản xem trước.", + "include_audio_head": "Bao gồm âm thanh", + "maximum_streaming_transcode_size_head": "Kích thước tối đa cho các luồng video đã chuyển mã", + "maximum_transcode_size_desc": "Kích thước tối đa cho các video chuyển mã được tạo ra", + "maximum_transcode_size_head": "Kích thước chuyển mã tối đa", + "metadata_path": { + "heading": "Vị trí thư mục chứa siêu dữ liệu", + "description": "Vị trí thư mục được sử dụng khi thực hiện xuất hoặc nhập toàn bộ dữ liệu" + }, + "number_of_parallel_task_for_scan_generation_head": "Số lượng tác vụ song song cho quá trình quét/tạo dữ liệu", + "parallel_scan_head": "Quét/Tạo dữ liệu song song", + "plugins_path": { + "description": "Vị trí thư mục chứa các tệp cấu hình plugin", + "heading": "Đường dẫn plugins" + }, + "preview_generation": "Tạo bản xem trước", + "python_path": { + "description": "Đường dẫn đến tệp Python (không chỉ là thư mục). Được sử dụng cho các trình quét (scraper) và plugin viết bằng script. Nếu để trống, hệ thống sẽ tự tìm Python từ môi trường", + "heading": "Đường dẫn tệp thực thi Python" + }, + "scrapers_path": { + "description": "Vị trí thư mục chứa các tệp cấu hình của trình quét (scraper)", + "heading": "Đường dẫn đến thư mục chứa các scraper" + }, + "scraping": "Thu thập dữ liệu từ website", + "video_ext_desc": "Danh sách phần mở rộng tệp sẽ được nhận diện là video, phân cách bằng dấu phẩy.", + "video_ext_head": "Định dạng của video", + "video_head": "Video", + "chrome_cdp_path": "Đường dẫn giao thức CDP của Chrome", + "chrome_cdp_path_desc": "Đường dẫn đến tệp thực thi của Chrome, hoặc một địa chỉ từ xa (bắt đầu bằng http:// hoặc https://, ví dụ http://localhost:9222/json/version) trỏ đến một phiên bản Chrome đang chạy.", + "excluded_image_gallery_patterns_desc": "Biểu thức chính quy (regex) của tệp ảnh và thư mục thư viện cần loại trừ khỏi quá trình Quét và thêm vào mục Dọn dẹp", + "funscript_heatmap_draw_range_desc": "Vẽ phạm vi chuyển động trên trục y của bản đồ nhiệt được tạo. Các bản đồ nhiệt hiện có sẽ cần được tạo lại sau khi thay đổi tùy chọn này.", + "generated_file_naming_hash_desc": "Sử dụng MD5 hoặc oshash để đặt tên cho các tệp được tạo. Việc thay đổi tùy chọn này yêu cầu tất cả các cảnh (scenes) phải có giá trị MD5/oshash tương ứng. Sau khi thay đổi, các tệp đã tạo trước đó sẽ cần được di chuyển hoặc tạo lại. Vui lòng xem trang Nhiệm vụ (Tasks) để thực hiện di chuyển.", + "maximum_streaming_transcode_size_desc": "Kích thước tối đa cho các luồng video đã chuyển mã", + "number_of_parallel_task_for_scan_generation_desc": "Đặt giá trị là 0 để hệ thống tự động phát hiện. Cảnh báo: chạy nhiều tác vụ hơn mức cần thiết để sử dụng 100% CPU sẽ làm giảm hiệu suất và có thể gây ra các sự cố khác.", + "scraper_user_agent": "User Agent cho trình quét (scraper)", + "scraper_user_agent_desc": "Chuỗi User-Agent được sử dụng trong các yêu cầu HTTP khi quét dữ liệu (scrape)", + "sqlite_location": "Vị trí tệp cơ sở dữ liệu SQLite (cần khởi động lại). CẢNH BÁO: Lưu cơ sở dữ liệu trên một hệ thống khác với nơi chạy Stash server (ví dụ: qua mạng) là không được hỗ trợ!", + "logging": "Ghi nhật ký" + }, + "advanced_mode": "Chế độ nâng cao", + "stashbox": { + "name": "Tên", + "title": "Các điểm cuối Stash-box", + "add_instance": "Thêm một phiên bản Stash-box", + "api_key": "API key", + "endpoint": "Điểm cuối (Endpoint)", + "graphql_endpoint": "Điểm cuối GraphQL", + "description": "Stash-box hỗ trợ gán tag tự động cho cảnh và diễn viên dựa trên dấu vân tay (fingerprints) và tên tệp.\nEndpoint và khóa API có thể được tìm thấy trong trang tài khoản của bạn trên phiên hoạt động của stash-box. Tên định danh là bắt buộc nếu bạn thêm nhiều hơn một phiên hoạt động.", + "max_requests_per_minute": "Số lượng yêu cầu tối đa mỗi phút", + "max_requests_per_minute_description": "Sử dụng giá trị mặc định là {defaultValue} nếu đặt là 0" + }, + "system": { + "transcoding": "Chuyển đổi định dạng video" + }, + "tasks": { + "added_job_to_queue": "Đã thêm {operation_name} vào hàng đợi công việc", + "anonymising_database": "Đang ẩn danh cơ sở dữ liệu", + "auto_tag": { + "auto_tagging_all_paths": "Tự động gắn tag cho tất cả các đường dẫn", + "auto_tagging_paths": "Đang tự động gắn tag cho các đường dẫn sau" + }, + "backing_up_database": "Sao lưu dữ liệu", + "backup_and_download": "Thực hiện sao lưu cơ sở dữ liệu và tải xuống tệp kết quả.", + "backup_database": "Thực hiện sao lưu cơ sở dữ liệu vào thư mục sao lưu (backups), với định dạng tên tệp là {filename_format}", + "cleanup_desc": "Kiểm tra các tệp bị thiếu và xóa chúng khỏi cơ sở dữ liệu. Đây là hành động có tính phá hủy.", + "clean_generated": { + "blob_files": "Tệp nhị phân (blob)", + "description": "Xóa các tệp đã được tạo nhưng không còn bản ghi tương ứng trong cơ sở dữ liệu.", + "image_thumbnails": "Ảnh thu nhỏ", + "markers": "Xem trước điểm đánh dấu", + "previews": "Xem trước của cảnh", + "previews_desc": "Ảnh và đoạn xem trước cảnh", + "sprites": "Bản ghép khung hình của cảnh", + "transcodes": "Bản video đã chuyển mã của cảnh", + "image_thumbnails_desc": "Ảnh thu nhỏ và đoạn xem trước" + }, + "data_management": "Quản lý dữ liệu", + "dont_include_file_extension_as_part_of_the_title": "Không bao gồm phần đuôi tệp trong tiêu đề", + "empty_queue": "Hiện không có tác vụ nào đang chạy.", + "generate": { + "generating_from_paths": "Đang tạo dữ liệu cho các cảnh từ những đường dẫn sau", + "generating_scenes": "Đang tạo dữ liệu cho {num} {scene}" + }, + "generate_clip_previews_during_scan": "Tạo bản xem trước cho các đoạn ảnh clip", + "generate_desc": "Tạo các tệp hỗ trợ bao gồm ảnh, sprite, video, vtt và các tệp khác.", + "generate_phashes_during_scan": "Tạo mã băm theo đặc điểm hình ảnh", + "generate_previews_during_scan": "Tạo ảnh xem trước động", + "anonymise_and_download": "Tạo một bản sao ẩn danh của cơ sở dữ liệu và tải xuống tệp kết quả.", + "generate_previews_during_scan_tooltip": "Cũng tạo các ảnh xem trước động (định dạng WebP), chỉ cần thiết khi kiểu xem trước Cảnh/Dấu mốc (Scene/Marker Wall Preview Type) được đặt thành Ảnh động. Khi duyệt nội dung, ảnh WebP tiêu tốn ít CPU hơn so với video preview, nhưng sẽ được tạo thêm bên cạnh video và có kích thước tệp lớn hơn.", + "anonymise_database": "Tạo một bản sao của cơ sở dữ liệu trong thư mục sao lưu (backups), đồng thời ẩn danh toàn bộ dữ liệu nhạy cảm. Bản sao này có thể được cung cấp cho người khác để hỗ trợ khắc phục sự cố và gỡ lỗi. Cơ sở dữ liệu gốc sẽ không bị thay đổi. Tệp cơ sở dữ liệu ẩn danh sẽ sử dụng định dạng tên file là {filename_format}.", + "generate_phashes_during_scan_tooltip": "Dùng để loại bỏ trùng lặp và nhận diện Scene.", + "defaults_set": "Giá trị mặc định đã được thiết lập và sẽ được sử dụng khi nhấn nút {action} trên trang Tác vụ (Tasks).", + "export_to_json": "Xuất nội dung cơ sở dữ liệu sang định dạng JSON trong thư mục metadata.", + "auto_tag_based_on_filenames": "Tự động gắn tag cho nội dung dựa trên đường dẫn tệp.", + "auto_tagging": "Gắn tag tự động", + "generate_sprites_during_scan": "Tạo ảnh xem trước cho thanh tua", + "generate_sprites_during_scan_tooltip": "Tập hợp hình ảnh được hiển thị bên dưới trình phát video để hỗ trợ điều hướng dễ dàng.", + "generate_thumbnails_during_scan": "Tạo ảnh thu nhỏ cho các hình ảnh", + "generate_video_covers_during_scan": "Tạo ảnh bìa cho từng cảnh quay", + "generate_video_previews_during_scan": "Tạo đoạn xem trước video", + "generate_video_previews_during_scan_tooltip": "Tạo video xem trước phát tự động khi rê chuột lên cảnh quay", + "generated_content": "Nội dung được tạo tự động", + "identify": { + "and_create_missing": "và tạo các mục còn thiếu", + "create_missing": "Tạo phần bị thiếu", + "default_options": "Tùy Chọn Mặc Định", + "description": "Tự động điền thông tin cảnh quay từ stash-box và các nguồn dữ liệu quét.", + "heading": "Nhận diện", + "identifying_from_paths": "Đang nhận diện các cảnh quay từ các đường dẫn sau", + "identifying_scenes": "Đang nhận diện {num} {scene}", + "include_male_performers": "Bao gồm diễn viên nam", + "set_cover_images": "Thiết lập ảnh bìa", + "set_organized": "Đánh dấu đã sắp xếp", + "skip_multiple_matches_tooltip": "Nếu tùy chọn này không được bật và có nhiều kết quả được trả về, một kết quả sẽ được chọn ngẫu nhiên để khớp", + "skip_single_name_performers_tooltip": "Nếu tùy chọn này không được bật, các diễn viên có tên chung chung như Samantha hoặc Olga vẫn sẽ được gán khớp", + "source": "Nguồn", + "source_options": "Tùy chọn cho {source}", + "sources": "Các nguồn", + "strategy": "Chiến lược", + "tag_skipped_matches": "Gắn thẻ cho các kết quả bị bỏ qua bằng", + "tag_skipped_performer_tooltip": "Tạo một thẻ như 'Nhận diện: Diễn viên một tên' để bạn có thể lọc trong chế độ xem Scene Tagger và tự chọn cách xử lý các diễn viên này", + "tag_skipped_performers": "Gắn thẻ cho các diễn viên bị bỏ qua bằng", + "field_options": "Tùy chọn trường dữ liệu", + "skip_single_name_performers": "Bỏ qua các diễn viên chỉ có một tên mà không có thông tin phân biệt rõ ràng", + "field_behaviour": "{strategy} {field}", + "field": "Trường dữ liệu", + "tag_skipped_matches_tooltip": "Tạo một thẻ như 'Nhận diện: Nhiều kết quả khớp' để bạn có thể lọc trong chế độ xem Scene Tagger và tự chọn kết quả đúng bằng tay", + "explicit_set_description": "Các thiết lập dưới đây sẽ áp dụng trừ khi có thiết lập riêng từ từng nguồn.", + "skip_multiple_matches": "Bỏ qua nếu tìm thấy nhiều kết quả trùng khớp" + }, + "incremental_import": "Chỉ nhập những dữ liệu còn thiếu từ tệp ZIP được cung cấp.", + "job_queue": "Hàng đợi tác vụ", + "maintenance": "Công cụ bảo trì hệ thống", + "migrate_blobs": { + "delete_old": "Xóa dữ liệu không còn sử dụng", + "description": "Di chuyển dữ liệu blob sang hệ thống lưu trữ blob hiện tại. Quá trình di chuyển này nên được thực hiện sau khi thay đổi hệ thống lưu trữ. Có thể chọn xóa dữ liệu cũ sau khi hoàn tất di chuyển." + }, + "migrate_scene_screenshots": { + "delete_files": "Xóa các tệp ảnh chụp màn hình", + "overwrite_existing": "Ghi đè các blob hiện có bằng dữ liệu ảnh chụp màn hình", + "description": "Di chuyển ảnh chụp cảnh quay sang hệ thống lưu trữ blob mới. Quá trình này nên được thực hiện sau khi nâng cấp hệ thống hiện tại lên phiên bản 0.20. Có thể tùy chọn xóa các ảnh chụp cũ sau khi di chuyển." + }, + "migrations": "Chuyển đổi dữ liệu", + "only_dry_run": "Chỉ thực hiện chạy thử. Không xóa bất kỳ dữ liệu nào", + "optimise_database": "Cố gắng cải thiện hiệu suất bằng cách phân tích và sau đó tái tạo lại toàn bộ tệp cơ sở dữ liệu.", + "plugin_tasks": "Các tác vụ của tiện ích mở rộng", + "rescan": "Quét lại tất cả các tệp", + "rescan_tooltip": "Quét lại mọi tệp trong đường dẫn. Dùng để buộc cập nhật metadata của tệp và quét lại các tệp ZIP.", + "scan": { + "scanning_all_paths": "Đang quét tất cả các đường dẫn", + "scanning_paths": "Đang quét các đường dẫn sau" + }, + "scan_for_content_desc": "Quét nội dung mới và thêm vào cơ sở dữ liệu.", + "set_name_date_details_from_metadata_if_present": "Thiết lập tên, ngày và thông tin chi tiết từ metadata được nhúng trong tệp", + "migrate_hash_files": "Được sử dụng sau khi thay đổi mã hash đặt tên tệp để đổi tên các tệp đã tạo sang định dạng hash mới.", + "import_from_exported_json": "Nhập dữ liệu từ tệp JSON đã xuất trong thư mục metadata. Hành động này sẽ xóa toàn bộ cơ sở dữ liệu hiện tại.", + "optimise_database_warning": "Cảnh báo: trong khi tác vụ này đang chạy, mọi thao tác có thay đổi cơ sở dữ liệu sẽ bị lỗi. Tùy vào kích thước cơ sở dữ liệu, quá trình này có thể mất vài phút để hoàn tất. Ngoài ra, bạn cần ít nhất dung lượng ổ đĩa trống tương đương với kích thước cơ sở dữ liệu, nhưng khuyến nghị là 1.5 lần để đảm bảo an toàn." + }, + "library": { + "exclusions": "Danh sách loại trừ", + "gallery_and_image_options": "Tùy chọn Thư viện và Hình ảnh", + "media_content_extensions": "Phần mở rộng của nội dung đa phương tiện" + }, + "logs": { + "log_level": "Cấp độ ghi nhật ký" + }, + "plugins": { + "available_plugins": "Plugin khả dụng", + "hooks": "Cơ chế kích hoạt tự động", + "installed_plugins": "Cài đặt plugin", + "triggers_on": "Kích hoạt khi" + }, + "scraping": { + "available_scrapers": "Scraper khả dụng", + "entity_scrapers": "Thông tin mô tả cho {entityType}", + "excluded_tag_patterns_head": "Mẫu tag bị loại trừ", + "installed_scrapers": "Các trình quét đã cài đặt", + "scraper": "Trình quét dữ liệu tự động", + "scrapers": "Các trình quét dữ liệu", + "search_by_name": "Tìm kiếm theo tên", + "supported_types": "Các loại được hỗ trợ", + "supported_urls": "URLs", + "entity_metadata": "Siêu dữ liệu {entityType}", + "excluded_tag_patterns_desc": "Biểu thức chính quy của tên tag cần loại trừ khỏi kết quả quét dữ liệu" + }, + "tools": { + "scene_duplicate_checker": "Kiểm tra cảnh quay bị trùng", + "scene_filename_parser": { + "add_field": "Thêm trường dữ liệu", + "capitalize_title": "Tự động viết hoa chữ cái đầu của mỗi từ trong tiêu đề", + "display_fields": "Hiển thị các trường dữ liệu", + "escape_chars": "Sử dụng \\ để thoát các ký tự đặc biệt", + "filename": "Tên tệp", + "filename_pattern": "Mẫu tên tệp", + "ignore_organized": "Bỏ qua các cảnh đã được sắp xếp", + "ignored_words": "Từ bị bỏ qua", + "matches_with": "Khớp với {i}", + "title": "Trình phân tích tên tệp cảnh quay", + "whitespace_chars": "Ký tự khoảng trắng", + "select_parser_recipe": "Chọn công thức phân tích", + "whitespace_chars_desc": "Các ký tự này sẽ được thay thế bằng khoảng trắng trong tiêu đề" + }, + "scene_tools": "Công cụ xử lý cảnh quay", + "graphql_playground": "Công cụ GraphGL", + "heading": "Công cụ" + }, + "ui": { + "abbreviate_counters": { + "description": "Rút gọn số đếm trong giao diện thẻ và trang chi tiết, ví dụ '1831' sẽ được định dạng thành '1.8K'.", + "heading": "Rút gọn số đếm" + }, + "basic_settings": "Cài đặt cơ bản", + "custom_css": { + "heading": "CSS tùy chỉnh", + "option_label": "Đã bật CSS tùy chỉnh", + "description": "Trang cần được tải lại để các thay đổi có hiệu lực. Không có gì đảm bảo rằng CSS tùy chỉnh sẽ tương thích với các phiên bản Stash trong tương lai." + }, + "custom_javascript": { + "description": "Hãy tải lại trang để áp dụng thay đổi. JavaScript tùy chỉnh có thể không tương thích với các bản cập nhật sau này.", + "option_label": "Đã bật JavaScript tùy chỉnh", + "heading": "JavaScript tùy chỉnh" + }, + "custom_locales": { + "heading": "Bản địa hóa tùy chỉnh", + "option_label": "Đã bật bản địa hóa tùy chỉnh", + "description": "Ghi đè các chuỗi ngôn ngữ riêng lẻ. Xem danh sách chính tại https://github.com/stashapp/stash/blob/develop/ui/v2.5/src/locales/en-GB.json. Trang cần được tải lại để các thay đổi có hiệu lực." + }, + "delete_options": { + "description": "Thiết lập mặc định cho thao tác xóa ảnh, gallery và cảnh.", + "heading": "Tùy chọn xóa", + "options": { + "delete_file": "Xóa tệp theo mặc định", + "delete_generated_supporting_files": "Xóa các tệp hỗ trợ đã tạo theo mặc định" + } + }, + "desktop_integration": { + "desktop_integration": "Tích hợp Desktop", + "notifications_enabled": "Cho phép Thông báo", + "send_desktop_notifications_for_events": "Gửi thông báo trên màn hình máy tính cho các sự kiện", + "skip_opening_browser": "Bỏ qua việc mở trình duyệt", + "skip_opening_browser_on_startup": "Bỏ qua việc tự động mở trình duyệt khi khởi động" + }, + "detail": { + "compact_expanded_details": { + "description": "Khi được bật, tùy chọn này sẽ hiển thị chi tiết mở rộng trong khi vẫn duy trì giao diện gọn gàng", + "heading": "Thu gọn chi tiết mở rộng" + }, + "enable_background_image": { + "description": "Hiển thị ảnh nền trên trang chi tiết.", + "heading": "Bật ảnh nền" + }, + "heading": "Trang Chi tiết", + "show_all_details": { + "heading": "Hiển thị tất cả chi tiết", + "description": "Khi được bật, tất cả các chi tiết nội dung sẽ được hiển thị theo mặc định và mỗi mục chi tiết sẽ nằm gọn trong một cột duy nhất" + } + }, + "editing": { + "disable_dropdown_create": { + "description": "Xóa bỏ khả năng tạo đối tượng mới từ các bộ chọn thả xuống", + "heading": "Tắt chức năng tạo mới từ danh sách thả xuống" + }, + "heading": "Chỉnh sửa", + "rating_system": { + "star_precision": { + "label": "Độ chính xác của sao đánh giá", + "options": { + "full": "Đầy", + "half": "Một nữa", + "quarter": "1/4", + "tenth": "1/10" + } + }, + "type": { + "label": "Loại Hệ thống Đánh giá", + "options": { + "decimal": "Thập phân", + "stars": "Sao" + } + } + }, + "max_options_shown": { + "label": "Số lượng mục tối đa hiển thị trong danh sách thả xuống" + } + }, + "funscript_offset": { + "description": "Độ lệch thời gian tính bằng mili giây cho việc phát lại các kịch bản tương tác.", + "heading": "Độ lệch Funscript (ms)" + }, + "handy_connection": { + "connect": "Kết nối", + "status": { + "heading": "Trạng thái Kết nối Handy" + }, + "sync": "Đồng bộ hóa", + "server_offset": { + "heading": "Độ lệch Máy chủ" + } + }, + "handy_connection_key": { + "heading": "Khóa Kết nối Handy", + "description": "Khóa kết nối Handy để sử dụng cho các cảnh tương tác. Việc thiết lập khóa này sẽ cho phép Stash chia sẻ thông tin cảnh hiện tại của bạn với handyfeeling.com" + }, + "image_lightbox": { + "heading": "Hộp đèn ảnh" + }, + "image_wall": { + "direction": "Phương hướng", + "heading": "Tường ảnh", + "margin": "Khoảng lề (pixel)" + }, + "images": { + "heading": "Hình ảnh", + "options": { + "create_image_clips_from_videos": { + "heading": "Quét các Phần mở rộng Video dưới dạng Clip hình ảnh", + "description": "Khi một thư viện bị tắt Video, các Tệp video (các tệp có phần mở rộng là Video Extension) sẽ được quét dưới dạng Clip hình ảnh." + }, + "write_image_thumbnails": { + "description": "Ghi hình thu nhỏ của ảnh ra đĩa khi chúng được tạo tự động", + "heading": "Ghi hình thu nhỏ của ảnh" + } + } + }, + "interactive_options": "Tùy chọn Tương tác", + "menu_items": { + "description": "Hiển thị hoặc ẩn các loại nội dung khác nhau trên thanh điều hướng", + "heading": "Mục Menu" + }, + "minimum_play_percent": { + "description": "Phần trăm thời lượng cảnh phải được phát trước khi số lượt phát của nó được tăng lên.", + "heading": "Phần trăm Phát tối thiểu" + }, + "scene_player": { + "options": { + "enable_chromecast": "Bật Chromecast", + "show_ab_loop_controls": "Hiển thị điều khiển plugin Vòng lặp AB", + "show_scrubber": "Hiển thị Thanh điều khiển", + "vr_tag": { + "description": "Nút VR sẽ chỉ hiển thị cho các cảnh có gắn thẻ này.", + "heading": "Thẻ VR" + }, + "show_range_markers": "Hiện thị phạm vị của điểm đánh dấu", + "track_activity": "Bật lịch sử phát cảnh quay", + "auto_start_video_on_play_selected": { + "description": "Tự động phát video cảnh quay khi phát từ hàng chờ, hoặc phát các cảnh được chọn hoặc ngẫu nhiên từ trang Cảnh Quay", + "heading": "Tự động phát video khi phát các mục đã chọn" + }, + "continue_playlist_default": { + "description": "Phát cảnh tiếp theo trong hàng chờ khi video kết thúc", + "heading": "Tiếp tục danh sách phát theo mặc định" + }, + "disable_mobile_media_auto_rotate": "Tắt tự động xoay phương tiện toàn màn hình trên thiết bị Di động", + "always_start_from_beginning": "Luôn phát video từ đầu", + "auto_start_video": "Tự động phát video" + }, + "heading": "Trình phát cảnh quay" + }, + "scene_wall": { + "options": { + "toggle_sound": "Bật âm thanh", + "display_title": "Hiển thị tiêu đề và thẻ" + }, + "heading": "Tường Cảnh Quay / Điểm Đánh Dấu" + }, + "scroll_attempts_before_change": { + "heading": "Số lần thử cuộn trước khi chuyển đổi", + "description": "Số lần thử cuộn trước khi chuyển sang mục tiếp theo/trước đó. Chỉ áp dụng cho chế độ cuộn Pan Y." + }, + "show_tag_card_on_hover": { + "description": "Hiển thị thẻ thông tin thẻ khi di chuột qua các huy hiệu thẻ", + "heading": "Chú giải công cụ thẻ thông tin" + }, + "slideshow_delay": { + "heading": "Độ trễ Trình chiếu (giây)", + "description": "Trình chiếu có sẵn trong các thư viện ảnh khi ở chế độ xem dạng tường" + }, + "studio_panel": { + "heading": "Chế độ xem Studio", + "options": { + "show_child_studio_content": { + "description": "Trong chế độ xem Studio, hãy hiển thị cả nội dung từ các studio phụ", + "heading": "Hiển thị nội dung của các studio phụ" + } + } + }, + "tag_panel": { + "heading": "Chế độ xem Thẻ", + "options": { + "show_child_tagged_content": { + "heading": "Hiển thị nội dung của thẻ phụ", + "description": "Trong chế độ xem thẻ, hãy hiển thị cả nội dung từ các thẻ phụ" + } + } + }, + "title": "Giao diện Người dùng", + "use_stash_hosted_funscript": { + "heading": "Phục vụ/Truyền funscript trực tiếp", + "description": "Khi được bật, funscript sẽ được phục vụ trực tiếp từ Stash đến thiết bị Handy của bạn mà không sử dụng máy chủ Handy của bên thứ ba. Yêu cầu Stash phải truy cập được từ thiết bị Handy của bạn và cần tạo khóa API nếu Stash có cấu hình thông tin xác thực." + }, + "max_loop_duration": { + "heading": "Thời lượng lặp tối đa", + "description": "Thời lượng cảnh tối đa (tính bằng giây) mà trình phát cảnh sẽ lặp lại video - 0 để tắt" + }, + "performers": { + "options": { + "image_location": { + "description": "Đường dẫn tùy chỉnh cho ảnh mặc định của người biểu diễn. Để trống để sử dụng các mặc định có sẵn", + "heading": "Đường dẫn Ảnh Người biểu diễn Tùy chỉnh" + } + } + }, + "preview_type": { + "description": "Tùy chọn mặc định là xem trước video (mp4). Để giảm sử dụng CPU khi duyệt, bạn có thể dùng xem trước ảnh động (webp). Tuy nhiên, chúng phải được tạo ra ngoài các bản xem trước video và có kích thước tệp lớn hơn.", + "heading": "Kiểu Xem trước", + "options": { + "animated": "Ảnh động", + "static": "Ảnh tĩnh", + "video": "Video" + } + }, + "scene_list": { + "heading": "Chế độ xem dạng lưới", + "options": { + "show_studio_as_text": "Hiển thị lớp phủ studio dưới dạng văn bản" + } + }, + "language": { + "heading": "Ngôn ngữ" + } } - } + }, + "age_on_date": "{age} tại thời điểm sản xuất", + "description": "Mô Tả", + "custom_fields": { + "title": "Tùy Chỉnh Trường (dữ liệu)", + "criteria_format_string": "{Tiêu chí} (trường tùy chỉnh) {Điều kiện} {Giá trị}", + "value": "Giá trị", + "criteria_format_string_others": "{Tiêu chí} (trường tùy chỉnh) {Điều kiện} {Giá trị} (+{số lượng khác} mục khác)", + "field": "Trường (dữ liệu)" + }, + "dialogs": { + "delete_entity_title": "{count, plural, one {Xóa {singularEntity}} other {Xóa {pluralEntity}}}", + "delete_galleries_extra": "...cộng với bất kỳ tệp ảnh nào không được đính kèm vào bất kỳ thư viện ảnh nào khác.", + "delete_object_title": "Xóa {count, plural, one {{singularEntity}} other {{pluralEntity}}}", + "lightbox": { + "scale_up": { + "description": "Phóng lớn ảnh nhỏ để lấp đầy màn hình", + "label": "Phóng lớn để vừa" + }, + "delay": "Độ Trễ (Giây)", + "display_mode": { + "fit_horizontally": "Căn chỉnh vừa theo chiều ngang", + "fit_to_screen": "Vừa màn hình", + "label": "Chế độ hiển thị", + "original": "Bản gốc" + }, + "options": "Tùy Chọn", + "page_header": "Trang {page} / {total}", + "reset_zoom_on_nav": "Đặt lại mức thu phóng khi đổi ảnh", + "scroll_mode": { + "description": "Giữ phím Shift để tạm thời dùng chế độ khác.", + "pan_y": "Pan (chiều) Y", + "label": "Chế độ cuộn", + "zoom": "Phóng" + } + }, + "clear_o_history_confirm": "Bạn có chắc chắn muốn xóa lịch sử O không?", + "clear_play_history_confirm": "Bạn có chắc muốn xóa lịch sử phát không?", + "create_new_entity": "Tạo mới {entity}", + "delete_entity_simple_desc": "{count, plural, one {Bạn có chắc chắn muốn xóa {singularEntity} này không?} other {Bạn có chắc chắn muốn xóa {pluralEntity} này không?}}", + "delete_gallery_files": "Xóa thư mục/tệp zip thư viện ảnh và bất kỳ ảnh nào không được đính kèm vào thư viện ảnh khác.", + "delete_object_desc": "Bạn có chắc muốn xóa {count, plural, one {{singularEntity} này} other {{pluralEntity} này} } không?", + "dont_show_until_updated": "Không hiển thị cho đến bản cập nhật tiếp theo", + "export_include_related_objects": "Bao gồm các đối tượng liên quan khi xuất", + "export_title": "Xuất (dữ liệu)", + "imagewall": { + "direction": { + "column": "Cột", + "description": "Bố cục dựa trên cột hoặc hàng.", + "row": "Hàng" + }, + "margin_desc": "Số lượng pixel lề xung quanh mỗi ảnh." + }, + "edit_entity_title": "Chỉnh sửa {count, plural, one {{singularEntity}} other {{pluralEntity}}}", + "delete_alert": "Các {count, plural, one {{singularEntity}} other {{pluralEntity}}} sau đây sẽ bị xóa vĩnh viễn:", + "delete_confirm": "Bạn có chắc chắn muốn xóa {entityName} không?", + "delete_entity_desc": "{count, plural, one {Bạn có chắc chắn muốn xóa {singularEntity} này không? Trừ khi tệp cũng bị xóa, {singularEntity} này sẽ được thêm lại khi quá trình quét được thực hiện.} other {Bạn có chắc chắn muốn xóa {pluralEntity} này không? Trừ khi các tệp cũng bị xóa, {pluralEntity} này sẽ được thêm lại khi quá trình quét được thực hiện.}}", + "delete_object_overflow": "...và {count} {count, plural, one {{singularEntity}} other {{pluralEntity}}} khác.", + "overwrite_filter_warning": "Bộ lọc đã lưu \"{entityName}\" sẽ bị ghi đè.", + "scene_gen": { + "clip_previews": "Xem trước Hình ảnh từ Clip", + "marker_screenshots": "Ảnh màn hình Điểm đánh dấu", + "marker_screenshots_tooltip": "Điểm đánh dấu ảnh tĩnh JPG", + "overwrite": "Ghi đè các tệp tin có sẫn", + "phash": "Băm (hash) nhận thức", + "preview_generation_options": "Lựa chọn Tạo ra Bản xem trước", + "covers": "Bìa cảnh quay", + "force_transcodes": "Ép chuyển mã", + "image_previews": "Xem trước Hình ảnh Động", + "image_thumbnails": "Hình thu nhỏ của Ảnh", + "interactive_heatmap_speed": "Tạo bản đồ nhiệt và tốc độ cho các cảnh tương tác", + "marker_image_previews": "Xem trước Điểm đánh dấu Ảnh động", + "marker_image_previews_tooltip": "Ngoài ra sẽ tạo nên những hình xem trước động (webp), chỉ bắt buộc khi Loại Cảnh/Dấu Tường Xem Trước được thành Ảnh Động. Khi lướt nó sử dụng ít CPU hơn video xem trước, nhưng khi tạo nên thì đi kèm với chúng và là những file lớn hơn.", + "markers": "Xem trước Điểm đánh dấu", + "markers_tooltip": "Video 20 giây bắt đầu tại điểm thời gian đã cho sẫn.", + "override_preview_generation_options": "Ghi đè các lựa chọn tạo ra Bản xem trước", + "phash_tooltip": "Cho việc khử trùng lặp và phát hiện cảnh quay", + "preview_exclude_end_time_desc": "Bỏ qua x giây cuối cùng từ các bản xem trước cảnh. Đây có thể là một giá trị bằng giây, hoặc phần trăm (ví dụ 2%) của tổng thời gian cảnh quay.", + "preview_exclude_start_time_head": "Bỏ qua thời gian bắt đầu", + "preview_options": "Lựa chọn Bản xem trước", + "preview_preset_desc": "Phần cài đặt trước điều chỉnh kích thước, chất lượng và thời gian mã hóa của bản xem trước. Các cài đặt trước vượt quá việc \"chậm\" có hiệu năng giảm dần và không được khuyến khích.", + "preview_preset_head": "Xem trước phần cài đặt trước cho việc mã hóa", + "preview_exclude_end_time_head": "Bỏ qua thời gian kết thúc", + "force_transcodes_tooltip": "Mặc định, việc chuyển mã sẽ được tạo ra khi file video không được hỗ trợ trong trình duyệt. Khi kích hoạt, việc chuyển mã sẽ bắt đầu kể cả khi file video có vẻ được hỗ trợ bởi trình duyệt.", + "image_previews_tooltip": "Ngoài ra sẽ tạo nên những hình xem trước động (webp), chỉ bắt buộc khi Loại Cảnh/Dấu Tường Xem Trước được thành Ảnh Động. Khi lướt nó sử dụng ít CPU hơn video xem trước, nhưng khi tạo nên thì đi kèm với chúng và là những file lớn hơn.", + "preview_exclude_start_time_desc": "Bỏ qua x giây đầu tiên từ các bản xem trước cảnh. Đây có thể là một giá trị bằng giây, hoặc phần trăm (ví dụ 2%) của tổng thời gian cảnh quay.", + "override_preview_generation_options_desc": "Ghi đè các lựa chọn tạo ra Bản xem trước cho hành động này. Những thiết lập mặc định được đặt trong Hệ thống -> Tạo ra Bản xem trước.", + "preview_seg_count_desc": "Số lượng phân đoạn trong các file bản xem trước.", + "preview_seg_count_head": "Số lượng phân đoạn trong bản xem trước", + "preview_seg_duration_desc": "Độ dài của mỗi đoạn xem trước, tính theo giây.", + "preview_seg_duration_head": "Độ dài đoạn xem trước", + "sprites": "Sprites của Phần tìm Phân cảnh", + "sprites_tooltip": "Danh sách ảnh hiển thị ở dưới video để dễ thao tác", + "transcodes": "Giải mã", + "video_previews": "Xem trước", + "transcodes_tooltip": "Mã chuyển đổi MP4 sẽ được tạo trước cho tất cả nội dung; hữu ích cho CPU chậm nhưng cần nhiều dung lượng hơn", + "video_previews_tooltip": "Bản xem trước video phát khi di chuột qua một cảnh" + }, + "merge": { + "destination": "Đích đến", + "source": "Nguồn", + "empty_results": "Giá trị điền vào mục Đích đến sẽ không bị thay đổi." + }, + "merge_tags": { + "destination": "Đích đến", + "source": "Nguồn" + }, + "performers_found": "Đã tìm thấy {count} diễn viên", + "reassign_entity_title": "{count, plural, one {Chỉnh lại {singularEntity}} other {Chỉnh lại {pluralEntity}}}", + "reassign_files": { + "destination": "Chỉnh lại đến" + }, + "scrape_results_existing": "Hiện có", + "set_default_filter_confirm": "Bạn có chắc chắn muốn đặt bộ lọc này làm mặc định không?", + "set_image_url_title": "URL hình ảnh", + "unsaved_changes": "Thay đổi chưa được lưu. Bạn có chắc chắn muốn thoát không?", + "scenes_found": "tìm được {count} cảnh quay" + }, + "configuration": "Cấu Hình", + "connection_monitor": { + "websocket_connection_failed": "Không thể tạo kết nối websocket: xem bảng điều khiển trình duyệt để biết chi tiết", + "websocket_connection_reestablished": "Kết nối Websocket đã được thiết lập lại" + }, + "containing_group": "Nhóm chứa", + "containing_groups": "Các Nhóm chứa", + "countables": { + "files": "{count, plural, one {Tệp} other {Các tệp}}", + "groups": "{count, plural, one {Nhóm} other {Các nhóm}}", + "images": "{count, plural, one {Ảnh} other {Các ảnh}}", + "markers": "{count, plural, one {Dấu} other {Các dấu}}", + "scenes": "{count, plural, one {Cảnh} other {Các cảnh}}", + "studios": "{count, plural, one {Studio} other {Các studio}}", + "tags": "{count, plural, one {Thẻ} other {Các thẻ}}", + "performers": "{count, plural, one {Người biểu diễn} other {Các người biểu diễn}}", + "galleries": "{count, plural, one {Thư viện ảnh} other {Các thư viện ảnh}}" + }, + "country": "Quốc Gia", + "cover_image": "Ảnh Bìa", + "created_at": "Thời gian tạo", + "criterion": { + "greater_than": "Lớn hơn", + "less_than": "Nhỏ hơn", + "value": "Giá trị" + }, + "criterion_modifier": { + "between": "Giữa", + "equals": "Là", + "format_string": "{criterion} {modifierString} {valueString}", + "format_string_excludes": "{Tiêu chí} {Điều kiện} {Giá trị} (loại trừ {Ngoại lệ})", + "format_string_excludes_depth": "{Tiêu chí} {Điều kiện} {Giá trị} (loại trừ {Ngoại lệ}) (+{depth, plural, =-1 {tất cả} other {{depth}}})", + "greater_than": "lớn hơn", + "includes": "Bao gồm", + "includes_all": "Bao gồm tất cả", + "is_null": "rỗng", + "less_than": "nhỏ hơn", + "matches_regex": "Khớp biểu thức chính quy", + "not_between": "không nằm giữa", + "not_equals": "không phải", + "not_null": "không rỗng", + "format_string_depth": "{criterion} {modifierString} {valueString} (+{depth, plural, =-1 {all} other {{depth}}})", + "not_matches_regex": "Không khớp biểu thức chính quy", + "excludes": "Không bao gồm" + }, + "death_date": "Ngày Mất", + "death_year": "Năm Mất", + "descending": "Giảm dần", + "details": "Thông tin chi tiết", + "developmentVersion": "Phiên bản Phát triển", + "criterion_modifier_values": { + "any_of": "bất kỳ nào trong số", + "none": "không gì cả", + "only": "Duy nhất", + "any": "bất kỳ" + }, + "custom": "Tùy chỉnh", + "date": "Ngày", + "date_format": "YYYY-MM-DD", + "containing_group_count": "Số lượng Nhóm chứa", + "detail": "Chi tiết", + "datetime_format": "YYYY-MM-DD HH:MM", + "dimensions": "Kích thước", + "director": "Đạo diễn", + "display_mode": { + "grid": "Lưới", + "list": "Danh sách", + "unknown": "Chưa biết", + "label_current": "Chế độ Hiển Thị: {current}", + "wall": "Tường" + }, + "distance": "Khoảng cách", + "donate": "Ủng hộ", + "dupe_check": { + "duration_diff": "Chênh lệch thời lượng tối đa", + "only_select_matching_codecs": "Chỉ chọn nếu tất cả codec khớp với nhóm trùng lặp", + "options": { + "high": "Cao", + "low": "Thấp", + "medium": "Trung bình", + "exact": "Chính xác" + }, + "search_accuracy_label": "Độ chính xác tìm kiếm", + "select_all_but_largest_file": "Chọn mọi tệp trong mỗi nhóm trùng lặp, ngoại trừ tệp lớn nhất", + "select_all_but_largest_resolution": "Chọn mọi tệp trong mỗi nhóm được sao chép, ngoại trừ tệp có độ phân giải cao nhất", + "select_none": "Chọn Không", + "select_oldest": "Chọn tệp cũ nhất trong nhóm trùng lặp", + "select_options": "Chọn Tùy chọn…", + "select_youngest": "Chọn tệp mớinhất trong nhóm trùng lặp", + "title": "Cảnh quay trùng lặp", + "duration_options": { + "any": "Bất kỳ", + "equal": "Tương đương" + } + }, + "duplicated_phash": "Trùng lặp (pHash)", + "duration": "Thời lượng", + "effect_filters": { + "aspect": "Tỷ lệ", + "blur": "Mờ", + "brightness": "Độ sáng", + "contrast": "Tương phản", + "green": "Xanh lá", + "hue": "Sắc thái", + "name": "Bộ lọc", + "name_transforms": "Biến đổi", + "red": "Đỏ", + "reset_filters": "Đặt lại bộ lọc", + "reset_transforms": "Đặt lại chuyển đổi", + "rotate": "Xoay", + "rotate_left_and_scale": "Xoay trái và thay đổi tỷ lệ", + "rotate_right_and_scale": "Xoay phải và thay đổi tỷ lệ", + "saturation": "Độ bão hòa", + "scale": "Tỉ lệ", + "warmth": "Sự ấm áp" + }, + "empty_server": "Thêm một số cảnh quay vào máy chủ của bạn để xem các đề xuất trên trang này." } diff --git a/ui/v2.5/src/locales/zh-CN.json b/ui/v2.5/src/locales/zh-CN.json index 6ebb8d7b6..5e0751171 100644 --- a/ui/v2.5/src/locales/zh-CN.json +++ b/ui/v2.5/src/locales/zh-CN.json @@ -141,7 +141,17 @@ "reset_play_duration": "重置播放时长", "reset_resume_time": "重置恢复时间", "add_sub_groups": "添加子集合", - "remove_from_containing_group": "从集合中移除" + "remove_from_containing_group": "从集合中移除", + "sidebar": { + "close": "关闭侧边栏", + "open": "打开侧边栏", + "toggle": "切换侧边栏" + }, + "play": "播放", + "show_results": "显示结果", + "show_count_results": "显示{count}个结果", + "load": "加载", + "load_filter": "加载过滤器" }, "actions_name": "操作", "age": "年龄", @@ -294,7 +304,9 @@ "password_desc": "登录 Stash 时所需的密码.留空表示关闭身份验证", "stash-box_integration": "整合 Stash-box", "username": "用户名", - "username_desc": "登录 Stash 时所需的用户名.留空表示关闭身份验证" + "username_desc": "登录 Stash 时所需的用户名.留空表示关闭身份验证", + "log_file_max_size": "最大日志尺寸", + "log_file_max_size_desc": "日志文件压缩前的最大大小(以兆字节为单位)。0MB 表示禁用此功能。需要重启。" }, "backup_directory_path": { "description": "备份SQLite 数据库文件的目录路径", @@ -446,7 +458,9 @@ "endpoint": "入口", "graphql_endpoint": "GraphQL 入口", "name": "名称", - "title": "Stash-box 入口" + "title": "Stash-box 入口", + "max_requests_per_minute": "每分钟最多可发起请求数量", + "max_requests_per_minute_description": "使用{defaultValue}的默认数值,当其数值设置为0时" }, "system": { "transcoding": "转码" @@ -572,7 +586,9 @@ "whitespace_chars": "空白字符", "whitespace_chars_desc": "这些字符在标题中会替换为空白字符" }, - "scene_tools": "短片工具" + "scene_tools": "短片工具", + "heading": "工具", + "graphql_playground": "GraphQL试验场" }, "ui": { "abbreviate_counters": { @@ -797,6 +813,18 @@ "use_stash_hosted_funscript": { "description": "启用后,funscript将直接从Stash提供到您的Handy设备,而无需使用第三方Handy服务器。要求可以从您的Handy设备访问Stash,并且如果stash配置了凭据,则会生成API密钥。", "heading": "直接提供funscripts服务" + }, + "performer_list": { + "heading": "演员列表", + "options": { + "show_links_on_grid_card": { + "heading": "在演员网格卡片上显示链接" + } + } + }, + "sfw_mode": { + "description": "如果使用 stash 存储SFW(工作场合安全)内容,请启用。它隐藏或更改了 UI 中与成人内容相关的某些方面。", + "heading": "SFW(工作场合安全)内容模式" } }, "advanced_mode": "高级模式" @@ -906,7 +934,6 @@ "destination": "目标", "source": "源" }, - "overwrite_filter_confirm": "确定要覆盖现有的已保存查询 {entityName} 吗?", "reassign_entity_title": "{count, plural, one {Reassign {singularEntity}} 其它 {Reassign {pluralEntity}}}", "reassign_files": { "destination": "重新指定至" @@ -959,7 +986,10 @@ "unsaved_changes": "更改未保存,确定离开吗?", "performers_found": "找到{count} 个演员", "clear_o_history_confirm": "真的确定要清空高潮记录吗?", - "clear_play_history_confirm": "真的确定要清空播放历史?" + "clear_play_history_confirm": "真的确定要清空播放历史?", + "set_default_filter_confirm": "你确定要设置这个过滤器为默认吗?", + "overwrite_filter_warning": "已保存的过滤器 \"{entityName}\" 将被覆盖。", + "clear_o_history_confirm_sfw": "你确定要清除点赞的历史?" }, "dimensions": "大小", "director": "导演", @@ -969,7 +999,8 @@ "list": "列表显示", "tagger": "标签工具", "unknown": "未知", - "wall": "预览墙" + "wall": "预览墙", + "label_current": "显示模式: {current}" }, "donate": "赞助", "dupe_check": { @@ -1082,8 +1113,8 @@ "syncing": "正在和服务器同步", "uploading": "上传脚本中" }, - "hasChapters": "已有章节", - "hasMarkers": "含有章节标记", + "hasChapters": "章节", + "hasMarkers": "章节标记", "height": "身高", "height_cm": "高(cm)", "help": "说明", @@ -1130,7 +1161,6 @@ "name": "名称", "new": "新增", "none": "空", - "o_counter": "高潮次数", "operations": "操作", "organized": "是否已经整理", "pagination": { @@ -1216,7 +1246,9 @@ "edit_filter": "编辑筛选器", "name": "过滤", "saved_filters": "保存过滤器", - "update_filter": "更新过滤器" + "update_filter": "更新过滤器", + "more_filter_criteria": "+{count}个更多", + "search_term": "搜索词" }, "second": "秒", "seconds": "秒", @@ -1263,7 +1295,7 @@ }, "paths": { "database_filename_empty_for_default": "数据库文件名 (留空则用默认名)", - "description": "接下来,我们需要决定哪里找到你的收藏,哪里存放 stash 数据库和产生资料文件。如果需要,这些设定可在以后再修改。", + "description": "接下来,我们需要决定哪里找到你的内容,哪里存放 stash 数据库和产生资料文件。如果需要,这些设定可在以后再修改。", "path_to_cache_directory_empty_for_default": "缓存目录的路径(默认为空)", "path_to_generated_directory_empty_for_default": "生成资料的文件夹路径 (留空则使用默认路径)", "set_up_your_paths": "设立你的路径", @@ -1274,14 +1306,17 @@ "where_can_stash_store_cache_files": "Stash可以在哪里存储缓存文件?", "where_can_stash_store_cache_files_description": "为了使HLS/DASH实时转码等功能正常运行,Stash需要一个临时文件的缓存目录。默认情况下,Stash将在包含您的配置文件的目录中创建一个cache目录。如果您想更改此设置,请输入绝对或相对(与当前工作目录)路径。如果Stash不存在,它将创建此目录。", "where_can_stash_store_its_database": "在哪里可以储存Stash的数据库?", - "where_can_stash_store_its_database_description": "Stash 使用 sqlite 数据库来存放你的收藏的元数据。默认情况下,会建立stash-go.sqlite在包含有你配置文件的目录里。如果你想改动,请输入一个绝对,或者相对(对于当前目录)的文件名。", + "where_can_stash_store_its_database_description": "Stash 使用 sqlite 数据库来存放你的内容的元数据。默认情况下,会建立stash-go.sqlite在包含有你配置文件的目录里。如果你想改动,请输入一个绝对,或者相对(对于当前目录)的文件名。", "where_can_stash_store_its_database_warning": "警告:不支持将数据库存储在运行 Stash 的不同系统上(例如,在另一台计算机上运行 Stash 服务器时将数据库存储到 NAS 上)!SQLite 不适合在网络上使用,尝试这样做很容易导致整个数据库损坏。", "where_can_stash_store_its_generated_content": "哪里可以存放Stash产生的资料?", "where_can_stash_store_its_generated_content_description": "为了可以提供缩图,预览和浏览图,Stash生成图片和视频。同时也包括将不支持的文件转码后的视频。默认情况下,Stash会建立一个generated文件夹在含有你配置文件的目录中。如果你要修改生成媒体的地方,请输入一个绝对,或者相对(对于当前工作目录)的路径。如果此目录不存在,Stash会自动建立它。", - "where_is_your_porn_located": "你的收藏在哪里?", - "where_is_your_porn_located_description": "添加含有你收藏的视频和图片的目录。Stash会在扫描时使用这些目录去寻找视频和图片。", + "where_is_your_porn_located": "你的内容存放在哪里?", + "where_is_your_porn_located_description": "添加含有你的视频和图片的目录。Stash会在扫描时使用这些目录去寻找视频和图片。", "path_to_blobs_directory_empty_for_default": "blobs目录的路径(默认为空)", - "store_blobs_in_database": "将 blobs存储到数据库" + "store_blobs_in_database": "将 blobs存储到数据库", + "sfw_content_settings": "为了SFW(工作场合安全)内容使用stash?", + "sfw_content_settings_description": "stash能被用来管理SFW(工作场合安全)内容,例如摄影、艺术、漫画等。启用此选项将调整部分界面行为,使其更适合SFW内容。", + "use_sfw_content_mode": "使用SFW(工作场合安全)模式" }, "stash_setup_wizard": "Stash 设定向导", "success": { @@ -1522,5 +1557,17 @@ }, "eta": "预估剩余时间", "sort_name": "排序用名", - "age_on_date": "在制作时{age}岁" + "age_on_date": "在制作时{age}岁", + "login": { + "username": "用户名", + "password": "密码", + "invalid_credentials": "无效的用户名或密码", + "internal_error": "意外的内部错误。有关更多详细信息,请查看日志", + "login": "登录" + }, + "scenes_duration": "场景持续时间", + "last_o_at_sfw": "最近一次点赞在", + "o_count_sfw": "点赞", + "o_history_sfw": "点赞历史", + "odate_recorded_no_sfw": "没有已记录的点赞日期" } diff --git a/ui/v2.5/src/locales/zh-TW.json b/ui/v2.5/src/locales/zh-TW.json index 264973de3..a3fe67cb8 100644 --- a/ui/v2.5/src/locales/zh-TW.json +++ b/ui/v2.5/src/locales/zh-TW.json @@ -141,7 +141,17 @@ "reset_resume_time": "重置恢復時間", "set_cover": "設為封面", "remove_from_containing_group": "從群組中刪除", - "add_sub_groups": "新增子分類" + "add_sub_groups": "新增子分類", + "sidebar": { + "close": "關閉側邊攔", + "open": "開啟側邊攔", + "toggle": "切換側邊欄" + }, + "show_results": "顯示結果", + "show_count_results": "顯示 {count} 筆結果", + "play": "播放", + "load": "載入", + "load_filter": "載入篩選結果" }, "actions_name": "動作", "age": "年齡", @@ -440,7 +450,9 @@ "endpoint": "端點", "graphql_endpoint": "GraphQL 端點", "name": "名稱", - "title": "Stash-box 端點" + "title": "Stash-box 端點", + "max_requests_per_minute": "每分鐘請求上限", + "max_requests_per_minute_description": "當設為 0 時,會套用預設值 {defaultValue}" }, "system": { "transcoding": "轉檔" @@ -566,7 +578,9 @@ "whitespace_chars": "空白字元", "whitespace_chars_desc": "這些字元將在標題中被空格取代" }, - "scene_tools": "短片工具" + "scene_tools": "短片工具", + "heading": "工具", + "graphql_playground": "GraphQL 測試環境" }, "ui": { "abbreviate_counters": { @@ -726,7 +740,8 @@ }, "enable_chromecast": "啟用 Chromecast", "show_ab_loop_controls": "顯示AB循環插件控件", - "disable_mobile_media_auto_rotate": "停用行動裝置上全螢幕媒體的自動旋轉功能" + "disable_mobile_media_auto_rotate": "停用行動裝置上全螢幕媒體的自動旋轉功能", + "show_range_markers": "顯示範圍標記" } }, "scene_wall": { @@ -790,6 +805,14 @@ "use_stash_hosted_funscript": { "description": "啟用後,funscript 將直接從 Stash 傳送至您的 Handy 裝置,而無需使用第三方 Handy 伺服器。要求可從您的 Handy 裝置存取 Stash,且如果 stash 已設定憑證,則會產生 API 金鑰。", "heading": "直接為 funscript 服務" + }, + "performer_list": { + "options": { + "show_links_on_grid_card": { + "heading": "在表演者卡片上顯示連結" + } + }, + "heading": "表演者清單" } }, "advanced_mode": "進階模式" @@ -889,7 +912,6 @@ "destination": "目的地", "source": "來源" }, - "overwrite_filter_confirm": "您確定要覆蓋現有的條件 {entityName} 嗎?", "reassign_entity_title": "{count, plural, one {重新指定{singularEntity}}}", "reassign_files": { "destination": "重新指定至" @@ -950,7 +972,9 @@ }, "clear_o_history_confirm": "您確定要清除尻尻紀錄嗎?", "clear_play_history_confirm": "您確定要清除播放紀錄嗎?", - "performers_found": "找到{count} 個演員" + "performers_found": "找到{count} 個演員", + "set_default_filter_confirm": "是否確定設定這一個過濾條件為預設?", + "overwrite_filter_warning": "篩選器 \"{entityName}\" 已存在,將被覆蓋。" }, "dimensions": "解析度", "director": "導演", @@ -960,7 +984,8 @@ "list": "條列顯示", "tagger": "標記工具", "unknown": "未知", - "wall": "預覽牆顯示" + "wall": "預覽牆顯示", + "label_current": "顯示模式:{current}" }, "donate": "贊助", "dupe_check": { @@ -1058,7 +1083,7 @@ "syncing": "與伺服器同步中", "uploading": "上傳腳本中" }, - "hasMarkers": "含有章節標記", + "hasMarkers": "章節標記", "height": "身高", "height_cm": "高度 (cm)", "help": "說明", @@ -1090,7 +1115,7 @@ "interactive_speed": "互動速度", "performer_card": { "age": "{age} {years_old}", - "age_context": "這齣戲裡面 {age} {years_old}" + "age_context": "這齣戲時 {age} {years_old}" }, "phash": "PHash", "play_count": "播放次數", @@ -1104,7 +1129,6 @@ "name": "名稱", "new": "新增", "none": "無", - "o_counter": "尻尻計數", "operations": "動作", "organized": "是否已整理", "pagination": { @@ -1190,7 +1214,9 @@ "name": "篩選", "saved_filters": "已儲存的過濾條件", "update_filter": "更新篩選", - "edit_filter": "編輯篩選器" + "edit_filter": "編輯篩選器", + "more_filter_criteria": "+{count} 更多", + "search_term": "搜尋詞組" }, "seconds": "秒", "settings": "設定", @@ -1236,16 +1262,16 @@ }, "paths": { "database_filename_empty_for_default": "資料庫檔案名稱(留空以使用預設)", - "description": "接下來,我們需要確定可以在哪裡找到你的片片,在哪裡儲存資料庫及其生成檔案等等。如果需要,您稍後可以再更改這些設定。", + "description": "接下來,我們需要確定可以在哪裡找到你的內容,在哪裡儲存資料庫及其生成檔案等等。如果需要,您稍後可以再更改這些設定。", "path_to_generated_directory_empty_for_default": "生成媒體資料夾路徑(留空以使用預設)", "set_up_your_paths": "設定你的路徑", "stash_alert": "您尚未選取任何路徑,Stash 將無法掃描你的檔案。你確定要繼續嗎?", "where_can_stash_store_its_database": "Stash 可以在哪裡儲存資料庫?", - "where_can_stash_store_its_database_description": "Stash 使用 SQLite 資料庫來儲存您片片的資料。預設情況下,Stash 將在您的設定檔路徑下以 stash-go.sqlite 這個檔案來儲存此資料庫內容。如果您想要更改此設定,請在此輸入您所想要的絕對或相對路徑(相對於目前工作目錄)。", + "where_can_stash_store_its_database_description": "Stash 使用 SQLite 資料庫來儲存您內容的資料。預設情況下,Stash 將在您的設定檔路徑下以 stash-go.sqlite 這個檔案來儲存此資料庫內容。如果您想要更改此設定,請在此輸入您所想要的絕對或相對路徑(相對於目前工作目錄)。", "where_can_stash_store_its_generated_content": "Stash 可以在哪裡儲存其生成內容?", "where_can_stash_store_its_generated_content_description": "為提供縮圖、預覽和其他預覽資料,Stash 將自動生成圖片和影片資訊。這包括不支援的檔案格式之轉檔。預設情況下,Stash 將在包含您設定檔案的資料夾中建立一個新的 generated 資料夾。如果要更改此生成媒體的儲存位置,請在此輸入絕對或相對路徑(相對於目前工作目錄)。如果該資料夾不存在,Stash 將自動建立此目錄。", - "where_is_your_porn_located": "你的片片都藏哪?", - "where_is_your_porn_located_description": "在此選擇你A片及圖片的資料夾,Stash 將在掃描影片及圖片時使用這些路徑。", + "where_is_your_porn_located": "你的內容都藏哪?", + "where_is_your_porn_located_description": "在此選擇你視訊及圖片的資料夾,Stash 將在掃描影片及圖片時使用這些路徑。", "path_to_blobs_directory_empty_for_default": "blobs 目錄的路徑 (預設為空)", "path_to_cache_directory_empty_for_default": "快取目錄的路徑 (預設為空)", "store_blobs_in_database": "將 blobs 儲存到資料庫", @@ -1388,7 +1414,7 @@ "group_count": "群組計數", "group_scene_number": "短片編號", "groups": "群組", - "hasChapters": "擁有章節", + "hasChapters": "章節", "history": "歷史紀錄", "image_index": "圖片#", "index_of_total": "第{index}個,共 {total}個", @@ -1515,6 +1541,19 @@ "custom_fields": { "field": "欄位", "title": "自訂欄位", - "value": "值" - } + "value": "值", + "criteria_format_string_others": "{criterion} (custom field) 條件:{modifierString} {valueString} (+{others} others)", + "criteria_format_string": "{criterion} (custom field) 條件:{modifierString} {valueString}" + }, + "login": { + "login": "登入", + "username": "使用者名稱", + "password": "密碼", + "invalid_credentials": "無效的使用者名稱或是密碼", + "internal_error": "系統發生未預期的內部錯誤。詳情請參考日誌" + }, + "sort_name": "分類名稱", + "eta": "預估剩餘時間", + "age_on_date": "在{age}歲時製作", + "scenes_duration": "場景持續時間" } diff --git a/ui/v2.5/src/models/list-filter/criteria/country.ts b/ui/v2.5/src/models/list-filter/criteria/country.ts index 2430c2a59..e29ac97ff 100644 --- a/ui/v2.5/src/models/list-filter/criteria/country.ts +++ b/ui/v2.5/src/models/list-filter/criteria/country.ts @@ -3,11 +3,11 @@ import { CriterionModifier } from "src/core/generated-graphql"; import { getCountryByISO } from "src/utils/country"; import { StringCriterion, StringCriterionOption } from "./criterion"; -export const CountryCriterionOption = new StringCriterionOption( - "country", - "country", - () => new CountryCriterion() -); +export const CountryCriterionOption = new StringCriterionOption({ + messageID: "country", + type: "country", + makeCriterion: () => new CountryCriterion(), +}); export class CountryCriterion extends StringCriterion { constructor() { diff --git a/ui/v2.5/src/models/list-filter/criteria/criterion.ts b/ui/v2.5/src/models/list-filter/criteria/criterion.ts index d06272c4c..8f30e5d17 100644 --- a/ui/v2.5/src/models/list-filter/criteria/criterion.ts +++ b/ui/v2.5/src/models/list-filter/criteria/criterion.ts @@ -78,7 +78,7 @@ export abstract class Criterion { protected cloneValues() {} - public abstract getLabel(intl: IntlShape): string; + public abstract getLabel(intl: IntlShape, sfwContentMode?: boolean): string; public getId(): string { return `${this.criterionOption.type}`; @@ -148,7 +148,7 @@ export abstract class ModifierCriterion< : ""; } - public getLabel(intl: IntlShape): string { + public getLabel(intl: IntlShape, sfwContentMode: boolean = false): string { const modifierString = ModifierCriterion.getModifierLabel( intl, this.modifier @@ -162,10 +162,14 @@ export abstract class ModifierCriterion< valueString = this.getLabelValue(intl); } + const messageID = !sfwContentMode + ? this.criterionOption.messageID + : this.criterionOption.sfwMessageID ?? this.criterionOption.messageID; + return intl.formatMessage( { id: "criterion_modifier.format_string" }, { - criterion: intl.formatMessage({ id: this.criterionOption.messageID }), + criterion: intl.formatMessage({ id: messageID }), modifierString, valueString, } @@ -257,12 +261,14 @@ interface ICriterionOptionParams { type: CriterionType; makeCriterion: MakeCriterionFn; hidden?: boolean; + sfwMessageID?: string; } export class CriterionOption { public readonly type: CriterionType; public readonly messageID: string; public readonly makeCriterionFn: MakeCriterionFn; + public readonly sfwMessageID?: string; // used for legacy criteria that are not shown in the UI public readonly hidden: boolean = false; @@ -272,6 +278,7 @@ export class CriterionOption { this.messageID = options.messageID; this.makeCriterionFn = options.makeCriterion; this.hidden = options.hidden ?? false; + this.sfwMessageID = options.sfwMessageID; } public makeCriterion(config?: ConfigDataFragment) { @@ -478,7 +485,7 @@ export class IHierarchicalLabeledIdCriterion extends ModifierCriterion ModifierCriterion + options: Partial< + Omit + > & + Pick ) { super({ - messageID, - type: value, modifierOptions: [ CriterionModifier.Equals, CriterionModifier.NotEquals, @@ -545,18 +555,22 @@ export class StringCriterionOption extends ModifierCriterionOption { ], defaultModifier: CriterionModifier.Equals, inputType: "text", - makeCriterion: makeCriterion - ? makeCriterion - : () => new StringCriterion(this), + makeCriterion: () => new StringCriterion(this), + ...options, }); } } export function createStringCriterionOption( type: CriterionType, - messageID?: string + messageID?: string, + options?: { nsfw?: boolean } ) { - return new StringCriterionOption(messageID ?? type, type); + return new StringCriterionOption({ + messageID: messageID ?? type, + type, + ...options, + }); } export class MandatoryStringCriterionOption extends ModifierCriterionOption { @@ -757,7 +771,8 @@ export class MandatoryNumberCriterionOption extends ModifierCriterionOption { constructor( messageID: string, value: CriterionType, - makeCriterion?: () => ModifierCriterion + makeCriterion?: () => ModifierCriterion, + options?: { sfwMessageID?: string } ) { super({ messageID, @@ -775,15 +790,22 @@ export class MandatoryNumberCriterionOption extends ModifierCriterionOption { makeCriterion: makeCriterion ? makeCriterion : () => new NumberCriterion(this), + ...options, }); } } export function createMandatoryNumberCriterionOption( value: CriterionType, - messageID?: string + messageID?: string, + options?: { sfwMessageID?: string } ) { - return new MandatoryNumberCriterionOption(messageID ?? value, value); + return new MandatoryNumberCriterionOption( + messageID ?? value, + value, + undefined, + options + ); } export function encodeRangeValue( diff --git a/ui/v2.5/src/models/list-filter/criteria/is-missing.ts b/ui/v2.5/src/models/list-filter/criteria/is-missing.ts index f7387e558..58e3535a6 100644 --- a/ui/v2.5/src/models/list-filter/criteria/is-missing.ts +++ b/ui/v2.5/src/models/list-filter/criteria/is-missing.ts @@ -32,7 +32,7 @@ export const SceneIsMissingCriterionOption = new IsMissingCriterionOption( "date", "galleries", "studio", - "movie", + "group", "performers", "tags", "stash_id", diff --git a/ui/v2.5/src/models/list-filter/criteria/path.ts b/ui/v2.5/src/models/list-filter/criteria/path.ts index 2b57faf85..42a7789cf 100644 --- a/ui/v2.5/src/models/list-filter/criteria/path.ts +++ b/ui/v2.5/src/models/list-filter/criteria/path.ts @@ -1,10 +1,12 @@ +import { CriterionModifier } from "src/core/generated-graphql"; import { StringCriterion, StringCriterionOption } from "./criterion"; -export const PathCriterionOption = new StringCriterionOption( - "path", - "path", - () => new PathCriterion() -); +export const PathCriterionOption = new StringCriterionOption({ + messageID: "path", + type: "path", + defaultModifier: CriterionModifier.Includes, + makeCriterion: () => new PathCriterion(), +}); export class PathCriterion extends StringCriterion { constructor() { diff --git a/ui/v2.5/src/models/list-filter/filter-options.ts b/ui/v2.5/src/models/list-filter/filter-options.ts index 68bc23e79..a63394f35 100644 --- a/ui/v2.5/src/models/list-filter/filter-options.ts +++ b/ui/v2.5/src/models/list-filter/filter-options.ts @@ -1,9 +1,10 @@ import { CriterionOption } from "./criteria/criterion"; import { DisplayMode } from "./types"; -interface ISortByOption { +export interface ISortByOption { messageID: string; value: string; + sfwMessageID?: string; } export const MediaSortByOptions = [ @@ -22,7 +23,7 @@ export class ListFilterOptions { public readonly displayModeOptions: DisplayMode[] = []; public readonly criterionOptions: CriterionOption[] = []; - public static createSortBy(value: string) { + public static createSortBy(value: string): ISortByOption { return { messageID: value, value, diff --git a/ui/v2.5/src/models/list-filter/filter.ts b/ui/v2.5/src/models/list-filter/filter.ts index e7cf6a6eb..4780f1ab6 100644 --- a/ui/v2.5/src/models/list-filter/filter.ts +++ b/ui/v2.5/src/models/list-filter/filter.ts @@ -183,7 +183,7 @@ export class ListFilterModel { ret.disp = Number.parseInt(params.disp, 10); } if (params.q) { - ret.q = params.q.trim(); + ret.q = params.q; } if (params.p) { ret.p = Number.parseInt(params.p, 10); @@ -476,13 +476,23 @@ export class ListFilterModel { return this.setCriteria(criteria); } - public clearCriteria() { + public clearCriteria(clearSearchTerm = false) { const ret = this.clone(); + if (clearSearchTerm) { + ret.searchTerm = ""; + } ret.criteria = []; ret.currentPage = 1; return ret; } + public clearSearchTerm() { + const ret = this.clone(); + ret.searchTerm = ""; + ret.currentPage = 1; // reset to first page + return ret; + } + public setCriteria(criteria: Criterion[]) { const ret = this.clone(); ret.criteria = criteria; @@ -521,6 +531,34 @@ export class ListFilterModel { public setPageSize(pageSize: number) { const ret = this.clone(); ret.itemsPerPage = pageSize; + ret.currentPage = 1; // reset to first page + return ret; + } + + public setSortBy(sortBy: string | undefined) { + const ret = this.clone(); + ret.sortBy = sortBy; + ret.currentPage = 1; // reset to first page + return ret; + } + + public toggleSortDirection() { + const ret = this.clone(); + + if (ret.sortDirection === SortDirectionEnum.Asc) { + ret.sortDirection = SortDirectionEnum.Desc; + } else { + ret.sortDirection = SortDirectionEnum.Asc; + } + + ret.currentPage = 1; // reset to first page + return ret; + } + + public reshuffleRandomSort() { + const ret = this.clone(); + ret.currentPage = 1; + ret.randomSeed = -1; return ret; } diff --git a/ui/v2.5/src/models/list-filter/groups.ts b/ui/v2.5/src/models/list-filter/groups.ts index c96fd8dc6..5a263b272 100644 --- a/ui/v2.5/src/models/list-filter/groups.ts +++ b/ui/v2.5/src/models/list-filter/groups.ts @@ -35,6 +35,11 @@ const sortByOptions = [ messageID: "scene_count", value: "scenes_count", }, + { + messageID: "o_count", + value: "o_counter", + sfwMessageID: "o_count_sfw", + }, ]); const displayModeOptions = [DisplayMode.Grid]; const criterionOptions = [ @@ -49,6 +54,9 @@ const criterionOptions = [ RatingCriterionOption, PerformersCriterionOption, createDateCriterionOption("date"), + createMandatoryNumberCriterionOption("o_counter", "o_count", { + sfwMessageID: "o_count_sfw", + }), ContainingGroupsCriterionOption, SubGroupsCriterionOption, createMandatoryNumberCriterionOption("containing_group_count"), diff --git a/ui/v2.5/src/models/list-filter/images.ts b/ui/v2.5/src/models/list-filter/images.ts index d8619112d..4d5630b1c 100644 --- a/ui/v2.5/src/models/list-filter/images.ts +++ b/ui/v2.5/src/models/list-filter/images.ts @@ -31,6 +31,7 @@ const sortByOptions = ["filesize", "file_count", "date", ...MediaSortByOptions] { messageID: "o_count", value: "o_counter", + sfwMessageID: "o_count_sfw", }, ]); const displayModeOptions = [DisplayMode.Grid, DisplayMode.Wall]; @@ -43,7 +44,9 @@ const criterionOptions = [ PathCriterionOption, GalleriesCriterionOption, OrganizedCriterionOption, - createMandatoryNumberCriterionOption("o_counter", "o_count"), + createMandatoryNumberCriterionOption("o_counter", "o_count", { + sfwMessageID: "o_count_sfw", + }), ResolutionCriterionOption, OrientationCriterionOption, ImageIsMissingCriterionOption, diff --git a/ui/v2.5/src/models/list-filter/performers.ts b/ui/v2.5/src/models/list-filter/performers.ts index a8d3c9096..fcc152d01 100644 --- a/ui/v2.5/src/models/list-filter/performers.ts +++ b/ui/v2.5/src/models/list-filter/performers.ts @@ -31,10 +31,10 @@ const sortByOptions = [ "penis_length", "play_count", "last_played_at", - "last_o_at", "career_length", "weight", "measurements", + "scenes_duration", ] .map(ListFilterOptions.createSortBy) .concat([ @@ -53,6 +53,12 @@ const sortByOptions = [ { messageID: "o_count", value: "o_counter", + sfwMessageID: "o_count_sfw", + }, + { + messageID: "last_o_at", + value: "last_o_at", + sfwMessageID: "last_o_at_sfw", }, ]); @@ -101,7 +107,9 @@ const criterionOptions = [ createMandatoryNumberCriterionOption("image_count"), createMandatoryNumberCriterionOption("gallery_count"), createMandatoryNumberCriterionOption("play_count"), - createMandatoryNumberCriterionOption("o_counter", "o_count"), + createMandatoryNumberCriterionOption("o_counter", "o_count", { + sfwMessageID: "o_count_sfw", + }), createBooleanCriterionOption("ignore_auto_tag"), CountryCriterionOption, createNumberCriterionOption("height_cm", "height"), diff --git a/ui/v2.5/src/models/list-filter/scenes.ts b/ui/v2.5/src/models/list-filter/scenes.ts index 592b8b6fe..cf2791567 100644 --- a/ui/v2.5/src/models/list-filter/scenes.ts +++ b/ui/v2.5/src/models/list-filter/scenes.ts @@ -46,13 +46,14 @@ const sortByOptions = [ "framerate", "bitrate", "last_played_at", - "last_o_at", "resume_time", "play_duration", "play_count", "interactive", "interactive_speed", "perceptual_similarity", + "performer_age", + "studio", ...MediaSortByOptions, ] .map(ListFilterOptions.createSortBy) @@ -60,6 +61,12 @@ const sortByOptions = [ { messageID: "o_count", value: "o_counter", + sfwMessageID: "o_count_sfw", + }, + { + messageID: "last_o_at", + value: "last_o_at", + sfwMessageID: "last_o_at_sfw", }, { messageID: "group_scene_number", @@ -77,6 +84,12 @@ const displayModeOptions = [ DisplayMode.Tagger, ]; +export const PerformerAgeCriterionOption = + createMandatoryNumberCriterionOption("performer_age"); + +export const DurationCriterionOption = + createDurationCriterionOption("duration"); + const criterionOptions = [ createStringCriterionOption("title"), createStringCriterionOption("code", "scene_code"), @@ -89,14 +102,16 @@ const criterionOptions = [ DuplicatedCriterionOption, OrganizedCriterionOption, RatingCriterionOption, - createMandatoryNumberCriterionOption("o_counter", "o_count"), + createMandatoryNumberCriterionOption("o_counter", "o_count", { + sfwMessageID: "o_count_sfw", + }), ResolutionCriterionOption, OrientationCriterionOption, createMandatoryNumberCriterionOption("framerate"), createMandatoryNumberCriterionOption("bitrate"), createStringCriterionOption("video_codec"), createStringCriterionOption("audio_codec"), - createDurationCriterionOption("duration"), + DurationCriterionOption, createDurationCriterionOption("resume_time"), createDurationCriterionOption("play_duration"), createMandatoryNumberCriterionOption("play_count"), @@ -108,7 +123,7 @@ const criterionOptions = [ PerformerTagsCriterionOption, PerformersCriterionOption, createMandatoryNumberCriterionOption("performer_count"), - createMandatoryNumberCriterionOption("performer_age"), + PerformerAgeCriterionOption, PerformerFavoriteCriterionOption, // StudioTagsCriterionOption, StudiosCriterionOption, diff --git a/ui/v2.5/src/models/list-filter/studios.ts b/ui/v2.5/src/models/list-filter/studios.ts index a25fd9e22..02dfae2f6 100644 --- a/ui/v2.5/src/models/list-filter/studios.ts +++ b/ui/v2.5/src/models/list-filter/studios.ts @@ -15,7 +15,13 @@ import { ListFilterOptions } from "./filter-options"; import { DisplayMode } from "./types"; const defaultSortBy = "name"; -const sortByOptions = ["name", "tag_count", "random", "rating"] +const sortByOptions = [ + "name", + "tag_count", + "random", + "rating", + "scenes_duration", +] .map(ListFilterOptions.createSortBy) .concat([ { diff --git a/ui/v2.5/src/models/list-filter/tags.ts b/ui/v2.5/src/models/list-filter/tags.ts index db3a84666..c664f218e 100644 --- a/ui/v2.5/src/models/list-filter/tags.ts +++ b/ui/v2.5/src/models/list-filter/tags.ts @@ -16,7 +16,7 @@ import { import { FavoriteTagCriterionOption } from "./criteria/favorite"; const defaultSortBy = "name"; -const sortByOptions = ["name", "random"] +const sortByOptions = ["name", "random", "scenes_duration"] .map(ListFilterOptions.createSortBy) .concat([ { diff --git a/ui/v2.5/src/patch.tsx b/ui/v2.5/src/patch.tsx index 548993a07..2d1d3543e 100644 --- a/ui/v2.5/src/patch.tsx +++ b/ui/v2.5/src/patch.tsx @@ -39,7 +39,13 @@ export function RegisterComponent( ) { // register with the plugin api if (components[component]) { - throw new Error("Component " + component + " has already been registered"); + // only throw an error in production, in development we allow + // multiple registrations to allow for hot reloading of components + if (!import.meta.env.DEV) { + throw new Error( + "Component " + component + " has already been registered" + ); + } } components[component] = fn; diff --git a/ui/v2.5/src/pluginApi.d.ts b/ui/v2.5/src/pluginApi.d.ts index 2e6d23266..da4a64765 100644 --- a/ui/v2.5/src/pluginApi.d.ts +++ b/ui/v2.5/src/pluginApi.d.ts @@ -652,88 +652,90 @@ declare namespace PluginApi { }>; } const components: { - HoverPopover: React.FC; - TagLink: React.FC; - LoadingIndicator: React.FC; - Icon: React.FC; - "MainNavBar.MenuItems": React.FC; - "MainNavBar.UtilityItems": React.FC; - PerformerSelect: React.FC; - PerformerIDSelect: React.FC; - TagSelect: React.FC; - TagIDSelect: React.FC; - StudioSelect: React.FC; - StudioIDSelect: React.FC; - GallerySelect: React.FC; - GalleryIDSelect: React.FC; - GroupSelect: React.FC; - GroupIDSelect: React.FC; - SceneSelect: React.FC; - SceneIDSelect: React.FC; - DateInput: React.FC; - CountrySelect: React.FC; - FolderSelect: React.FC; - "SceneCard.Popovers": React.FC; - "SceneCard.Details": React.FC; - "SceneCard.Overlays": React.FC; - "SceneCard.Image": React.FC; - PluginSettings: React.FC; - Setting: React.FC; - SettingGroup: React.FC; + AlertModal: React.FC; + BackgroundImage: React.FC; BooleanSetting: React.FC; - SelectSetting: React.FC; ChangeButtonSetting: React.FC; - SettingModal: React.FC; - ModalSetting: React.FC; - StringSetting: React.FC; - NumberSetting: React.FC; - StringListSetting: React.FC; ConstantSetting: React.FC; - SceneFileInfoPanel: React.FC; - PerformerPage: React.FC; - PerformerAppearsWithPanel: React.FC; - PerformerGalleriesPanel: React.FC; - PerformerGroupsPanel: React.FC; - PerformerHeaderImage: React.FC; - PerformerScenesPanel: React.FC; - PerformerImagesPanel: React.FC; - TabTitleCounter: React.FC; - PerformerCard: React.FC; + CountrySelect: React.FC; + CustomFieldInput: React.FC; + CustomFields: React.FC; + DateInput: React.FC; + DetailImage: React.FC; ExternalLinkButtons: React.FC; ExternalLinksButton: React.FC; - CustomFields: React.FC; - CustomFieldInput: React.FC; - ImageInput: React.FC; - DetailImage: React.FC; - HeaderImage: React.FC; - LightboxLink: React.FC; - "PerformerCard.Popovers": React.FC; - "PerformerCard.Details": React.FC; - "PerformerCard.Overlays": React.FC; - "PerformerCard.Image": React.FC; - "PerformerCard.Title": React.FC; - "TagCard.Popovers": React.FC; - "TagCard.Details": React.FC; - "TagCard.Overlays": React.FC; - "TagCard.Image": React.FC; - "TagCard.Title": React.FC; - ScenePage: React.FC; - "ScenePage.Tabs": React.FC; - "ScenePage.TabContent": React.FC; - ScenePlayer: React.FC; + FolderSelect: React.FC; FrontPage: React.FC; GalleryCard: React.FC; "GalleryCard.Details": React.FC; "GalleryCard.Image": React.FC; "GalleryCard.Overlays": React.FC; "GalleryCard.Popovers": React.FC; - TruncatedText: React.FC; - SweatDrops: React.FC; - AlertModal: React.FC; - BackgroundImage: React.FC; + GalleryIDSelect: React.FC; + GallerySelect: React.FC; + GroupIDSelect: React.FC; + GroupSelect: React.FC; + HeaderImage: React.FC; + HoverPopover: React.FC; + Icon: React.FC; + ImageInput: React.FC; + LightboxLink: React.FC; + LoadingIndicator: React.FC; + "MainNavBar.MenuItems": React.FC; + "MainNavBar.UtilityItems": React.FC; + ModalSetting: React.FC; + NumberSetting: React.FC; + PerformerAppearsWithPanel: React.FC; + PerformerCard: React.FC; + "PerformerCard.Details": React.FC; + "PerformerCard.Image": React.FC; + "PerformerCard.Overlays": React.FC; + "PerformerCard.Popovers": React.FC; + "PerformerCard.Title": React.FC; + PerformerDetailsPanel: React.FC; + "PerformerDetailsPanel.DetailGroup": React.FC; + PerformerGalleriesPanel: React.FC; + PerformerGroupsPanel: React.FC; + PerformerHeaderImage: React.FC; + PerformerIDSelect: React.FC; + PerformerImagesPanel: React.FC; + PerformerPage: React.FC; + PerformerScenesPanel: React.FC; + PerformerSelect: React.FC; + PluginSettings: React.FC; RatingNumber: React.FC; RatingStars: React.FC; RatingSystem: React.FC; + SceneFileInfoPanel: React.FC; + SceneIDSelect: React.FC; + ScenePage: React.FC; + "ScenePage.TabContent": React.FC; + "ScenePage.Tabs": React.FC; + ScenePlayer: React.FC; + SceneSelect: React.FC; + "SceneCard.Details": React.FC; + "SceneCard.Image": React.FC; + "SceneCard.Overlays": React.FC; + "SceneCard.Popovers": React.FC; + SelectSetting: React.FC; + Setting: React.FC; + SettingGroup: React.FC; + SettingModal: React.FC; + StringListSetting: React.FC; + StringSetting: React.FC; + StudioIDSelect: React.FC; + StudioSelect: React.FC; + SweatDrops: React.FC; + TabTitleCounter: React.FC; + TagIDSelect: React.FC; + "TagCard.Details": React.FC; + "TagCard.Image": React.FC; + "TagCard.Overlays": React.FC; + "TagCard.Popovers": React.FC; + "TagCard.Title": React.FC; + TagLink: React.FC; + TagSelect: React.FC; + TruncatedText: React.FC; }; type PatchableComponentNames = keyof typeof components | string; namespace utils { diff --git a/ui/v2.5/src/pluginApi.tsx b/ui/v2.5/src/pluginApi.tsx index 99d4a5992..e534dddef 100644 --- a/ui/v2.5/src/pluginApi.tsx +++ b/ui/v2.5/src/pluginApi.tsx @@ -16,9 +16,10 @@ import * as ReactSelect from "react-select"; import { useSpriteInfo } from "./hooks/sprite"; import { useToast } from "./hooks/Toast"; import Event from "./hooks/event"; -import { before, instead, after, components, RegisterComponent } from "./patch"; +import { after, before, components, instead, RegisterComponent } from "./patch"; import { useSettings } from "./components/Settings/context"; import { useInteractive } from "./hooks/Interactive/context"; +import InteractiveUtils from "./hooks/Interactive/utils"; import { useLightbox, useGalleryLightbox } from "./hooks/Lightbox/hooks"; // due to code splitting, some components may not have been loaded when a plugin @@ -152,6 +153,7 @@ export const PluginApi = { }, components, utils: { + InteractiveUtils, NavUtils, StashService, loadComponents, diff --git a/ui/v2.5/src/polyfills.ts b/ui/v2.5/src/polyfills.ts index 55914e1d9..ca5620e81 100644 --- a/ui/v2.5/src/polyfills.ts +++ b/ui/v2.5/src/polyfills.ts @@ -3,7 +3,6 @@ import { shouldPolyfill as shouldPolyfillCanonicalLocales } from "@formatjs/intl import { shouldPolyfill as shouldPolyfillLocale } from "@formatjs/intl-locale/should-polyfill"; import { shouldPolyfill as shouldPolyfillNumberformat } from "@formatjs/intl-numberformat/should-polyfill"; import { shouldPolyfill as shouldPolyfillPluralRules } from "@formatjs/intl-pluralrules/should-polyfill"; -import "intersection-observer"; // needed for older safari versions import "event-target-polyfill"; @@ -27,11 +26,6 @@ async function checkPolyfills() { await import("@formatjs/intl-pluralrules/polyfill"); await import("@formatjs/intl-pluralrules/locale-data/en"); } - - if (!("ResizeObserver" in window)) { - const ResizeObserver = await import("resize-observer-polyfill"); - window.ResizeObserver = ResizeObserver.default; - } } export const initPolyfills = async () => { diff --git a/ui/v2.5/src/sfw-mode.scss b/ui/v2.5/src/sfw-mode.scss new file mode 100644 index 000000000..9883afb4b --- /dev/null +++ b/ui/v2.5/src/sfw-mode.scss @@ -0,0 +1,91 @@ +// hide nsfw elements when in sfw-content mode +// stylelint-disable selector-class-pattern +.sfw-content-mode { + // hide adult-oriented performer fields in sort by select + .sort-by-select, + .performer-table { + [data-value="ethnicity"], + [data-value="hair_color"], + [data-value="eye_color"], + [data-value="measurements"], + [data-value="weight"], + [data-value="weight_kg"], + [data-value="penis_length"], + [data-value="penis_length_cm"], + [data-value="circumcised"], + [data-value="fake_tits"] { + display: none; + } + } + + .performer-table { + td, + th { + &.ethnicity, + &.hair_color, + &.eye_color, + &.height, + &.measurements, + &.weight_kg, + &.penis_length_cm, + &.circumcised, + &.fake_tits { + &-head, + &-data { + display: none; + } + } + } + } + + #performer-edit, + &.scrape-dialog { + [data-field="ethnicity"], + [data-field="hair_color"], + [data-field="eye_color"], + [data-field="measurements"], + [data-field="weight"], + [data-field="penis_length"], + [data-field="circumcised"], + [data-field="fake_tits"], + [data-field="tattoos"], + [data-field="piercings"] { + display: none; + } + } + + &.edit-filter-dialog { + [data-type="ethnicity"], + [data-type="hair_color"], + [data-type="eye_color"], + [data-type="measurements"], + [data-type="weight"], + [data-type="penis_length"], + [data-type="circumcised"], + [data-type="fake_tits"], + [data-type="tattoos"], + [data-type="piercings"] { + display: none; + } + } + + #performer-page { + .detail-item.ethnicity, + .detail-item.hair_color, + .detail-item.eye_color, + .detail-item.measurements, + .detail-item.weight, + .detail-item.penis_length, + .detail-item.circumcised, + .detail-item.fake_tits, + .detail-item.tattoos, + .detail-item.piercings { + display: none; + } + } + + // hide performer age on performer cards + .performer-card__age { + display: none; + } +} diff --git a/ui/v2.5/src/utils/focus.ts b/ui/v2.5/src/utils/focus.ts index f1ede47f9..cf1b20a88 100644 --- a/ui/v2.5/src/utils/focus.ts +++ b/ui/v2.5/src/utils/focus.ts @@ -2,10 +2,14 @@ import { useRef, useEffect, useCallback } from "react"; const useFocus = () => { const htmlElRef = useRef(null); - const setFocus = useCallback(() => { + const setFocus = useCallback((selectAll?: boolean) => { const currentEl = htmlElRef.current; if (currentEl) { - currentEl.focus(); + if (selectAll) { + currentEl.select(); + } else { + currentEl.focus(); + } } }, []); diff --git a/ui/v2.5/src/utils/form.tsx b/ui/v2.5/src/utils/form.tsx index f518d5700..1fef74cf2 100644 --- a/ui/v2.5/src/utils/form.tsx +++ b/ui/v2.5/src/utils/form.tsx @@ -175,7 +175,7 @@ export function formikUtils( props?: IProps ) { return ( - + {title} {control} diff --git a/ui/v2.5/src/utils/history.ts b/ui/v2.5/src/utils/history.ts new file mode 100644 index 000000000..6ae7b637f --- /dev/null +++ b/ui/v2.5/src/utils/history.ts @@ -0,0 +1,11 @@ +import { useHistory } from "react-router-dom"; + +type History = ReturnType; + +export function goBackOrReplace(history: History, defaultPath: string) { + if (history.length > 1) { + history.goBack(); + } else { + history.replace(defaultPath); + } +} diff --git a/ui/v2.5/yarn.lock b/ui/v2.5/yarn.lock deleted file mode 100644 index 76a398f9f..000000000 --- a/ui/v2.5/yarn.lock +++ /dev/null @@ -1,8344 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@ant-design/react-slick@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@ant-design/react-slick/-/react-slick-1.0.0.tgz#4696eecaa2dea0429e47ae24c267015cfd6df35c" - integrity sha512-OKxZsn8TAf8fYxP79rDXgLs9zvKMTslK6dJ4iLhDXOujUqC5zJPBRszyrcEHXcMPOm1Sgk40JgyF3yiL/Swd7w== - dependencies: - "@babel/runtime" "^7.10.4" - classnames "^2.2.5" - json2mq "^0.2.0" - resize-observer-polyfill "^1.5.1" - throttle-debounce "^5.0.0" - -"@apollo/client@^3.8.0", "@apollo/client@^3.8.10": - version "3.8.10" - resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.8.10.tgz#db6ee4378212d93c1f22b90a2aa474f6e9664b68" - integrity sha512-p/22RZ8ehHyvySnC20EHPPe0gdu8Xp6ZCiXOfdEe1ZORw5cUteD/TLc66tfKv8qu8NLIfbiWoa+6s70XnKvxqg== - dependencies: - "@graphql-typed-document-node/core" "^3.1.1" - "@wry/equality" "^0.5.6" - "@wry/trie" "^0.5.0" - graphql-tag "^2.12.6" - hoist-non-react-statics "^3.3.2" - optimism "^0.18.0" - prop-types "^15.7.2" - response-iterator "^0.2.6" - symbol-observable "^4.0.0" - ts-invariant "^0.10.3" - tslib "^2.3.0" - zen-observable-ts "^1.2.5" - -"@ardatan/relay-compiler@12.0.0": - version "12.0.0" - resolved "https://registry.yarnpkg.com/@ardatan/relay-compiler/-/relay-compiler-12.0.0.tgz#2e4cca43088e807adc63450e8cab037020e91106" - integrity sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q== - dependencies: - "@babel/core" "^7.14.0" - "@babel/generator" "^7.14.0" - "@babel/parser" "^7.14.0" - "@babel/runtime" "^7.0.0" - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.0.0" - babel-preset-fbjs "^3.4.0" - chalk "^4.0.0" - fb-watchman "^2.0.0" - fbjs "^3.0.0" - glob "^7.1.1" - immutable "~3.7.6" - invariant "^2.2.4" - nullthrows "^1.1.1" - relay-runtime "12.0.0" - signedsource "^1.0.0" - yargs "^15.3.1" - -"@ardatan/sync-fetch@^0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@ardatan/sync-fetch/-/sync-fetch-0.0.1.tgz#3385d3feedceb60a896518a1db857ec1e945348f" - integrity sha512-xhlTqH0m31mnsG0tIP4ETgfSB6gXDaYYsUWTrlUV93fFQPI9dd8hE0Ot6MHLCtqgB32hwJAC3YZMWlXZw7AleA== - dependencies: - node-fetch "^2.6.1" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== - dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" - -"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5", "@babel/compat-data@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" - integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== - -"@babel/core@^7.14.0", "@babel/core@^7.20.12", "@babel/core@^7.22.9", "@babel/core@^7.9.0": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.9.tgz#b028820718000f267870822fec434820e9b1e4d1" - integrity sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.23.9" - "@babel/parser" "^7.23.9" - "@babel/template" "^7.23.9" - "@babel/traverse" "^7.23.9" - "@babel/types" "^7.23.9" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@^7.14.0", "@babel/generator@^7.18.13", "@babel/generator@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" - integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== - dependencies: - "@babel/types" "^7.23.6" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/helper-annotate-as-pure@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" - integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb" - integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.18.6" - "@babel/types" "^7.18.9" - -"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.0", "@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== - dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.0.tgz#64f49ecb0020532f19b1d014b03bccaa1ab85fb9" - integrity sha512-Q8wNiMIdwsv5la5SPxNYzzkPnjgC0Sy0i7jLkVOCdllu/xcVNkr3TeZzbHBJrj+XXRqzX5uCyCoV9eu6xUG7KQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-member-expression-to-functions" "^7.21.0" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-replace-supers" "^7.20.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/helper-split-export-declaration" "^7.18.6" - -"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.20.5": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.0.tgz#53ff78472e5ce10a52664272a239787107603ebb" - integrity sha512-N+LaFW/auRSWdx7SHD/HiARwXQju1vXTW4fKr4u5SgBUTm51OKEjKgj+cs00ggW3kEvNqwErnlwuq7Y3xBe4eg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - regexpu-core "^5.3.1" - -"@babel/helper-define-polyfill-provider@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz#8612e55be5d51f0cd1f36b4a5a83924e89884b7a" - integrity sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww== - dependencies: - "@babel/helper-compilation-targets" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - -"@babel/helper-environment-visitor@^7.18.9", "@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-explode-assignable-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" - integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0", "@babel/helper-function-name@^7.21.0", "@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.18.6", "@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-member-expression-to-functions@^7.20.7", "@babel/helper-member-expression-to-functions@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz#319c6a940431a133897148515877d2f3269c3ba5" - integrity sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q== - dependencies: - "@babel/types" "^7.21.0" - -"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== - dependencies: - "@babel/types" "^7.22.15" - -"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" - integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.20" - -"@babel/helper-optimise-call-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" - integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" - integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== - -"@babel/helper-remap-async-to-generator@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" - integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-wrap-function" "^7.18.9" - "@babel/types" "^7.18.9" - -"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz#243ecd2724d2071532b2c8ad2f0f9f083bcae331" - integrity sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-member-expression-to-functions" "^7.20.7" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.20.7" - "@babel/types" "^7.20.7" - -"@babel/helper-simple-access@^7.20.2", "@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-skip-transparent-expression-wrappers@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" - integrity sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg== - dependencies: - "@babel/types" "^7.20.0" - -"@babel/helper-split-export-declaration@^7.18.6", "@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== - -"@babel/helper-validator-identifier@^7.19.1", "@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-option@^7.18.6", "@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== - -"@babel/helper-wrap-function@^7.18.9": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3" - integrity sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q== - dependencies: - "@babel/helper-function-name" "^7.19.0" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.20.5" - "@babel/types" "^7.20.5" - -"@babel/helpers@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.9.tgz#c3e20bbe7f7a7e10cb9b178384b4affdf5995c7d" - integrity sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ== - dependencies: - "@babel/template" "^7.23.9" - "@babel/traverse" "^7.23.9" - "@babel/types" "^7.23.9" - -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.14.0", "@babel/parser@^7.16.8", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.9.tgz#7b903b6149b0f8fa7ad564af646c4c38a77fc44b" - integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA== - -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" - integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz#d9c85589258539a22a901033853101a6198d4ef1" - integrity sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/plugin-proposal-optional-chaining" "^7.20.7" - -"@babel/plugin-proposal-async-generator-functions@^7.20.1": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326" - integrity sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-remap-async-to-generator" "^7.18.9" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" - integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-class-static-block@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz#77bdd66fb7b605f3a61302d224bdfacf5547977d" - integrity sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.21.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - -"@babel/plugin-proposal-dynamic-import@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94" - integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - -"@babel/plugin-proposal-export-namespace-from@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203" - integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - -"@babel/plugin-proposal-json-strings@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b" - integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-json-strings" "^7.8.3" - -"@babel/plugin-proposal-logical-assignment-operators@^7.18.9": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz#dfbcaa8f7b4d37b51e8bfb46d94a5aea2bb89d83" - integrity sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" - integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-numeric-separator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" - integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - -"@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.20.2": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" - integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== - dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.20.7" - -"@babel/plugin-proposal-optional-catch-binding@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb" - integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.18.9", "@babel/plugin-proposal-optional-chaining@^7.20.7": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz#886f5c8978deb7d30f678b2e24346b287234d3ea" - integrity sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-proposal-private-methods@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea" - integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-private-property-in-object@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz#19496bd9883dd83c23c7d7fc45dcd9ad02dfa1dc" - integrity sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-create-class-features-plugin" "^7.21.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - -"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" - integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.0.0", "@babel/plugin-syntax-class-properties@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" - integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-export-namespace-from@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" - integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz#774d825256f2379d06139be0c723c4dd444f3ca1" - integrity sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-syntax-import-assertions@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz#bb50e0d4bea0957235390641209394e87bdb9cc4" - integrity sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ== - dependencies: - "@babel/helper-plugin-utils" "^7.19.0" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.17.12", "@babel/plugin-syntax-jsx@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" - integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" - integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-top-level-await@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-arrow-functions@^7.0.0", "@babel/plugin-transform-arrow-functions@^7.18.6": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz#bea332b0e8b2dab3dafe55a163d8227531ab0551" - integrity sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-async-to-generator@^7.18.6": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz#dfee18623c8cb31deb796aa3ca84dda9cea94354" - integrity sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q== - dependencies: - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-remap-async-to-generator" "^7.18.9" - -"@babel/plugin-transform-block-scoped-functions@^7.0.0", "@babel/plugin-transform-block-scoped-functions@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8" - integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-block-scoping@^7.0.0", "@babel/plugin-transform-block-scoping@^7.20.2": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz#e737b91037e5186ee16b76e7ae093358a5634f02" - integrity sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-classes@^7.0.0", "@babel/plugin-transform-classes@^7.20.2": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz#f469d0b07a4c5a7dbb21afad9e27e57b47031665" - integrity sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-replace-supers" "^7.20.7" - "@babel/helper-split-export-declaration" "^7.18.6" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.0.0", "@babel/plugin-transform-computed-properties@^7.18.9": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz#704cc2fd155d1c996551db8276d55b9d46e4d0aa" - integrity sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/template" "^7.20.7" - -"@babel/plugin-transform-destructuring@^7.0.0", "@babel/plugin-transform-destructuring@^7.20.2": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz#8bda578f71620c7de7c93af590154ba331415454" - integrity sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8" - integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-duplicate-keys@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e" - integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-exponentiation-operator@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd" - integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-flow-strip-types@^7.0.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz#e9e8606633287488216028719638cbbb2f2dde8f" - integrity sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg== - dependencies: - "@babel/helper-plugin-utils" "^7.19.0" - "@babel/plugin-syntax-flow" "^7.18.6" - -"@babel/plugin-transform-for-of@^7.0.0", "@babel/plugin-transform-for-of@^7.18.8": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz#964108c9988de1a60b4be2354a7d7e245f36e86e" - integrity sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-function-name@^7.0.0", "@babel/plugin-transform-function-name@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0" - integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== - dependencies: - "@babel/helper-compilation-targets" "^7.18.9" - "@babel/helper-function-name" "^7.18.9" - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-literals@^7.0.0", "@babel/plugin-transform-literals@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc" - integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-member-expression-literals@^7.0.0", "@babel/plugin-transform-member-expression-literals@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e" - integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-modules-amd@^7.19.6": - version "7.20.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz#3daccca8e4cc309f03c3a0c4b41dc4b26f55214a" - integrity sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g== - dependencies: - "@babel/helper-module-transforms" "^7.20.11" - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-modules-commonjs@^7.0.0", "@babel/plugin-transform-modules-commonjs@^7.19.6": - version "7.20.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz#8cb23010869bf7669fd4b3098598b6b2be6dc607" - integrity sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw== - dependencies: - "@babel/helper-module-transforms" "^7.20.11" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-simple-access" "^7.20.2" - -"@babel/plugin-transform-modules-systemjs@^7.19.6": - version "7.20.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz#467ec6bba6b6a50634eea61c9c232654d8a4696e" - integrity sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw== - dependencies: - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-module-transforms" "^7.20.11" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-validator-identifier" "^7.19.1" - -"@babel/plugin-transform-modules-umd@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9" - integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== - dependencies: - "@babel/helper-module-transforms" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.19.1": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz#626298dd62ea51d452c3be58b285d23195ba69a8" - integrity sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.20.5" - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-new-target@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8" - integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-object-super@^7.0.0", "@babel/plugin-transform-object-super@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c" - integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-replace-supers" "^7.18.6" - -"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.20.1", "@babel/plugin-transform-parameters@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz#0ee349e9d1bc96e78e3b37a7af423a4078a7083f" - integrity sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-transform-property-literals@^7.0.0", "@babel/plugin-transform-property-literals@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3" - integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-react-display-name@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415" - integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-react-jsx-self@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz#3849401bab7ae8ffa1e3e5687c94a753fc75bda7" - integrity sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-react-jsx-source@^7.19.6": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz#88578ae8331e5887e8ce28e4c9dc83fb29da0b86" - integrity sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ== - dependencies: - "@babel/helper-plugin-utils" "^7.19.0" - -"@babel/plugin-transform-react-jsx@^7.0.0": - version "7.20.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.20.13.tgz#f950f0b0c36377503d29a712f16287cedf886cbb" - integrity sha512-MmTZx/bkUrfJhhYAYt3Urjm+h8DQGrPrnKQ94jLo7NLuOU+T89a7IByhKmrb8SKhrIYIQ0FN0CHMbnFRen4qNw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-jsx" "^7.18.6" - "@babel/types" "^7.20.7" - -"@babel/plugin-transform-regenerator@^7.18.6": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz#57cda588c7ffb7f4f8483cc83bdcea02a907f04d" - integrity sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - regenerator-transform "^0.15.1" - -"@babel/plugin-transform-reserved-words@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a" - integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-shorthand-properties@^7.0.0", "@babel/plugin-transform-shorthand-properties@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" - integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-spread@^7.0.0", "@babel/plugin-transform-spread@^7.19.0": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz#c2d83e0b99d3bf83e07b11995ee24bf7ca09401e" - integrity sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - -"@babel/plugin-transform-sticky-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc" - integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-template-literals@^7.0.0", "@babel/plugin-transform-template-literals@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e" - integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-typeof-symbol@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0" - integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-unicode-escapes@^7.18.10": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246" - integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ== - dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - -"@babel/plugin-transform-unicode-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca" - integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/preset-env@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.20.2.tgz#9b1642aa47bb9f43a86f9630011780dab7f86506" - integrity sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg== - dependencies: - "@babel/compat-data" "^7.20.1" - "@babel/helper-compilation-targets" "^7.20.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-validator-option" "^7.18.6" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" - "@babel/plugin-proposal-async-generator-functions" "^7.20.1" - "@babel/plugin-proposal-class-properties" "^7.18.6" - "@babel/plugin-proposal-class-static-block" "^7.18.6" - "@babel/plugin-proposal-dynamic-import" "^7.18.6" - "@babel/plugin-proposal-export-namespace-from" "^7.18.9" - "@babel/plugin-proposal-json-strings" "^7.18.6" - "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" - "@babel/plugin-proposal-numeric-separator" "^7.18.6" - "@babel/plugin-proposal-object-rest-spread" "^7.20.2" - "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" - "@babel/plugin-proposal-optional-chaining" "^7.18.9" - "@babel/plugin-proposal-private-methods" "^7.18.6" - "@babel/plugin-proposal-private-property-in-object" "^7.18.6" - "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-import-assertions" "^7.20.0" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.18.6" - "@babel/plugin-transform-async-to-generator" "^7.18.6" - "@babel/plugin-transform-block-scoped-functions" "^7.18.6" - "@babel/plugin-transform-block-scoping" "^7.20.2" - "@babel/plugin-transform-classes" "^7.20.2" - "@babel/plugin-transform-computed-properties" "^7.18.9" - "@babel/plugin-transform-destructuring" "^7.20.2" - "@babel/plugin-transform-dotall-regex" "^7.18.6" - "@babel/plugin-transform-duplicate-keys" "^7.18.9" - "@babel/plugin-transform-exponentiation-operator" "^7.18.6" - "@babel/plugin-transform-for-of" "^7.18.8" - "@babel/plugin-transform-function-name" "^7.18.9" - "@babel/plugin-transform-literals" "^7.18.9" - "@babel/plugin-transform-member-expression-literals" "^7.18.6" - "@babel/plugin-transform-modules-amd" "^7.19.6" - "@babel/plugin-transform-modules-commonjs" "^7.19.6" - "@babel/plugin-transform-modules-systemjs" "^7.19.6" - "@babel/plugin-transform-modules-umd" "^7.18.6" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1" - "@babel/plugin-transform-new-target" "^7.18.6" - "@babel/plugin-transform-object-super" "^7.18.6" - "@babel/plugin-transform-parameters" "^7.20.1" - "@babel/plugin-transform-property-literals" "^7.18.6" - "@babel/plugin-transform-regenerator" "^7.18.6" - "@babel/plugin-transform-reserved-words" "^7.18.6" - "@babel/plugin-transform-shorthand-properties" "^7.18.6" - "@babel/plugin-transform-spread" "^7.19.0" - "@babel/plugin-transform-sticky-regex" "^7.18.6" - "@babel/plugin-transform-template-literals" "^7.18.9" - "@babel/plugin-transform-typeof-symbol" "^7.18.9" - "@babel/plugin-transform-unicode-escapes" "^7.18.10" - "@babel/plugin-transform-unicode-regex" "^7.18.6" - "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.20.2" - babel-plugin-polyfill-corejs2 "^0.3.3" - babel-plugin-polyfill-corejs3 "^0.6.0" - babel-plugin-polyfill-regenerator "^0.4.1" - core-js-compat "^3.25.1" - semver "^6.3.0" - -"@babel/preset-modules@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" - integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - -"@babel/regjsgen@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" - integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== - -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.8", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": - version "7.27.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.0.tgz#fbee7cf97c709518ecc1f590984481d5460d4762" - integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.22.15", "@babel/template@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.23.9.tgz#f881d0487cba2828d3259dcb9ef5005a9731011a" - integrity sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.23.9" - "@babel/types" "^7.23.9" - -"@babel/traverse@^7.14.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.23.9": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.9.tgz#2f9d6aead6b564669394c5ce0f9302bb65b9d950" - integrity sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.9" - "@babel/types" "^7.23.9" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.16.8", "@babel/types@^7.18.13", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.23.9", "@babel/types@^7.3.0", "@babel/types@^7.4.4", "@babel/types@^7.9.5": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.9.tgz#1dd7b59a9a2b5c87f8b41e52770b5ecbf492e002" - integrity sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - -"@csstools/css-parser-algorithms@^2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.3.0.tgz#0cc3a656dc2d638370ecf6f98358973bfbd00141" - integrity sha512-dTKSIHHWc0zPvcS5cqGP+/TPFUJB0ekJ9dGKvMAFoNuBFhDPBt9OMGNZiIA5vTiNdGHHBeScYPXIGBMnVOahsA== - -"@csstools/css-tokenizer@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-2.1.1.tgz#07ae11a0a06365d7ec686549db7b729bc036528e" - integrity sha512-GbrTj2Z8MCTUv+52GE0RbFGM527xuXZ0Xa5g0Z+YN573uveS4G0qi6WNOMyz3yrFM/jaILTTwJ0+umx81EzqfA== - -"@csstools/media-query-list-parser@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.2.tgz#6ef642b728d30c1009bfbba3211c7e4c11302728" - integrity sha512-M8cFGGwl866o6++vIY7j1AKuq9v57cf+dGepScwCcbut9ypJNr4Cj+LLTWligYUZ0uyhEoJDKt5lvyBfh2L3ZQ== - -"@csstools/selector-specificity@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz#798622546b63847e82389e473fd67f2707d82247" - integrity sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g== - -"@emotion/babel-plugin@^11.10.5": - version "11.10.5" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz#65fa6e1790ddc9e23cc22658a4c5dea423c55c3c" - integrity sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA== - dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/plugin-syntax-jsx" "^7.17.12" - "@babel/runtime" "^7.18.3" - "@emotion/hash" "^0.9.0" - "@emotion/memoize" "^0.8.0" - "@emotion/serialize" "^1.1.1" - babel-plugin-macros "^3.1.0" - convert-source-map "^1.5.0" - escape-string-regexp "^4.0.0" - find-root "^1.1.0" - source-map "^0.5.7" - stylis "4.1.3" - -"@emotion/cache@^11.10.5", "@emotion/cache@^11.4.0": - version "11.10.5" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.5.tgz#c142da9351f94e47527ed458f7bbbbe40bb13c12" - integrity sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA== - dependencies: - "@emotion/memoize" "^0.8.0" - "@emotion/sheet" "^1.2.1" - "@emotion/utils" "^1.2.0" - "@emotion/weak-memoize" "^0.3.0" - stylis "4.1.3" - -"@emotion/hash@^0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7" - integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ== - -"@emotion/memoize@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f" - integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA== - -"@emotion/react@^11.8.1": - version "11.10.5" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.5.tgz#95fff612a5de1efa9c0d535384d3cfa115fe175d" - integrity sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A== - dependencies: - "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.10.5" - "@emotion/cache" "^11.10.5" - "@emotion/serialize" "^1.1.1" - "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" - "@emotion/utils" "^1.2.0" - "@emotion/weak-memoize" "^0.3.0" - hoist-non-react-statics "^3.3.1" - -"@emotion/serialize@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.1.tgz#0595701b1902feded8a96d293b26be3f5c1a5cf0" - integrity sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA== - dependencies: - "@emotion/hash" "^0.9.0" - "@emotion/memoize" "^0.8.0" - "@emotion/unitless" "^0.8.0" - "@emotion/utils" "^1.2.0" - csstype "^3.0.2" - -"@emotion/sheet@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.1.tgz#0767e0305230e894897cadb6c8df2c51e61a6c2c" - integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA== - -"@emotion/unitless@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db" - integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw== - -"@emotion/use-insertion-effect-with-fallbacks@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df" - integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A== - -"@emotion/utils@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561" - integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw== - -"@emotion/weak-memoize@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" - integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== - -"@esbuild/android-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" - integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== - -"@esbuild/android-arm@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" - integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== - -"@esbuild/android-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" - integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== - -"@esbuild/darwin-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" - integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== - -"@esbuild/darwin-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" - integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== - -"@esbuild/freebsd-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" - integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== - -"@esbuild/freebsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" - integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== - -"@esbuild/linux-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" - integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== - -"@esbuild/linux-arm@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" - integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== - -"@esbuild/linux-ia32@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" - integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== - -"@esbuild/linux-loong64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" - integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== - -"@esbuild/linux-mips64el@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" - integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== - -"@esbuild/linux-ppc64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" - integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== - -"@esbuild/linux-riscv64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" - integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== - -"@esbuild/linux-s390x@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" - integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== - -"@esbuild/linux-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" - integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== - -"@esbuild/netbsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" - integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== - -"@esbuild/openbsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" - integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== - -"@esbuild/sunos-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" - integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== - -"@esbuild/win32-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" - integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== - -"@esbuild/win32-ia32@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" - integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== - -"@esbuild/win32-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" - integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== - -"@eslint/eslintrc@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e" - integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.4.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" - -"@floating-ui/core@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.1.tgz#074182a1d277f94569c50a6b456e62585d463c8e" - integrity sha512-LSqwPZkK3rYfD7GKoIeExXOyYx6Q1O4iqZWwIehDNuv3Dv425FIAE8PRwtAx1imEolFTHgBEcoFHm9MDnYgPCg== - -"@floating-ui/dom@^1.0.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.1.tgz#8f93906e1a3b9f606ce78afb058e874344dcbe07" - integrity sha512-Rt45SmRiV8eU+xXSB9t0uMYiQ/ZWGE/jumse2o3i5RGlyvcbqOF4q+1qBnzLE2kZ5JGhq0iMkcGXUKbFe7MpTA== - dependencies: - "@floating-ui/core" "^1.2.1" - -"@formatjs/ecma402-abstract@1.14.3": - version "1.14.3" - resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.14.3.tgz#6428f243538a11126180d121ce8d4b2f17465738" - integrity sha512-SlsbRC/RX+/zg4AApWIFNDdkLtFbkq3LNoZWXZCE/nHVKqoIJyaoQyge/I0Y38vLxowUn9KTtXgusLD91+orbg== - dependencies: - "@formatjs/intl-localematcher" "0.2.32" - tslib "^2.4.0" - -"@formatjs/ecma402-abstract@1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.4.0.tgz#ac6c17a8fffac43c6d68c849a7b732626d32654c" - integrity sha512-Mv027hcLFjE45K8UJ8PjRpdDGfR0aManEFj1KzoN8zXNveHGEygpZGfFf/FTTMl+QEVSrPAUlyxaCApvmv47AQ== - dependencies: - tslib "^2.0.1" - -"@formatjs/ecma402-abstract@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.5.0.tgz#759c8f11ff45e96f8fb58741e7fbdb41096d5ddd" - integrity sha512-wXv36yo+mfWllweN0Fq7sUs7PUiNopn7I0JpLTe3hGu6ZMR4CV7LqK1llhB18pndwpKoafQKb1et2DCJAOW20Q== - dependencies: - tslib "^2.0.1" - -"@formatjs/fast-memoize@1.2.8": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.2.8.tgz#425a69f783005f69e11f9e38a7f87f8822d330c6" - integrity sha512-PemNUObyoIZcqdQ1ixTPugzAzhEj7j6AHIyrq/qR6x5BFTvOQeXHYsVZUqBEFduAIscUaDfou+U+xTqOiunJ3Q== - dependencies: - tslib "^2.4.0" - -"@formatjs/icu-messageformat-parser@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.2.0.tgz#9221f7f4dbaf634a84e459a49017a872e708dcfa" - integrity sha512-NT/jKI9nvqNIsosTm+Cxv3BHutB1RIDFa4rAa2b664Od4sBnXtK7afXvAqNa3XDFxljKTij9Cp+kRMJbXozUww== - dependencies: - "@formatjs/ecma402-abstract" "1.14.3" - "@formatjs/icu-skeleton-parser" "1.3.18" - tslib "^2.4.0" - -"@formatjs/icu-skeleton-parser@1.3.18": - version "1.3.18" - resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.18.tgz#7aed3d60e718c8ad6b0e64820be44daa1e29eeeb" - integrity sha512-ND1ZkZfmLPcHjAH1sVpkpQxA+QYfOX3py3SjKWMUVGDow18gZ0WPqz3F+pJLYQMpS2LnnQ5zYR2jPVYTbRwMpg== - dependencies: - "@formatjs/ecma402-abstract" "1.14.3" - tslib "^2.4.0" - -"@formatjs/intl-displaynames@6.2.4": - version "6.2.4" - resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.2.4.tgz#e2cc5f5828074f3263e44247491f2698fa4c22dd" - integrity sha512-CmTbSjnmAZHNGuA9vBkWoDHvrcrRauDb0OWc6nk2dAPtesQdadr49Q9N18fr8IV7n3rblgKiYaFVjg68UkRxNg== - dependencies: - "@formatjs/ecma402-abstract" "1.14.3" - "@formatjs/intl-localematcher" "0.2.32" - tslib "^2.4.0" - -"@formatjs/intl-getcanonicallocales@2.0.5", "@formatjs/intl-getcanonicallocales@^2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@formatjs/intl-getcanonicallocales/-/intl-getcanonicallocales-2.0.5.tgz#d405cf5221f49531e62ecfde50acdfb62fcc4854" - integrity sha512-YOk+Fa5gpPq5bdpm8JDAY5bkfCkR+NENZKQbLHeqhm8JchHcclPwZ9FU48gYGg3CW6Wi/cTCOvmOrzsIhlkr0w== - dependencies: - tslib "^2.4.0" - -"@formatjs/intl-listformat@7.1.7": - version "7.1.7" - resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.1.7.tgz#b46fec1038ef9ca062d1e7b9b3412c2a14dca18f" - integrity sha512-Zzf5ruPpfJnrAA2hGgf/6pMgQ3tx9oJVhpqycFDavHl3eEzrwdHddGqGdSNwhd0bB4NAFttZNQdmKDldc5iDZw== - dependencies: - "@formatjs/ecma402-abstract" "1.14.3" - "@formatjs/intl-localematcher" "0.2.32" - tslib "^2.4.0" - -"@formatjs/intl-locale@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@formatjs/intl-locale/-/intl-locale-3.0.11.tgz#6b3bee5692fab3c70a0ce9c642c2a2bec3700aa4" - integrity sha512-gLEX9kzebBjIVCkXMMN+VFMUV2aj0vhmrP+nke2muxUSJ3fLs/DJjlkv+s59rAL3nNaGdvphqKLhQsul0mmhAw== - dependencies: - "@formatjs/ecma402-abstract" "1.14.3" - "@formatjs/intl-getcanonicallocales" "2.0.5" - tslib "^2.4.0" - -"@formatjs/intl-localematcher@0.2.32": - version "0.2.32" - resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.32.tgz#00d4d307cd7d514b298e15a11a369b86c8933ec1" - integrity sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ== - dependencies: - tslib "^2.4.0" - -"@formatjs/intl-numberformat@^5.5.2": - version "5.7.6" - resolved "https://registry.yarnpkg.com/@formatjs/intl-numberformat/-/intl-numberformat-5.7.6.tgz#630206bb0acefd2d508ccf4f82367c6875cad611" - integrity sha512-ZlZfYtvbVHYZY5OG3RXizoCwxKxEKOrzEe2YOw9wbzoxF3PmFn0SAgojCFGLyNXkkR6xVxlylhbuOPf1dkIVNg== - dependencies: - "@formatjs/ecma402-abstract" "1.4.0" - tslib "^2.0.1" - -"@formatjs/intl-numberformat@^8.3.3": - version "8.3.3" - resolved "https://registry.yarnpkg.com/@formatjs/intl-numberformat/-/intl-numberformat-8.3.3.tgz#bfba1a90a22a28479dae4cf8cc16fb81ff659a36" - integrity sha512-11mSFZb5RsCVZMVaHbRcDYNxQ+tsstReL62AJcTCBZdvAZMqECOEsDkJODZ90nf/ClKqp0/KxwVlshxprn22Nw== - dependencies: - "@formatjs/ecma402-abstract" "1.14.3" - "@formatjs/intl-localematcher" "0.2.32" - tslib "^2.4.0" - -"@formatjs/intl-pluralrules@^5.1.8": - version "5.1.8" - resolved "https://registry.yarnpkg.com/@formatjs/intl-pluralrules/-/intl-pluralrules-5.1.8.tgz#11eeca3cde088fd68d258a09b0791b327a8eb019" - integrity sha512-uevO916EWoeuueqeNzHjnUzpfWZzXFJibC/sEvPR/ZiZH5btWuOLeJLdb1To4nMH8ZJQlmAf8SDpFf+eWvz5lQ== - dependencies: - "@formatjs/ecma402-abstract" "1.14.3" - "@formatjs/intl-localematcher" "0.2.32" - tslib "^2.4.0" - -"@formatjs/intl@2.6.5": - version "2.6.5" - resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.6.5.tgz#349dc624a06978b143135201dcf63d40ba3cd816" - integrity sha512-kNH221hsdbTAMdsF6JAxSFV4N/9p5azXZvCLQBxl10Q4D2caPODLtne98gRhinIJ8Hv3djBabPdJG32OQaHuMA== - dependencies: - "@formatjs/ecma402-abstract" "1.14.3" - "@formatjs/fast-memoize" "1.2.8" - "@formatjs/icu-messageformat-parser" "2.2.0" - "@formatjs/intl-displaynames" "6.2.4" - "@formatjs/intl-listformat" "7.1.7" - intl-messageformat "10.3.0" - tslib "^2.4.0" - -"@formatjs/ts-transformer@^2.6.0": - version "2.13.0" - resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-2.13.0.tgz#df47b35cdd209269d282a411f1646e0498aa8fdc" - integrity sha512-mu7sHXZk1NWZrQ3eUqugpSYo8x5/tXkrI4uIbFqCEC0eNgQaIcoKgVeDFgDAcgG+cEme2atAUYSFF+DFWC4org== - dependencies: - intl-messageformat-parser "6.1.2" - tslib "^2.0.1" - typescript "^4.0" - -"@fortawesome/fontawesome-common-types@6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz#51f734e64511dbc3674cd347044d02f4dd26e86b" - integrity sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg== - -"@fortawesome/fontawesome-svg-core@^6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz#b6a17d48d231ac1fad93e43fca7271676bf316cf" - integrity sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw== - dependencies: - "@fortawesome/fontawesome-common-types" "6.3.0" - -"@fortawesome/free-brands-svg-icons@^6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.3.0.tgz#436e5fcba4f4f0902edcceaec5c4ff887ba7328f" - integrity sha512-xI0c+a8xnKItAXCN8rZgCNCJQiVAd2Y7p9e2ND6zN3J3ekneu96qrePieJ7yA7073C1JxxoM3vH1RU7rYsaj8w== - dependencies: - "@fortawesome/fontawesome-common-types" "6.3.0" - -"@fortawesome/free-regular-svg-icons@^6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.3.0.tgz#286f87f777e6c96af59151e86647c81083029ee2" - integrity sha512-cZnwiVHZ51SVzWHOaNCIA+u9wevZjCuAGSvSYpNlm6A4H4Vhwh8481Bf/5rwheIC3fFKlgXxLKaw8Xeroz8Ntg== - dependencies: - "@fortawesome/fontawesome-common-types" "6.3.0" - -"@fortawesome/free-solid-svg-icons@^6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz#d3bd33ae18bb15fdfc3ca136e2fea05f32768a65" - integrity sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA== - dependencies: - "@fortawesome/fontawesome-common-types" "6.3.0" - -"@fortawesome/react-fontawesome@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz#d90dd8a9211830b4e3c08e94b63a0ba7291ddcf4" - integrity sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw== - dependencies: - prop-types "^15.8.1" - -"@graphql-codegen/cli@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@graphql-codegen/cli/-/cli-5.0.0.tgz#761dcf08cfee88bbdd9cdf8097b2343445ec6f0a" - integrity sha512-A7J7+be/a6e+/ul2KI5sfJlpoqeqwX8EzktaKCeduyVKgOLA6W5t+NUGf6QumBDXU8PEOqXk3o3F+RAwCWOiqA== - dependencies: - "@babel/generator" "^7.18.13" - "@babel/template" "^7.18.10" - "@babel/types" "^7.18.13" - "@graphql-codegen/core" "^4.0.0" - "@graphql-codegen/plugin-helpers" "^5.0.1" - "@graphql-tools/apollo-engine-loader" "^8.0.0" - "@graphql-tools/code-file-loader" "^8.0.0" - "@graphql-tools/git-loader" "^8.0.0" - "@graphql-tools/github-loader" "^8.0.0" - "@graphql-tools/graphql-file-loader" "^8.0.0" - "@graphql-tools/json-file-loader" "^8.0.0" - "@graphql-tools/load" "^8.0.0" - "@graphql-tools/prisma-loader" "^8.0.0" - "@graphql-tools/url-loader" "^8.0.0" - "@graphql-tools/utils" "^10.0.0" - "@whatwg-node/fetch" "^0.8.0" - chalk "^4.1.0" - cosmiconfig "^8.1.3" - debounce "^1.2.0" - detect-indent "^6.0.0" - graphql-config "^5.0.2" - inquirer "^8.0.0" - is-glob "^4.0.1" - jiti "^1.17.1" - json-to-pretty-yaml "^1.2.2" - listr2 "^4.0.5" - log-symbols "^4.0.0" - micromatch "^4.0.5" - shell-quote "^1.7.3" - string-env-interpolation "^1.0.1" - ts-log "^2.2.3" - tslib "^2.4.0" - yaml "^2.3.1" - yargs "^17.0.0" - -"@graphql-codegen/core@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@graphql-codegen/core/-/core-4.0.0.tgz#b29c911746a532a675e33720acb4eb2119823e01" - integrity sha512-JAGRn49lEtSsZVxeIlFVIRxts2lWObR+OQo7V2LHDJ7ohYYw3ilv7nJ8pf8P4GTg/w6ptcYdSdVVdkI8kUHB/Q== - dependencies: - "@graphql-codegen/plugin-helpers" "^5.0.0" - "@graphql-tools/schema" "^10.0.0" - "@graphql-tools/utils" "^10.0.0" - tslib "~2.5.0" - -"@graphql-codegen/plugin-helpers@^2.7.2": - version "2.7.2" - resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-2.7.2.tgz#6544f739d725441c826a8af6a49519f588ff9bed" - integrity sha512-kln2AZ12uii6U59OQXdjLk5nOlh1pHis1R98cDZGFnfaiAbX9V3fxcZ1MMJkB7qFUymTALzyjZoXXdyVmPMfRg== - dependencies: - "@graphql-tools/utils" "^8.8.0" - change-case-all "1.0.14" - common-tags "1.8.2" - import-from "4.0.0" - lodash "~4.17.0" - tslib "~2.4.0" - -"@graphql-codegen/plugin-helpers@^3.0.0": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-3.1.2.tgz#69a2e91178f478ea6849846ade0a59a844d34389" - integrity sha512-emOQiHyIliVOIjKVKdsI5MXj312zmRDwmHpyUTZMjfpvxq/UVAHUJIVdVf+lnjjrI+LXBTgMlTWTgHQfmICxjg== - dependencies: - "@graphql-tools/utils" "^9.0.0" - change-case-all "1.0.15" - common-tags "1.8.2" - import-from "4.0.0" - lodash "~4.17.0" - tslib "~2.4.0" - -"@graphql-codegen/plugin-helpers@^5.0.0", "@graphql-codegen/plugin-helpers@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-5.0.1.tgz#e2429fcfba3f078d5aa18aa062d46c922bbb0d55" - integrity sha512-6L5sb9D8wptZhnhLLBcheSPU7Tg//DGWgc5tQBWX46KYTOTQHGqDpv50FxAJJOyFVJrveN9otWk9UT9/yfY4ww== - dependencies: - "@graphql-tools/utils" "^10.0.0" - change-case-all "1.0.15" - common-tags "1.8.2" - import-from "4.0.0" - lodash "~4.17.0" - tslib "~2.5.0" - -"@graphql-codegen/schema-ast@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@graphql-codegen/schema-ast/-/schema-ast-4.0.0.tgz#5d60996c87b64f81847da8fcb2d8ef50ede89755" - integrity sha512-WIzkJFa9Gz28FITAPILbt+7A8+yzOyd1NxgwFh7ie+EmO9a5zQK6UQ3U/BviirguXCYnn+AR4dXsoDrSrtRA1g== - dependencies: - "@graphql-codegen/plugin-helpers" "^5.0.0" - "@graphql-tools/utils" "^10.0.0" - tslib "~2.5.0" - -"@graphql-codegen/time@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@graphql-codegen/time/-/time-5.0.0.tgz#832754bcc3dfa62a5e9c612fc3c8a0fe852ea533" - integrity sha512-RI9b3Wm2kci046atAqYfldHtVETi8/mewtfaRJyQn/xBCWwvTEJUL3gr/IxQbEgHRmZEadsWKtIyn7p/OOYQmg== - dependencies: - "@graphql-codegen/plugin-helpers" "^5.0.0" - moment "~2.29.1" - -"@graphql-codegen/typescript-operations@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-operations/-/typescript-operations-4.0.1.tgz#930af3e2d2ae8ff06de696291be28fe7046a2fef" - integrity sha512-GpUWWdBVUec/Zqo23aFLBMrXYxN2irypHqDcKjN78JclDPdreasAEPcIpMfqf4MClvpmvDLy4ql+djVAwmkjbw== - dependencies: - "@graphql-codegen/plugin-helpers" "^5.0.0" - "@graphql-codegen/typescript" "^4.0.1" - "@graphql-codegen/visitor-plugin-common" "4.0.1" - auto-bind "~4.0.0" - tslib "~2.5.0" - -"@graphql-codegen/typescript-react-apollo@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-react-apollo/-/typescript-react-apollo-4.1.0.tgz#d900c5d6c259f9b986f917ee280d6bd539f7ecc4" - integrity sha512-G7l4ECoilGnW1zJeqgsFQEVup9ME3w3811ZxHP5yvTra3ZNsbZO4WbYBOPKyS5uc4swsTAxj70a28hNF7kdVcw== - dependencies: - "@graphql-codegen/plugin-helpers" "^3.0.0" - "@graphql-codegen/visitor-plugin-common" "2.13.1" - auto-bind "~4.0.0" - change-case-all "1.0.15" - tslib "~2.6.0" - -"@graphql-codegen/typescript@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript/-/typescript-4.0.1.tgz#7481d68f59bea802dd10e278dce73c8a1552b2a4" - integrity sha512-3YziQ21dCVdnHb+Us1uDb3pA6eG5Chjv0uTK+bt9dXeMlwYBU8MbtzvQTo4qvzWVC1AxSOKj0rgfNu1xCXqJyA== - dependencies: - "@graphql-codegen/plugin-helpers" "^5.0.0" - "@graphql-codegen/schema-ast" "^4.0.0" - "@graphql-codegen/visitor-plugin-common" "4.0.1" - auto-bind "~4.0.0" - tslib "~2.5.0" - -"@graphql-codegen/visitor-plugin-common@2.13.1": - version "2.13.1" - resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-2.13.1.tgz#2228660f6692bcdb96b1f6d91a0661624266b76b" - integrity sha512-mD9ufZhDGhyrSaWQGrU1Q1c5f01TeWtSWy/cDwXYjJcHIj1Y/DG2x0tOflEfCvh5WcnmHNIw4lzDsg1W7iFJEg== - dependencies: - "@graphql-codegen/plugin-helpers" "^2.7.2" - "@graphql-tools/optimize" "^1.3.0" - "@graphql-tools/relay-operation-optimizer" "^6.5.0" - "@graphql-tools/utils" "^8.8.0" - auto-bind "~4.0.0" - change-case-all "1.0.14" - dependency-graph "^0.11.0" - graphql-tag "^2.11.0" - parse-filepath "^1.0.2" - tslib "~2.4.0" - -"@graphql-codegen/visitor-plugin-common@4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-4.0.1.tgz#64e293728b3c186f6767141e41fcdb310e50d367" - integrity sha512-Bi/1z0nHg4QMsAqAJhds+ForyLtk7A3HQOlkrZNm3xEkY7lcBzPtiOTLBtvziwopBsXUxqeSwVjOOFPLS5Yw1Q== - dependencies: - "@graphql-codegen/plugin-helpers" "^5.0.0" - "@graphql-tools/optimize" "^2.0.0" - "@graphql-tools/relay-operation-optimizer" "^7.0.0" - "@graphql-tools/utils" "^10.0.0" - auto-bind "~4.0.0" - change-case-all "1.0.15" - dependency-graph "^0.11.0" - graphql-tag "^2.11.0" - parse-filepath "^1.0.2" - tslib "~2.5.0" - -"@graphql-tools/apollo-engine-loader@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.0.tgz#ac1f351cbe41508411784f25757f5557b0f27489" - integrity sha512-axQTbN5+Yxs1rJ6cWQBOfw3AEeC+fvIuZSfJLPLLvFJLj4pUm9fhxey/g6oQZAAQJqKPfw+tLDUQvnfvRK8Kmg== - dependencies: - "@ardatan/sync-fetch" "^0.0.1" - "@graphql-tools/utils" "^10.0.0" - "@whatwg-node/fetch" "^0.9.0" - tslib "^2.4.0" - -"@graphql-tools/batch-execute@^9.0.1": - version "9.0.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/batch-execute/-/batch-execute-9.0.2.tgz#5ac3257501e7941fad40661bb5e1110d6312f58b" - integrity sha512-Y2uwdZI6ZnatopD/SYfZ1eGuQFI7OU2KGZ2/B/7G9ISmgMl5K+ZZWz/PfIEXeiHirIDhyk54s4uka5rj2xwKqQ== - dependencies: - "@graphql-tools/utils" "^10.0.5" - dataloader "^2.2.2" - tslib "^2.4.0" - value-or-promise "^1.0.12" - -"@graphql-tools/code-file-loader@^8.0.0": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/code-file-loader/-/code-file-loader-8.1.0.tgz#1092594f02f2c54fc1dd8b997921ccb8db642272" - integrity sha512-HKWW/B2z15ves8N9+xnVbGmFEVGyHEK80a4ghrjeTa6nwNZaKDVfq5CoYFfF0xpfjtH6gOVUExo2XCOEz4B8mQ== - dependencies: - "@graphql-tools/graphql-tag-pluck" "8.2.0" - "@graphql-tools/utils" "^10.0.13" - globby "^11.0.3" - tslib "^2.4.0" - unixify "^1.0.0" - -"@graphql-tools/delegate@^10.0.0", "@graphql-tools/delegate@^10.0.3": - version "10.0.3" - resolved "https://registry.yarnpkg.com/@graphql-tools/delegate/-/delegate-10.0.3.tgz#2d0e133da94ca92c24e0c7360414e5592321cf2d" - integrity sha512-Jor9oazZ07zuWkykD3OOhT/2XD74Zm6Ar0ENZMk75MDD51wB2UWUIMljtHxbJhV5A6UBC2v8x6iY0xdCGiIlyw== - dependencies: - "@graphql-tools/batch-execute" "^9.0.1" - "@graphql-tools/executor" "^1.0.0" - "@graphql-tools/schema" "^10.0.0" - "@graphql-tools/utils" "^10.0.5" - dataloader "^2.2.2" - tslib "^2.5.0" - -"@graphql-tools/executor-graphql-ws@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-1.1.0.tgz#7727159ebaa9df4dc793d0d02e74dd1ca4a7cc60" - integrity sha512-yM67SzwE8rYRpm4z4AuGtABlOp9mXXVy6sxXnTJRoYIdZrmDbKVfIY+CpZUJCqS0FX3xf2+GoHlsj7Qswaxgcg== - dependencies: - "@graphql-tools/utils" "^10.0.2" - "@types/ws" "^8.0.0" - graphql-ws "^5.14.0" - isomorphic-ws "^5.0.0" - tslib "^2.4.0" - ws "^8.13.0" - -"@graphql-tools/executor-http@^1.0.0", "@graphql-tools/executor-http@^1.0.5": - version "1.0.7" - resolved "https://registry.yarnpkg.com/@graphql-tools/executor-http/-/executor-http-1.0.7.tgz#c358f91d4f88e49b9be7408a517f77a3079b2d91" - integrity sha512-/MoRYzQS50Tz5mxRfq3ZmeZ2SOins9wGZAGetsJ55F3PxL0PmHdSGlCq12KzffZDbwHV5YMlwigBsSGWq4y9Iw== - dependencies: - "@graphql-tools/utils" "^10.0.2" - "@repeaterjs/repeater" "^3.0.4" - "@whatwg-node/fetch" "^0.9.0" - extract-files "^11.0.0" - meros "^1.2.1" - tslib "^2.4.0" - value-or-promise "^1.0.12" - -"@graphql-tools/executor-legacy-ws@^1.0.0": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.0.5.tgz#07de9d6e0e49febbcb87d6558bbeebf3940ff25a" - integrity sha512-w54AZ7zkNuvpyV09FH+eGHnnAmaxhBVHg4Yh2ICcsMfRg0brkLt77PlbjBuxZ4HY8XZnKJaYWf+tKazQZtkQtg== - dependencies: - "@graphql-tools/utils" "^10.0.0" - "@types/ws" "^8.0.0" - isomorphic-ws "^5.0.0" - tslib "^2.4.0" - ws "^8.15.0" - -"@graphql-tools/executor@^1.0.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/executor/-/executor-1.2.0.tgz#6c45f4add765769d9820c4c4405b76957ba39c79" - integrity sha512-SKlIcMA71Dha5JnEWlw4XxcaJ+YupuXg0QCZgl2TOLFz4SkGCwU/geAsJvUJFwK2RbVLpQv/UMq67lOaBuwDtg== - dependencies: - "@graphql-tools/utils" "^10.0.0" - "@graphql-typed-document-node/core" "3.2.0" - "@repeaterjs/repeater" "^3.0.4" - tslib "^2.4.0" - value-or-promise "^1.0.12" - -"@graphql-tools/git-loader@^8.0.0": - version "8.0.4" - resolved "https://registry.yarnpkg.com/@graphql-tools/git-loader/-/git-loader-8.0.4.tgz#663a42e28f1705ba29c0e41ac2f89e7436751608" - integrity sha512-fBmKtnOVqzMT2N8L6nggM4skPq3y2t0eBITZJXCOuxeIlIRAeCOdjNLPKgyGb0rezIyGsn55DKMua5101VN0Sg== - dependencies: - "@graphql-tools/graphql-tag-pluck" "8.2.0" - "@graphql-tools/utils" "^10.0.13" - is-glob "4.0.3" - micromatch "^4.0.4" - tslib "^2.4.0" - unixify "^1.0.0" - -"@graphql-tools/github-loader@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/github-loader/-/github-loader-8.0.0.tgz#683195800618364701cfea9bc6f88674486f053b" - integrity sha512-VuroArWKcG4yaOWzV0r19ElVIV6iH6UKDQn1MXemND0xu5TzrFme0kf3U9o0YwNo0kUYEk9CyFM0BYg4he17FA== - dependencies: - "@ardatan/sync-fetch" "^0.0.1" - "@graphql-tools/executor-http" "^1.0.0" - "@graphql-tools/graphql-tag-pluck" "^8.0.0" - "@graphql-tools/utils" "^10.0.0" - "@whatwg-node/fetch" "^0.9.0" - tslib "^2.4.0" - value-or-promise "^1.0.12" - -"@graphql-tools/graphql-file-loader@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-file-loader/-/graphql-file-loader-8.0.0.tgz#a2026405bce86d974000455647511bf65df4f211" - integrity sha512-wRXj9Z1IFL3+zJG1HWEY0S4TXal7+s1vVhbZva96MSp0kbb/3JBF7j0cnJ44Eq0ClccMgGCDFqPFXty4JlpaPg== - dependencies: - "@graphql-tools/import" "7.0.0" - "@graphql-tools/utils" "^10.0.0" - globby "^11.0.3" - tslib "^2.4.0" - unixify "^1.0.0" - -"@graphql-tools/graphql-tag-pluck@8.2.0", "@graphql-tools/graphql-tag-pluck@^8.0.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.2.0.tgz#958e07d3bdd94c2a7ac958364b7383c17d009ce2" - integrity sha512-aGIuHxyrJB+LlUfXrH73NVlQTA6LkFbLKQzHojFuwXZJpf7wPkxceN2yp7VjMedARkLJg589IoXgZeMb1EztGQ== - dependencies: - "@babel/core" "^7.22.9" - "@babel/parser" "^7.16.8" - "@babel/plugin-syntax-import-assertions" "^7.20.0" - "@babel/traverse" "^7.16.8" - "@babel/types" "^7.16.8" - "@graphql-tools/utils" "^10.0.13" - tslib "^2.4.0" - -"@graphql-tools/import@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/import/-/import-7.0.0.tgz#a6a91a90a707d5f46bad0fd3fde2f407b548b2be" - integrity sha512-NVZiTO8o1GZs6OXzNfjB+5CtQtqsZZpQOq+Uu0w57kdUkT4RlQKlwhT8T81arEsbV55KpzkpFsOZP7J1wdmhBw== - dependencies: - "@graphql-tools/utils" "^10.0.0" - resolve-from "5.0.0" - tslib "^2.4.0" - -"@graphql-tools/json-file-loader@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/json-file-loader/-/json-file-loader-8.0.0.tgz#9b1b62902f766ef3f1c9cd1c192813ea4f48109c" - integrity sha512-ki6EF/mobBWJjAAC84xNrFMhNfnUFD6Y0rQMGXekrUgY0NdeYXHU0ZUgHzC9O5+55FslqUmAUHABePDHTyZsLg== - dependencies: - "@graphql-tools/utils" "^10.0.0" - globby "^11.0.3" - tslib "^2.4.0" - unixify "^1.0.0" - -"@graphql-tools/load@^8.0.0": - version "8.0.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/load/-/load-8.0.1.tgz#498f2230448601cb87894b8a93df7867daef69ea" - integrity sha512-qSMsKngJhDqRbuWyo3NvakEFqFL6+eSjy8ooJ1o5qYD26N7dqXkKzIMycQsX7rBK19hOuINAUSaRcVWH6hTccw== - dependencies: - "@graphql-tools/schema" "^10.0.0" - "@graphql-tools/utils" "^10.0.11" - p-limit "3.1.0" - tslib "^2.4.0" - -"@graphql-tools/merge@^9.0.0", "@graphql-tools/merge@^9.0.1": - version "9.0.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-9.0.1.tgz#693f15da152339284469b1ce5c6827e3ae350a29" - integrity sha512-hIEExWO9fjA6vzsVjJ3s0cCQ+Q/BEeMVJZtMXd7nbaVefVy0YDyYlEkeoYYNV3NVVvu1G9lr6DM1Qd0DGo9Caw== - dependencies: - "@graphql-tools/utils" "^10.0.10" - tslib "^2.4.0" - -"@graphql-tools/optimize@^1.3.0": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/optimize/-/optimize-1.3.1.tgz#29407991478dbbedc3e7deb8c44f46acb4e9278b" - integrity sha512-5j5CZSRGWVobt4bgRRg7zhjPiSimk+/zIuColih8E8DxuFOaJ+t0qu7eZS5KXWBkjcd4BPNuhUPpNlEmHPqVRQ== - dependencies: - tslib "^2.4.0" - -"@graphql-tools/optimize@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/optimize/-/optimize-2.0.0.tgz#7a9779d180824511248a50c5a241eff6e7a2d906" - integrity sha512-nhdT+CRGDZ+bk68ic+Jw1OZ99YCDIKYA5AlVAnBHJvMawSx9YQqQAIj4refNc1/LRieGiuWvhbG3jvPVYho0Dg== - dependencies: - tslib "^2.4.0" - -"@graphql-tools/prisma-loader@^8.0.0": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/prisma-loader/-/prisma-loader-8.0.2.tgz#3a7126ec2389a7aa7846bd0e441629ac5a1934fc" - integrity sha512-8d28bIB0bZ9Bj0UOz9sHagVPW+6AHeqvGljjERtwCnWl8OCQw2c2pNboYXISLYUG5ub76r4lDciLLTU+Ks7Q0w== - dependencies: - "@graphql-tools/url-loader" "^8.0.0" - "@graphql-tools/utils" "^10.0.8" - "@types/js-yaml" "^4.0.0" - "@types/json-stable-stringify" "^1.0.32" - "@whatwg-node/fetch" "^0.9.0" - chalk "^4.1.0" - debug "^4.3.1" - dotenv "^16.0.0" - graphql-request "^6.0.0" - http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.0" - jose "^5.0.0" - js-yaml "^4.0.0" - json-stable-stringify "^1.0.1" - lodash "^4.17.20" - scuid "^1.1.0" - tslib "^2.4.0" - yaml-ast-parser "^0.0.43" - -"@graphql-tools/relay-operation-optimizer@^6.5.0": - version "6.5.17" - resolved "https://registry.yarnpkg.com/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-6.5.17.tgz#4e4e2675d696a2a31f106b09ed436c43f7976f37" - integrity sha512-hHPEX6ccRF3+9kfVz0A3In//Dej7QrHOLGZEokBmPDMDqn9CS7qUjpjyGzclbOX0tRBtLfuFUZ68ABSac3P1nA== - dependencies: - "@ardatan/relay-compiler" "12.0.0" - "@graphql-tools/utils" "9.2.1" - tslib "^2.4.0" - -"@graphql-tools/relay-operation-optimizer@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.0.tgz#24367666af87bc5a81748de5e8e9b3c523fd4207" - integrity sha512-UNlJi5y3JylhVWU4MBpL0Hun4Q7IoJwv9xYtmAz+CgRa066szzY7dcuPfxrA7cIGgG/Q6TVsKsYaiF4OHPs1Fw== - dependencies: - "@ardatan/relay-compiler" "12.0.0" - "@graphql-tools/utils" "^10.0.0" - tslib "^2.4.0" - -"@graphql-tools/schema@^10.0.0": - version "10.0.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-10.0.2.tgz#21bc2ee25a65fb4890d2e5f9f22ef1f733aa81da" - integrity sha512-TbPsIZnWyDCLhgPGnDjt4hosiNU2mF/rNtSk5BVaXWnZqvKJ6gzJV4fcHcvhRIwtscDMW2/YTnK6dLVnk8pc4w== - dependencies: - "@graphql-tools/merge" "^9.0.1" - "@graphql-tools/utils" "^10.0.10" - tslib "^2.4.0" - value-or-promise "^1.0.12" - -"@graphql-tools/url-loader@^8.0.0": - version "8.0.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/url-loader/-/url-loader-8.0.1.tgz#91247247d253c538c4c28376ca74d944fa8cfb82" - integrity sha512-B2k8KQEkEQmfV1zhurT5GLoXo8jbXP+YQHUayhCSxKYlRV7j/1Fhp1b21PDM8LXIDGlDRXaZ0FbWKOs7eYXDuQ== - dependencies: - "@ardatan/sync-fetch" "^0.0.1" - "@graphql-tools/delegate" "^10.0.0" - "@graphql-tools/executor-graphql-ws" "^1.0.0" - "@graphql-tools/executor-http" "^1.0.5" - "@graphql-tools/executor-legacy-ws" "^1.0.0" - "@graphql-tools/utils" "^10.0.0" - "@graphql-tools/wrap" "^10.0.0" - "@types/ws" "^8.0.0" - "@whatwg-node/fetch" "^0.9.0" - isomorphic-ws "^5.0.0" - tslib "^2.4.0" - value-or-promise "^1.0.11" - ws "^8.12.0" - -"@graphql-tools/utils@9.2.1", "@graphql-tools/utils@^9.0.0": - version "9.2.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-9.2.1.tgz#1b3df0ef166cfa3eae706e3518b17d5922721c57" - integrity sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A== - dependencies: - "@graphql-typed-document-node/core" "^3.1.1" - tslib "^2.4.0" - -"@graphql-tools/utils@^10.0.0", "@graphql-tools/utils@^10.0.10", "@graphql-tools/utils@^10.0.11", "@graphql-tools/utils@^10.0.13", "@graphql-tools/utils@^10.0.2", "@graphql-tools/utils@^10.0.5", "@graphql-tools/utils@^10.0.8": - version "10.0.13" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-10.0.13.tgz#d0ab7a4dd02a8405f5ef62dd140b7579ba69f8cb" - integrity sha512-fMILwGr5Dm2zefNItjQ6C2rauigklv69LIwppccICuGTnGaOp3DspLt/6Lxj72cbg5d9z60Sr+Egco3CJKLsNg== - dependencies: - "@graphql-typed-document-node/core" "^3.1.1" - cross-inspect "1.0.0" - dset "^3.1.2" - tslib "^2.4.0" - -"@graphql-tools/utils@^8.8.0": - version "8.13.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.13.1.tgz#b247607e400365c2cd87ff54654d4ad25a7ac491" - integrity sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw== - dependencies: - tslib "^2.4.0" - -"@graphql-tools/wrap@^10.0.0": - version "10.0.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/wrap/-/wrap-10.0.1.tgz#9e3d27d2723962c26c4377d5d7ab0d3038bf728c" - integrity sha512-Cw6hVrKGM2OKBXeuAGltgy4tzuqQE0Nt7t/uAqnuokSXZhMHXJUb124Bnvxc2gPZn5chfJSDafDe4Cp8ZAVJgg== - dependencies: - "@graphql-tools/delegate" "^10.0.3" - "@graphql-tools/schema" "^10.0.0" - "@graphql-tools/utils" "^10.0.0" - tslib "^2.4.0" - value-or-promise "^1.0.12" - -"@graphql-typed-document-node/core@3.2.0", "@graphql-typed-document-node/core@^3.1.1", "@graphql-typed-document-node/core@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" - integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== - -"@humanwhocodes/config-array@^0.11.8": - version "0.11.8" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" - integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== - dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.5" - -"@humanwhocodes/module-importer@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" - integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== - -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== - -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - -"@jridgewell/source-map@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" - integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" - integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" - -"@juggle/resize-observer@^3.3.1": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60" - integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA== - -"@kamilkisiela/fast-url-parser@^1.1.4": - version "1.1.4" - resolved "https://registry.yarnpkg.com/@kamilkisiela/fast-url-parser/-/fast-url-parser-1.1.4.tgz#9d68877a489107411b953c54ea65d0658b515809" - integrity sha512-gbkePEBupNydxCelHCESvFSFM8XPh1Zs/OAVRW/rKpEqPAl5PbOM90Si8mv9bvnR53uPD2s/FiRxdvSejpRJew== - -"@mapbox/hast-util-table-cell-style@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@mapbox/hast-util-table-cell-style/-/hast-util-table-cell-style-0.2.0.tgz#1003f59d54fae6f638cb5646f52110fb3da95b4d" - integrity sha512-gqaTIGC8My3LVSnU38IwjHVKJC94HSonjvFHDk8/aSrApL8v4uWgm8zJkK7MJIIbHuNOr/+Mv2KkQKcxs6LEZA== - dependencies: - unist-util-visit "^1.4.1" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@peculiar/asn1-schema@^2.1.6", "@peculiar/asn1-schema@^2.3.0": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.3.3.tgz#21418e1f3819e0b353ceff0c2dad8ccb61acd777" - integrity sha512-6GptMYDMyWBHTUKndHaDsRZUO/XMSgIns2krxcm2L7SEExRHwawFvSwNBhqNPR9HJwv3MruAiF1bhN0we6j6GQ== - dependencies: - asn1js "^3.0.5" - pvtsutils "^1.3.2" - tslib "^2.4.0" - -"@peculiar/json-schema@^1.1.12": - version "1.1.12" - resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.12.tgz#fe61e85259e3b5ba5ad566cb62ca75b3d3cd5339" - integrity sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w== - dependencies: - tslib "^2.0.0" - -"@peculiar/webcrypto@^1.4.0": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.4.1.tgz#821493bd5ad0f05939bd5f53b28536f68158360a" - integrity sha512-eK4C6WTNYxoI7JOabMoZICiyqRRtJB220bh0Mbj5RwRycleZf9BPyZoxsTvpP0FpmVS2aS13NKOuh5/tN3sIRw== - dependencies: - "@peculiar/asn1-schema" "^2.3.0" - "@peculiar/json-schema" "^1.1.12" - pvtsutils "^1.3.2" - tslib "^2.4.1" - webcrypto-core "^1.7.4" - -"@popperjs/core@^2.11.6", "@popperjs/core@^2.9.2": - version "2.11.6" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" - integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== - -"@react-hook/latest@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@react-hook/latest/-/latest-1.0.3.tgz#c2d1d0b0af8b69ec6e2b3a2412ba0768ac82db80" - integrity sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg== - -"@react-hook/passive-layout-effect@^1.2.0": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@react-hook/passive-layout-effect/-/passive-layout-effect-1.2.1.tgz#c06dac2d011f36d61259aa1c6df4f0d5e28bc55e" - integrity sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg== - -"@react-hook/resize-observer@^1.2.6": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@react-hook/resize-observer/-/resize-observer-1.2.6.tgz#9a8cf4c5abb09becd60d1d65f6bf10eec211e291" - integrity sha512-DlBXtLSW0DqYYTW3Ft1/GQFZlTdKY5VAFIC4+km6IK5NiPPDFchGbEJm1j6pSgMqPRHbUQgHJX7RaR76ic1LWA== - dependencies: - "@juggle/resize-observer" "^3.3.1" - "@react-hook/latest" "^1.0.2" - "@react-hook/passive-layout-effect" "^1.2.0" - -"@repeaterjs/repeater@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@repeaterjs/repeater/-/repeater-3.0.4.tgz#a04d63f4d1bf5540a41b01a921c9a7fddc3bd1ca" - integrity sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA== - -"@restart/context@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@restart/context/-/context-2.1.4.tgz#a99d87c299a34c28bd85bb489cb07bfd23149c02" - integrity sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q== - -"@restart/hooks@^0.4.7": - version "0.4.9" - resolved "https://registry.yarnpkg.com/@restart/hooks/-/hooks-0.4.9.tgz#ad858fb39d99e252cccce19416adc18fc3f18fcb" - integrity sha512-3BekqcwB6Umeya+16XPooARn4qEPW6vNvwYnlofIYe6h9qG1/VeD7UvShCWx11eFz5ELYmwIEshz+MkPX3wjcQ== - dependencies: - dequal "^2.0.2" - -"@silvermine/videojs-airplay@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@silvermine/videojs-airplay/-/videojs-airplay-1.2.0.tgz#3ca6464c8e94c97bb9f35c2926f59a5aa662cebd" - integrity sha512-4KzHoM/wJaq3au8IBLxnz8+btAB/M/2AdMoAoOdZRpp9DGG8SGU/UPw2w+CRMknvfbGtvlhlNrNiiXVWA6Cn0A== - -"@silvermine/videojs-chromecast@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@silvermine/videojs-chromecast/-/videojs-chromecast-1.4.1.tgz#a5763eb85dfd4bc8f47a1b8b150d5dadbb8ea658" - integrity sha512-tXeikkWoNC3WIl2WSkIag1CLMbGsgn+26LM4LoB4qx0TQ8mkg7pgpldCTkvXxLVaDluQ/uEm2uxrgrMmjOc6sw== - dependencies: - webcomponents.js "git+https://git@github.com/webcomponents/webcomponentsjs.git#v0.7.24" - -"@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" - integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== - -"@tweenjs/tween.js@~18.6.4": - version "18.6.4" - resolved "https://registry.yarnpkg.com/@tweenjs/tween.js/-/tween.js-18.6.4.tgz#40a3d0a93647124872dec8e0fd1bd5926695b6ca" - integrity sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ== - -"@types/apollo-upload-client@^18.0.0": - version "18.0.0" - resolved "https://registry.yarnpkg.com/@types/apollo-upload-client/-/apollo-upload-client-18.0.0.tgz#1f7e2ff0c0e6508bc1bd19b2340339c7abd117c3" - integrity sha512-cMgITNemktxasqvp6jiPj15dv84n3FTMvMoYBP1+xonDS+0l6JygIJrj2LJh85rShRzTOOkrElrAsCXXARa3KA== - dependencies: - "@apollo/client" "^3.8.0" - "@types/extract-files" "*" - graphql "14 - 16" - -"@types/babel__core@^7.1.7": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.0.tgz#61bc5a4cae505ce98e1e36c5445e4bee060d8891" - integrity sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ== - dependencies: - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*": - version "7.18.3" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.3.tgz#dfc508a85781e5698d5b33443416b6268c4b3e8d" - integrity sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w== - dependencies: - "@babel/types" "^7.3.0" - -"@types/cookie@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" - integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== - -"@types/crypto-js@^4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@types/crypto-js/-/crypto-js-4.2.2.tgz#771c4a768d94eb5922cc202a3009558204df0cea" - integrity sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ== - -"@types/extract-files@*": - version "13.0.1" - resolved "https://registry.yarnpkg.com/@types/extract-files/-/extract-files-13.0.1.tgz#3ec057a3fa25f778245a76a17271d23b71ee31d7" - integrity sha512-/fRbzc2lAd7jDJSSnxWiUyXWjdUZZ4HbISLJzVgt1AvrdOa7U49YRPcvuCUywkmURZ7uwJOheDjx19itbQ5KvA== - -"@types/fs-extra@^9.0.1": - version "9.0.13" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45" - integrity sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA== - dependencies: - "@types/node" "*" - -"@types/history@^4.7.11": - version "4.7.11" - resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" - integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== - -"@types/hoist-non-react-statics@^3.3.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== - dependencies: - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - -"@types/invariant@^2.2.33": - version "2.2.35" - resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.35.tgz#cd3ebf581a6557452735688d8daba6cf0bd5a3be" - integrity sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg== - -"@types/js-yaml@^4.0.0": - version "4.0.5" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138" - integrity sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA== - -"@types/json-schema@^7.0.5", "@types/json-schema@^7.0.9": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== - -"@types/json-stable-stringify@^1.0.32": - version "1.0.34" - resolved "https://registry.yarnpkg.com/@types/json-stable-stringify/-/json-stable-stringify-1.0.34.tgz#c0fb25e4d957e0ee2e497c1f553d7f8bb668fd75" - integrity sha512-s2cfwagOQAS8o06TcwKfr9Wx11dNGbH2E9vJz1cqV+a/LOyhWNLUNd6JSRYNzvB4d29UuJX2M0Dj9vE1T8fRXw== - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== - -"@types/lodash-es@^4.17.6": - version "4.17.6" - resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.6.tgz#c2ed4c8320ffa6f11b43eb89e9eaeec65966a0a0" - integrity sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg== - dependencies: - "@types/lodash" "*" - -"@types/lodash@*": - version "4.14.191" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa" - integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ== - -"@types/mdast@^3.0.0": - version "3.0.10" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" - integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== - dependencies: - "@types/unist" "*" - -"@types/minimist@^1.2.0", "@types/minimist@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" - integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== - -"@types/mousetrap@^1.6.11": - version "1.6.11" - resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.11.tgz#ef9620160fdcefcb85bccda8aaa3e84d7429376d" - integrity sha512-F0oAily9Q9QQpv9JKxKn0zMKfOo36KHCW7myYsmUyf2t0g+sBTbG3UleTPoguHdE1z3GLFr3p7/wiOio52QFjQ== - -"@types/node@*", "@types/node@^18.13.0": - version "18.13.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850" - integrity sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg== - -"@types/normalize-package-data@^2.4.0": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" - integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== - -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - -"@types/prop-types@*", "@types/prop-types@^15.7.3": - version "15.7.5" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" - integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== - -"@types/react-datepicker@^4.10.0": - version "4.10.0" - resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-4.10.0.tgz#fcb0e6a7787491bf2f37fbda2b537062608a0056" - integrity sha512-Cq+ks20vBIU6XN67TbkCHu8M7V46Y6vJrKE2n+8q/GfueJyWWTIKeC3Z7cz/d+qxGDq/VCrqA929R0U4lNuztg== - dependencies: - "@popperjs/core" "^2.9.2" - "@types/react" "*" - date-fns "^2.0.1" - react-popper "^2.2.5" - -"@types/react-dom@^17.0.19": - version "17.0.19" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.19.tgz#36feef3aa35d045cacd5ed60fe0eef5272f19492" - integrity sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ== - dependencies: - "@types/react" "^17" - -"@types/react-helmet@^6.1.6": - version "6.1.6" - resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-6.1.6.tgz#7d1afd8cbf099616894e8240e9ef70e3c6d7506d" - integrity sha512-ZKcoOdW/Tg+kiUbkFCBtvDw0k3nD4HJ/h/B9yWxN4uDO8OkRksWTO+EL+z/Qu3aHTeTll3Ro0Cc/8UhwBCMG5A== - dependencies: - "@types/react" "*" - -"@types/react-router-bootstrap@^0.24.5": - version "0.24.5" - resolved "https://registry.yarnpkg.com/@types/react-router-bootstrap/-/react-router-bootstrap-0.24.5.tgz#9257ba3dfb01cda201aac9fa05cde3eb09ea5b27" - integrity sha512-GRx/8xF/skw4/Pmm6d+xbExi8gobCLOe8Eoz9kXPQGbYo7p5Wbi61tjpOF5AbfJ5XMN+fIzweToTi56odj/LOQ== - dependencies: - "@types/react" "*" - "@types/react-router-dom" "*" - -"@types/react-router-dom@*": - version "5.3.3" - resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" - integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-router" "*" - -"@types/react-router-hash-link@^2.4.5": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@types/react-router-hash-link/-/react-router-hash-link-2.4.5.tgz#41dcb55279351fedc9062115bb35db921d1d69f6" - integrity sha512-YsiD8xCWtRBebzPqG6kXjDQCI35LCN9MhV/MbgYF8y0trOp7VSUNmSj8HdIGyH99WCfSOLZB2pIwUMN/IwIDQg== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-router-dom" "*" - -"@types/react-router@*": - version "5.1.20" - resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.20.tgz#88eccaa122a82405ef3efbcaaa5dcdd9f021387c" - integrity sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - -"@types/react-transition-group@^4.4.0", "@types/react-transition-group@^4.4.1": - version "4.4.5" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416" - integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA== - dependencies: - "@types/react" "*" - -"@types/react@*", "@types/react@16 || 17 || 18", "@types/react@>=16.14.8", "@types/react@>=16.9.11", "@types/react@^17", "@types/react@^17.0.53": - version "17.0.53" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.53.tgz#10d4d5999b8af3d6bc6a9369d7eb953da82442ab" - integrity sha512-1yIpQR2zdYu1Z/dc1OxC+MA6GR240u3gcnP4l6mvj/PJiVaqHsQPmWttsvHsfnhfPbU2FuGmo0wSITPygjBmsw== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - -"@types/scheduler@*": - version "0.16.2" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== - -"@types/schema-utils@^2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@types/schema-utils/-/schema-utils-2.4.0.tgz#9983012045d541dcee053e685a27c9c87c840fcd" - integrity sha512-454hrj5gz/FXcUE20ygfEiN4DxZ1sprUo0V1gqIqkNZ/CzoEzAZEll2uxMsuyz6BYjiQan4Aa65xbTemfzW9hQ== - dependencies: - schema-utils "*" - -"@types/semver@^7.3.12": - version "7.3.13" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" - integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== - -"@types/stats.js@*": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@types/stats.js/-/stats.js-0.17.0.tgz#0ed81d48e03b590c24da85540c1d952077a9fe20" - integrity sha512-9w+a7bR8PeB0dCT/HBULU2fMqf6BAzvKbxFboYhmDtDkKPiyXYbjoe2auwsXlEFI7CFNMF1dCv3dFH5Poy9R1w== - -"@types/three@^0.154.0": - version "0.154.0" - resolved "https://registry.yarnpkg.com/@types/three/-/three-0.154.0.tgz#91f4384930ed050a14d7f13c09d5785cc167a064" - integrity sha512-IioqpGhch6FdLDh4zazRn3rXHj6Vn2nVOziJdXVbJFi9CaI65LtP9qqUtpzbsHK2Ezlox8NtsLNHSw3AQzucjA== - dependencies: - "@tweenjs/tween.js" "~18.6.4" - "@types/stats.js" "*" - "@types/webxr" "*" - fflate "~0.6.9" - lil-gui "~0.17.0" - meshoptimizer "~0.18.1" - -"@types/ua-parser-js@^0.7.36": - version "0.7.36" - resolved "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz" - integrity sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ== - -"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" - integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== - -"@types/video.js@*", "@types/video.js@^7.3.51": - version "7.3.51" - resolved "https://registry.yarnpkg.com/@types/video.js/-/video.js-7.3.51.tgz#ce69e02681ed6ed8abe61bb3802dd032a74d63e8" - integrity sha512-xLlt/ZfCuWYBvG2MRn018RvaEplcK6dI63aOiVUeeAWFyjx3Br1hL749ndFgbrvNdY4m9FoHG1FQ/PB6IpfSAQ== - -"@types/videojs-mobile-ui@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@types/videojs-mobile-ui/-/videojs-mobile-ui-0.8.0.tgz#0fb82810155f3dee9620ea411c8b9bd17e1ac645" - integrity sha512-Q8p7ezQLZzf8pnvYd8GZ/6tcg2oX0269Q94dDoqNnq2QMmqWp1sj8npU3gGnTaLkYvvdrO8UjBOIzX68RkQLew== - dependencies: - "@types/video.js" "*" - -"@types/videojs-seek-buttons@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@types/videojs-seek-buttons/-/videojs-seek-buttons-2.1.0.tgz#2c59007ad6f4d6f86df810b6e84daeb8c2e62fc4" - integrity sha512-vaTCELmPea/cgkf82P8RaeFBBZnd4nnuOiMaciSeMKiWzbflSvcvjnHfvKcBmJEi3hnSQ12bVXlmUvvOrgmpjQ== - dependencies: - "@types/video.js" "*" - -"@types/warning@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52" - integrity sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA== - -"@types/webxr@*": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@types/webxr/-/webxr-0.5.2.tgz#5d9627b0ffe223aa3b166de7112ac8a9460dc54f" - integrity sha512-szL74BnIcok9m7QwYtVmQ+EdIKwbjPANudfuvDrAF8Cljg9MKUlIoc1w5tjj9PMpeSH3U1Xnx//czQybJ0EfSw== - -"@types/ws@^8.0.0": - version "8.5.4" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.4.tgz#bb10e36116d6e570dd943735f86c933c1587b8a5" - integrity sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg== - dependencies: - "@types/node" "*" - -"@typescript-eslint/eslint-plugin@^5.52.0": - version "5.52.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz#5fb0d43574c2411f16ea80f5fc335b8eaa7b28a8" - integrity sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg== - dependencies: - "@typescript-eslint/scope-manager" "5.52.0" - "@typescript-eslint/type-utils" "5.52.0" - "@typescript-eslint/utils" "5.52.0" - debug "^4.3.4" - grapheme-splitter "^1.0.4" - ignore "^5.2.0" - natural-compare-lite "^1.4.0" - regexpp "^3.2.0" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/parser@^5.52.0": - version "5.52.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.52.0.tgz#73c136df6c0133f1d7870de7131ccf356f5be5a4" - integrity sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA== - dependencies: - "@typescript-eslint/scope-manager" "5.52.0" - "@typescript-eslint/types" "5.52.0" - "@typescript-eslint/typescript-estree" "5.52.0" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@5.52.0": - version "5.52.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz#a993d89a0556ea16811db48eabd7c5b72dcb83d1" - integrity sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw== - dependencies: - "@typescript-eslint/types" "5.52.0" - "@typescript-eslint/visitor-keys" "5.52.0" - -"@typescript-eslint/type-utils@5.52.0": - version "5.52.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz#9fd28cd02e6f21f5109e35496df41893f33167aa" - integrity sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw== - dependencies: - "@typescript-eslint/typescript-estree" "5.52.0" - "@typescript-eslint/utils" "5.52.0" - debug "^4.3.4" - tsutils "^3.21.0" - -"@typescript-eslint/types@5.52.0": - version "5.52.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.52.0.tgz#19e9abc6afb5bd37a1a9bea877a1a836c0b3241b" - integrity sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ== - -"@typescript-eslint/typescript-estree@5.52.0": - version "5.52.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz#6408cb3c2ccc01c03c278cb201cf07e73347dfca" - integrity sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ== - dependencies: - "@typescript-eslint/types" "5.52.0" - "@typescript-eslint/visitor-keys" "5.52.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.52.0": - version "5.52.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.52.0.tgz#b260bb5a8f6b00a0ed51db66bdba4ed5e4845a72" - integrity sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA== - dependencies: - "@types/json-schema" "^7.0.9" - "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.52.0" - "@typescript-eslint/types" "5.52.0" - "@typescript-eslint/typescript-estree" "5.52.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - semver "^7.3.7" - -"@typescript-eslint/visitor-keys@5.52.0": - version "5.52.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz#e38c971259f44f80cfe49d97dbffa38e3e75030f" - integrity sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA== - dependencies: - "@typescript-eslint/types" "5.52.0" - eslint-visitor-keys "^3.3.0" - -"@videojs/http-streaming@2.16.2": - version "2.16.2" - resolved "https://registry.yarnpkg.com/@videojs/http-streaming/-/http-streaming-2.16.2.tgz#a9be925b4e368a41dbd67d49c4f566715169b84b" - integrity sha512-etPTUdCFu7gUWc+1XcbiPr+lrhOcBu3rV5OL1M+3PDW89zskScAkkcdqYzP4pFodBPye/ydamQoTDScOnElw5A== - dependencies: - "@babel/runtime" "^7.12.5" - "@videojs/vhs-utils" "3.0.5" - aes-decrypter "3.1.3" - global "^4.4.0" - m3u8-parser "4.8.0" - mpd-parser "^0.22.1" - mux.js "6.0.1" - video.js "^6 || ^7" - -"@videojs/vhs-utils@3.0.5", "@videojs/vhs-utils@^3.0.4", "@videojs/vhs-utils@^3.0.5": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz#665ba70d78258ba1ab977364e2fe9f4d4799c46c" - integrity sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw== - dependencies: - "@babel/runtime" "^7.12.5" - global "^4.4.0" - url-toolkit "^2.2.1" - -"@videojs/xhr@2.6.0": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@videojs/xhr/-/xhr-2.6.0.tgz#cd897e0ad54faf497961bcce3fa16dc15a26bb80" - integrity sha512-7J361GiN1tXpm+gd0xz2QWr3xNWBE+rytvo8J3KuggFaLg+U37gZQ2BuPLcnkfGffy2e+ozY70RHC8jt7zjA6Q== - dependencies: - "@babel/runtime" "^7.5.5" - global "~4.4.0" - is-function "^1.0.1" - -"@vitejs/plugin-legacy@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-legacy/-/plugin-legacy-4.0.1.tgz#122e334ac0b8dba2cbd44cc15209e67c9a014463" - integrity sha512-/ZV63NagI1c9TB5E4ijGmycY//fNm/2L02nsnXXxACwYaF9W+/OyVlgIW24jYUIS+g0yQRtn+N5hzBc8RLNhGA== - dependencies: - "@babel/core" "^7.20.12" - "@babel/preset-env" "^7.20.2" - browserslist "^4.21.4" - core-js "^3.27.2" - magic-string "^0.27.0" - regenerator-runtime "^0.13.11" - systemjs "^6.13.0" - -"@vitejs/plugin-react@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-3.1.0.tgz#d1091f535eab8b83d6e74034d01e27d73c773240" - integrity sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g== - dependencies: - "@babel/core" "^7.20.12" - "@babel/plugin-transform-react-jsx-self" "^7.18.6" - "@babel/plugin-transform-react-jsx-source" "^7.19.6" - magic-string "^0.27.0" - react-refresh "^0.14.0" - -"@whatwg-node/events@^0.0.2": - version "0.0.2" - resolved "https://registry.yarnpkg.com/@whatwg-node/events/-/events-0.0.2.tgz#7b7107268d2982fc7b7aff5ee6803c64018f84dd" - integrity sha512-WKj/lI4QjnLuPrim0cfO7i+HsDSXHxNv1y0CrJhdntuO3hxWZmnXCwNDnwOvry11OjRin6cgWNF+j/9Pn8TN4w== - -"@whatwg-node/events@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@whatwg-node/events/-/events-0.1.1.tgz#0ca718508249419587e130da26d40e29d99b5356" - integrity sha512-AyQEn5hIPV7Ze+xFoXVU3QTHXVbWPrzaOkxtENMPMuNL6VVHrp4hHfDt9nrQpjO7BgvuM95dMtkycX5M/DZR3w== - -"@whatwg-node/fetch@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@whatwg-node/fetch/-/fetch-0.8.1.tgz#ee3c94746132f217e17f78f9e073bb342043d630" - integrity sha512-Fkd1qQHK2tAWxKlC85h9L86Lgbq3BzxMnHSnTsnzNZMMzn6Xi+HlN8/LJ90LxorhSqD54td+Q864LgwUaYDj1Q== - dependencies: - "@peculiar/webcrypto" "^1.4.0" - "@whatwg-node/node-fetch" "^0.3.0" - busboy "^1.6.0" - urlpattern-polyfill "^6.0.2" - web-streams-polyfill "^3.2.1" - -"@whatwg-node/fetch@^0.9.0": - version "0.9.16" - resolved "https://registry.yarnpkg.com/@whatwg-node/fetch/-/fetch-0.9.16.tgz#c833eb714f41f5d2caf1a345bed7a05f56db7b16" - integrity sha512-mqasZiUNquRe3ea9+aCAuo81BR6vq5opUKprPilIHTnrg8a21Z1T1OrI+KiMFX8OmwO5HUJe/vro47lpj2JPWQ== - dependencies: - "@whatwg-node/node-fetch" "^0.5.5" - urlpattern-polyfill "^10.0.0" - -"@whatwg-node/node-fetch@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@whatwg-node/node-fetch/-/node-fetch-0.3.0.tgz#7c7e90d03fa09d0ddebff29add6f16d923327d58" - integrity sha512-mPM8WnuHiI/3kFxDeE0SQQXAElbz4onqmm64fEGCwYEcBes2UsvIDI8HwQIqaXCH42A9ajJUPv4WsYoN/9oG6w== - dependencies: - "@whatwg-node/events" "^0.0.2" - busboy "^1.6.0" - fast-querystring "^1.1.1" - fast-url-parser "^1.1.3" - tslib "^2.3.1" - -"@whatwg-node/node-fetch@^0.5.5": - version "0.5.5" - resolved "https://registry.yarnpkg.com/@whatwg-node/node-fetch/-/node-fetch-0.5.5.tgz#40c45e5f5f4185fa3391ff75f619287e0f225c7f" - integrity sha512-LhE0Oo95+dOrrzrJncrpCaR3VHSjJ5Gvkl5g9WVfkPKSKkxCbMeOsRQ+v9LrU9lRvXBJn8JicXqSufKFEpyRbQ== - dependencies: - "@kamilkisiela/fast-url-parser" "^1.1.4" - "@whatwg-node/events" "^0.1.0" - busboy "^1.6.0" - fast-querystring "^1.1.1" - tslib "^2.3.1" - -"@wry/caches@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@wry/caches/-/caches-1.0.1.tgz#8641fd3b6e09230b86ce8b93558d44cf1ece7e52" - integrity sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA== - dependencies: - tslib "^2.3.0" - -"@wry/context@^0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.7.0.tgz#be88e22c0ddf62aeb0ae9f95c3d90932c619a5c8" - integrity sha512-LcDAiYWRtwAoSOArfk7cuYvFXytxfVrdX7yxoUmK7pPITLk5jYh2F8knCwS7LjgYL8u1eidPlKKV6Ikqq0ODqQ== - dependencies: - tslib "^2.3.0" - -"@wry/equality@^0.5.6": - version "0.5.7" - resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.7.tgz#72ec1a73760943d439d56b7b1e9985aec5d497bb" - integrity sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw== - dependencies: - tslib "^2.3.0" - -"@wry/trie@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.4.3.tgz#077d52c22365871bf3ffcbab8e95cb8bc5689af4" - integrity sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w== - dependencies: - tslib "^2.3.0" - -"@wry/trie@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.5.0.tgz#11e783f3a53f6e4cd1d42d2d1323f5bc3fa99c94" - integrity sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA== - dependencies: - tslib "^2.3.0" - -"@xmldom/xmldom@^0.8.3": - version "0.8.6" - resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.6.tgz#8a1524eb5bd5e965c1e3735476f0262469f71440" - integrity sha512-uRjjusqpoqfmRkTaNuLJ2VohVr67Q5YwDATW3VU7PfzTj6IRaihGrYI7zckGZjxQPBIp63nfvJbM+Yu5ICh0Bg== - -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^8.4.1, acorn@^8.5.0, acorn@^8.8.0: - version "8.8.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== - -aes-decrypter@3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/aes-decrypter/-/aes-decrypter-3.1.3.tgz#65ff5f2175324d80c41083b0e135d1464b12ac35" - integrity sha512-VkG9g4BbhMBy+N5/XodDeV6F02chEk9IpgRTq/0bS80y4dzy79VH2Gtms02VXomf3HmyRe3yyJYkJ990ns+d6A== - dependencies: - "@babel/runtime" "^7.12.5" - "@videojs/vhs-utils" "^3.0.5" - global "^4.4.0" - pkcs7 "^1.0.4" - -agent-base@^7.0.2, agent-base@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" - integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== - dependencies: - debug "^4.3.4" - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -ajv-formats@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" - integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== - dependencies: - ajv "^8.0.0" - -ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv-keywords@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" - integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== - dependencies: - fast-deep-equal "^3.1.3" - -ajv@^6.10.0, ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - 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" - -ajv@^8.0.0, ajv@^8.0.1, ajv@^8.8.0: - version "8.12.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" - integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -apollo-upload-client@^18.0.1: - version "18.0.1" - resolved "https://registry.yarnpkg.com/apollo-upload-client/-/apollo-upload-client-18.0.1.tgz#e3811f2f5a36bffef23954f796daf331be748dcb" - integrity sha512-OQvZg1rK05VNI79D658FUmMdoI2oB/KJKb6QGMa2Si25QXOaAvLMBFUEwJct7wf+19U8vk9ILhidBOU1ZWv6QA== - dependencies: - extract-files "^13.0.0" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -aria-query@^5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" - integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== - dependencies: - deep-equal "^2.0.5" - -array-includes@^3.1.5, array-includes@^3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" - is-string "^1.0.7" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array.prototype.flat@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" - integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - -array.prototype.flatmap@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" - integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - -array.prototype.tosorted@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" - integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - get-intrinsic "^1.1.3" - -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== - -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== - -asn1js@^3.0.1, asn1js@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.5.tgz#5ea36820443dbefb51cc7f88a2ebb5b462114f38" - integrity sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ== - dependencies: - pvtsutils "^1.3.2" - pvutils "^1.1.3" - tslib "^2.4.0" - -ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== - -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - -auto-bind@~4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb" - integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ== - -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -axe-core@^4.6.2: - version "4.6.3" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.6.3.tgz#fc0db6fdb65cc7a80ccf85286d91d64ababa3ece" - integrity sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg== - -axobject-query@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.1.1.tgz#3b6e5c6d4e43ca7ba51c5babf99d22a9c68485e1" - integrity sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg== - dependencies: - deep-equal "^2.0.5" - -b64-to-blob@^1.2.19: - version "1.2.19" - resolved "https://registry.yarnpkg.com/b64-to-blob/-/b64-to-blob-1.2.19.tgz#157d85fdc8811665b9a35d29ffbc6a522ba28fbe" - integrity sha512-L3nSu8GgF4iEyNYakCQSfL2F5GI5aCXcot9mNTf+4N0/BMhpxqqHyOb6jIR24iq2xLjQZLG8FOt3gnUcV+9NVg== - -babel-plugin-macros@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" - integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== - dependencies: - "@babel/runtime" "^7.12.5" - cosmiconfig "^7.0.0" - resolve "^1.19.0" - -babel-plugin-polyfill-corejs2@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" - integrity sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q== - dependencies: - "@babel/compat-data" "^7.17.7" - "@babel/helper-define-polyfill-provider" "^0.3.3" - semver "^6.1.1" - -babel-plugin-polyfill-corejs3@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz#56ad88237137eade485a71b52f72dbed57c6230a" - integrity sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" - core-js-compat "^3.25.1" - -babel-plugin-polyfill-regenerator@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz#390f91c38d90473592ed43351e801a9d3e0fd747" - integrity sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" - -babel-plugin-react-intl@^7.0.0: - version "7.9.4" - resolved "https://registry.yarnpkg.com/babel-plugin-react-intl/-/babel-plugin-react-intl-7.9.4.tgz#1fc9ab50470d41b934df50d8f436578ee1732cb0" - integrity sha512-cMKrHEXrw43yT4M89Wbgq8A8N8lffSquj1Piwov/HVukR7jwOw8gf9btXNsQhT27ccyqEwy+M286JQYy0jby2g== - dependencies: - "@babel/core" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/types" "^7.9.5" - "@formatjs/ts-transformer" "^2.6.0" - "@types/babel__core" "^7.1.7" - "@types/fs-extra" "^9.0.1" - "@types/schema-utils" "^2.4.0" - fs-extra "^9.0.0" - intl-messageformat-parser "^5.3.7" - schema-utils "^2.6.6" - -babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: - version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" - integrity sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ== - -babel-preset-fbjs@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz#38a14e5a7a3b285a3f3a86552d650dca5cf6111c" - integrity sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow== - dependencies: - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-syntax-class-properties" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.0.0" - "@babel/plugin-syntax-jsx" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-block-scoped-functions" "^7.0.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-for-of" "^7.0.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-member-expression-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-object-super" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-property-literals" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-template-literals" "^7.0.0" - babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" - -bail@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" - integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -balanced-match@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" - integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== - -base64-blob@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/base64-blob/-/base64-blob-1.4.1.tgz#f8dfc16c22b24ee499e2782719bcce800132c18a" - integrity sha512-n5Ov4cPTbLBTX1PiFbaB5AmK7LMigO9HWh5Lzx+Kcx/yx1MppeeLYtAH8aLv1m++WNoHQnr+xbGSqcZinopwlw== - dependencies: - b64-to-blob "^1.2.19" - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -bcp-47-match@^1.0.0, bcp-47-match@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/bcp-47-match/-/bcp-47-match-1.0.3.tgz#cb8d03071389a10aff2062b862d6575ffd7cd7ef" - integrity sha512-LggQ4YTdjWQSKELZF5JwchnBa1u0pIQSZf5lSdOHEdbVP55h0qICA/FUp3+W99q0xqxYa1ZQizTUH87gecII5w== - -bcp-47-normalize@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/bcp-47-normalize/-/bcp-47-normalize-1.1.1.tgz#d2c76218d132f223c44e4a06a7224be3030f8ec3" - integrity sha512-jWZ1Jdu3cs0EZdfCkS0UE9Gg01PtxnChjEBySeB+Zo6nkqtFfnvtoQQgP1qU1Oo4qgJgxhTI6Sf9y/pZIhPs0A== - dependencies: - bcp-47 "^1.0.0" - bcp-47-match "^1.0.0" - -bcp-47@^1.0.0: - version "1.0.8" - resolved "https://registry.yarnpkg.com/bcp-47/-/bcp-47-1.0.8.tgz#bf63ae4269faabe7c100deac0811121a48b6a561" - integrity sha512-Y9y1QNBBtYtv7hcmoX0tR+tUNSFZGZ6OL6vKPObq8BbOhkCoyayF6ogfLTgAli/KuAEbsYHYUNq2AQuY6IuLag== - dependencies: - is-alphabetical "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -bl@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - -bootstrap@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.6.2.tgz#8e0cd61611728a5bf65a3a2b8d6ff6c77d5d7479" - integrity sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -browserslist@^4.21.4, browserslist@^4.21.5, browserslist@^4.22.2: - version "4.22.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.3.tgz#299d11b7e947a6b843981392721169e27d60c5a6" - integrity sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A== - dependencies: - caniuse-lite "^1.0.30001580" - electron-to-chromium "^1.4.648" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -busboy@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" - integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== - dependencies: - streamsearch "^1.1.0" - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camel-case@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" - integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== - dependencies: - pascal-case "^3.1.2" - tslib "^2.0.3" - -camelcase-keys@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" - integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== - dependencies: - camelcase "^5.3.1" - map-obj "^4.0.0" - quick-lru "^4.0.1" - -camelcase-keys@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-7.0.2.tgz#d048d8c69448745bb0de6fc4c1c52a30dfbe7252" - integrity sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg== - dependencies: - camelcase "^6.3.0" - map-obj "^4.1.0" - quick-lru "^5.1.1" - type-fest "^1.2.1" - -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -caniuse-lite@^1.0.30001580: - version "1.0.30001580" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001580.tgz#e3c76bc6fe020d9007647044278954ff8cd17d1e" - integrity sha512-mtj5ur2FFPZcCEpXFy8ADXbDACuNFXg6mxVDqp7tqooX6l3zwm+d8EPoeOSIFRDvHs8qu7/SLFOGniULkcH2iA== - -capital-case@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" - integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - upper-case-first "^2.0.2" - -cardboard-vr-display@^1.0.19: - version "1.0.19" - resolved "https://registry.yarnpkg.com/cardboard-vr-display/-/cardboard-vr-display-1.0.19.tgz#81dcde1804b329b8228b757ac00e1fd2afa9d748" - integrity sha512-+MjcnWKAkb95p68elqZLDPzoiF/dGncQilLGvPBM5ZorABp/ao3lCs7nnRcYBckmuNkg1V/5rdGDKoUaCVsHzQ== - dependencies: - gl-preserve-state "^1.0.0" - nosleep.js "^0.7.0" - webvr-polyfill-dpdb "^1.0.17" - -ccount@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" - integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg== - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -change-case-all@1.0.14: - version "1.0.14" - resolved "https://registry.yarnpkg.com/change-case-all/-/change-case-all-1.0.14.tgz#bac04da08ad143278d0ac3dda7eccd39280bfba1" - integrity sha512-CWVm2uT7dmSHdO/z1CXT/n47mWonyypzBbuCy5tN7uMg22BsfkhwT6oHmFCAk+gL1LOOxhdbB9SZz3J1KTY3gA== - dependencies: - change-case "^4.1.2" - is-lower-case "^2.0.2" - is-upper-case "^2.0.2" - lower-case "^2.0.2" - lower-case-first "^2.0.2" - sponge-case "^1.0.1" - swap-case "^2.0.2" - title-case "^3.0.3" - upper-case "^2.0.2" - upper-case-first "^2.0.2" - -change-case-all@1.0.15: - version "1.0.15" - resolved "https://registry.yarnpkg.com/change-case-all/-/change-case-all-1.0.15.tgz#de29393167fc101d646cd76b0ef23e27d09756ad" - integrity sha512-3+GIFhk3sNuvFAJKU46o26OdzudQlPNBCu1ZQi3cMeMHhty1bhDxu2WrEilVNYaGvqUtR1VSigFcJOiS13dRhQ== - dependencies: - change-case "^4.1.2" - is-lower-case "^2.0.2" - is-upper-case "^2.0.2" - lower-case "^2.0.2" - lower-case-first "^2.0.2" - sponge-case "^1.0.1" - swap-case "^2.0.2" - title-case "^3.0.3" - upper-case "^2.0.2" - upper-case-first "^2.0.2" - -change-case@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12" - integrity sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A== - dependencies: - camel-case "^4.1.2" - capital-case "^1.0.4" - constant-case "^3.0.4" - dot-case "^3.0.4" - header-case "^2.0.4" - no-case "^3.0.4" - param-case "^3.0.4" - pascal-case "^3.1.2" - path-case "^3.0.4" - sentence-case "^3.0.4" - snake-case "^3.0.4" - tslib "^2.0.3" - -character-entities-legacy@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" - integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== - -character-entities@^1.0.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" - integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== - -character-reference-invalid@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" - integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -"chokidar@>=3.0.0 <4.0.0": - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" - integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-spinners@^2.5.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a" - integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== - -cli-truncate@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" - integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== - dependencies: - slice-ansi "^3.0.0" - string-width "^4.2.0" - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== - -codem-isoboxer@0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/codem-isoboxer/-/codem-isoboxer-0.3.6.tgz#867f670459b881d44f39168d5ff2a8f14c16151d" - integrity sha512-LuO8/7LW6XuR5ERn1yavXAfodGRhuY2yP60JTZIw5yNYMCE5lUVbk3NFUCJxjnphQH+Xemp5hOGb1LgUXm00Xw== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colord@^2.9.3: - version "2.9.3" - resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" - integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== - -colorette@^2.0.16: - version "2.0.19" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" - integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== - -comma-separated-tokens@^1.0.0: - version "1.0.8" - resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" - integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== - -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -common-tags@1.8.2: - version "1.8.2" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" - integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -confusing-browser-globals@^1.0.10: - version "1.0.11" - resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" - integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== - -constant-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1" - integrity sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - upper-case "^2.0.2" - -convert-source-map@^1.5.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -cookie@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== - -core-js-compat@^3.25.1: - version "3.28.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.28.0.tgz#c08456d854608a7264530a2afa281fadf20ecee6" - integrity sha512-myzPgE7QodMg4nnd3K1TDoES/nADRStM8Gpz0D6nhkwbmwEnE0ZGJgoWsvQ722FR8D7xS0n0LV556RcEicjTyg== - dependencies: - browserslist "^4.21.5" - -core-js@^3.27.2: - version "3.28.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.28.0.tgz#ed8b9e99c273879fdfff0edfc77ee709a5800e4a" - integrity sha512-GiZn9D4Z/rSYvTeg1ljAIsEqFm0LaN9gVtwDCrKL80zHtS31p9BAjmTxVqTQDMpwlMolJZOFntUG2uwyj7DAqw== - -cosmiconfig@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" - integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" - -cosmiconfig@^8.1.0, cosmiconfig@^8.1.3, cosmiconfig@^8.2.0: - version "8.3.6" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" - integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== - dependencies: - import-fresh "^3.3.0" - js-yaml "^4.1.0" - parse-json "^5.2.0" - path-type "^4.0.0" - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cross-fetch@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== - dependencies: - node-fetch "2.6.7" - -cross-inspect@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cross-inspect/-/cross-inspect-1.0.0.tgz#5fda1af759a148594d2d58394a9e21364f6849af" - integrity sha512-4PFfn4b5ZN6FMNGSZlyb7wUhuN8wvj8t/VQHZdM4JsDcruGJ8L2kf9zao98QIrBPFCpdk27qst/AGTl7pL3ypQ== - dependencies: - tslib "^2.4.0" - -cross-spawn@^7.0.2: - version "7.0.6" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" - integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypto-js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" - integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== - -css-functions-list@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.1.0.tgz#cf5b09f835ad91a00e5959bcfc627cd498e1321b" - integrity sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w== - -css-tree@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20" - integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== - dependencies: - mdn-data "2.0.30" - source-map-js "^1.0.1" - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -csstype@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" - integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== - -damerau-levenshtein@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" - integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== - -dashjs@^4.2.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/dashjs/-/dashjs-4.6.0.tgz#124c8371e192f1218746ce60b6aa0f175d4dcda4" - integrity sha512-0PDoSBM9PXb+Io0pRnw2CmO7aV9W8FC/BqBRNhLxzM3/e5Kfj7BLy0OWkkSB58ULg6Md6r+6jkGOTUhut/35rg== - dependencies: - bcp-47-match "^1.0.3" - bcp-47-normalize "^1.1.1" - codem-isoboxer "0.3.6" - es6-promise "^4.2.8" - fast-deep-equal "2.0.1" - html-entities "^1.2.1" - imsc "^1.0.2" - localforage "^1.7.1" - path-browserify "^1.0.1" - ua-parser-js "^1.0.2" - -dataloader@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.2.2.tgz#216dc509b5abe39d43a9b9d97e6e5e473dfbe3e0" - integrity sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g== - -date-fns@^2.0.1, date-fns@^2.24.0: - version "2.29.3" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" - integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== - -debounce@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" - integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== - -debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -decamelize-keys@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" - integrity sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg== - dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" - -decamelize@^1.1.0, decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== - -decamelize@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.1.tgz#db11a92e58c741ef339fb0a2868d8a06a9a7b1e9" - integrity sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA== - -deep-equal@^2.0.5: - version "2.2.0" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.0.tgz#5caeace9c781028b9ff459f33b779346637c43e6" - integrity sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw== - dependencies: - call-bind "^1.0.2" - es-get-iterator "^1.1.2" - get-intrinsic "^1.1.3" - is-arguments "^1.1.1" - is-array-buffer "^3.0.1" - is-date-object "^1.0.5" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - isarray "^2.0.5" - object-is "^1.1.5" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - side-channel "^1.0.4" - which-boxed-primitive "^1.0.2" - which-collection "^1.0.1" - which-typed-array "^1.1.9" - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -deepmerge@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" - integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== - -defaults@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" - integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== - dependencies: - clone "^1.0.2" - -define-properties@^1.1.3, define-properties@^1.1.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" - integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -dependency-graph@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" - integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== - -dequal@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" - integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== - -detect-indent@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" - integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== - -diacritics@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/diacritics/-/diacritics-1.3.0.tgz#3efa87323ebb863e6696cebb0082d48ff3d6f7a1" - integrity sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dom-helpers@^5.0.1, dom-helpers@^5.2.0, dom-helpers@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" - integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== - dependencies: - "@babel/runtime" "^7.8.7" - csstype "^3.0.2" - -dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== - -dot-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" - integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - -dotenv@^16.0.0: - version "16.0.3" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" - integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== - -dset@^3.1.2: - version "3.1.4" - resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.4.tgz#f8eaf5f023f068a036d08cd07dc9ffb7d0065248" - integrity sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA== - -electron-to-chromium@^1.4.648: - version "1.4.648" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.648.tgz#c7b46c9010752c37bb4322739d6d2dd82354fbe4" - integrity sha512-EmFMarXeqJp9cUKu/QEciEApn0S/xRcpZWuAm32U7NgoZCimjsilKXHRO9saeEW55eHZagIDg6XTUOv32w9pjg== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.21.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6" - integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-set-tostringtag "^2.0.1" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" - get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - internal-slot "^1.0.4" - is-array-buffer "^3.0.1" - is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-typed-array "^1.1.10" - is-weakref "^1.0.2" - object-inspect "^1.12.2" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - safe-regex-test "^1.0.0" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" - typed-array-length "^1.0.4" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.9" - -es-get-iterator@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" - integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - has-symbols "^1.0.3" - is-arguments "^1.1.1" - is-map "^2.0.2" - is-set "^2.0.2" - is-string "^1.0.7" - isarray "^2.0.5" - stop-iteration-iterator "^1.0.0" - -es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== - dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - has-tostringtag "^1.0.0" - -es-shim-unscopables@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== - dependencies: - has "^1.0.3" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es6-promise@^4.2.8: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -esbuild@^0.18.10: - version "0.18.20" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" - integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== - optionalDependencies: - "@esbuild/android-arm" "0.18.20" - "@esbuild/android-arm64" "0.18.20" - "@esbuild/android-x64" "0.18.20" - "@esbuild/darwin-arm64" "0.18.20" - "@esbuild/darwin-x64" "0.18.20" - "@esbuild/freebsd-arm64" "0.18.20" - "@esbuild/freebsd-x64" "0.18.20" - "@esbuild/linux-arm" "0.18.20" - "@esbuild/linux-arm64" "0.18.20" - "@esbuild/linux-ia32" "0.18.20" - "@esbuild/linux-loong64" "0.18.20" - "@esbuild/linux-mips64el" "0.18.20" - "@esbuild/linux-ppc64" "0.18.20" - "@esbuild/linux-riscv64" "0.18.20" - "@esbuild/linux-s390x" "0.18.20" - "@esbuild/linux-x64" "0.18.20" - "@esbuild/netbsd-x64" "0.18.20" - "@esbuild/openbsd-x64" "0.18.20" - "@esbuild/sunos-x64" "0.18.20" - "@esbuild/win32-arm64" "0.18.20" - "@esbuild/win32-ia32" "0.18.20" - "@esbuild/win32-x64" "0.18.20" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-config-airbnb-base@^15.0.0: - version "15.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz#6b09add90ac79c2f8d723a2580e07f3925afd236" - integrity sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig== - dependencies: - confusing-browser-globals "^1.0.10" - object.assign "^4.1.2" - object.entries "^1.1.5" - semver "^6.3.0" - -eslint-config-airbnb-typescript@^17.0.0: - version "17.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.0.0.tgz#360dbcf810b26bbcf2ff716198465775f1c49a07" - integrity sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g== - dependencies: - eslint-config-airbnb-base "^15.0.0" - -eslint-config-airbnb@^19.0.4: - version "19.0.4" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz#84d4c3490ad70a0ffa571138ebcdea6ab085fdc3" - integrity sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew== - dependencies: - eslint-config-airbnb-base "^15.0.0" - object.assign "^4.1.2" - object.entries "^1.1.5" - -eslint-config-prettier@^8.6.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz#dec1d29ab728f4fa63061774e1672ac4e363d207" - integrity sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA== - -eslint-import-resolver-node@^0.3.7: - version "0.3.7" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" - integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== - dependencies: - debug "^3.2.7" - is-core-module "^2.11.0" - resolve "^1.22.1" - -eslint-module-utils@^2.7.4: - version "2.7.4" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" - integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== - dependencies: - debug "^3.2.7" - -eslint-plugin-import@^2.27.5: - version "2.27.5" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65" - integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== - dependencies: - array-includes "^3.1.6" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" - debug "^3.2.7" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" - eslint-module-utils "^2.7.4" - has "^1.0.3" - is-core-module "^2.11.0" - is-glob "^4.0.3" - minimatch "^3.1.2" - object.values "^1.1.6" - resolve "^1.22.1" - semver "^6.3.0" - tsconfig-paths "^3.14.1" - -eslint-plugin-jsx-a11y@^6.7.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz#fca5e02d115f48c9a597a6894d5bcec2f7a76976" - integrity sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA== - dependencies: - "@babel/runtime" "^7.20.7" - aria-query "^5.1.3" - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - ast-types-flow "^0.0.7" - axe-core "^4.6.2" - axobject-query "^3.1.1" - damerau-levenshtein "^1.0.8" - emoji-regex "^9.2.2" - has "^1.0.3" - jsx-ast-utils "^3.3.3" - language-tags "=1.0.5" - minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - semver "^6.3.0" - -eslint-plugin-react-hooks@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" - integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== - -eslint-plugin-react@^7.32.2: - version "7.32.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10" - integrity sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg== - dependencies: - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - array.prototype.tosorted "^1.1.1" - doctrine "^2.1.0" - estraverse "^5.3.0" - jsx-ast-utils "^2.4.1 || ^3.0.0" - minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - object.hasown "^1.1.2" - object.values "^1.1.6" - prop-types "^15.8.1" - resolve "^2.0.0-next.4" - semver "^6.3.0" - string.prototype.matchall "^4.0.8" - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== - -eslint@^8.34.0: - version "8.34.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.34.0.tgz#fe0ab0ef478104c1f9ebc5537e303d25a8fb22d6" - integrity sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg== - dependencies: - "@eslint/eslintrc" "^1.4.1" - "@humanwhocodes/config-array" "^0.11.8" - "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" - 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.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.4.0" - esquery "^1.4.0" - 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" - grapheme-splitter "^1.0.4" - ignore "^5.2.0" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-sdsl "^4.1.4" - 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.1" - regexpp "^3.2.0" - strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" - text-table "^0.2.0" - -espree@^9.4.0: - version "9.4.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" - integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== - dependencies: - acorn "^8.8.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.1.tgz#ddb8e1e2666750113b78c15f59e977564f52b116" - integrity sha512-3ZggxvMv5EEY1ssUVyHSVt0oPreyBfbUi1XikJVfjFiBeBDLdrb0IWoDiEwqT/2sUQi0TGaWtFhOGDD8RTpXgQ== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -event-target-polyfill@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/event-target-polyfill/-/event-target-polyfill-0.0.4.tgz#060ee66e85aaedc76b6fa66079782dcc11cba496" - integrity sha512-Gs6RLjzlLRdT8X9ZipJdIZI/Y6/HhRLyq9RdDlCsnpxr/+Nn6bU2EFGuC94GjxqhM+Nmij2Vcq98yoHrU8uNFQ== - -extend@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extract-files@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-11.0.0.tgz#b72d428712f787eef1f5193aff8ab5351ca8469a" - integrity sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ== - -extract-files@^13.0.0: - version "13.0.0" - resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-13.0.0.tgz#9065073dedbcfb5e2ae8a90988cf609834b217ec" - integrity sha512-FXD+2Tsr8Iqtm3QZy1Zmwscca7Jx3mMC5Crr+sEP1I303Jy1CYMuYCm7hRTplFNg3XdUavErkxnTzpaqdSoi6g== - dependencies: - is-plain-obj "^4.1.0" - -extract-react-intl-messages@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/extract-react-intl-messages/-/extract-react-intl-messages-4.1.1.tgz#cd01d99053bb053ecc8410ccdccb9ac56daae91c" - integrity sha512-dPogci5X7HVtV7VbUxajH/1YgfNRaW2VtEiVidZ/31Tq8314uzOtzVMNo0IrAPD2E+H1wHoPiu/j565TZsyIZg== - dependencies: - "@babel/core" "^7.9.0" - babel-plugin-react-intl "^7.0.0" - flat "^5.0.0" - glob "^7.1.6" - js-yaml "^3.13.1" - load-json-file "^6.2.0" - lodash.merge "^4.6.2" - lodash.mergewith "^4.6.2" - lodash.pick "^4.4.0" - meow "^6.1.0" - mkdirp "^1.0.3" - pify "^5.0.0" - read-babelrc-up "^1.1.0" - sort-keys "^4.0.0" - write-json-file "^4.3.0" - -fast-decode-uri-component@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" - integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== - -fast-deep-equal@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w== - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.2.9, fast-glob@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.0.tgz#7c40cb491e1e2ed5664749e87bfb516dbe8727c0" - integrity sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA== - 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" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - -fast-querystring@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/fast-querystring/-/fast-querystring-1.1.1.tgz#f4c56ef56b1a954880cfd8c01b83f9e1a3d3fda2" - integrity sha512-qR2r+e3HvhEFmpdHMv//U8FnFlnYjaC6QKDuaXALDkw2kvHO8WDjxH+f/rHGR4Me4pnk8p9JAkRNTjYHAKRn2Q== - dependencies: - fast-decode-uri-component "^1.0.1" - -fast-url-parser@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" - integrity sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ== - dependencies: - punycode "^1.3.2" - -fastest-levenshtein@^1.0.16: - version "1.0.16" - resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" - integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== - -fastq@^1.6.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" - integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== - dependencies: - reusify "^1.0.4" - -fb-watchman@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" - integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== - dependencies: - bser "2.1.1" - -fbjs-css-vars@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" - integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== - -fbjs@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.4.tgz#e1871c6bd3083bac71ff2da868ad5067d37716c6" - integrity sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ== - dependencies: - cross-fetch "^3.1.5" - fbjs-css-vars "^1.0.0" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.30" - -fflate@~0.6.9: - version "0.6.10" - resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.6.10.tgz#5f40f9659205936a2d18abf88b2e7781662b6d43" - integrity sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg== - -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - -find-root@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== - -find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flag-icons@^6.6.6: - version "6.6.6" - resolved "https://registry.yarnpkg.com/flag-icons/-/flag-icons-6.6.6.tgz#9ddff81e1126778ca6a5a1e0e2cfac2e865f2cb7" - integrity sha512-4lHDKxldnQ7q617pf9Dx9nAetT+9zcMpUexbRrc9kjLw9KJgZ83zA5Dky3Vv7ZDzUjAiZ46x/cy5P0HnEnqA2A== - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flat@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - -flatted@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== - -flexbin@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/flexbin/-/flexbin-0.2.0.tgz#0126306d3d595fcb7dfcb87149b9c9599ff8f4e9" - integrity sha512-dgCeT6/oVljr0eao0f7Eg2VXutK/+rp02J6Nkw22uTTFE4HSC7zfYRzjuy2/r0dhr/sUBRMJM2tMyOCi+HeU+A== - -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - -formik@^2.4.5: - version "2.4.5" - resolved "https://registry.yarnpkg.com/formik/-/formik-2.4.5.tgz#f899b5b7a6f103a8fabb679823e8fafc7e0ee1b4" - integrity sha512-Gxlht0TD3vVdzMDHwkiNZqJ7Mvg77xQNfmBRrNtvzcHZs72TJppSTDKHpImCMJZwcWPBJ8jSQQ95GJzXFf1nAQ== - dependencies: - "@types/hoist-non-react-statics" "^3.3.1" - deepmerge "^2.1.1" - hoist-non-react-statics "^3.3.0" - lodash "^4.17.21" - lodash-es "^4.17.21" - react-fast-compare "^2.0.1" - tiny-warning "^1.0.2" - tslib "^2.0.0" - -fs-extra@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" - integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-extra@^9.0.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" - -functions-have-names@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" - integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" - -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -gl-preserve-state@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gl-preserve-state/-/gl-preserve-state-1.0.0.tgz#4ef710d62873f1470ed015c6546c37dacddd4198" - integrity sha512-zQZ25l3haD4hvgJZ6C9+s0ebdkW9y+7U2qxvGu1uWOJh8a4RU+jURIKEQhf8elIlFpMH6CrAY2tH0mYrRjet3Q== - -glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob@^7.1.1, glob@^7.1.3, glob@^7.1.6: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - 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" - -global-modules@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" - integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== - dependencies: - global-prefix "^3.0.0" - -global-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" - integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== - dependencies: - ini "^1.3.5" - kind-of "^6.0.2" - which "^1.3.1" - -global@^4.3.1, global@^4.3.2, global@^4.4.0, global@~4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== - dependencies: - min-document "^2.19.0" - process "^0.11.10" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^13.19.0: - version "13.20.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== - dependencies: - type-fest "^0.20.2" - -globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== - dependencies: - define-properties "^1.1.3" - -globby@^11.0.3, globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - 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" - -globjoin@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" - integrity sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg== - -globrex@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" - integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== - -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -graceful-fs@^4.1.15, graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== - -grapheme-splitter@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" - integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== - -graphql-config@^5.0.2: - version "5.0.3" - resolved "https://registry.yarnpkg.com/graphql-config/-/graphql-config-5.0.3.tgz#d9aa2954cf47a927f9cb83cdc4e42ae55d0b321e" - integrity sha512-BNGZaoxIBkv9yy6Y7omvsaBUHOzfFcII3UN++tpH8MGOKFPFkCPZuwx09ggANMt8FgyWP1Od8SWPmrUEZca4NQ== - dependencies: - "@graphql-tools/graphql-file-loader" "^8.0.0" - "@graphql-tools/json-file-loader" "^8.0.0" - "@graphql-tools/load" "^8.0.0" - "@graphql-tools/merge" "^9.0.0" - "@graphql-tools/url-loader" "^8.0.0" - "@graphql-tools/utils" "^10.0.0" - cosmiconfig "^8.1.0" - jiti "^1.18.2" - minimatch "^4.2.3" - string-env-interpolation "^1.0.1" - tslib "^2.4.0" - -graphql-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f" - integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw== - dependencies: - "@graphql-typed-document-node/core" "^3.2.0" - cross-fetch "^3.1.5" - -graphql-tag@^2.11.0, graphql-tag@^2.12.6: - version "2.12.6" - resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" - integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== - dependencies: - tslib "^2.1.0" - -graphql-ws@^5.14.0, graphql-ws@^5.14.3: - version "5.14.3" - resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-5.14.3.tgz#fb1fba011a0ae9c4e86d831cae2ec27955168b9a" - integrity sha512-F/i2xNIVbaEF2xWggID0X/UZQa2V8kqKDPO8hwmu53bVOcTL7uNkxnexeEgSCVxYBQUTUNEI8+e4LO1FOhKPKQ== - -"graphql@14 - 16", graphql@^16.8.1: - version "16.8.1" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07" - integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== - -hard-rejection@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" - integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== - -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== - dependencies: - get-intrinsic "^1.1.1" - -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== - -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" - integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== - -hast-to-hyperscript@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d" - integrity sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA== - dependencies: - "@types/unist" "^2.0.3" - comma-separated-tokens "^1.0.0" - property-information "^5.3.0" - space-separated-tokens "^1.0.0" - style-to-object "^0.3.0" - unist-util-is "^4.0.0" - web-namespaces "^1.0.0" - -header-case@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063" - integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q== - dependencies: - capital-case "^1.0.4" - tslib "^2.0.3" - -history@^4.9.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - dependencies: - "@babel/runtime" "^7.1.2" - loose-envify "^1.2.0" - resolve-pathname "^3.0.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - value-equal "^1.0.1" - -hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - -hosted-git-info@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" - integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== - dependencies: - lru-cache "^6.0.0" - -html-entities@^1.2.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" - integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== - -html-tags@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce" - integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ== - -http-proxy-agent@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673" - integrity sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ== - dependencies: - agent-base "^7.1.0" - debug "^4.3.4" - -https-proxy-agent@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" - integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== - dependencies: - agent-base "^7.0.2" - debug "4" - -i18n-iso-countries@^7.5.0: - version "7.5.0" - resolved "https://registry.yarnpkg.com/i18n-iso-countries/-/i18n-iso-countries-7.5.0.tgz#74fedd72619526a195cfb2e768fe1d82eed2123f" - integrity sha512-PtfKJNWLVhhU0KBX/8asmywjAcuyQk07mmmMwxFJcddTNBJJ1yvpY2qxVmyxbtVF+9+6eg9phgpv83XPUKU5CA== - dependencies: - diacritics "1.3.0" - -iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ieee754@^1.1.13: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore@^5.2.0, ignore@^5.2.4: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== - -immediate@~3.0.5: - version "3.0.6" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" - integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== - -immutable@^4.0.0: - version "4.2.4" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.2.4.tgz#83260d50889526b4b531a5e293709a77f7c55a2a" - integrity sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w== - -immutable@~3.7.6: - version "3.7.6" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" - integrity sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw== - -import-fresh@^3.0.0, import-fresh@^3.2.1, import-fresh@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-from@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-4.0.0.tgz#2710b8d66817d232e16f4166e319248d3d5492e2" - integrity sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ== - -import-lazy@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" - integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== - -imsc@^1.0.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/imsc/-/imsc-1.1.3.tgz#e96a60a50d4000dd7b44097272768b9fd6a4891d" - integrity sha512-IY0hMkVTNoqoYwKEp5UvNNKp/A5jeJUOrIO7judgOyhHT+xC6PA4VBOMAOhdtAYbMRHx9DTgI8p6Z6jhYQPFDA== - dependencies: - sax "1.2.1" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -indent-string@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5" - integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg== - -individual@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/individual/-/individual-2.0.0.tgz#833b097dad23294e76117a98fb38e0d9ad61bb97" - integrity sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.3, inherits@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@^1.3.5: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -inline-style-parser@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" - integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== - -inquirer@^8.0.0: - version "8.2.5" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8" - integrity sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.1" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.21" - mute-stream "0.0.8" - ora "^5.4.1" - run-async "^2.4.0" - rxjs "^7.5.5" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - wrap-ansi "^7.0.0" - -internal-slot@^1.0.3, internal-slot@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" - integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== - dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" - side-channel "^1.0.4" - -intersection-observer@^0.12.2: - version "0.12.2" - resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.2.tgz#4a45349cc0cd91916682b1f44c28d7ec737dc375" - integrity sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg== - -intl-messageformat-parser@6.1.2: - version "6.1.2" - resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-6.1.2.tgz#28c65f3689f538e66c7cf628881548d6a82ff3c2" - integrity sha512-4GQDEPhl/ZMNDKwMsLqyw1LG2IAWjmLJXdmnRcHKeLQzpgtNYZI6lVw1279pqIkRk2MfKb9aDsVFzm565azK5A== - dependencies: - "@formatjs/ecma402-abstract" "1.5.0" - tslib "^2.0.1" - -intl-messageformat-parser@^5.3.7: - version "5.5.1" - resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-5.5.1.tgz#f09a692755813e6220081e3374df3fb1698bd0c6" - integrity sha512-TvB3LqF2VtP6yI6HXlRT5TxX98HKha6hCcrg9dwlPwNaedVNuQA9KgBdtWKgiyakyCTYHQ+KJeFEstNKfZr64w== - dependencies: - "@formatjs/intl-numberformat" "^5.5.2" - -intl-messageformat@10.3.0: - version "10.3.0" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.3.0.tgz#6a3a30882bf94dfa7014cc642c66abdafd942c0e" - integrity sha512-FKeBZKH9T2Ue4RUXCuwY/hEaRHU8cgICevlGKog0qSBuz/amtRKNBLetBLmRxiHeEkF7JBBckC+56GIwshlRwA== - dependencies: - "@formatjs/ecma402-abstract" "1.14.3" - "@formatjs/fast-memoize" "1.2.8" - "@formatjs/icu-messageformat-parser" "2.2.0" - tslib "^2.4.0" - -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -is-absolute@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" - integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== - dependencies: - is-relative "^1.0.0" - is-windows "^1.0.1" - -is-alphabetical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" - integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== - -is-alphanumerical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" - integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== - dependencies: - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - -is-arguments@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-array-buffer@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.1.tgz#deb1db4fcae48308d54ef2442706c0393997052a" - integrity sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-typed-array "^1.1.10" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-buffer@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== - -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - -is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.5.0, is-core-module@^2.9.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" - integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== - dependencies: - has "^1.0.3" - -is-date-object@^1.0.1, is-date-object@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-decimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" - integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-function@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" - integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== - -is-glob@4.0.3, is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-hexadecimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" - integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== - -is-interactive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" - integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== - -is-lower-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-2.0.2.tgz#1c0884d3012c841556243483aa5d522f47396d2a" - integrity sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ== - dependencies: - tslib "^2.0.3" - -is-map@^2.0.1, is-map@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== - -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-path-inside@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== - -is-plain-obj@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - -is-plain-obj@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" - integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== - -is-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-relative@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" - integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== - dependencies: - is-unc-path "^1.0.0" - -is-set@^2.0.1, is-set@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== - -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.10, is-typed-array@^1.1.9: - version "1.1.10" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - -is-unc-path@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" - integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== - dependencies: - unc-path-regex "^0.1.2" - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -is-upper-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-2.0.2.tgz#f1105ced1fe4de906a5f39553e7d3803fd804649" - integrity sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ== - dependencies: - tslib "^2.0.3" - -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== - -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -is-weakset@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" - integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -is-windows@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -isomorphic-ws@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" - integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== - -jiti@^1.17.1, jiti@^1.18.2: - version "1.21.0" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" - integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== - -jose@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/jose/-/jose-5.2.0.tgz#d0ffd7f7e31253f633eefb190a930cd14a916995" - integrity sha512-oW3PCnvyrcm1HMvGTzqjxxfnEs9EoFOFWi2HsEGhlFVOXxTE3K9GKWVMFoFw06yPUqwpvEWic1BmtUZBI/tIjw== - -js-sdsl@^4.1.4: - version "4.3.0" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711" - integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ== - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^4.0.0, js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - -json-stable-stringify@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz#e06f23128e0bbe342dc996ed5a19e28b57b580e0" - integrity sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g== - dependencies: - jsonify "^0.0.1" - -json-to-pretty-yaml@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/json-to-pretty-yaml/-/json-to-pretty-yaml-1.2.2.tgz#f4cd0bd0a5e8fe1df25aaf5ba118b099fd992d5b" - integrity sha512-rvm6hunfCcqegwYaG5T4yKJWxc9FXFgBVrcTZ4XfSVRwa5HA/Xs+vB/Eo9treYYHCeNM0nrSUr82V/M31Urc7A== - dependencies: - remedial "^1.0.7" - remove-trailing-spaces "^1.0.6" - -json2mq@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" - integrity sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA== - dependencies: - string-convert "^0.2.0" - -json5@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - -json5@^2.1.2, json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonify@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" - integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== - -"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" - integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw== - dependencies: - array-includes "^3.1.5" - object.assign "^4.1.3" - -keycode@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.1.tgz#09c23b2be0611d26117ea2501c2c391a01f39eff" - integrity sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg== - -kind-of@^6.0.2, kind-of@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -known-css-properties@^0.27.0: - version "0.27.0" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.27.0.tgz#82a9358dda5fe7f7bd12b5e7142c0a205393c0c5" - integrity sha512-uMCj6+hZYDoffuvAJjFAPz56E9uoowFHmTkqRtRq5WyC5Q6Cu/fTZKNQpX/RbzChBYLLl3lo8CjFZBAZXq9qFg== - -language-subtag-registry@~0.3.2: - version "0.3.22" - resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" - integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== - -language-tags@=1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" - integrity sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ== - dependencies: - language-subtag-registry "~0.3.2" - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -lie@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" - integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== - dependencies: - immediate "~3.0.5" - -lil-gui@~0.17.0: - version "0.17.0" - resolved "https://registry.yarnpkg.com/lil-gui/-/lil-gui-0.17.0.tgz#b41ae55d0023fcd9185f7395a218db0f58189663" - integrity sha512-MVBHmgY+uEbmJNApAaPbtvNh1RCAeMnKym82SBjtp5rODTYKWtM+MXHCifLe2H2Ti1HuBGBtK/5SyG4ShQ3pUQ== - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -listr2@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5" - integrity sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA== - dependencies: - cli-truncate "^2.1.0" - colorette "^2.0.16" - log-update "^4.0.0" - p-map "^4.0.0" - rfdc "^1.3.0" - rxjs "^7.5.5" - through "^2.3.8" - wrap-ansi "^7.0.0" - -load-json-file@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" - integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== - dependencies: - graceful-fs "^4.1.15" - parse-json "^5.0.0" - strip-bom "^4.0.0" - type-fest "^0.6.0" - -localforage@^1.10.0, localforage@^1.7.1: - version "1.10.0" - resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" - integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== - dependencies: - lie "3.1.1" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash-es@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" - integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.mergewith@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" - integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== - -lodash.pick@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" - integrity sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q== - -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== - -lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.0: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@^4.0.0, log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -log-update@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" - integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== - dependencies: - ansi-escapes "^4.3.0" - cli-cursor "^3.1.0" - slice-ansi "^4.0.0" - wrap-ansi "^6.2.0" - -longest-streak@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" - integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lower-case-first@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-2.0.2.tgz#64c2324a2250bf7c37c5901e76a5b5309301160b" - integrity sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg== - dependencies: - tslib "^2.0.3" - -lower-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" - integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== - dependencies: - tslib "^2.0.3" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -m3u8-parser@4.8.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/m3u8-parser/-/m3u8-parser-4.8.0.tgz#4a2d591fdf6f2579d12a327081198df8af83083d" - integrity sha512-UqA2a/Pw3liR6Df3gwxrqghCP17OpPlQj6RBPLYygf/ZSQ4MoSgvdvhvt35qV+3NaaA0FSZx93Ix+2brT1U7cA== - dependencies: - "@babel/runtime" "^7.12.5" - "@videojs/vhs-utils" "^3.0.5" - global "^4.4.0" - -magic-string@^0.27.0: - version "0.27.0" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3" - integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.13" - -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -map-cache@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== - -map-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== - -map-obj@^4.0.0, map-obj@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" - integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== - -markdown-table@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-2.0.0.tgz#194a90ced26d31fe753d8b9434430214c011865b" - integrity sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A== - dependencies: - repeat-string "^1.0.0" - -mathml-tag-names@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" - integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== - -mdast-util-definitions@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz#c5c1a84db799173b4dcf7643cda999e440c24db2" - integrity sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ== - dependencies: - unist-util-visit "^2.0.0" - -mdast-util-find-and-replace@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-1.1.1.tgz#b7db1e873f96f66588c321f1363069abf607d1b5" - integrity sha512-9cKl33Y21lyckGzpSmEQnIDjEfeeWelN5s1kUW1LwdB0Fkuq2u+4GdqcGEygYxJE8GVqCl0741bYXHgamfWAZA== - dependencies: - escape-string-regexp "^4.0.0" - unist-util-is "^4.0.0" - unist-util-visit-parents "^3.0.0" - -mdast-util-from-markdown@^0.8.0: - version "0.8.5" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz#d1ef2ca42bc377ecb0463a987910dae89bd9a28c" - integrity sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-string "^2.0.0" - micromark "~2.11.0" - parse-entities "^2.0.0" - unist-util-stringify-position "^2.0.0" - -mdast-util-gfm-autolink-literal@^0.1.0: - version "0.1.3" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.3.tgz#9c4ff399c5ddd2ece40bd3b13e5447d84e385fb7" - integrity sha512-GjmLjWrXg1wqMIO9+ZsRik/s7PLwTaeCHVB7vRxUwLntZc8mzmTsLVr6HW1yLokcnhfURsn5zmSVdi3/xWWu1A== - dependencies: - ccount "^1.0.0" - mdast-util-find-and-replace "^1.1.0" - micromark "^2.11.3" - -mdast-util-gfm-strikethrough@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.3.tgz#45eea337b7fff0755a291844fbea79996c322890" - integrity sha512-5OQLXpt6qdbttcDG/UxYY7Yjj3e8P7X16LzvpX8pIQPYJ/C2Z1qFGMmcw+1PZMUM3Z8wt8NRfYTvCni93mgsgA== - dependencies: - mdast-util-to-markdown "^0.6.0" - -mdast-util-gfm-table@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.6.tgz#af05aeadc8e5ee004eeddfb324b2ad8c029b6ecf" - integrity sha512-j4yDxQ66AJSBwGkbpFEp9uG/LS1tZV3P33fN1gkyRB2LoRL+RR3f76m0HPHaby6F4Z5xr9Fv1URmATlRRUIpRQ== - dependencies: - markdown-table "^2.0.0" - mdast-util-to-markdown "~0.6.0" - -mdast-util-gfm-task-list-item@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.6.tgz#70c885e6b9f543ddd7e6b41f9703ee55b084af10" - integrity sha512-/d51FFIfPsSmCIRNp7E6pozM9z1GYPIkSy1urQ8s/o4TC22BZ7DqfHFWiqBD23bc7J3vV1Fc9O4QIHBlfuit8A== - dependencies: - mdast-util-to-markdown "~0.6.0" - -mdast-util-gfm@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-0.1.2.tgz#8ecddafe57d266540f6881f5c57ff19725bd351c" - integrity sha512-NNkhDx/qYcuOWB7xHUGWZYVXvjPFFd6afg6/e2g+SV4r9q5XUcCbV4Wfa3DLYIiD+xAEZc6K4MGaE/m0KDcPwQ== - dependencies: - mdast-util-gfm-autolink-literal "^0.1.0" - mdast-util-gfm-strikethrough "^0.2.0" - mdast-util-gfm-table "^0.1.0" - mdast-util-gfm-task-list-item "^0.1.0" - mdast-util-to-markdown "^0.6.1" - -mdast-util-to-hast@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-10.2.0.tgz#61875526a017d8857b71abc9333942700b2d3604" - integrity sha512-JoPBfJ3gBnHZ18icCwHR50orC9kNH81tiR1gs01D8Q5YpV6adHNO9nKNuFBCJQ941/32PT1a63UF/DitmS3amQ== - dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - mdast-util-definitions "^4.0.0" - mdurl "^1.0.0" - unist-builder "^2.0.0" - unist-util-generated "^1.0.0" - unist-util-position "^3.0.0" - unist-util-visit "^2.0.0" - -mdast-util-to-markdown@^0.6.0, mdast-util-to-markdown@^0.6.1, mdast-util-to-markdown@~0.6.0: - version "0.6.5" - resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz#b33f67ca820d69e6cc527a93d4039249b504bebe" - integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ== - dependencies: - "@types/unist" "^2.0.0" - longest-streak "^2.0.0" - mdast-util-to-string "^2.0.0" - parse-entities "^2.0.0" - repeat-string "^1.0.0" - zwitch "^1.0.0" - -mdast-util-to-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" - integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== - -mdn-data@2.0.30: - version "2.0.30" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" - integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== - -mdurl@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" - integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== - -memoize-one@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" - integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== - -meow@^10.1.5: - version "10.1.5" - resolved "https://registry.yarnpkg.com/meow/-/meow-10.1.5.tgz#be52a1d87b5f5698602b0f32875ee5940904aa7f" - integrity sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw== - dependencies: - "@types/minimist" "^1.2.2" - camelcase-keys "^7.0.0" - decamelize "^5.0.0" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^3.0.2" - read-pkg-up "^8.0.0" - redent "^4.0.0" - trim-newlines "^4.0.2" - type-fest "^1.2.2" - yargs-parser "^20.2.9" - -meow@^6.1.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/meow/-/meow-6.1.1.tgz#1ad64c4b76b2a24dfb2f635fddcadf320d251467" - integrity sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "^4.0.2" - normalize-package-data "^2.5.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.13.1" - yargs-parser "^18.1.3" - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -meros@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/meros/-/meros-1.2.1.tgz#056f7a76e8571d0aaf3c7afcbe7eb6407ff7329e" - integrity sha512-R2f/jxYqCAGI19KhAvaxSOxALBMkaXWH2a7rOyqQw+ZmizX5bKkEYWLzdhC+U82ZVVPVp6MCXe3EkVligh+12g== - -meshoptimizer@~0.18.1: - version "0.18.1" - resolved "https://registry.yarnpkg.com/meshoptimizer/-/meshoptimizer-0.18.1.tgz#cdb90907f30a7b5b1190facd3b7ee6b7087797d8" - integrity sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw== - -micromark-extension-gfm-autolink-literal@~0.5.0: - version "0.5.7" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-0.5.7.tgz#53866c1f0c7ef940ae7ca1f72c6faef8fed9f204" - integrity sha512-ePiDGH0/lhcngCe8FtH4ARFoxKTUelMp4L7Gg2pujYD5CSMb9PbblnyL+AAMud/SNMyusbS2XDSiPIRcQoNFAw== - dependencies: - micromark "~2.11.3" - -micromark-extension-gfm-strikethrough@~0.6.5: - version "0.6.5" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-0.6.5.tgz#96cb83356ff87bf31670eefb7ad7bba73e6514d1" - integrity sha512-PpOKlgokpQRwUesRwWEp+fHjGGkZEejj83k9gU5iXCbDG+XBA92BqnRKYJdfqfkrRcZRgGuPuXb7DaK/DmxOhw== - dependencies: - micromark "~2.11.0" - -micromark-extension-gfm-table@~0.4.0: - version "0.4.3" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-0.4.3.tgz#4d49f1ce0ca84996c853880b9446698947f1802b" - integrity sha512-hVGvESPq0fk6ALWtomcwmgLvH8ZSVpcPjzi0AjPclB9FsVRgMtGZkUcpE0zgjOCFAznKepF4z3hX8z6e3HODdA== - dependencies: - micromark "~2.11.0" - -micromark-extension-gfm-tagfilter@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-0.3.0.tgz#d9f26a65adee984c9ccdd7e182220493562841ad" - integrity sha512-9GU0xBatryXifL//FJH+tAZ6i240xQuFrSL7mYi8f4oZSbc+NvXjkrHemeYP0+L4ZUT+Ptz3b95zhUZnMtoi/Q== - -micromark-extension-gfm-task-list-item@~0.3.0: - version "0.3.3" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-0.3.3.tgz#d90c755f2533ed55a718129cee11257f136283b8" - integrity sha512-0zvM5iSLKrc/NQl84pZSjGo66aTGd57C1idmlWmE87lkMcXrTxg1uXa/nXomxJytoje9trP0NDLvw4bZ/Z/XCQ== - dependencies: - micromark "~2.11.0" - -micromark-extension-gfm@^0.3.0: - version "0.3.3" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-0.3.3.tgz#36d1a4c089ca8bdfd978c9bd2bf1a0cb24e2acfe" - integrity sha512-oVN4zv5/tAIA+l3GbMi7lWeYpJ14oQyJ3uEim20ktYFAcfX1x3LNlFGGlmrZHt7u9YlKExmyJdDGaTt6cMSR/A== - dependencies: - micromark "~2.11.0" - micromark-extension-gfm-autolink-literal "~0.5.0" - micromark-extension-gfm-strikethrough "~0.6.5" - micromark-extension-gfm-table "~0.4.0" - micromark-extension-gfm-tagfilter "~0.3.0" - micromark-extension-gfm-task-list-item "~0.3.0" - -micromark@^2.11.3, micromark@~2.11.0, micromark@~2.11.3: - version "2.11.4" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a" - integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA== - dependencies: - debug "^4.0.0" - parse-entities "^2.0.0" - -micromatch@^4.0.4, micromatch@^4.0.5: - version "4.0.8" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" - integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== - dependencies: - braces "^3.0.3" - picomatch "^2.3.1" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ== - dependencies: - dom-walk "^0.1.0" - -min-indent@^1.0.0, min-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== - -minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.3.tgz#b4dcece1d674dee104bb0fb833ebb85a78cbbca6" - integrity sha512-lIUdtK5hdofgCTu3aT0sOaHsYR37viUuIc0rwnnDXImbwFRcumyLMeZaM0t0I/fgxS6s6JMfu0rLD1Wz9pv1ng== - dependencies: - brace-expansion "^1.1.7" - -minimist-options@4.1.0, minimist-options@^4.0.2: - version "4.1.0" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" - integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - kind-of "^6.0.3" - -minimist@^1.2.0, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -mkdirp@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -moment@^2.30.1: - version "2.30.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" - integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== - -moment@~2.29.1: - version "2.29.4" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" - integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== - -mousetrap-pause@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mousetrap-pause/-/mousetrap-pause-1.0.0.tgz#91c429f2f5f9ad71508fa0561bb53be3fdf9a9d0" - integrity sha512-/92qasq/TIkogCZKRYZdX+XAiPOD8dBDIipaar+caXSdKrfhYQIe6UmweiXO9yQeETjhNAUWdopwLsU6po/IPw== - -mousetrap@^1.6.5: - version "1.6.5" - resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.5.tgz#8a766d8c272b08393d5f56074e0b5ec183485bf9" - integrity sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA== - -mpd-parser@0.22.1, mpd-parser@^0.22.1: - version "0.22.1" - resolved "https://registry.yarnpkg.com/mpd-parser/-/mpd-parser-0.22.1.tgz#bc2bf7d3e56368e4b0121035b055675401871521" - integrity sha512-fwBebvpyPUU8bOzvhX0VQZgSohncbgYwUyJJoTSNpmy7ccD2ryiCvM7oRkn/xQH5cv73/xU7rJSNCLjdGFor0Q== - dependencies: - "@babel/runtime" "^7.12.5" - "@videojs/vhs-utils" "^3.0.5" - "@xmldom/xmldom" "^0.8.3" - global "^4.4.0" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - -mux.js@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-6.0.1.tgz#65ce0f7a961d56c006829d024d772902d28c7755" - integrity sha512-22CHb59rH8pWGcPGW5Og7JngJ9s+z4XuSlYvnxhLuc58cA1WqGDQPzuG8I+sPm1/p0CdgpzVTaKW408k5DNn8w== - dependencies: - "@babel/runtime" "^7.11.2" - global "^4.4.0" - -nanoid@^3.3.6: - version "3.3.8" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" - integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== - -natural-compare-lite@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" - integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -no-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" - integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== - dependencies: - lower-case "^2.0.2" - tslib "^2.0.3" - -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - -node-fetch@^2.6.1: - version "2.6.9" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" - integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== - dependencies: - whatwg-url "^5.0.0" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== - -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== - -normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-package-data@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" - integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== - dependencies: - hosted-git-info "^4.0.1" - is-core-module "^2.5.0" - semver "^7.3.4" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-url@^4.5.1: - version "4.5.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - -nosleep.js@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/nosleep.js/-/nosleep.js-0.7.0.tgz#cfd919c25523ca0d0f4a69fb3305c083adaee289" - integrity sha512-Z4B1HgvzR+en62ghwZf6BwAR6x4/pjezsiMcbF9KMLh7xoscpoYhaSXfY3lLkqC68AtW+/qLJ1lzvBIj0FGaTA== - -nullthrows@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" - integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== - -object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-inspect@^1.12.2, object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== - -object-is@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.2, object.assign@^4.1.3, object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.entries@^1.1.5, object.entries@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23" - integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.fromentries@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" - integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.hasown@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" - integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw== - dependencies: - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.values@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" - integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^5.1.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -optimism@^0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.18.0.tgz#e7bb38b24715f3fdad8a9a7fc18e999144bbfa63" - integrity sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ== - dependencies: - "@wry/caches" "^1.0.0" - "@wry/context" "^0.7.0" - "@wry/trie" "^0.4.3" - tslib "^2.3.0" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - 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.3" - -ora@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" - integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== - dependencies: - bl "^4.1.0" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - is-unicode-supported "^0.1.0" - log-symbols "^4.1.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== - -p-limit@3.1.0, p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -param-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" - integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-entities@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" - integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" - -parse-filepath@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" - integrity sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q== - dependencies: - is-absolute "^1.0.0" - map-cache "^0.2.0" - path-root "^0.1.1" - -parse-json@^5.0.0, parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -pascal-case@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" - integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - -path-browserify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== - -path-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f" - integrity sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg== - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-root-regex@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" - integrity sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ== - -path-root@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" - integrity sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg== - dependencies: - path-root-regex "^0.1.0" - -path-to-regexp@^1.7.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.9.0.tgz#5dc0753acbf8521ca2e0f137b4578b917b10cf24" - integrity sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g== - dependencies: - isarray "0.0.1" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" - integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== - -pkcs7@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/pkcs7/-/pkcs7-1.0.4.tgz#6090b9e71160dabf69209d719cbafa538b00a1cb" - integrity sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ== - dependencies: - "@babel/runtime" "^7.5.5" - -postcss-resolve-nested-selector@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" - integrity sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw== - -postcss-safe-parser@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz#bb4c29894171a94bc5c996b9a30317ef402adaa1" - integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ== - -postcss-scss@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-4.0.6.tgz#5d62a574b950a6ae12f2aa89b60d63d9e4432bfd" - integrity sha512-rLDPhJY4z/i4nVFZ27j9GqLxj1pwxE80eAzUNRMXtcpipFYIeowerzBgG3yJhMtObGEXidtIgbUpQ3eLDsf5OQ== - -postcss-selector-parser@^6.0.13: - version "6.0.13" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" - integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-sorting@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/postcss-sorting/-/postcss-sorting-8.0.1.tgz#d03852914979ac0a1ef3ca6e517bf4b53c045f35" - integrity sha512-go9Zoxx7KQH+uLrJ9xa5wRErFeXu01ydA6O8m7koPXkmAN7Ts//eRcIqjo0stBR4+Nir2gMYDOWAOx7O5EPUZA== - -postcss-value-parser@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" - integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== - -postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.27, postcss@^8.4.31: - version "8.4.31" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" - integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== - dependencies: - nanoid "^3.3.6" - picocolors "^1.0.0" - source-map-js "^1.0.2" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier@^2.8.4: - version "2.8.4" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3" - integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" - integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== - dependencies: - asap "~2.0.3" - -prop-types-extra@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/prop-types-extra/-/prop-types-extra-1.1.1.tgz#58c3b74cbfbb95d304625975aa2f0848329a010b" - integrity sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew== - dependencies: - react-is "^16.3.2" - warning "^4.0.0" - -prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - -prop-types@~15.7.2: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.8.1" - -property-expr@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4" - integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA== - -property-information@^5.3.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" - integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== - dependencies: - xtend "^4.0.0" - -punycode@^1.3.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== - -punycode@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== - -pvtsutils@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.2.tgz#9f8570d132cdd3c27ab7d51a2799239bf8d8d5de" - integrity sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ== - dependencies: - tslib "^2.4.0" - -pvutils@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" - integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -quick-lru@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" - integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== - -quick-lru@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" - integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== - -react-bootstrap@^1.6.6: - version "1.6.6" - resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-1.6.6.tgz#3f3b274f8923b9886008a0e61485b5ac9a2b3073" - integrity sha512-pSzYyJT5u4rc8+5myM8Vid2JG52L8AmYSkpznReH/GM4+FhLqEnxUa0+6HRTaGwjdEixQNGchwY+b3xCdYWrDA== - dependencies: - "@babel/runtime" "^7.14.0" - "@restart/context" "^2.1.4" - "@restart/hooks" "^0.4.7" - "@types/invariant" "^2.2.33" - "@types/prop-types" "^15.7.3" - "@types/react" ">=16.14.8" - "@types/react-transition-group" "^4.4.1" - "@types/warning" "^3.0.0" - classnames "^2.3.1" - dom-helpers "^5.2.1" - invariant "^2.2.4" - prop-types "^15.7.2" - prop-types-extra "^1.1.0" - react-overlays "^5.1.2" - react-transition-group "^4.4.1" - uncontrollable "^7.2.1" - warning "^4.0.3" - -react-datepicker@^4.10.0: - version "4.10.0" - resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.10.0.tgz#3f386ac5873dac5ea56544e51cdc01109938796c" - integrity sha512-6IfBCZyWj54ZZGLmEZJ9c4Yph0s9MVfEGDC2evOvf9AmVz+RRcfP2Czqad88Ff9wREbcbqa4dk7IFYeXF1d3Ag== - dependencies: - "@popperjs/core" "^2.9.2" - classnames "^2.2.6" - date-fns "^2.24.0" - prop-types "^15.7.2" - react-onclickoutside "^6.12.2" - react-popper "^2.3.0" - -react-dom@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" - -react-fast-compare@^2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" - integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== - -react-fast-compare@^3.0.1, react-fast-compare@^3.1.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.1.tgz#53933d9e14f364281d6cba24bfed7a4afb808b5f" - integrity sha512-xTYf9zFim2pEif/Fw16dBiXpe0hoy5PxcD8+OwBnTtNLfIm3g6WxhKNurY+6OmdH1u6Ta/W/Vl6vjbYP1MFnDg== - -react-helmet@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726" - integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw== - dependencies: - object-assign "^4.1.1" - prop-types "^15.7.2" - react-fast-compare "^3.1.1" - react-side-effect "^2.1.0" - -react-intl@^6.2.8: - version "6.2.8" - resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-6.2.8.tgz#f61fffc14e69490607d3be9253704ac5afc49d56" - integrity sha512-Njzmbmk58rBx6i0bGQbBLYj+KbR9IXbFfbK2u0AFayjDx+VJW30MdJV6aNL9EiPaXfcOcAYm31R777e/UHWeEw== - dependencies: - "@formatjs/ecma402-abstract" "1.14.3" - "@formatjs/icu-messageformat-parser" "2.2.0" - "@formatjs/intl" "2.6.5" - "@formatjs/intl-displaynames" "6.2.4" - "@formatjs/intl-listformat" "7.1.7" - "@types/hoist-non-react-statics" "^3.3.1" - "@types/react" "16 || 17 || 18" - hoist-non-react-statics "^3.3.2" - intl-messageformat "10.3.0" - tslib "^2.4.0" - -react-is@^16.13.1, react-is@^16.3.2, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-lifecycles-compat@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" - integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== - -react-onclickoutside@^6.12.2: - version "6.12.2" - resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.12.2.tgz#8e6cf80c7d17a79f2c908399918158a7b02dda01" - integrity sha512-NMXGa223OnsrGVp5dJHkuKxQ4czdLmXSp5jSV9OqiCky9LOpPATn3vLldc+q5fK3gKbEHvr7J1u0yhBh/xYkpA== - -react-overlays@^5.1.2: - version "5.2.1" - resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-5.2.1.tgz#49dc007321adb6784e1f212403f0fb37a74ab86b" - integrity sha512-GLLSOLWr21CqtJn8geSwQfoJufdt3mfdsnIiQswouuQ2MMPns+ihZklxvsTDKD3cR2tF8ELbi5xUsvqVhR6WvA== - dependencies: - "@babel/runtime" "^7.13.8" - "@popperjs/core" "^2.11.6" - "@restart/hooks" "^0.4.7" - "@types/warning" "^3.0.0" - dom-helpers "^5.2.0" - prop-types "^15.7.2" - uncontrollable "^7.2.1" - warning "^4.0.3" - -react-photo-gallery@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/react-photo-gallery/-/react-photo-gallery-8.0.0.tgz#04ff9f902a2342660e63e6817b4f010488db02b8" - integrity sha512-Y9458yygEB9cIZAWlBWuenlR+ghin1RopmmU3Vice8BeJl0Se7hzfxGDq8W1armB/ic/kphGg+G1jq5fOEd0sw== - dependencies: - prop-types "~15.7.2" - resize-observer-polyfill "^1.5.0" - -react-popper@^2.2.5, react-popper@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.3.0.tgz#17891c620e1320dce318bad9fede46a5f71c70ba" - integrity sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q== - dependencies: - react-fast-compare "^3.0.1" - warning "^4.0.2" - -react-refresh@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" - integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== - -react-remark@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/react-remark/-/react-remark-2.1.0.tgz#dd68a32ab2d022e598b27dbfb754400e8f68555c" - integrity sha512-7dEPxRGQ23sOdvteuRGaQAs9cEOH/BOeCN4CqsJdk3laUDIDYRCWnM6a3z92PzXHUuxIRLXQNZx7SiO0ijUcbw== - dependencies: - rehype-react "^6.0.0" - remark-parse "^9.0.0" - remark-rehype "^8.0.0" - unified "^9.0.0" - -react-router-bootstrap@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/react-router-bootstrap/-/react-router-bootstrap-0.25.0.tgz#5d1a99b5b8a2016c011fc46019d2397e563ce0df" - integrity sha512-/22eqxjn6Zv5fvY2rZHn57SKmjmJfK7xzJ6/G1OgxAjLtKVfWgV5sn41W2yiqzbtV5eE4/i4LeDLBGYTqx7jbA== - dependencies: - prop-types "^15.5.10" - -react-router-dom@^5.3.4: - version "5.3.4" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.4.tgz#2ed62ffd88cae6db134445f4a0c0ae8b91d2e5e6" - integrity sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - loose-envify "^1.3.1" - prop-types "^15.6.2" - react-router "5.3.4" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - -react-router-hash-link@^2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/react-router-hash-link/-/react-router-hash-link-2.4.3.tgz#570824d53d6c35ce94d73a46c8e98673a127bf08" - integrity sha512-NU7GWc265m92xh/aYD79Vr1W+zAIXDWp3L2YZOYP4rCqPnJ6LI6vh3+rKgkidtYijozHclaEQTAHaAaMWPVI4A== - dependencies: - prop-types "^15.7.2" - -react-router@5.3.4: - version "5.3.4" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.3.4.tgz#8ca252d70fcc37841e31473c7a151cf777887bb5" - integrity sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - hoist-non-react-statics "^3.1.0" - loose-envify "^1.3.1" - path-to-regexp "^1.7.0" - prop-types "^15.6.2" - react-is "^16.6.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - -react-select@^5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.7.0.tgz#82921b38f1fcf1471a0b62304da01f2896cd8ce6" - integrity sha512-lJGiMxCa3cqnUr2Jjtg9YHsaytiZqeNOKeibv6WF5zbK/fPegZ1hg3y/9P1RZVLhqBTs0PfqQLKuAACednYGhQ== - dependencies: - "@babel/runtime" "^7.12.0" - "@emotion/cache" "^11.4.0" - "@emotion/react" "^11.8.1" - "@floating-ui/dom" "^1.0.1" - "@types/react-transition-group" "^4.4.0" - memoize-one "^6.0.0" - prop-types "^15.6.0" - react-transition-group "^4.3.0" - use-isomorphic-layout-effect "^1.1.2" - -react-side-effect@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.2.tgz#dc6345b9e8f9906dc2eeb68700b615e0b4fe752a" - integrity sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw== - -react-transition-group@^4.3.0, react-transition-group@^4.4.1: - version "4.4.5" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" - integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== - dependencies: - "@babel/runtime" "^7.5.5" - dom-helpers "^5.0.1" - loose-envify "^1.4.0" - prop-types "^15.6.2" - -react@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -read-babelrc-up@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-babelrc-up/-/read-babelrc-up-1.1.0.tgz#10fd5baaf6ca03eaba6748fa65ddae25bca61e70" - integrity sha512-fcl0JeI85Ss3//kfC3z2rsG2VxSiHl1bJgpjQWrne2YuQEewZpAgAjb17A6q/Q3ozWeZsUSroiIBVsnjmOU8vw== - dependencies: - find-up "^4.1.0" - json5 "^2.1.2" - -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - -read-pkg-up@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-8.0.0.tgz#72f595b65e66110f43b052dd9af4de6b10534670" - integrity sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ== - dependencies: - find-up "^5.0.0" - read-pkg "^6.0.0" - type-fest "^1.0.1" - -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - -read-pkg@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-6.0.0.tgz#a67a7d6a1c2b0c3cd6aa2ea521f40c458a4a504c" - integrity sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^3.0.2" - parse-json "^5.2.0" - type-fest "^1.0.1" - -readable-stream@^3.4.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -redent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" - integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== - dependencies: - indent-string "^4.0.0" - strip-indent "^3.0.0" - -redent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-4.0.0.tgz#0c0ba7caabb24257ab3bb7a4fd95dd1d5c5681f9" - integrity sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag== - dependencies: - indent-string "^5.0.0" - strip-indent "^4.0.0" - -regenerate-unicode-properties@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" - integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== - dependencies: - regenerate "^1.4.2" - -regenerate@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== - -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== - -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - -regenerator-transform@^0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" - integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== - dependencies: - "@babel/runtime" "^7.8.4" - -regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" - -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -regexpu-core@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.1.tgz#66900860f88def39a5cb79ebd9490e84f17bcdfb" - integrity sha512-nCOzW2V/X15XpLsK2rlgdwrysrBq+AauCn+omItIz4R1pIcmeot5zvjdmOBRLzEH/CkC6IxMJVmxDe3QcMuNVQ== - dependencies: - "@babel/regjsgen" "^0.8.0" - regenerate "^1.4.2" - regenerate-unicode-properties "^10.1.0" - regjsparser "^0.9.1" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.1.0" - -regjsparser@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" - integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== - dependencies: - jsesc "~0.5.0" - -rehype-react@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/rehype-react/-/rehype-react-6.2.1.tgz#9b9bf188451ad6f63796b784fe1f51165c67b73a" - integrity sha512-f9KIrjktvLvmbGc7si25HepocOg4z0MuNOtweigKzBcDjiGSTGhyz6VSgaV5K421Cq1O+z4/oxRJ5G9owo0KVg== - dependencies: - "@mapbox/hast-util-table-cell-style" "^0.2.0" - hast-to-hyperscript "^9.0.0" - -relay-runtime@12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/relay-runtime/-/relay-runtime-12.0.0.tgz#1e039282bdb5e0c1b9a7dc7f6b9a09d4f4ff8237" - integrity sha512-QU6JKr1tMsry22DXNy9Whsq5rmvwr3LSZiiWV/9+DFpuTWvp+WFhobWMc8TC4OjKFfNhEZy7mOiqUAn5atQtug== - dependencies: - "@babel/runtime" "^7.0.0" - fbjs "^3.0.0" - invariant "^2.2.4" - -remark-gfm@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-1.0.0.tgz#9213643001be3f277da6256464d56fd28c3b3c0d" - integrity sha512-KfexHJCiqvrdBZVbQ6RopMZGwaXz6wFJEfByIuEwGf0arvITHjiKKZ1dpXujjH9KZdm1//XJQwgfnJ3lmXaDPA== - dependencies: - mdast-util-gfm "^0.1.0" - micromark-extension-gfm "^0.3.0" - -remark-parse@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-9.0.0.tgz#4d20a299665880e4f4af5d90b7c7b8a935853640" - integrity sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw== - dependencies: - mdast-util-from-markdown "^0.8.0" - -remark-rehype@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-8.1.0.tgz#610509a043484c1e697437fa5eb3fd992617c945" - integrity sha512-EbCu9kHgAxKmW1yEYjx3QafMyGY3q8noUbNUI5xyKbaFP89wbhDrKxyIQNukNYthzjNHZu6J7hwFg7hRm1svYA== - dependencies: - mdast-util-to-hast "^10.2.0" - -remedial@^1.0.7: - version "1.0.8" - resolved "https://registry.yarnpkg.com/remedial/-/remedial-1.0.8.tgz#a5e4fd52a0e4956adbaf62da63a5a46a78c578a0" - integrity sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg== - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== - -remove-trailing-spaces@^1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/remove-trailing-spaces/-/remove-trailing-spaces-1.0.8.tgz#4354d22f3236374702f58ee373168f6d6887ada7" - integrity sha512-O3vsMYfWighyFbTd8hk8VaSj9UAGENxAtX+//ugIst2RMk5e03h6RoIS+0ylsFxY1gvmPuAY/PO4It+gPEeySA== - -repeat-string@^1.0.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -resize-observer-polyfill@^1.5.0, resize-observer-polyfill@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" - integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== - -resolve-from@5.0.0, resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - -resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.1: - version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -resolve@^2.0.0-next.4: - version "2.0.0-next.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" - integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== - dependencies: - is-core-module "^2.9.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -response-iterator@^0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/response-iterator/-/response-iterator-0.2.6.tgz#249005fb14d2e4eeb478a3f735a28fd8b4c9f3da" - integrity sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw== - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rollup@^3.27.1: - version "3.29.5" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.5.tgz#8a2e477a758b520fb78daf04bca4c522c1da8a54" - integrity sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w== - optionalDependencies: - fsevents "~2.3.2" - -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -rust-result@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rust-result/-/rust-result-1.0.0.tgz#34c75b2e6dc39fe5875e5bdec85b5e0f91536f72" - integrity sha512-6cJzSBU+J/RJCF063onnQf0cDUOHs9uZI1oroSGnHOph+CQTIJ5Pp2hK5kEQq1+7yE/EEWfulSNXAQ2jikPthA== - dependencies: - individual "^2.0.0" - -rxjs@^7.5.5: - version "7.8.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" - integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== - dependencies: - tslib "^2.1.0" - -safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-json-parse@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-4.0.0.tgz#7c0f578cfccd12d33a71c0e05413e2eca171eaac" - integrity sha512-RjZPPHugjK0TOzFrLZ8inw44s9bKox99/0AZW9o/BEQVrJfhI+fIHMErnPyRa89/yRXUUr93q+tiN6zhoVV4wQ== - dependencies: - rust-result "^1.0.0" - -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-regex "^1.1.4" - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sass@^1.58.1: - version "1.58.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.58.1.tgz#17ab0390076a50578ed0733f1cc45429e03405f6" - integrity sha512-bnINi6nPXbP1XNRaranMFEBZWUfdW/AF16Ql5+ypRxfTvCRTTKrLsMIakyDcayUt2t/RZotmL4kgJwNH5xO+bg== - dependencies: - chokidar ">=3.0.0 <4.0.0" - immutable "^4.0.0" - source-map-js ">=0.6.2 <2.0.0" - -sax@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" - integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA== - -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -schema-utils@*: - version "4.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" - integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== - dependencies: - "@types/json-schema" "^7.0.9" - ajv "^8.8.0" - ajv-formats "^2.1.1" - ajv-keywords "^5.0.0" - -schema-utils@^2.6.6: - version "2.7.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" - integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== - dependencies: - "@types/json-schema" "^7.0.5" - ajv "^6.12.4" - ajv-keywords "^3.5.2" - -scuid@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/scuid/-/scuid-1.1.0.tgz#d3f9f920956e737a60f72d0e4ad280bf324d5dab" - integrity sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg== - -"semver@2 || 3 || 4 || 5": - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.3.4, semver@^7.3.7: - version "7.5.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - -sentence-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" - integrity sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - upper-case-first "^2.0.2" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shell-quote@^1.7.3: - version "1.8.0" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.0.tgz#20d078d0eaf71d54f43bd2ba14a1b5b9bfa5c8ba" - integrity sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ== - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -signal-exit@^3.0.2: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -signal-exit@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.2.tgz#ff55bb1d9ff2114c13b400688fa544ac63c36967" - integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q== - -signedsource@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/signedsource/-/signedsource-1.0.0.tgz#1ddace4981798f93bd833973803d80d52e93ad6a" - integrity sha512-6+eerH9fEnNmi/hyM1DXcRK3pWdoMQtlkQ+ns0ntzunjKqp5i3sKCc80ym8Fib3iaYhdJUOPdhlJWj1tvge2Ww== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" - integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -slick-carousel@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/slick-carousel/-/slick-carousel-1.8.1.tgz#a4bfb29014887bb66ce528b90bd0cda262cc8f8d" - integrity sha512-XB9Ftrf2EEKfzoQXt3Nitrt/IPbT+f1fgqBdoxO3W/+JYvtEOW6EgxnWfr9GH6nmULv7Y2tPmEX3koxThVmebA== - -snake-case@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" - integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - -sort-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-4.2.0.tgz#6b7638cee42c506fff8c1cecde7376d21315be18" - integrity sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg== - dependencies: - is-plain-obj "^2.0.0" - -"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - -source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -space-separated-tokens@^1.0.0: - version "1.1.5" - resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" - integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== - -spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.12" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz#69077835abe2710b65f03969898b6637b505a779" - integrity sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA== - -sponge-case@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sponge-case/-/sponge-case-1.0.1.tgz#260833b86453883d974f84854cdb63aecc5aef4c" - integrity sha512-dblb9Et4DAtiZ5YSUZHLl4XhH4uK80GhAZrVXdN4O2P4gQ40Wa5UIOPUHlA/nFd2PLblBZWUioLMMAVrgpoYcA== - dependencies: - tslib "^2.0.3" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -stop-iteration-iterator@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" - integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== - dependencies: - internal-slot "^1.0.4" - -streamsearch@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" - integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== - -string-convert@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" - integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A== - -string-env-interpolation@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz#ad4397ae4ac53fe6c91d1402ad6f6a52862c7152" - integrity sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg== - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string.prototype.matchall@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" - integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" - has-symbols "^1.0.3" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.4.3" - side-channel "^1.0.4" - -string.prototype.replaceall@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.replaceall/-/string.prototype.replaceall-1.0.7.tgz#6cf36b20bcb12d55653e1119ddf5bc1d6363103d" - integrity sha512-xB2WV2GlSCSJT5dMGdhdH1noMPiAB91guiepwTYyWY9/0Vq/TZ7RPmnOSUGAEvry08QIK7EMr28aAii+9jC6kw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" - has-symbols "^1.0.3" - is-regex "^1.1.4" - -string.prototype.trimend@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" - integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string.prototype.trimstart@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" - integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" - integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== - dependencies: - min-indent "^1.0.0" - -strip-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-4.0.0.tgz#b41379433dd06f5eae805e21d631e07ee670d853" - integrity sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA== - dependencies: - min-indent "^1.0.1" - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -style-search@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" - integrity sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg== - -style-to-object@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" - integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA== - dependencies: - inline-style-parser "0.1.1" - -stylelint-order@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-6.0.2.tgz#df54d3ed9aa5a45d4563ada0375e670140a798c2" - integrity sha512-yuac0BE6toHd27wUPvYVVQicAJthKFIv1HPQFH3Q0dExiO3Z6Uam7geoO0tUd5Z9ddsATYK++1qWNDX4RxMH5Q== - dependencies: - postcss "^8.4.21" - postcss-sorting "^8.0.1" - -stylelint@^15.10.1: - version "15.10.1" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-15.10.1.tgz#93f189958687e330c106b010cbec0c41dcae506d" - integrity sha512-CYkzYrCFfA/gnOR+u9kJ1PpzwG10WLVnoxHDuBA/JiwGqdM9+yx9+ou6SE/y9YHtfv1mcLo06fdadHTOx4gBZQ== - dependencies: - "@csstools/css-parser-algorithms" "^2.3.0" - "@csstools/css-tokenizer" "^2.1.1" - "@csstools/media-query-list-parser" "^2.1.2" - "@csstools/selector-specificity" "^3.0.0" - balanced-match "^2.0.0" - colord "^2.9.3" - cosmiconfig "^8.2.0" - css-functions-list "^3.1.0" - css-tree "^2.3.1" - debug "^4.3.4" - fast-glob "^3.3.0" - fastest-levenshtein "^1.0.16" - file-entry-cache "^6.0.1" - global-modules "^2.0.0" - globby "^11.1.0" - globjoin "^0.1.4" - html-tags "^3.3.1" - ignore "^5.2.4" - import-lazy "^4.0.0" - imurmurhash "^0.1.4" - is-plain-object "^5.0.0" - known-css-properties "^0.27.0" - mathml-tag-names "^2.1.3" - meow "^10.1.5" - micromatch "^4.0.5" - normalize-path "^3.0.0" - picocolors "^1.0.0" - postcss "^8.4.24" - postcss-resolve-nested-selector "^0.1.1" - postcss-safe-parser "^6.0.0" - postcss-selector-parser "^6.0.13" - postcss-value-parser "^4.2.0" - resolve-from "^5.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - style-search "^0.1.0" - supports-hyperlinks "^3.0.0" - svg-tags "^1.0.0" - table "^6.8.1" - write-file-atomic "^5.0.1" - -stylis@4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" - integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.0.0, supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-hyperlinks@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz#c711352a5c89070779b4dad54c05a2f14b15c94b" - integrity sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -svg-tags@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" - integrity sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA== - -swap-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-2.0.2.tgz#671aedb3c9c137e2985ef51c51f9e98445bf70d9" - integrity sha512-kc6S2YS/2yXbtkSMunBtKdah4VFETZ8Oh6ONSmSd9bRxhqTrtARUCBUiWXH3xVPpvR7tz2CSnkuXVE42EcGnMw== - dependencies: - tslib "^2.0.3" - -symbol-observable@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" - integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== - -systemjs@^6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-6.13.0.tgz#7b28e74b44352e1650e8652499f42de724c3fc7f" - integrity sha512-P3cgh2bpaPvAO2NE3uRp/n6hmk4xPX4DQf+UzTlCAycssKdqhp6hjw+ENWe+aUS7TogKRFtptMosTSFeC6R55g== - -table@^6.8.1: - version "6.8.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" - integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== - dependencies: - ajv "^8.0.1" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - -terser@^5.9.0: - version "5.16.4" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.4.tgz#51284b440b93242291a98f2a9903c024cfb70e6e" - integrity sha512-5yEGuZ3DZradbogeYQ1NaGz7rXVBDWujWlx1PT8efXO6Txn+eWbfKqB2bTDVmFXmePFkoLU6XI8UektMIEA0ug== - dependencies: - "@jridgewell/source-map" "^0.3.2" - acorn "^8.5.0" - commander "^2.20.0" - source-map-support "~0.5.20" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -thehandy@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/thehandy/-/thehandy-1.0.3.tgz#51c5e9bae5932a6e5c563203711d78610b99d402" - integrity sha512-zuuyWKBx/jqku9+MZkdkoK2oLM2mS8byWVR/vkQYq/ygAT6gPAXwiT94rfGuqv+1BLmsyJxm69nhVIzOZjfyIg== - -three@0.93.0: - version "0.93.0" - resolved "https://registry.yarnpkg.com/three/-/three-0.93.0.tgz#3fd6c367ef4554abbb6e16ad69936283e895c123" - integrity sha512-Ys9+UBBsd6FxTZZl4BH7B4b2F+B2uR0cOwY7OQ/aCzU/VgO4Wmmr1LbWPH1fsTvSVik9KAuwxwOHlSC4IMGOLA== - -throttle-debounce@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-5.0.0.tgz#a17a4039e82a2ed38a5e7268e4132d6960d41933" - integrity sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg== - -through@^2.3.6, through@^2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - -tiny-case@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" - integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== - -tiny-invariant@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" - integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== - -tiny-warning@^1.0.0, tiny-warning@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - -title-case@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/title-case/-/title-case-3.0.3.tgz#bc689b46f02e411f1d1e1d081f7c3deca0489982" - integrity sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA== - dependencies: - tslib "^2.0.3" - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toposort@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" - integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg== - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -trim-newlines@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" - integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== - -trim-newlines@^4.0.2: - version "4.1.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-4.1.1.tgz#28c88deb50ed10c7ba6dc2474421904a00139125" - integrity sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ== - -trough@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" - integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== - -ts-invariant@^0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.10.3.tgz#3e048ff96e91459ffca01304dbc7f61c1f642f6c" - integrity sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ== - dependencies: - tslib "^2.1.0" - -ts-log@^2.2.3: - version "2.2.5" - resolved "https://registry.yarnpkg.com/ts-log/-/ts-log-2.2.5.tgz#aef3252f1143d11047e2cb6f7cfaac7408d96623" - integrity sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA== - -ts-node@^10.9.1: - version "10.9.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" - integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -tsconfck@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/tsconfck/-/tsconfck-2.0.2.tgz#860a488f9acd024a85b2db458888410009b5383d" - integrity sha512-H3DWlwKpow+GpVLm/2cpmok72pwRr1YFROV3YzAmvzfGFiC1zEM/mc9b7+1XnrxuXtEbhJ7xUSIqjPFbedp7aQ== - -tsconfig-paths@^3.14.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" - integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.1" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.5.0, tslib@~2.6.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== - -tslib@~2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" - integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== - -tslib@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" - integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-fest@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" - integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -type-fest@^1.0.1, type-fest@^1.2.1, type-fest@^1.2.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" - integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== - -type-fest@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" - integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== - -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - is-typed-array "^1.1.9" - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -typescript@^4.0, typescript@~4.8.4: - version "4.8.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" - integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== - -ua-parser-js@^0.7.30: - version "0.7.33" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532" - integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw== - -ua-parser-js@^1.0.2, ua-parser-js@^1.0.34: - version "1.0.34" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.34.tgz#b33f41c415325839f354005d25a2f588be296976" - integrity sha512-K9mwJm/DaB6mRLZfw6q8IMXipcrmuT6yfhYmwhAkuh+81sChuYstYA+znlgaflUPaYUa3odxKPKGw6Vw/lANew== - -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - -unc-path-regex@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" - integrity sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg== - -uncontrollable@^7.2.1: - version "7.2.1" - resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-7.2.1.tgz#1fa70ba0c57a14d5f78905d533cf63916dc75738" - integrity sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ== - dependencies: - "@babel/runtime" "^7.6.3" - "@types/react" ">=16.9.11" - invariant "^2.2.4" - react-lifecycles-compat "^3.0.4" - -unicode-canonical-property-names-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" - integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== - -unicode-match-property-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" - integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== - dependencies: - unicode-canonical-property-names-ecmascript "^2.0.0" - unicode-property-aliases-ecmascript "^2.0.0" - -unicode-match-property-value-ecmascript@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" - integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== - -unicode-property-aliases-ecmascript@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" - integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== - -unified@^9.0.0: - version "9.2.2" - resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.2.tgz#67649a1abfc3ab85d2969502902775eb03146975" - integrity sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ== - dependencies: - bail "^1.0.0" - extend "^3.0.0" - is-buffer "^2.0.0" - is-plain-obj "^2.0.0" - trough "^1.0.0" - vfile "^4.0.0" - -unist-builder@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436" - integrity sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw== - -unist-util-generated@^1.0.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.6.tgz#5ab51f689e2992a472beb1b35f2ce7ff2f324d4b" - integrity sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg== - -unist-util-is@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd" - integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A== - -unist-util-is@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" - integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== - -unist-util-position@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47" - integrity sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA== - -unist-util-stringify-position@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" - integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== - dependencies: - "@types/unist" "^2.0.2" - -unist-util-visit-parents@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz#25e43e55312166f3348cae6743588781d112c1e9" - integrity sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g== - dependencies: - unist-util-is "^3.0.0" - -unist-util-visit-parents@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6" - integrity sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^4.0.0" - -unist-util-visit@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3" - integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw== - dependencies: - unist-util-visit-parents "^2.0.0" - -unist-util-visit@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c" - integrity sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^4.0.0" - unist-util-visit-parents "^3.0.0" - -universal-cookie@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/universal-cookie/-/universal-cookie-4.0.4.tgz#06e8b3625bf9af049569ef97109b4bb226ad798d" - integrity sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw== - dependencies: - "@types/cookie" "^0.3.3" - cookie "^0.4.0" - -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - -unixify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unixify/-/unixify-1.0.0.tgz#3a641c8c2ffbce4da683a5c70f03a462940c2090" - integrity sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg== - dependencies: - normalize-path "^2.1.1" - -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -upper-case-first@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" - integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== - dependencies: - tslib "^2.0.3" - -upper-case@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a" - integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg== - dependencies: - tslib "^2.0.3" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -url-toolkit@^2.2.1: - version "2.2.5" - resolved "https://registry.yarnpkg.com/url-toolkit/-/url-toolkit-2.2.5.tgz#58406b18e12c58803e14624df5e374f638b0f607" - integrity sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg== - -urlpattern-polyfill@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz#f0a03a97bfb03cdf33553e5e79a2aadd22cac8ec" - integrity sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg== - -urlpattern-polyfill@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-6.0.2.tgz#a193fe773459865a2a5c93b246bb794b13d07256" - integrity sha512-5vZjFlH9ofROmuWmXM9yj2wljYKgWstGwe8YTyiqM7hVum/g9LyCizPZtb3UqsuppVwety9QJmfc42VggLpTgg== - dependencies: - braces "^3.0.2" - -use-isomorphic-layout-effect@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" - integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== - -util-deprecate@^1.0.1, util-deprecate@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== - -value-or-promise@^1.0.11, value-or-promise@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.12.tgz#0e5abfeec70148c78460a849f6b003ea7986f15c" - integrity sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q== - -vfile-message@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" - integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== - dependencies: - "@types/unist" "^2.0.0" - unist-util-stringify-position "^2.0.0" - -vfile@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" - integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA== - dependencies: - "@types/unist" "^2.0.0" - is-buffer "^2.0.0" - unist-util-stringify-position "^2.0.0" - vfile-message "^2.0.0" - -"video.js@^5.18.0 || ^6 || ^7", "video.js@^6 || ^7", video.js@^7.21.3: - version "7.21.3" - resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.21.3.tgz#1a5f6379e713de3f5dc036ecdef02efb80765bdd" - integrity sha512-fIboXbSDCT3P8eVzIEC3hnLDKC/y+6QftcHdFGUVGn5a7qmH62Mh0Bt/SrBAgdmKDQM1qdZXfXAxPg5+IaiIXQ== - dependencies: - "@babel/runtime" "^7.12.5" - "@videojs/http-streaming" "2.16.2" - "@videojs/vhs-utils" "^3.0.4" - "@videojs/xhr" "2.6.0" - aes-decrypter "3.1.3" - global "^4.4.0" - keycode "^2.2.0" - m3u8-parser "4.8.0" - mpd-parser "0.22.1" - mux.js "6.0.1" - safe-json-parse "4.0.0" - videojs-font "3.2.0" - videojs-vtt.js "^0.15.4" - -videojs-abloop@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/videojs-abloop/-/videojs-abloop-1.2.0.tgz#ead4054400e6107d6512553ddff2a97260decf3e" - integrity sha512-6/hvtB5gNQUr5FJ969UhXVg5H+3wxhOzh9AVftlezOXlhzzaWfNfiOJYqNKo01Gc/eSQOvfttrOX7jH+aHpwrw== - -videojs-contrib-dash@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/videojs-contrib-dash/-/videojs-contrib-dash-5.1.1.tgz#9f50191677815a7d816c500977811a926aee0643" - integrity sha512-MI0kPHuQ3KH9Mc2mLVLqvFKCoEyTfXzHc02fm8pqMk8v7LXrJKnIv9xfugBccRF7vZHDZISftedD/CmEJfvvrA== - dependencies: - dashjs "^4.2.0" - global "^4.3.2" - video.js "^5.18.0 || ^6 || ^7" - -videojs-font@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/videojs-font/-/videojs-font-3.2.0.tgz#212c9d3f4e4ec3fa7345167d64316add35e92232" - integrity sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA== - -videojs-mobile-ui@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/videojs-mobile-ui/-/videojs-mobile-ui-0.8.0.tgz#40a1c6f9302071b9bbe95937c934114600916ac5" - integrity sha512-Jd+u/ctjUkbZlT1cAA0umTu0LQwSZSFG+02cJxShuwq27B6rfrRALETK/gsuTc7U27lB9fbwcF7HBMaNxW62nA== - dependencies: - global "^4.4.0" - -videojs-seek-buttons@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/videojs-seek-buttons/-/videojs-seek-buttons-3.0.1.tgz#cc2adc23a6372e8aa6c2e9fd0fe7e7831a46747f" - integrity sha512-scVWOqCMqHajlbwYZIzJ5nBYkDXTAhEpWjfcdCu8ykksA1barrKnEKdQvS84TtDWOx6UXDD/e/x0acYEZCDMEQ== - dependencies: - global "^4.4.0" - -videojs-vr@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/videojs-vr/-/videojs-vr-1.8.0.tgz#7f2f07f760d8a329c615acd316e49da6ee8edd34" - integrity sha512-776gXqt8g6/rLeV56nn/aUcO0sRy+mgFITCw8cIqzTzl93SE1PEK/QE3YNqtppUfU5igayrx7WKsWhDOpsXMpw== - dependencies: - "@babel/runtime" "^7.14.5" - global "^4.4.0" - three "0.93.0" - video.js "^6 || ^7" - webvr-polyfill "0.10.12" - -videojs-vtt.js@^0.15.4: - version "0.15.4" - resolved "https://registry.yarnpkg.com/videojs-vtt.js/-/videojs-vtt.js-0.15.4.tgz#5dc5aabcd82ba40c5595469bd855ea8230ca152c" - integrity sha512-r6IhM325fcLb1D6pgsMkTQT1PpFdUdYZa1iqk7wJEu+QlibBwATPfPc9Bg8Jiym0GE5yP1AG2rMLu+QMVWkYtA== - dependencies: - global "^4.3.1" - -vite-plugin-compression@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/vite-plugin-compression/-/vite-plugin-compression-0.5.1.tgz#a75b0d8f48357ebb377b65016da9f20885ef39b6" - integrity sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg== - dependencies: - chalk "^4.1.2" - debug "^4.3.3" - fs-extra "^10.0.0" - -vite-tsconfig-paths@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-4.0.5.tgz#c7c54e2cf7ccc5e600db565cecd7b368a1fa8889" - integrity sha512-/L/eHwySFYjwxoYt1WRJniuK/jPv+WGwgRGBYx3leciR5wBeqntQpUE6Js6+TJemChc+ter7fDBKieyEWDx4yQ== - dependencies: - debug "^4.1.1" - globrex "^0.1.2" - tsconfck "^2.0.1" - -vite@^4.5.14: - version "4.5.14" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.14.tgz#2e652bc1d898265d987d6543ce866ecd65fa4086" - integrity sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g== - dependencies: - esbuild "^0.18.10" - postcss "^8.4.27" - rollup "^3.27.1" - optionalDependencies: - fsevents "~2.3.2" - -warning@^4.0.0, warning@^4.0.2, warning@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" - integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== - dependencies: - loose-envify "^1.0.0" - -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== - dependencies: - defaults "^1.0.3" - -web-namespaces@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" - integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== - -web-streams-polyfill@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" - integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== - -"webcomponents.js@git+https://git@github.com/webcomponents/webcomponentsjs.git#v0.7.24": - version "0.7.24" - resolved "git+https://git@github.com/webcomponents/webcomponentsjs.git#8a2e40557b177e2cca0def2553f84c8269c8f93e" - -webcrypto-core@^1.7.4: - version "1.7.6" - resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.6.tgz#e32c4a12a13de4251f8f9ef336a6cba7cdec9b55" - integrity sha512-TBPiewB4Buw+HI3EQW+Bexm19/W4cP/qZG/02QJCXN+iN+T5sl074vZ3rJcle/ZtDBQSgjkbsQO/1eFcxnSBUA== - dependencies: - "@peculiar/asn1-schema" "^2.1.6" - "@peculiar/json-schema" "^1.1.12" - asn1js "^3.0.1" - pvtsutils "^1.3.2" - tslib "^2.4.0" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -webvr-polyfill-dpdb@^1.0.17: - version "1.0.18" - resolved "https://registry.yarnpkg.com/webvr-polyfill-dpdb/-/webvr-polyfill-dpdb-1.0.18.tgz#258484ce06b057bf18898acc911bd173847bce11" - integrity sha512-O0S1ZGEWyPvyZEkS2VbyV7mtir/NM9MNK3EuhbHPoJ8EHTky2pTXehjIl+IiDPr+Lldgx129QGt3NGly7rwRPw== - -webvr-polyfill@0.10.12: - version "0.10.12" - resolved "https://registry.yarnpkg.com/webvr-polyfill/-/webvr-polyfill-0.10.12.tgz#47ea0b0d558f09e089bc49fa7b47a4ee7e4b8148" - integrity sha512-trDJEVUQnRIVAnmImjEQ0BlL1NfuWl8+eaEdu+bs4g59c7OtETi/5tFkgEFDRaWEYwHntXs/uFF3OXZuutNGGA== - dependencies: - cardboard-vr-display "^1.0.19" - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== - dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== - -which-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" - -which@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f" - integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA== - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -write-file-atomic@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" - integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^4.0.1" - -write-json-file@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-4.3.0.tgz#908493d6fd23225344af324016e4ca8f702dd12d" - integrity sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ== - dependencies: - detect-indent "^6.0.0" - graceful-fs "^4.1.15" - is-plain-obj "^2.0.0" - make-dir "^3.0.0" - sort-keys "^4.0.0" - write-file-atomic "^3.0.0" - -ws@^8.12.0, ws@^8.13.0, ws@^8.15.0: - version "8.17.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" - integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== - -xtend@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml-ast-parser@^0.0.43: - version "0.0.43" - resolved "https://registry.yarnpkg.com/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz#e8a23e6fb4c38076ab92995c5dca33f3d3d7c9bb" - integrity sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A== - -yaml@^1.10.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - -yaml@^2.3.1: - version "2.3.4" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" - integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== - -yargs-parser@^18.1.2, yargs-parser@^18.1.3: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^20.2.9: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yargs@^15.3.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" - integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.2" - -yargs@^17.0.0: - version "17.6.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.2.tgz#2e23f2944e976339a1ee00f18c77fedee8332541" - integrity sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -yup@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/yup/-/yup-1.3.2.tgz#afffc458f1513ed386e6aaf4bcaa4e67a9e270dc" - integrity sha512-6KCM971iQtJ+/KUaHdrhVr2LDkfhBtFPRnsG1P8F4q3uUVQ2RfEM9xekpha9aA4GXWJevjM10eDcPQ1FfWlmaQ== - dependencies: - property-expr "^2.0.5" - tiny-case "^1.0.3" - toposort "^2.0.2" - type-fest "^2.19.0" - -zen-observable-ts@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz#6c6d9ea3d3a842812c6e9519209365a122ba8b58" - integrity sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg== - dependencies: - zen-observable "0.8.15" - -zen-observable@0.8.15: - version "0.8.15" - resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" - integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== - -zwitch@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" - integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==