├── .gitattributes ├── .github └── workflows │ ├── data.yml │ └── dist.yml ├── .gitignore ├── .gitpod.yml ├── .prettierrc.yml ├── LICENSE ├── README.md ├── eslint.config.mjs ├── images ├── panel.png ├── screenshot-1280x800.png └── screenshot.png ├── package-lock.json ├── package.json ├── packages ├── baha-anime-skip-db │ ├── README.md │ ├── data.json │ ├── package.json │ ├── scripts │ │ ├── slice.ts │ │ └── validate.ts │ ├── src │ │ └── index.ts │ └── tsup.config.ts ├── baha-anime-skip-ext │ ├── .gitignore │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── privacy-policy.md │ ├── src │ │ ├── assets │ │ │ └── icons │ │ │ │ ├── icon-128.png │ │ │ │ ├── icon-16.png │ │ │ │ ├── icon-32.png │ │ │ │ ├── icon-48.png │ │ │ │ ├── icon.png │ │ │ │ └── icon.svg │ │ ├── background │ │ │ └── index.ts │ │ ├── components │ │ │ ├── AddEndpoint.svelte │ │ │ ├── EndpointList.svelte │ │ │ ├── SkipButton.svelte │ │ │ └── SkipTab.svelte │ │ ├── content │ │ │ ├── index.ts │ │ │ ├── manager.ts │ │ │ ├── mount.ts │ │ │ └── utils.ts │ │ ├── log.ts │ │ ├── manifest.config.ts │ │ ├── storage.ts │ │ ├── styles.css │ │ └── vite-env.d.ts │ ├── svelte.config.js │ ├── tailwind.config.cjs │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── baha-anime-skip │ ├── README.md │ ├── package.json │ ├── src │ │ ├── button.ts │ │ ├── config.ts │ │ ├── index.ts │ │ ├── prefetch.ts │ │ ├── tab.ts │ │ ├── types.ts │ │ └── utils.ts │ └── tsup.config.ts └── marker │ ├── package.json │ └── src │ ├── app.ts │ ├── cache.ts │ ├── data.ts │ ├── list.ts │ ├── marker.ts │ ├── run.ts │ └── types.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── renovate.json └── tsconfig.json /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/data.yml: -------------------------------------------------------------------------------- 1 | name: Build Data 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - packages/baha-anime-skip-db/data.json 9 | workflow_dispatch: 10 | 11 | jobs: 12 | build_data: 13 | name: Build Data 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v3 18 | 19 | - name: Setup PNPM 20 | uses: pnpm/action-setup@v2.2.4 21 | with: 22 | run_install: true 23 | 24 | - name: Build 25 | run: pnpm -r run slice 26 | 27 | - name: Deploy 28 | uses: peaceiris/actions-gh-pages@v3 29 | with: 30 | github_token: ${{ secrets.GITHUB_TOKEN }} 31 | publish_dir: "./packages/baha-anime-skip-db/data" 32 | publish_branch: "data" 33 | -------------------------------------------------------------------------------- /.github/workflows/dist.yml: -------------------------------------------------------------------------------- 1 | name: Build Script 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - packages/baha-anime-skip/** 9 | workflow_dispatch: 10 | 11 | jobs: 12 | build_script: 13 | name: Build Script 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v3 18 | 19 | - name: Setup PNPM 20 | uses: pnpm/action-setup@v2.2.4 21 | with: 22 | run_install: true 23 | 24 | - name: Build 25 | run: pnpm -r run build 26 | 27 | - name: Deploy 28 | uses: peaceiris/actions-gh-pages@v3 29 | with: 30 | github_token: ${{ secrets.GITHUB_TOKEN }} 31 | publish_dir: "./packages/baha-anime-skip/dist" 32 | publish_branch: "dist" 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Serverless directories 108 | .serverless/ 109 | 110 | # FuseBox cache 111 | .fusebox/ 112 | 113 | # DynamoDB Local files 114 | .dynamodb/ 115 | 116 | # TernJS port file 117 | .tern-port 118 | 119 | # Stores VSCode versions used for testing VSCode extensions 120 | .vscode-test 121 | 122 | # yarn v2 123 | .yarn/cache 124 | .yarn/unplugged 125 | .yarn/build-state.yml 126 | .yarn/install-state.gz 127 | .pnp.* 128 | 129 | **/.DS_Store 130 | lib/ 131 | data/ 132 | docs/ 133 | *.cache 134 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | # This configuration file was automatically generated by Gitpod. 2 | # Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file) 3 | # and commit this file to your remote git repository to share the goodness with others. 4 | 5 | tasks: 6 | - init: pnpm install && pnpm run build 7 | -------------------------------------------------------------------------------- /.prettierrc.yml: -------------------------------------------------------------------------------- 1 | --- 2 | printWidth: 100 3 | tabWidth: 4 4 | useTabs: false 5 | trailingComma: all 6 | semi: true 7 | singleQuote: false 8 | overrides: 9 | - files: "*.{md,yml,yaml}" 10 | options: 11 | tabWidth: 2 12 | 13 | plugins: 14 | - prettier-plugin-svelte 15 | - prettier-plugin-organize-imports 16 | - prettier-plugin-tailwindcss 17 | 18 | organizeImportsSkipDestructiveCodeActions: true 19 | 20 | tailwindConfig: packages/baha-anime-skip-ext/tailwind.config.cjs 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 JacobLinCool 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Baha Anime Skip 2 | 3 | Skip OP or other things on Bahamut Anime. 4 | 5 | ## Database 6 | 7 | Database is stored in [`packages/baha-anime-skip-db/data.json`](packages/baha-anime-skip-db/data.json). 8 | 9 | Currently, the database includes OP timestamp of **10,000+** episodes. Most of them are automatically detected by programs based on some hypotheses, source code is available in [`marker`](packages/marker). 10 | 11 | **Any PRs or Issues are welcome.** 12 | 13 | The schema details are in [`packages/baha-anime-skip-db/README.md`](packages/baha-anime-skip-db/README.md). 14 | 15 | ## Tampermonkey Script 16 | 17 | > Prerequisite: Tampermonkey installed. 18 | 19 | Install from [here](https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/dist/index.user.js). 20 | 21 | The button will show up if there is a event record for the current episode and the time is in the event range. 22 | 23 | ![Screenshot](./images/screenshot.png) 24 | 25 | A panel with report link and debug info is also attached. If you click the link, a pre-filled issue will be opened in this repo. 26 | 27 | ![Panel](./images/panel.png) 28 | 29 | ## Submit Issue 30 | 31 | You can simply click "GitHub Issues" button in the panel, then add some additional information to the issue body. 32 | 33 | https://user-images.githubusercontent.com/28478594/192158622-d82e8527-3523-4469-84e6-691be23e099f.mp4 34 | 35 | ## Sponsors 36 | 37 | Thanks the following generous sponsors for supporting this project. 38 | 39 | - [`@limitx0`](https://github.com/limitx0) for 30 days of premium service. 🎉 40 | - [`@LianSheng197`](https://github.com/LianSheng197) for the sponsorship of premium service. 🎉 41 | 42 | If you want to sponsor this project, you can send a Bahamut Anime Redeem Code to my email: [`hi@jacoblin.cool`](mailto:hi@jacoblin.cool?subject=%5BSponsor%5D%20Bahamut%20Anime%20Redeem%20Code&body=Code%3A%20......%0D%0A%0D%0AAnything%20you%20want%20to%20tell%20me:%20%0D%0A). And if you want, I will put your name here. 43 | 44 | A premium account is useful because it can save my time to wait for the AD when I am testing the program. 45 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import eslint from "@eslint/js"; 2 | import eslintConfigPrettier from "eslint-config-prettier"; 3 | import tseslint from "typescript-eslint"; 4 | 5 | export default [ 6 | eslint.configs.recommended, 7 | ...tseslint.configs.recommended, 8 | eslintConfigPrettier, 9 | { 10 | rules: { 11 | "@typescript-eslint/explicit-module-boundary-types": [ 12 | "error", 13 | { allowArgumentsExplicitlyTypedAsAny: true }, 14 | ], 15 | }, 16 | }, 17 | { 18 | ignores: ["**/lib/**", "**/dist/**", "**/docs/**"], 19 | }, 20 | ]; 21 | -------------------------------------------------------------------------------- /images/panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/19f01bece74fbd73f9c3b685446d0f9b2a0d3444/images/panel.png -------------------------------------------------------------------------------- /images/screenshot-1280x800.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/19f01bece74fbd73f9c3b685446d0f9b2a0d3444/images/screenshot-1280x800.png -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/19f01bece74fbd73f9c3b685446d0f9b2a0d3444/images/screenshot.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "baha-anime-skip", 4 | "version": "0.1.0", 5 | "description": "Skip OP or other things on Bahamut Anime.", 6 | "keywords": [], 7 | "author": "JacobLinCool (https://github.com/JacobLinCool)", 8 | "license": "MIT", 9 | "main": "lib/index.js", 10 | "module": "lib/index.mjs", 11 | "types": "lib/index.d.ts", 12 | "files": [ 13 | "lib", 14 | "data.json" 15 | ], 16 | "scripts": { 17 | "test": "pnpm -r run test", 18 | "build": "pnpm -r run build", 19 | "docs": "pnpm -r run docs", 20 | "format": "prettier --write '**/*.{js,cjs,ts,jsx,tsx,json,yml,yaml,md,html,svelte}' --ignore-path .gitignore", 21 | "lint": "eslint .", 22 | "recent": "pnpm -r run recent && pnpm test", 23 | "fast-up": "git pull && pnpm recent && git commit packages/baha-anime-skip-db/data.json -m 'feat(db): auto-detected OPs' && git push" 24 | }, 25 | "devDependencies": { 26 | "@types/jest": "^29.5.12", 27 | "@types/node": "^20.12.11", 28 | "eslint": "^9.2.0", 29 | "eslint-config-prettier": "^9.1.0", 30 | "jest": "^29.7.0", 31 | "prettier": "^3.2.5", 32 | "prettier-plugin-organize-imports": "^3.2.4", 33 | "prettier-plugin-svelte": "^3.2.3", 34 | "prettier-plugin-tailwindcss": "^0.5.14", 35 | "ts-jest": "^29.1.2", 36 | "tsup": "^8.0.2", 37 | "tsx": "^4.9.5", 38 | "typedoc": "^0.25.13", 39 | "typescript": "^5.4.5", 40 | "typescript-eslint": "^7.8.0", 41 | "zod": "^3.23.8" 42 | }, 43 | "packageManager": "pnpm@8.15.8" 44 | } 45 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-db/README.md: -------------------------------------------------------------------------------- 1 | # baha-anime-skip-db 2 | 3 | Database. 4 | 5 | Schema: 6 | 7 | ```ts 8 | { 9 | "episode-sn": { 10 | "chapter-type": [start, duration] 11 | } 12 | } 13 | ``` 14 | 15 | Common chapter types: - `"OP"` - `"ED"` 16 | 17 | The unit of `start` and `duration` is second. (can be float) 18 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-db/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baha-anime-skip-db", 3 | "version": "0.1.0", 4 | "description": "Skip OP or other things on Bahamut Anime.", 5 | "keywords": [], 6 | "author": "JacobLinCool (https://github.com/JacobLinCool)", 7 | "license": "MIT", 8 | "type": "module", 9 | "main": "lib/index.js", 10 | "types": "lib/index.d.ts", 11 | "files": [ 12 | "lib", 13 | "data.json" 14 | ], 15 | "scripts": { 16 | "test": "tsx scripts/validate.ts", 17 | "build": "tsup", 18 | "slice": "tsx scripts/slice.ts", 19 | "docs": "typedoc src" 20 | }, 21 | "devDependencies": { 22 | "prettier": "^3.0.3", 23 | "tsup": "^7.2.0", 24 | "tsx": "^3.13.0", 25 | "typedoc": "^0.25.1", 26 | "typescript": "^5.2.2", 27 | "zod": "^3.22.2" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-db/scripts/slice.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs"; 2 | 3 | const data: Record> = JSON.parse( 4 | fs.readFileSync("data.json", "utf-8"), 5 | ); 6 | 7 | const dir = "data"; 8 | if (!fs.existsSync(dir)) { 9 | fs.mkdirSync(dir); 10 | } 11 | 12 | for (const [key, value] of Object.entries(data)) { 13 | fs.writeFileSync(`${dir}/${key}.json`, JSON.stringify(value)); 14 | } 15 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-db/scripts/validate.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs"; 2 | import prettier from "prettier"; 3 | import { z } from "zod"; 4 | 5 | const schema = z.record(z.string().regex(/^\d+$/), z.record(z.tuple([z.number(), z.number()]))); 6 | 7 | const data = JSON.parse(fs.readFileSync("data.json", "utf-8")); 8 | 9 | schema.parse(data); 10 | 11 | prettier.format(JSON.stringify(data), { parser: "json", tabWidth: 4 }).then((formatted) => { 12 | fs.writeFileSync("data.json", formatted); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-db/src/index.ts: -------------------------------------------------------------------------------- 1 | import json from "../data.json"; 2 | 3 | export const data = json; 4 | export default json; 5 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-db/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig((options) => ({ 4 | entry: ["src/index.ts"], 5 | outDir: "lib", 6 | target: "node16", 7 | format: ["cjs", "esm"], 8 | shims: true, 9 | clean: true, 10 | splitting: false, 11 | dts: true, 12 | minify: !options.watch, 13 | })); 14 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chrome-extension-svelte-typescript-boilerplate", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "chrome-extension-svelte-typescript-boilerplate", 9 | "version": "1.0.0", 10 | "devDependencies": { 11 | "@crxjs/vite-plugin": "2.0.0-beta.18", 12 | "@sveltejs/vite-plugin-svelte": "2.4.5", 13 | "@tsconfig/svelte": "5.0.2", 14 | "@types/chrome": "0.0.243", 15 | "svelte": "4.2.0", 16 | "svelte-check": "3.5.0", 17 | "svelte-preprocess": "5.0.4", 18 | "tslib": "2.6.2", 19 | "typescript": "5.2.2", 20 | "vite": "4.2.3" 21 | } 22 | }, 23 | "node_modules/@ampproject/remapping": { 24 | "version": "2.2.1", 25 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", 26 | "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", 27 | "dev": true, 28 | "dependencies": { 29 | "@jridgewell/gen-mapping": "^0.3.0", 30 | "@jridgewell/trace-mapping": "^0.3.9" 31 | }, 32 | "engines": { 33 | "node": ">=6.0.0" 34 | } 35 | }, 36 | "node_modules/@crxjs/vite-plugin": { 37 | "version": "2.0.0-beta.18", 38 | "resolved": "https://registry.npmjs.org/@crxjs/vite-plugin/-/vite-plugin-2.0.0-beta.18.tgz", 39 | "integrity": "sha512-3jW20cUE04wTTg8HtoQD7bIL4Nhu91pRX4PHazMu2/tzzSTaR4stW5DHRIJOjFuRpOSCNNpyamyXwxS6qOv7Bg==", 40 | "dev": true, 41 | "dependencies": { 42 | "@rollup/pluginutils": "^4.1.2", 43 | "@webcomponents/custom-elements": "^1.5.0", 44 | "acorn-walk": "^8.2.0", 45 | "cheerio": "^1.0.0-rc.10", 46 | "connect-injector": "^0.4.4", 47 | "convert-source-map": "^1.7.0", 48 | "debug": "^4.3.3", 49 | "es-module-lexer": "^0.10.0", 50 | "fast-glob": "^3.2.11", 51 | "fs-extra": "^10.0.1", 52 | "jsesc": "^3.0.2", 53 | "magic-string": "^0.26.0", 54 | "picocolors": "^1.0.0", 55 | "react-refresh": "^0.13.0", 56 | "rollup": "2.78.1", 57 | "rxjs": "7.5.7" 58 | } 59 | }, 60 | "node_modules/@esbuild/android-arm": { 61 | "version": "0.17.19", 62 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", 63 | "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", 64 | "cpu": [ 65 | "arm" 66 | ], 67 | "dev": true, 68 | "optional": true, 69 | "os": [ 70 | "android" 71 | ], 72 | "engines": { 73 | "node": ">=12" 74 | } 75 | }, 76 | "node_modules/@esbuild/android-arm64": { 77 | "version": "0.17.19", 78 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", 79 | "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", 80 | "cpu": [ 81 | "arm64" 82 | ], 83 | "dev": true, 84 | "optional": true, 85 | "os": [ 86 | "android" 87 | ], 88 | "engines": { 89 | "node": ">=12" 90 | } 91 | }, 92 | "node_modules/@esbuild/android-x64": { 93 | "version": "0.17.19", 94 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", 95 | "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", 96 | "cpu": [ 97 | "x64" 98 | ], 99 | "dev": true, 100 | "optional": true, 101 | "os": [ 102 | "android" 103 | ], 104 | "engines": { 105 | "node": ">=12" 106 | } 107 | }, 108 | "node_modules/@esbuild/darwin-arm64": { 109 | "version": "0.17.19", 110 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", 111 | "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", 112 | "cpu": [ 113 | "arm64" 114 | ], 115 | "dev": true, 116 | "optional": true, 117 | "os": [ 118 | "darwin" 119 | ], 120 | "engines": { 121 | "node": ">=12" 122 | } 123 | }, 124 | "node_modules/@esbuild/darwin-x64": { 125 | "version": "0.17.19", 126 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", 127 | "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", 128 | "cpu": [ 129 | "x64" 130 | ], 131 | "dev": true, 132 | "optional": true, 133 | "os": [ 134 | "darwin" 135 | ], 136 | "engines": { 137 | "node": ">=12" 138 | } 139 | }, 140 | "node_modules/@esbuild/freebsd-arm64": { 141 | "version": "0.17.19", 142 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", 143 | "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", 144 | "cpu": [ 145 | "arm64" 146 | ], 147 | "dev": true, 148 | "optional": true, 149 | "os": [ 150 | "freebsd" 151 | ], 152 | "engines": { 153 | "node": ">=12" 154 | } 155 | }, 156 | "node_modules/@esbuild/freebsd-x64": { 157 | "version": "0.17.19", 158 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", 159 | "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", 160 | "cpu": [ 161 | "x64" 162 | ], 163 | "dev": true, 164 | "optional": true, 165 | "os": [ 166 | "freebsd" 167 | ], 168 | "engines": { 169 | "node": ">=12" 170 | } 171 | }, 172 | "node_modules/@esbuild/linux-arm": { 173 | "version": "0.17.19", 174 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", 175 | "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", 176 | "cpu": [ 177 | "arm" 178 | ], 179 | "dev": true, 180 | "optional": true, 181 | "os": [ 182 | "linux" 183 | ], 184 | "engines": { 185 | "node": ">=12" 186 | } 187 | }, 188 | "node_modules/@esbuild/linux-arm64": { 189 | "version": "0.17.19", 190 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", 191 | "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", 192 | "cpu": [ 193 | "arm64" 194 | ], 195 | "dev": true, 196 | "optional": true, 197 | "os": [ 198 | "linux" 199 | ], 200 | "engines": { 201 | "node": ">=12" 202 | } 203 | }, 204 | "node_modules/@esbuild/linux-ia32": { 205 | "version": "0.17.19", 206 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", 207 | "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", 208 | "cpu": [ 209 | "ia32" 210 | ], 211 | "dev": true, 212 | "optional": true, 213 | "os": [ 214 | "linux" 215 | ], 216 | "engines": { 217 | "node": ">=12" 218 | } 219 | }, 220 | "node_modules/@esbuild/linux-loong64": { 221 | "version": "0.17.19", 222 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", 223 | "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", 224 | "cpu": [ 225 | "loong64" 226 | ], 227 | "dev": true, 228 | "optional": true, 229 | "os": [ 230 | "linux" 231 | ], 232 | "engines": { 233 | "node": ">=12" 234 | } 235 | }, 236 | "node_modules/@esbuild/linux-mips64el": { 237 | "version": "0.17.19", 238 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", 239 | "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", 240 | "cpu": [ 241 | "mips64el" 242 | ], 243 | "dev": true, 244 | "optional": true, 245 | "os": [ 246 | "linux" 247 | ], 248 | "engines": { 249 | "node": ">=12" 250 | } 251 | }, 252 | "node_modules/@esbuild/linux-ppc64": { 253 | "version": "0.17.19", 254 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", 255 | "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", 256 | "cpu": [ 257 | "ppc64" 258 | ], 259 | "dev": true, 260 | "optional": true, 261 | "os": [ 262 | "linux" 263 | ], 264 | "engines": { 265 | "node": ">=12" 266 | } 267 | }, 268 | "node_modules/@esbuild/linux-riscv64": { 269 | "version": "0.17.19", 270 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", 271 | "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", 272 | "cpu": [ 273 | "riscv64" 274 | ], 275 | "dev": true, 276 | "optional": true, 277 | "os": [ 278 | "linux" 279 | ], 280 | "engines": { 281 | "node": ">=12" 282 | } 283 | }, 284 | "node_modules/@esbuild/linux-s390x": { 285 | "version": "0.17.19", 286 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", 287 | "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", 288 | "cpu": [ 289 | "s390x" 290 | ], 291 | "dev": true, 292 | "optional": true, 293 | "os": [ 294 | "linux" 295 | ], 296 | "engines": { 297 | "node": ">=12" 298 | } 299 | }, 300 | "node_modules/@esbuild/linux-x64": { 301 | "version": "0.17.19", 302 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", 303 | "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", 304 | "cpu": [ 305 | "x64" 306 | ], 307 | "dev": true, 308 | "optional": true, 309 | "os": [ 310 | "linux" 311 | ], 312 | "engines": { 313 | "node": ">=12" 314 | } 315 | }, 316 | "node_modules/@esbuild/netbsd-x64": { 317 | "version": "0.17.19", 318 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", 319 | "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", 320 | "cpu": [ 321 | "x64" 322 | ], 323 | "dev": true, 324 | "optional": true, 325 | "os": [ 326 | "netbsd" 327 | ], 328 | "engines": { 329 | "node": ">=12" 330 | } 331 | }, 332 | "node_modules/@esbuild/openbsd-x64": { 333 | "version": "0.17.19", 334 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", 335 | "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", 336 | "cpu": [ 337 | "x64" 338 | ], 339 | "dev": true, 340 | "optional": true, 341 | "os": [ 342 | "openbsd" 343 | ], 344 | "engines": { 345 | "node": ">=12" 346 | } 347 | }, 348 | "node_modules/@esbuild/sunos-x64": { 349 | "version": "0.17.19", 350 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", 351 | "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", 352 | "cpu": [ 353 | "x64" 354 | ], 355 | "dev": true, 356 | "optional": true, 357 | "os": [ 358 | "sunos" 359 | ], 360 | "engines": { 361 | "node": ">=12" 362 | } 363 | }, 364 | "node_modules/@esbuild/win32-arm64": { 365 | "version": "0.17.19", 366 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", 367 | "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", 368 | "cpu": [ 369 | "arm64" 370 | ], 371 | "dev": true, 372 | "optional": true, 373 | "os": [ 374 | "win32" 375 | ], 376 | "engines": { 377 | "node": ">=12" 378 | } 379 | }, 380 | "node_modules/@esbuild/win32-ia32": { 381 | "version": "0.17.19", 382 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", 383 | "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", 384 | "cpu": [ 385 | "ia32" 386 | ], 387 | "dev": true, 388 | "optional": true, 389 | "os": [ 390 | "win32" 391 | ], 392 | "engines": { 393 | "node": ">=12" 394 | } 395 | }, 396 | "node_modules/@esbuild/win32-x64": { 397 | "version": "0.17.19", 398 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", 399 | "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", 400 | "cpu": [ 401 | "x64" 402 | ], 403 | "dev": true, 404 | "optional": true, 405 | "os": [ 406 | "win32" 407 | ], 408 | "engines": { 409 | "node": ">=12" 410 | } 411 | }, 412 | "node_modules/@jridgewell/gen-mapping": { 413 | "version": "0.3.3", 414 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 415 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 416 | "dev": true, 417 | "dependencies": { 418 | "@jridgewell/set-array": "^1.0.1", 419 | "@jridgewell/sourcemap-codec": "^1.4.10", 420 | "@jridgewell/trace-mapping": "^0.3.9" 421 | }, 422 | "engines": { 423 | "node": ">=6.0.0" 424 | } 425 | }, 426 | "node_modules/@jridgewell/resolve-uri": { 427 | "version": "3.1.1", 428 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 429 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 430 | "dev": true, 431 | "engines": { 432 | "node": ">=6.0.0" 433 | } 434 | }, 435 | "node_modules/@jridgewell/set-array": { 436 | "version": "1.1.2", 437 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 438 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 439 | "dev": true, 440 | "engines": { 441 | "node": ">=6.0.0" 442 | } 443 | }, 444 | "node_modules/@jridgewell/sourcemap-codec": { 445 | "version": "1.4.15", 446 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 447 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 448 | "dev": true 449 | }, 450 | "node_modules/@jridgewell/trace-mapping": { 451 | "version": "0.3.19", 452 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", 453 | "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", 454 | "dev": true, 455 | "dependencies": { 456 | "@jridgewell/resolve-uri": "^3.1.0", 457 | "@jridgewell/sourcemap-codec": "^1.4.14" 458 | } 459 | }, 460 | "node_modules/@nodelib/fs.scandir": { 461 | "version": "2.1.5", 462 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 463 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 464 | "dev": true, 465 | "dependencies": { 466 | "@nodelib/fs.stat": "2.0.5", 467 | "run-parallel": "^1.1.9" 468 | }, 469 | "engines": { 470 | "node": ">= 8" 471 | } 472 | }, 473 | "node_modules/@nodelib/fs.stat": { 474 | "version": "2.0.5", 475 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 476 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 477 | "dev": true, 478 | "engines": { 479 | "node": ">= 8" 480 | } 481 | }, 482 | "node_modules/@nodelib/fs.walk": { 483 | "version": "1.2.8", 484 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 485 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 486 | "dev": true, 487 | "dependencies": { 488 | "@nodelib/fs.scandir": "2.1.5", 489 | "fastq": "^1.6.0" 490 | }, 491 | "engines": { 492 | "node": ">= 8" 493 | } 494 | }, 495 | "node_modules/@rollup/pluginutils": { 496 | "version": "4.2.1", 497 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 498 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 499 | "dev": true, 500 | "dependencies": { 501 | "estree-walker": "^2.0.1", 502 | "picomatch": "^2.2.2" 503 | }, 504 | "engines": { 505 | "node": ">= 8.0.0" 506 | } 507 | }, 508 | "node_modules/@sveltejs/vite-plugin-svelte": { 509 | "version": "2.4.5", 510 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.5.tgz", 511 | "integrity": "sha512-UJKsFNwhzCVuiZd06jM/psscyNJNDwjQC+qIeb7GBJK9iWeQCcIyfcPWDvbCudfcJggY9jtxJeeaZH7uny93FQ==", 512 | "dev": true, 513 | "dependencies": { 514 | "@sveltejs/vite-plugin-svelte-inspector": "^1.0.3", 515 | "debug": "^4.3.4", 516 | "deepmerge": "^4.3.1", 517 | "kleur": "^4.1.5", 518 | "magic-string": "^0.30.2", 519 | "svelte-hmr": "^0.15.3", 520 | "vitefu": "^0.2.4" 521 | }, 522 | "engines": { 523 | "node": "^14.18.0 || >= 16" 524 | }, 525 | "peerDependencies": { 526 | "svelte": "^3.54.0 || ^4.0.0", 527 | "vite": "^4.0.0" 528 | } 529 | }, 530 | "node_modules/@sveltejs/vite-plugin-svelte-inspector": { 531 | "version": "1.0.4", 532 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.4.tgz", 533 | "integrity": "sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==", 534 | "dev": true, 535 | "dependencies": { 536 | "debug": "^4.3.4" 537 | }, 538 | "engines": { 539 | "node": "^14.18.0 || >= 16" 540 | }, 541 | "peerDependencies": { 542 | "@sveltejs/vite-plugin-svelte": "^2.2.0", 543 | "svelte": "^3.54.0 || ^4.0.0", 544 | "vite": "^4.0.0" 545 | } 546 | }, 547 | "node_modules/@sveltejs/vite-plugin-svelte/node_modules/magic-string": { 548 | "version": "0.30.3", 549 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz", 550 | "integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==", 551 | "dev": true, 552 | "dependencies": { 553 | "@jridgewell/sourcemap-codec": "^1.4.15" 554 | }, 555 | "engines": { 556 | "node": ">=12" 557 | } 558 | }, 559 | "node_modules/@tsconfig/svelte": { 560 | "version": "5.0.2", 561 | "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.2.tgz", 562 | "integrity": "sha512-BRbo1fOtyVbhfLyuCWw6wAWp+U8UQle+ZXu84MYYWzYSEB28dyfnRBIE99eoG+qdAC0po6L2ScIEivcT07UaMA==", 563 | "dev": true 564 | }, 565 | "node_modules/@types/chrome": { 566 | "version": "0.0.243", 567 | "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.243.tgz", 568 | "integrity": "sha512-4PHv0kxxxpZFHWPBiJJ9TWH8kbx0567j1b2djnhpJjpiSGNI7UKkz7dSEECBtQ0B3N5nQTMwSB/5IopkWGAbEA==", 569 | "dev": true, 570 | "dependencies": { 571 | "@types/filesystem": "*", 572 | "@types/har-format": "*" 573 | } 574 | }, 575 | "node_modules/@types/estree": { 576 | "version": "1.0.1", 577 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", 578 | "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", 579 | "dev": true 580 | }, 581 | "node_modules/@types/filesystem": { 582 | "version": "0.0.32", 583 | "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.32.tgz", 584 | "integrity": "sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ==", 585 | "dev": true, 586 | "dependencies": { 587 | "@types/filewriter": "*" 588 | } 589 | }, 590 | "node_modules/@types/filewriter": { 591 | "version": "0.0.29", 592 | "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.29.tgz", 593 | "integrity": "sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ==", 594 | "dev": true 595 | }, 596 | "node_modules/@types/har-format": { 597 | "version": "1.2.12", 598 | "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.12.tgz", 599 | "integrity": "sha512-P20p/YBrqUBmzD6KhIQ8EiY4/RRzlekL4eCvfQnulFPfjmiGxKIoyCeI7qam5I7oKH3P8EU4ptEi0EfyGoLysw==", 600 | "dev": true 601 | }, 602 | "node_modules/@types/pug": { 603 | "version": "2.0.6", 604 | "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz", 605 | "integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==", 606 | "dev": true 607 | }, 608 | "node_modules/@webcomponents/custom-elements": { 609 | "version": "1.6.0", 610 | "resolved": "https://registry.npmjs.org/@webcomponents/custom-elements/-/custom-elements-1.6.0.tgz", 611 | "integrity": "sha512-CqTpxOlUCPWRNUPZDxT5v2NnHXA4oox612iUGnmTUGQFhZ1Gkj8kirtl/2wcF6MqX7+PqqicZzOCBKKfIn0dww==", 612 | "dev": true 613 | }, 614 | "node_modules/acorn": { 615 | "version": "8.10.0", 616 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", 617 | "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", 618 | "dev": true, 619 | "bin": { 620 | "acorn": "bin/acorn" 621 | }, 622 | "engines": { 623 | "node": ">=0.4.0" 624 | } 625 | }, 626 | "node_modules/acorn-walk": { 627 | "version": "8.2.0", 628 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 629 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 630 | "dev": true, 631 | "engines": { 632 | "node": ">=0.4.0" 633 | } 634 | }, 635 | "node_modules/anymatch": { 636 | "version": "3.1.3", 637 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 638 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 639 | "dev": true, 640 | "dependencies": { 641 | "normalize-path": "^3.0.0", 642 | "picomatch": "^2.0.4" 643 | }, 644 | "engines": { 645 | "node": ">= 8" 646 | } 647 | }, 648 | "node_modules/aria-query": { 649 | "version": "5.3.0", 650 | "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", 651 | "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", 652 | "dev": true, 653 | "dependencies": { 654 | "dequal": "^2.0.3" 655 | } 656 | }, 657 | "node_modules/axobject-query": { 658 | "version": "3.2.1", 659 | "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", 660 | "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", 661 | "dev": true, 662 | "dependencies": { 663 | "dequal": "^2.0.3" 664 | } 665 | }, 666 | "node_modules/balanced-match": { 667 | "version": "1.0.2", 668 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 669 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 670 | "dev": true 671 | }, 672 | "node_modules/binary-extensions": { 673 | "version": "2.2.0", 674 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 675 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 676 | "dev": true, 677 | "engines": { 678 | "node": ">=8" 679 | } 680 | }, 681 | "node_modules/boolbase": { 682 | "version": "1.0.0", 683 | "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", 684 | "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", 685 | "dev": true 686 | }, 687 | "node_modules/brace-expansion": { 688 | "version": "1.1.11", 689 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 690 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 691 | "dev": true, 692 | "dependencies": { 693 | "balanced-match": "^1.0.0", 694 | "concat-map": "0.0.1" 695 | } 696 | }, 697 | "node_modules/braces": { 698 | "version": "3.0.2", 699 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 700 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 701 | "dev": true, 702 | "dependencies": { 703 | "fill-range": "^7.0.1" 704 | }, 705 | "engines": { 706 | "node": ">=8" 707 | } 708 | }, 709 | "node_modules/buffer-crc32": { 710 | "version": "0.2.13", 711 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 712 | "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", 713 | "dev": true, 714 | "engines": { 715 | "node": "*" 716 | } 717 | }, 718 | "node_modules/callsites": { 719 | "version": "3.1.0", 720 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 721 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 722 | "dev": true, 723 | "engines": { 724 | "node": ">=6" 725 | } 726 | }, 727 | "node_modules/cheerio": { 728 | "version": "1.0.0-rc.12", 729 | "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", 730 | "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", 731 | "dev": true, 732 | "dependencies": { 733 | "cheerio-select": "^2.1.0", 734 | "dom-serializer": "^2.0.0", 735 | "domhandler": "^5.0.3", 736 | "domutils": "^3.0.1", 737 | "htmlparser2": "^8.0.1", 738 | "parse5": "^7.0.0", 739 | "parse5-htmlparser2-tree-adapter": "^7.0.0" 740 | }, 741 | "engines": { 742 | "node": ">= 6" 743 | }, 744 | "funding": { 745 | "url": "https://github.com/cheeriojs/cheerio?sponsor=1" 746 | } 747 | }, 748 | "node_modules/cheerio-select": { 749 | "version": "2.1.0", 750 | "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", 751 | "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", 752 | "dev": true, 753 | "dependencies": { 754 | "boolbase": "^1.0.0", 755 | "css-select": "^5.1.0", 756 | "css-what": "^6.1.0", 757 | "domelementtype": "^2.3.0", 758 | "domhandler": "^5.0.3", 759 | "domutils": "^3.0.1" 760 | }, 761 | "funding": { 762 | "url": "https://github.com/sponsors/fb55" 763 | } 764 | }, 765 | "node_modules/chokidar": { 766 | "version": "3.5.3", 767 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 768 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 769 | "dev": true, 770 | "funding": [ 771 | { 772 | "type": "individual", 773 | "url": "https://paulmillr.com/funding/" 774 | } 775 | ], 776 | "dependencies": { 777 | "anymatch": "~3.1.2", 778 | "braces": "~3.0.2", 779 | "glob-parent": "~5.1.2", 780 | "is-binary-path": "~2.1.0", 781 | "is-glob": "~4.0.1", 782 | "normalize-path": "~3.0.0", 783 | "readdirp": "~3.6.0" 784 | }, 785 | "engines": { 786 | "node": ">= 8.10.0" 787 | }, 788 | "optionalDependencies": { 789 | "fsevents": "~2.3.2" 790 | } 791 | }, 792 | "node_modules/code-red": { 793 | "version": "1.0.4", 794 | "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", 795 | "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", 796 | "dev": true, 797 | "dependencies": { 798 | "@jridgewell/sourcemap-codec": "^1.4.15", 799 | "@types/estree": "^1.0.1", 800 | "acorn": "^8.10.0", 801 | "estree-walker": "^3.0.3", 802 | "periscopic": "^3.1.0" 803 | } 804 | }, 805 | "node_modules/code-red/node_modules/estree-walker": { 806 | "version": "3.0.3", 807 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", 808 | "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", 809 | "dev": true, 810 | "dependencies": { 811 | "@types/estree": "^1.0.0" 812 | } 813 | }, 814 | "node_modules/concat-map": { 815 | "version": "0.0.1", 816 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 817 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 818 | "dev": true 819 | }, 820 | "node_modules/connect-injector": { 821 | "version": "0.4.4", 822 | "resolved": "https://registry.npmjs.org/connect-injector/-/connect-injector-0.4.4.tgz", 823 | "integrity": "sha512-hdBG8nXop42y2gWCqOV8y1O3uVk4cIU+SoxLCPyCUKRImyPiScoNiSulpHjoktRU1BdI0UzoUdxUa87thrcmHw==", 824 | "dev": true, 825 | "dependencies": { 826 | "debug": "^2.0.0", 827 | "q": "^1.0.1", 828 | "stream-buffers": "^0.2.3", 829 | "uberproto": "^1.1.0" 830 | }, 831 | "engines": { 832 | "node": ">= 0.8.0" 833 | } 834 | }, 835 | "node_modules/connect-injector/node_modules/debug": { 836 | "version": "2.6.9", 837 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 838 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 839 | "dev": true, 840 | "dependencies": { 841 | "ms": "2.0.0" 842 | } 843 | }, 844 | "node_modules/connect-injector/node_modules/ms": { 845 | "version": "2.0.0", 846 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 847 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 848 | "dev": true 849 | }, 850 | "node_modules/convert-source-map": { 851 | "version": "1.9.0", 852 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", 853 | "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", 854 | "dev": true 855 | }, 856 | "node_modules/css-select": { 857 | "version": "5.1.0", 858 | "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", 859 | "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", 860 | "dev": true, 861 | "dependencies": { 862 | "boolbase": "^1.0.0", 863 | "css-what": "^6.1.0", 864 | "domhandler": "^5.0.2", 865 | "domutils": "^3.0.1", 866 | "nth-check": "^2.0.1" 867 | }, 868 | "funding": { 869 | "url": "https://github.com/sponsors/fb55" 870 | } 871 | }, 872 | "node_modules/css-tree": { 873 | "version": "2.3.1", 874 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", 875 | "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", 876 | "dev": true, 877 | "dependencies": { 878 | "mdn-data": "2.0.30", 879 | "source-map-js": "^1.0.1" 880 | }, 881 | "engines": { 882 | "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" 883 | } 884 | }, 885 | "node_modules/css-what": { 886 | "version": "6.1.0", 887 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", 888 | "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", 889 | "dev": true, 890 | "engines": { 891 | "node": ">= 6" 892 | }, 893 | "funding": { 894 | "url": "https://github.com/sponsors/fb55" 895 | } 896 | }, 897 | "node_modules/debug": { 898 | "version": "4.3.4", 899 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 900 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 901 | "dev": true, 902 | "dependencies": { 903 | "ms": "2.1.2" 904 | }, 905 | "engines": { 906 | "node": ">=6.0" 907 | }, 908 | "peerDependenciesMeta": { 909 | "supports-color": { 910 | "optional": true 911 | } 912 | } 913 | }, 914 | "node_modules/deepmerge": { 915 | "version": "4.3.1", 916 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", 917 | "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", 918 | "dev": true, 919 | "engines": { 920 | "node": ">=0.10.0" 921 | } 922 | }, 923 | "node_modules/dequal": { 924 | "version": "2.0.3", 925 | "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", 926 | "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", 927 | "dev": true, 928 | "engines": { 929 | "node": ">=6" 930 | } 931 | }, 932 | "node_modules/detect-indent": { 933 | "version": "6.1.0", 934 | "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", 935 | "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", 936 | "dev": true, 937 | "engines": { 938 | "node": ">=8" 939 | } 940 | }, 941 | "node_modules/dom-serializer": { 942 | "version": "2.0.0", 943 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", 944 | "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", 945 | "dev": true, 946 | "dependencies": { 947 | "domelementtype": "^2.3.0", 948 | "domhandler": "^5.0.2", 949 | "entities": "^4.2.0" 950 | }, 951 | "funding": { 952 | "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" 953 | } 954 | }, 955 | "node_modules/domelementtype": { 956 | "version": "2.3.0", 957 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", 958 | "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", 959 | "dev": true, 960 | "funding": [ 961 | { 962 | "type": "github", 963 | "url": "https://github.com/sponsors/fb55" 964 | } 965 | ] 966 | }, 967 | "node_modules/domhandler": { 968 | "version": "5.0.3", 969 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", 970 | "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", 971 | "dev": true, 972 | "dependencies": { 973 | "domelementtype": "^2.3.0" 974 | }, 975 | "engines": { 976 | "node": ">= 4" 977 | }, 978 | "funding": { 979 | "url": "https://github.com/fb55/domhandler?sponsor=1" 980 | } 981 | }, 982 | "node_modules/domutils": { 983 | "version": "3.1.0", 984 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", 985 | "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", 986 | "dev": true, 987 | "dependencies": { 988 | "dom-serializer": "^2.0.0", 989 | "domelementtype": "^2.3.0", 990 | "domhandler": "^5.0.3" 991 | }, 992 | "funding": { 993 | "url": "https://github.com/fb55/domutils?sponsor=1" 994 | } 995 | }, 996 | "node_modules/entities": { 997 | "version": "4.5.0", 998 | "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", 999 | "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", 1000 | "dev": true, 1001 | "engines": { 1002 | "node": ">=0.12" 1003 | }, 1004 | "funding": { 1005 | "url": "https://github.com/fb55/entities?sponsor=1" 1006 | } 1007 | }, 1008 | "node_modules/es-module-lexer": { 1009 | "version": "0.10.5", 1010 | "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.10.5.tgz", 1011 | "integrity": "sha512-+7IwY/kiGAacQfY+YBhKMvEmyAJnw5grTUgjG85Pe7vcUI/6b7pZjZG8nQ7+48YhzEAEqrEgD2dCz/JIK+AYvw==", 1012 | "dev": true 1013 | }, 1014 | "node_modules/es6-promise": { 1015 | "version": "3.3.1", 1016 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", 1017 | "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", 1018 | "dev": true 1019 | }, 1020 | "node_modules/esbuild": { 1021 | "version": "0.17.19", 1022 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", 1023 | "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", 1024 | "dev": true, 1025 | "hasInstallScript": true, 1026 | "bin": { 1027 | "esbuild": "bin/esbuild" 1028 | }, 1029 | "engines": { 1030 | "node": ">=12" 1031 | }, 1032 | "optionalDependencies": { 1033 | "@esbuild/android-arm": "0.17.19", 1034 | "@esbuild/android-arm64": "0.17.19", 1035 | "@esbuild/android-x64": "0.17.19", 1036 | "@esbuild/darwin-arm64": "0.17.19", 1037 | "@esbuild/darwin-x64": "0.17.19", 1038 | "@esbuild/freebsd-arm64": "0.17.19", 1039 | "@esbuild/freebsd-x64": "0.17.19", 1040 | "@esbuild/linux-arm": "0.17.19", 1041 | "@esbuild/linux-arm64": "0.17.19", 1042 | "@esbuild/linux-ia32": "0.17.19", 1043 | "@esbuild/linux-loong64": "0.17.19", 1044 | "@esbuild/linux-mips64el": "0.17.19", 1045 | "@esbuild/linux-ppc64": "0.17.19", 1046 | "@esbuild/linux-riscv64": "0.17.19", 1047 | "@esbuild/linux-s390x": "0.17.19", 1048 | "@esbuild/linux-x64": "0.17.19", 1049 | "@esbuild/netbsd-x64": "0.17.19", 1050 | "@esbuild/openbsd-x64": "0.17.19", 1051 | "@esbuild/sunos-x64": "0.17.19", 1052 | "@esbuild/win32-arm64": "0.17.19", 1053 | "@esbuild/win32-ia32": "0.17.19", 1054 | "@esbuild/win32-x64": "0.17.19" 1055 | } 1056 | }, 1057 | "node_modules/estree-walker": { 1058 | "version": "2.0.2", 1059 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 1060 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 1061 | "dev": true 1062 | }, 1063 | "node_modules/fast-glob": { 1064 | "version": "3.3.1", 1065 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", 1066 | "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", 1067 | "dev": true, 1068 | "dependencies": { 1069 | "@nodelib/fs.stat": "^2.0.2", 1070 | "@nodelib/fs.walk": "^1.2.3", 1071 | "glob-parent": "^5.1.2", 1072 | "merge2": "^1.3.0", 1073 | "micromatch": "^4.0.4" 1074 | }, 1075 | "engines": { 1076 | "node": ">=8.6.0" 1077 | } 1078 | }, 1079 | "node_modules/fastq": { 1080 | "version": "1.15.0", 1081 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 1082 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 1083 | "dev": true, 1084 | "dependencies": { 1085 | "reusify": "^1.0.4" 1086 | } 1087 | }, 1088 | "node_modules/fill-range": { 1089 | "version": "7.0.1", 1090 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1091 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1092 | "dev": true, 1093 | "dependencies": { 1094 | "to-regex-range": "^5.0.1" 1095 | }, 1096 | "engines": { 1097 | "node": ">=8" 1098 | } 1099 | }, 1100 | "node_modules/fs-extra": { 1101 | "version": "10.1.0", 1102 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", 1103 | "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", 1104 | "dev": true, 1105 | "dependencies": { 1106 | "graceful-fs": "^4.2.0", 1107 | "jsonfile": "^6.0.1", 1108 | "universalify": "^2.0.0" 1109 | }, 1110 | "engines": { 1111 | "node": ">=12" 1112 | } 1113 | }, 1114 | "node_modules/fs.realpath": { 1115 | "version": "1.0.0", 1116 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1117 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 1118 | "dev": true 1119 | }, 1120 | "node_modules/fsevents": { 1121 | "version": "2.3.3", 1122 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1123 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1124 | "dev": true, 1125 | "hasInstallScript": true, 1126 | "optional": true, 1127 | "os": [ 1128 | "darwin" 1129 | ], 1130 | "engines": { 1131 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1132 | } 1133 | }, 1134 | "node_modules/function-bind": { 1135 | "version": "1.1.1", 1136 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1137 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 1138 | "dev": true 1139 | }, 1140 | "node_modules/glob": { 1141 | "version": "7.2.3", 1142 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 1143 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 1144 | "dev": true, 1145 | "dependencies": { 1146 | "fs.realpath": "^1.0.0", 1147 | "inflight": "^1.0.4", 1148 | "inherits": "2", 1149 | "minimatch": "^3.1.1", 1150 | "once": "^1.3.0", 1151 | "path-is-absolute": "^1.0.0" 1152 | }, 1153 | "engines": { 1154 | "node": "*" 1155 | }, 1156 | "funding": { 1157 | "url": "https://github.com/sponsors/isaacs" 1158 | } 1159 | }, 1160 | "node_modules/glob-parent": { 1161 | "version": "5.1.2", 1162 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1163 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1164 | "dev": true, 1165 | "dependencies": { 1166 | "is-glob": "^4.0.1" 1167 | }, 1168 | "engines": { 1169 | "node": ">= 6" 1170 | } 1171 | }, 1172 | "node_modules/graceful-fs": { 1173 | "version": "4.2.11", 1174 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 1175 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 1176 | "dev": true 1177 | }, 1178 | "node_modules/has": { 1179 | "version": "1.0.3", 1180 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1181 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1182 | "dev": true, 1183 | "dependencies": { 1184 | "function-bind": "^1.1.1" 1185 | }, 1186 | "engines": { 1187 | "node": ">= 0.4.0" 1188 | } 1189 | }, 1190 | "node_modules/htmlparser2": { 1191 | "version": "8.0.2", 1192 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", 1193 | "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", 1194 | "dev": true, 1195 | "funding": [ 1196 | "https://github.com/fb55/htmlparser2?sponsor=1", 1197 | { 1198 | "type": "github", 1199 | "url": "https://github.com/sponsors/fb55" 1200 | } 1201 | ], 1202 | "dependencies": { 1203 | "domelementtype": "^2.3.0", 1204 | "domhandler": "^5.0.3", 1205 | "domutils": "^3.0.1", 1206 | "entities": "^4.4.0" 1207 | } 1208 | }, 1209 | "node_modules/import-fresh": { 1210 | "version": "3.3.0", 1211 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 1212 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 1213 | "dev": true, 1214 | "dependencies": { 1215 | "parent-module": "^1.0.0", 1216 | "resolve-from": "^4.0.0" 1217 | }, 1218 | "engines": { 1219 | "node": ">=6" 1220 | }, 1221 | "funding": { 1222 | "url": "https://github.com/sponsors/sindresorhus" 1223 | } 1224 | }, 1225 | "node_modules/inflight": { 1226 | "version": "1.0.6", 1227 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1228 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 1229 | "dev": true, 1230 | "dependencies": { 1231 | "once": "^1.3.0", 1232 | "wrappy": "1" 1233 | } 1234 | }, 1235 | "node_modules/inherits": { 1236 | "version": "2.0.4", 1237 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1238 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1239 | "dev": true 1240 | }, 1241 | "node_modules/is-binary-path": { 1242 | "version": "2.1.0", 1243 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1244 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1245 | "dev": true, 1246 | "dependencies": { 1247 | "binary-extensions": "^2.0.0" 1248 | }, 1249 | "engines": { 1250 | "node": ">=8" 1251 | } 1252 | }, 1253 | "node_modules/is-core-module": { 1254 | "version": "2.13.0", 1255 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", 1256 | "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", 1257 | "dev": true, 1258 | "dependencies": { 1259 | "has": "^1.0.3" 1260 | }, 1261 | "funding": { 1262 | "url": "https://github.com/sponsors/ljharb" 1263 | } 1264 | }, 1265 | "node_modules/is-extglob": { 1266 | "version": "2.1.1", 1267 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1268 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1269 | "dev": true, 1270 | "engines": { 1271 | "node": ">=0.10.0" 1272 | } 1273 | }, 1274 | "node_modules/is-glob": { 1275 | "version": "4.0.3", 1276 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1277 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1278 | "dev": true, 1279 | "dependencies": { 1280 | "is-extglob": "^2.1.1" 1281 | }, 1282 | "engines": { 1283 | "node": ">=0.10.0" 1284 | } 1285 | }, 1286 | "node_modules/is-number": { 1287 | "version": "7.0.0", 1288 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1289 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1290 | "dev": true, 1291 | "engines": { 1292 | "node": ">=0.12.0" 1293 | } 1294 | }, 1295 | "node_modules/is-reference": { 1296 | "version": "3.0.1", 1297 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.1.tgz", 1298 | "integrity": "sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==", 1299 | "dev": true, 1300 | "dependencies": { 1301 | "@types/estree": "*" 1302 | } 1303 | }, 1304 | "node_modules/jsesc": { 1305 | "version": "3.0.2", 1306 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", 1307 | "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", 1308 | "dev": true, 1309 | "bin": { 1310 | "jsesc": "bin/jsesc" 1311 | }, 1312 | "engines": { 1313 | "node": ">=6" 1314 | } 1315 | }, 1316 | "node_modules/jsonfile": { 1317 | "version": "6.1.0", 1318 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 1319 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 1320 | "dev": true, 1321 | "dependencies": { 1322 | "universalify": "^2.0.0" 1323 | }, 1324 | "optionalDependencies": { 1325 | "graceful-fs": "^4.1.6" 1326 | } 1327 | }, 1328 | "node_modules/kleur": { 1329 | "version": "4.1.5", 1330 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", 1331 | "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", 1332 | "dev": true, 1333 | "engines": { 1334 | "node": ">=6" 1335 | } 1336 | }, 1337 | "node_modules/locate-character": { 1338 | "version": "3.0.0", 1339 | "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", 1340 | "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", 1341 | "dev": true 1342 | }, 1343 | "node_modules/magic-string": { 1344 | "version": "0.26.7", 1345 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", 1346 | "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", 1347 | "dev": true, 1348 | "dependencies": { 1349 | "sourcemap-codec": "^1.4.8" 1350 | }, 1351 | "engines": { 1352 | "node": ">=12" 1353 | } 1354 | }, 1355 | "node_modules/mdn-data": { 1356 | "version": "2.0.30", 1357 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", 1358 | "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", 1359 | "dev": true 1360 | }, 1361 | "node_modules/merge2": { 1362 | "version": "1.4.1", 1363 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1364 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1365 | "dev": true, 1366 | "engines": { 1367 | "node": ">= 8" 1368 | } 1369 | }, 1370 | "node_modules/micromatch": { 1371 | "version": "4.0.5", 1372 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 1373 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 1374 | "dev": true, 1375 | "dependencies": { 1376 | "braces": "^3.0.2", 1377 | "picomatch": "^2.3.1" 1378 | }, 1379 | "engines": { 1380 | "node": ">=8.6" 1381 | } 1382 | }, 1383 | "node_modules/min-indent": { 1384 | "version": "1.0.1", 1385 | "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", 1386 | "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", 1387 | "dev": true, 1388 | "engines": { 1389 | "node": ">=4" 1390 | } 1391 | }, 1392 | "node_modules/minimatch": { 1393 | "version": "3.1.2", 1394 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1395 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1396 | "dev": true, 1397 | "dependencies": { 1398 | "brace-expansion": "^1.1.7" 1399 | }, 1400 | "engines": { 1401 | "node": "*" 1402 | } 1403 | }, 1404 | "node_modules/minimist": { 1405 | "version": "1.2.8", 1406 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 1407 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 1408 | "dev": true, 1409 | "funding": { 1410 | "url": "https://github.com/sponsors/ljharb" 1411 | } 1412 | }, 1413 | "node_modules/mkdirp": { 1414 | "version": "0.5.6", 1415 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", 1416 | "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", 1417 | "dev": true, 1418 | "dependencies": { 1419 | "minimist": "^1.2.6" 1420 | }, 1421 | "bin": { 1422 | "mkdirp": "bin/cmd.js" 1423 | } 1424 | }, 1425 | "node_modules/mri": { 1426 | "version": "1.2.0", 1427 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", 1428 | "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", 1429 | "dev": true, 1430 | "engines": { 1431 | "node": ">=4" 1432 | } 1433 | }, 1434 | "node_modules/ms": { 1435 | "version": "2.1.2", 1436 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1437 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1438 | "dev": true 1439 | }, 1440 | "node_modules/nanoid": { 1441 | "version": "3.3.6", 1442 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 1443 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", 1444 | "dev": true, 1445 | "funding": [ 1446 | { 1447 | "type": "github", 1448 | "url": "https://github.com/sponsors/ai" 1449 | } 1450 | ], 1451 | "bin": { 1452 | "nanoid": "bin/nanoid.cjs" 1453 | }, 1454 | "engines": { 1455 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1456 | } 1457 | }, 1458 | "node_modules/normalize-path": { 1459 | "version": "3.0.0", 1460 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1461 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1462 | "dev": true, 1463 | "engines": { 1464 | "node": ">=0.10.0" 1465 | } 1466 | }, 1467 | "node_modules/nth-check": { 1468 | "version": "2.1.1", 1469 | "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", 1470 | "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", 1471 | "dev": true, 1472 | "dependencies": { 1473 | "boolbase": "^1.0.0" 1474 | }, 1475 | "funding": { 1476 | "url": "https://github.com/fb55/nth-check?sponsor=1" 1477 | } 1478 | }, 1479 | "node_modules/once": { 1480 | "version": "1.4.0", 1481 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1482 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 1483 | "dev": true, 1484 | "dependencies": { 1485 | "wrappy": "1" 1486 | } 1487 | }, 1488 | "node_modules/parent-module": { 1489 | "version": "1.0.1", 1490 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1491 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1492 | "dev": true, 1493 | "dependencies": { 1494 | "callsites": "^3.0.0" 1495 | }, 1496 | "engines": { 1497 | "node": ">=6" 1498 | } 1499 | }, 1500 | "node_modules/parse5": { 1501 | "version": "7.1.2", 1502 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", 1503 | "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", 1504 | "dev": true, 1505 | "dependencies": { 1506 | "entities": "^4.4.0" 1507 | }, 1508 | "funding": { 1509 | "url": "https://github.com/inikulin/parse5?sponsor=1" 1510 | } 1511 | }, 1512 | "node_modules/parse5-htmlparser2-tree-adapter": { 1513 | "version": "7.0.0", 1514 | "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", 1515 | "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", 1516 | "dev": true, 1517 | "dependencies": { 1518 | "domhandler": "^5.0.2", 1519 | "parse5": "^7.0.0" 1520 | }, 1521 | "funding": { 1522 | "url": "https://github.com/inikulin/parse5?sponsor=1" 1523 | } 1524 | }, 1525 | "node_modules/path-is-absolute": { 1526 | "version": "1.0.1", 1527 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1528 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 1529 | "dev": true, 1530 | "engines": { 1531 | "node": ">=0.10.0" 1532 | } 1533 | }, 1534 | "node_modules/path-parse": { 1535 | "version": "1.0.7", 1536 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1537 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1538 | "dev": true 1539 | }, 1540 | "node_modules/periscopic": { 1541 | "version": "3.1.0", 1542 | "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", 1543 | "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", 1544 | "dev": true, 1545 | "dependencies": { 1546 | "@types/estree": "^1.0.0", 1547 | "estree-walker": "^3.0.0", 1548 | "is-reference": "^3.0.0" 1549 | } 1550 | }, 1551 | "node_modules/periscopic/node_modules/estree-walker": { 1552 | "version": "3.0.3", 1553 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", 1554 | "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", 1555 | "dev": true, 1556 | "dependencies": { 1557 | "@types/estree": "^1.0.0" 1558 | } 1559 | }, 1560 | "node_modules/picocolors": { 1561 | "version": "1.0.0", 1562 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 1563 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 1564 | "dev": true 1565 | }, 1566 | "node_modules/picomatch": { 1567 | "version": "2.3.1", 1568 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1569 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1570 | "dev": true, 1571 | "engines": { 1572 | "node": ">=8.6" 1573 | }, 1574 | "funding": { 1575 | "url": "https://github.com/sponsors/jonschlinkert" 1576 | } 1577 | }, 1578 | "node_modules/postcss": { 1579 | "version": "8.4.28", 1580 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", 1581 | "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", 1582 | "dev": true, 1583 | "funding": [ 1584 | { 1585 | "type": "opencollective", 1586 | "url": "https://opencollective.com/postcss/" 1587 | }, 1588 | { 1589 | "type": "tidelift", 1590 | "url": "https://tidelift.com/funding/github/npm/postcss" 1591 | }, 1592 | { 1593 | "type": "github", 1594 | "url": "https://github.com/sponsors/ai" 1595 | } 1596 | ], 1597 | "dependencies": { 1598 | "nanoid": "^3.3.6", 1599 | "picocolors": "^1.0.0", 1600 | "source-map-js": "^1.0.2" 1601 | }, 1602 | "engines": { 1603 | "node": "^10 || ^12 || >=14" 1604 | } 1605 | }, 1606 | "node_modules/q": { 1607 | "version": "1.5.1", 1608 | "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", 1609 | "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", 1610 | "dev": true, 1611 | "engines": { 1612 | "node": ">=0.6.0", 1613 | "teleport": ">=0.2.0" 1614 | } 1615 | }, 1616 | "node_modules/queue-microtask": { 1617 | "version": "1.2.3", 1618 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1619 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1620 | "dev": true, 1621 | "funding": [ 1622 | { 1623 | "type": "github", 1624 | "url": "https://github.com/sponsors/feross" 1625 | }, 1626 | { 1627 | "type": "patreon", 1628 | "url": "https://www.patreon.com/feross" 1629 | }, 1630 | { 1631 | "type": "consulting", 1632 | "url": "https://feross.org/support" 1633 | } 1634 | ] 1635 | }, 1636 | "node_modules/react-refresh": { 1637 | "version": "0.13.0", 1638 | "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.13.0.tgz", 1639 | "integrity": "sha512-XP8A9BT0CpRBD+NYLLeIhld/RqG9+gktUjW1FkE+Vm7OCinbG1SshcK5tb9ls4kzvjZr9mOQc7HYgBngEyPAXg==", 1640 | "dev": true, 1641 | "engines": { 1642 | "node": ">=0.10.0" 1643 | } 1644 | }, 1645 | "node_modules/readdirp": { 1646 | "version": "3.6.0", 1647 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1648 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1649 | "dev": true, 1650 | "dependencies": { 1651 | "picomatch": "^2.2.1" 1652 | }, 1653 | "engines": { 1654 | "node": ">=8.10.0" 1655 | } 1656 | }, 1657 | "node_modules/resolve": { 1658 | "version": "1.22.4", 1659 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", 1660 | "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", 1661 | "dev": true, 1662 | "dependencies": { 1663 | "is-core-module": "^2.13.0", 1664 | "path-parse": "^1.0.7", 1665 | "supports-preserve-symlinks-flag": "^1.0.0" 1666 | }, 1667 | "bin": { 1668 | "resolve": "bin/resolve" 1669 | }, 1670 | "funding": { 1671 | "url": "https://github.com/sponsors/ljharb" 1672 | } 1673 | }, 1674 | "node_modules/resolve-from": { 1675 | "version": "4.0.0", 1676 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1677 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1678 | "dev": true, 1679 | "engines": { 1680 | "node": ">=4" 1681 | } 1682 | }, 1683 | "node_modules/reusify": { 1684 | "version": "1.0.4", 1685 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1686 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1687 | "dev": true, 1688 | "engines": { 1689 | "iojs": ">=1.0.0", 1690 | "node": ">=0.10.0" 1691 | } 1692 | }, 1693 | "node_modules/rimraf": { 1694 | "version": "2.7.1", 1695 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 1696 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 1697 | "dev": true, 1698 | "dependencies": { 1699 | "glob": "^7.1.3" 1700 | }, 1701 | "bin": { 1702 | "rimraf": "bin.js" 1703 | } 1704 | }, 1705 | "node_modules/rollup": { 1706 | "version": "2.78.1", 1707 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz", 1708 | "integrity": "sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==", 1709 | "dev": true, 1710 | "bin": { 1711 | "rollup": "dist/bin/rollup" 1712 | }, 1713 | "engines": { 1714 | "node": ">=10.0.0" 1715 | }, 1716 | "optionalDependencies": { 1717 | "fsevents": "~2.3.2" 1718 | } 1719 | }, 1720 | "node_modules/run-parallel": { 1721 | "version": "1.2.0", 1722 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1723 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1724 | "dev": true, 1725 | "funding": [ 1726 | { 1727 | "type": "github", 1728 | "url": "https://github.com/sponsors/feross" 1729 | }, 1730 | { 1731 | "type": "patreon", 1732 | "url": "https://www.patreon.com/feross" 1733 | }, 1734 | { 1735 | "type": "consulting", 1736 | "url": "https://feross.org/support" 1737 | } 1738 | ], 1739 | "dependencies": { 1740 | "queue-microtask": "^1.2.2" 1741 | } 1742 | }, 1743 | "node_modules/rxjs": { 1744 | "version": "7.5.7", 1745 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", 1746 | "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", 1747 | "dev": true, 1748 | "dependencies": { 1749 | "tslib": "^2.1.0" 1750 | } 1751 | }, 1752 | "node_modules/sade": { 1753 | "version": "1.8.1", 1754 | "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", 1755 | "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", 1756 | "dev": true, 1757 | "dependencies": { 1758 | "mri": "^1.1.0" 1759 | }, 1760 | "engines": { 1761 | "node": ">=6" 1762 | } 1763 | }, 1764 | "node_modules/sander": { 1765 | "version": "0.5.1", 1766 | "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", 1767 | "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", 1768 | "dev": true, 1769 | "dependencies": { 1770 | "es6-promise": "^3.1.2", 1771 | "graceful-fs": "^4.1.3", 1772 | "mkdirp": "^0.5.1", 1773 | "rimraf": "^2.5.2" 1774 | } 1775 | }, 1776 | "node_modules/sorcery": { 1777 | "version": "0.11.0", 1778 | "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", 1779 | "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==", 1780 | "dev": true, 1781 | "dependencies": { 1782 | "@jridgewell/sourcemap-codec": "^1.4.14", 1783 | "buffer-crc32": "^0.2.5", 1784 | "minimist": "^1.2.0", 1785 | "sander": "^0.5.0" 1786 | }, 1787 | "bin": { 1788 | "sorcery": "bin/sorcery" 1789 | } 1790 | }, 1791 | "node_modules/source-map-js": { 1792 | "version": "1.0.2", 1793 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1794 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 1795 | "dev": true, 1796 | "engines": { 1797 | "node": ">=0.10.0" 1798 | } 1799 | }, 1800 | "node_modules/sourcemap-codec": { 1801 | "version": "1.4.8", 1802 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 1803 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 1804 | "deprecated": "Please use @jridgewell/sourcemap-codec instead", 1805 | "dev": true 1806 | }, 1807 | "node_modules/stream-buffers": { 1808 | "version": "0.2.6", 1809 | "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-0.2.6.tgz", 1810 | "integrity": "sha512-ZRpmWyuCdg0TtNKk8bEqvm13oQvXMmzXDsfD4cBgcx5LouborvU5pm3JMkdTP3HcszyUI08AM1dHMXA5r2g6Sg==", 1811 | "dev": true, 1812 | "engines": { 1813 | "node": ">= 0.3.0" 1814 | } 1815 | }, 1816 | "node_modules/strip-indent": { 1817 | "version": "3.0.0", 1818 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", 1819 | "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", 1820 | "dev": true, 1821 | "dependencies": { 1822 | "min-indent": "^1.0.0" 1823 | }, 1824 | "engines": { 1825 | "node": ">=8" 1826 | } 1827 | }, 1828 | "node_modules/supports-preserve-symlinks-flag": { 1829 | "version": "1.0.0", 1830 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1831 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1832 | "dev": true, 1833 | "engines": { 1834 | "node": ">= 0.4" 1835 | }, 1836 | "funding": { 1837 | "url": "https://github.com/sponsors/ljharb" 1838 | } 1839 | }, 1840 | "node_modules/svelte": { 1841 | "version": "4.2.0", 1842 | "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.0.tgz", 1843 | "integrity": "sha512-kVsdPjDbLrv74SmLSUzAsBGquMs4MPgWGkGLpH+PjOYnFOziAvENVzgJmyOCV2gntxE32aNm8/sqNKD6LbIpeQ==", 1844 | "dev": true, 1845 | "dependencies": { 1846 | "@ampproject/remapping": "^2.2.1", 1847 | "@jridgewell/sourcemap-codec": "^1.4.15", 1848 | "@jridgewell/trace-mapping": "^0.3.18", 1849 | "acorn": "^8.9.0", 1850 | "aria-query": "^5.3.0", 1851 | "axobject-query": "^3.2.1", 1852 | "code-red": "^1.0.3", 1853 | "css-tree": "^2.3.1", 1854 | "estree-walker": "^3.0.3", 1855 | "is-reference": "^3.0.1", 1856 | "locate-character": "^3.0.0", 1857 | "magic-string": "^0.30.0", 1858 | "periscopic": "^3.1.0" 1859 | }, 1860 | "engines": { 1861 | "node": ">=16" 1862 | } 1863 | }, 1864 | "node_modules/svelte-check": { 1865 | "version": "3.5.0", 1866 | "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.5.0.tgz", 1867 | "integrity": "sha512-KHujbn4k17xKYLmtCwv0sKKM7uiHTYcQvXnvrCcNU6a7hcszh99zFTIoiu/Sp/ewAw5aJmillJ1Cs8gKLmcX4A==", 1868 | "dev": true, 1869 | "dependencies": { 1870 | "@jridgewell/trace-mapping": "^0.3.17", 1871 | "chokidar": "^3.4.1", 1872 | "fast-glob": "^3.2.7", 1873 | "import-fresh": "^3.2.1", 1874 | "picocolors": "^1.0.0", 1875 | "sade": "^1.7.4", 1876 | "svelte-preprocess": "^5.0.4", 1877 | "typescript": "^5.0.3" 1878 | }, 1879 | "bin": { 1880 | "svelte-check": "bin/svelte-check" 1881 | }, 1882 | "peerDependencies": { 1883 | "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0" 1884 | } 1885 | }, 1886 | "node_modules/svelte-hmr": { 1887 | "version": "0.15.3", 1888 | "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", 1889 | "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", 1890 | "dev": true, 1891 | "engines": { 1892 | "node": "^12.20 || ^14.13.1 || >= 16" 1893 | }, 1894 | "peerDependencies": { 1895 | "svelte": "^3.19.0 || ^4.0.0" 1896 | } 1897 | }, 1898 | "node_modules/svelte-preprocess": { 1899 | "version": "5.0.4", 1900 | "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz", 1901 | "integrity": "sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==", 1902 | "dev": true, 1903 | "hasInstallScript": true, 1904 | "dependencies": { 1905 | "@types/pug": "^2.0.6", 1906 | "detect-indent": "^6.1.0", 1907 | "magic-string": "^0.27.0", 1908 | "sorcery": "^0.11.0", 1909 | "strip-indent": "^3.0.0" 1910 | }, 1911 | "engines": { 1912 | "node": ">= 14.10.0" 1913 | }, 1914 | "peerDependencies": { 1915 | "@babel/core": "^7.10.2", 1916 | "coffeescript": "^2.5.1", 1917 | "less": "^3.11.3 || ^4.0.0", 1918 | "postcss": "^7 || ^8", 1919 | "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0", 1920 | "pug": "^3.0.0", 1921 | "sass": "^1.26.8", 1922 | "stylus": "^0.55.0", 1923 | "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", 1924 | "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0", 1925 | "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" 1926 | }, 1927 | "peerDependenciesMeta": { 1928 | "@babel/core": { 1929 | "optional": true 1930 | }, 1931 | "coffeescript": { 1932 | "optional": true 1933 | }, 1934 | "less": { 1935 | "optional": true 1936 | }, 1937 | "postcss": { 1938 | "optional": true 1939 | }, 1940 | "postcss-load-config": { 1941 | "optional": true 1942 | }, 1943 | "pug": { 1944 | "optional": true 1945 | }, 1946 | "sass": { 1947 | "optional": true 1948 | }, 1949 | "stylus": { 1950 | "optional": true 1951 | }, 1952 | "sugarss": { 1953 | "optional": true 1954 | }, 1955 | "typescript": { 1956 | "optional": true 1957 | } 1958 | } 1959 | }, 1960 | "node_modules/svelte-preprocess/node_modules/magic-string": { 1961 | "version": "0.27.0", 1962 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", 1963 | "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", 1964 | "dev": true, 1965 | "dependencies": { 1966 | "@jridgewell/sourcemap-codec": "^1.4.13" 1967 | }, 1968 | "engines": { 1969 | "node": ">=12" 1970 | } 1971 | }, 1972 | "node_modules/svelte/node_modules/estree-walker": { 1973 | "version": "3.0.3", 1974 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", 1975 | "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", 1976 | "dev": true, 1977 | "dependencies": { 1978 | "@types/estree": "^1.0.0" 1979 | } 1980 | }, 1981 | "node_modules/svelte/node_modules/magic-string": { 1982 | "version": "0.30.3", 1983 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz", 1984 | "integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==", 1985 | "dev": true, 1986 | "dependencies": { 1987 | "@jridgewell/sourcemap-codec": "^1.4.15" 1988 | }, 1989 | "engines": { 1990 | "node": ">=12" 1991 | } 1992 | }, 1993 | "node_modules/to-regex-range": { 1994 | "version": "5.0.1", 1995 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1996 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1997 | "dev": true, 1998 | "dependencies": { 1999 | "is-number": "^7.0.0" 2000 | }, 2001 | "engines": { 2002 | "node": ">=8.0" 2003 | } 2004 | }, 2005 | "node_modules/tslib": { 2006 | "version": "2.6.2", 2007 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", 2008 | "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", 2009 | "dev": true 2010 | }, 2011 | "node_modules/typescript": { 2012 | "version": "5.2.2", 2013 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", 2014 | "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", 2015 | "dev": true, 2016 | "bin": { 2017 | "tsc": "bin/tsc", 2018 | "tsserver": "bin/tsserver" 2019 | }, 2020 | "engines": { 2021 | "node": ">=14.17" 2022 | } 2023 | }, 2024 | "node_modules/uberproto": { 2025 | "version": "1.2.0", 2026 | "resolved": "https://registry.npmjs.org/uberproto/-/uberproto-1.2.0.tgz", 2027 | "integrity": "sha512-pGtPAQmLwh+R9w81WVHzui1FfedpQWQpiaIIfPCwhtsBez4q6DYbJFfyXPVHPUTNFnedAvNEnkoFiLuhXIR94w==", 2028 | "dev": true, 2029 | "engines": { 2030 | "node": "*" 2031 | } 2032 | }, 2033 | "node_modules/universalify": { 2034 | "version": "2.0.0", 2035 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", 2036 | "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", 2037 | "dev": true, 2038 | "engines": { 2039 | "node": ">= 10.0.0" 2040 | } 2041 | }, 2042 | "node_modules/vite": { 2043 | "version": "4.2.3", 2044 | "resolved": "https://registry.npmjs.org/vite/-/vite-4.2.3.tgz", 2045 | "integrity": "sha512-kLU+m2q0Y434Y1kCy3TchefAdtFso0ILi0dLyFV8Us3InXTU11H/B5ZTqCKIQHzSKNxVG/yEx813EA9f1imQ9A==", 2046 | "dev": true, 2047 | "dependencies": { 2048 | "esbuild": "^0.17.5", 2049 | "postcss": "^8.4.21", 2050 | "resolve": "^1.22.1", 2051 | "rollup": "^3.18.0" 2052 | }, 2053 | "bin": { 2054 | "vite": "bin/vite.js" 2055 | }, 2056 | "engines": { 2057 | "node": "^14.18.0 || >=16.0.0" 2058 | }, 2059 | "optionalDependencies": { 2060 | "fsevents": "~2.3.2" 2061 | }, 2062 | "peerDependencies": { 2063 | "@types/node": ">= 14", 2064 | "less": "*", 2065 | "sass": "*", 2066 | "stylus": "*", 2067 | "sugarss": "*", 2068 | "terser": "^5.4.0" 2069 | }, 2070 | "peerDependenciesMeta": { 2071 | "@types/node": { 2072 | "optional": true 2073 | }, 2074 | "less": { 2075 | "optional": true 2076 | }, 2077 | "sass": { 2078 | "optional": true 2079 | }, 2080 | "stylus": { 2081 | "optional": true 2082 | }, 2083 | "sugarss": { 2084 | "optional": true 2085 | }, 2086 | "terser": { 2087 | "optional": true 2088 | } 2089 | } 2090 | }, 2091 | "node_modules/vite/node_modules/rollup": { 2092 | "version": "3.28.1", 2093 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz", 2094 | "integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==", 2095 | "dev": true, 2096 | "bin": { 2097 | "rollup": "dist/bin/rollup" 2098 | }, 2099 | "engines": { 2100 | "node": ">=14.18.0", 2101 | "npm": ">=8.0.0" 2102 | }, 2103 | "optionalDependencies": { 2104 | "fsevents": "~2.3.2" 2105 | } 2106 | }, 2107 | "node_modules/vitefu": { 2108 | "version": "0.2.4", 2109 | "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.4.tgz", 2110 | "integrity": "sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==", 2111 | "dev": true, 2112 | "peerDependencies": { 2113 | "vite": "^3.0.0 || ^4.0.0" 2114 | }, 2115 | "peerDependenciesMeta": { 2116 | "vite": { 2117 | "optional": true 2118 | } 2119 | } 2120 | }, 2121 | "node_modules/wrappy": { 2122 | "version": "1.0.2", 2123 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2124 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 2125 | "dev": true 2126 | } 2127 | } 2128 | } 2129 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baha-anime-skip-ext", 3 | "displayName": "Bahamut Anime Skip", 4 | "description": "Skip Opening and Ending on Bahamut Anime", 5 | "version": "0.1.0", 6 | "type": "module", 7 | "scripts": { 8 | "dev": "vite", 9 | "build": "vite build", 10 | "check": "svelte-check --tsconfig ./tsconfig.json" 11 | }, 12 | "dependencies": { 13 | "debug": "^4.3.4", 14 | "wait-elm": "^0.1.0" 15 | }, 16 | "devDependencies": { 17 | "@crxjs/vite-plugin": "2.0.0-beta.18", 18 | "@sveltejs/vite-plugin-svelte": "2.4.6", 19 | "@tailwindcss/typography": "^0.5.10", 20 | "@tsconfig/svelte": "5.0.2", 21 | "@types/chrome": "0.0.246", 22 | "@types/debug": "^4.1.9", 23 | "autoprefixer": "^10.4.16", 24 | "daisyui": "^3.8.2", 25 | "postcss": "^8.4.31", 26 | "svelte": "4.2.1", 27 | "svelte-check": "3.5.2", 28 | "svelte-preprocess": "5.0.4", 29 | "tailwindcss": "^3.3.3", 30 | "tslib": "2.6.2", 31 | "typescript": "5.2.2", 32 | "vite": "4.4.9" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/privacy-policy.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | By installing and using the Extension, you agree to the collection, storage, and use of your information as outlined in this Privacy Policy. 4 | 5 | ## Information We Collect 6 | 7 | ### Serial Number of Video (SN) 8 | 9 | When you use the Extension, we automatically collect the Serial Number (SN) associated with the video you are watching on the Bahamut Anime platform. This SN is used to find and load the skip sections related to the video from remote (configurable) servers. 10 | 11 | ## How We Use Information 12 | 13 | The SN collected is used for the following purposes: 14 | 15 | 1. To provide the core functionality of the Extension, which includes locating and applying skip sections for the videos you are watching. 16 | 17 | ## Information Sharing 18 | 19 | We do not sell, trade, or otherwise transfer your information to external parties. However, we may share the SN with remote servers as configured by you within the Extension settings to fetch the relevant skip sections. 20 | 21 | ## User Choices 22 | 23 | You can configure the remote servers from which the Extension fetches the skip sections. This is entirely optional and can be configured through the Extension settings. 24 | 25 | ## Changes to Privacy Policy 26 | 27 | We reserve the right to update or modify this Privacy Policy at any time. The date of the last modification will be noted at the top of this page. It is your responsibility to review this Privacy Policy periodically. 28 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/assets/icons/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/19f01bece74fbd73f9c3b685446d0f9b2a0d3444/packages/baha-anime-skip-ext/src/assets/icons/icon-128.png -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/assets/icons/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/19f01bece74fbd73f9c3b685446d0f9b2a0d3444/packages/baha-anime-skip-ext/src/assets/icons/icon-16.png -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/assets/icons/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/19f01bece74fbd73f9c3b685446d0f9b2a0d3444/packages/baha-anime-skip-ext/src/assets/icons/icon-32.png -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/assets/icons/icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/19f01bece74fbd73f9c3b685446d0f9b2a0d3444/packages/baha-anime-skip-ext/src/assets/icons/icon-48.png -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/assets/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/19f01bece74fbd73f9c3b685446d0f9b2a0d3444/packages/baha-anime-skip-ext/src/assets/icons/icon.png -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/assets/icons/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 258 | 259 | 260 | 261 | 263 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 277 | 278 | 279 | 280 | 281 | 282 | 284 | 285 | 287 | 288 | 290 | 291 | 293 | 294 | 295 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/background/index.ts: -------------------------------------------------------------------------------- 1 | import { storage } from "../storage"; 2 | 3 | // Background service workers 4 | // https://developer.chrome.com/docs/extensions/mv3/service_workers/ 5 | 6 | chrome.runtime.onInstalled.addListener(() => { 7 | storage.get().then(console.log); 8 | }); 9 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/components/AddEndpoint.svelte: -------------------------------------------------------------------------------- 1 | 31 | 32 |
33 |
34 | e.key === "Enter" && add_endpoint()} 40 | /> 41 |
42 | 45 |
46 |
47 | {#if error} 48 |
{error}
49 | {/if} 50 |
51 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/components/EndpointList.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | {#each endpoints as endpoint} 6 |
7 |
8 | {endpoint} 9 |
10 |
11 | 19 |
20 |
21 | {/each} 22 | 23 | 28 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/components/SkipButton.svelte: -------------------------------------------------------------------------------- 1 | 84 | 85 | 111 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/components/SkipTab.svelte: -------------------------------------------------------------------------------- 1 | 32 | 33 |
34 |
35 |

36 | 37 | Bahamut Anime Skip 38 | 39 |

40 |
41 |
通報資料錯誤或遺失
42 |
43 | GitHub Issues 44 |
45 |
46 |
47 |
48 | 資料庫端點 52 |
53 |
54 | 55 | 56 |
57 |
58 |
59 |
60 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/content/index.ts: -------------------------------------------------------------------------------- 1 | import { log } from "../log"; 2 | import "../styles.css"; 3 | import { TabManager } from "./manager"; 4 | import { mount } from "./mount"; 5 | 6 | if (TabManager.attachable()) { 7 | attach(); 8 | } else { 9 | document.body.addEventListener("DOMContentLoaded", attach); 10 | } 11 | 12 | function attach() { 13 | log("attach"); 14 | const manager = new TabManager(); 15 | 16 | manager.add({ 17 | name: "Skip", 18 | mount, 19 | unmount: () => {}, 20 | }); 21 | log("attached"); 22 | } 23 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/content/manager.ts: -------------------------------------------------------------------------------- 1 | import { log } from "../log"; 2 | 3 | export interface Tab { 4 | name: string; 5 | mount: (target: HTMLDivElement) => void | Promise; 6 | unmount: () => void | Promise; 7 | } 8 | 9 | export class TabManager { 10 | protected nav = document.querySelector(".ani-tabs"); 11 | protected wrapper = document.querySelector(".ani-tab-content"); 12 | protected tabs: { 13 | data: Tab; 14 | target: HTMLDivElement; 15 | nav: HTMLDivElement; 16 | }[] = []; 17 | 18 | constructor() { 19 | if (!this.nav || !this.wrapper) { 20 | throw new Error("Cannot find nav or wrapper"); 21 | } 22 | 23 | [...this.nav.children].forEach((tab) => { 24 | const link = tab.querySelector("a"); 25 | const name = link?.innerText; 26 | const id = "#" + link?.href.split("#")[1]; 27 | const target = document.querySelector(id); 28 | log("attaching other tabs", { link, name, id, target }); 29 | if (name && target) { 30 | this.tabs.push({ 31 | data: { name, mount: () => {}, unmount: () => {} }, 32 | target, 33 | nav: tab as HTMLDivElement, 34 | }); 35 | log("attached other tabs", { name }); 36 | } 37 | }); 38 | 39 | this.hide_all(); 40 | this.show(this.tabs[0]); 41 | } 42 | 43 | protected hide_all(): void { 44 | if (!this.wrapper) { 45 | throw new Error("Cannot find wrapper"); 46 | } 47 | 48 | [...this.wrapper.children].forEach((child) => { 49 | if (child instanceof HTMLElement) { 50 | child.style.display = "none"; 51 | } 52 | }); 53 | 54 | this.tabs.forEach((tab) => { 55 | tab.nav.querySelector("a")?.classList.remove("is-active"); 56 | }); 57 | } 58 | 59 | protected show(tab: { data: Tab; target: HTMLDivElement; nav: HTMLDivElement }): void { 60 | tab.target.style.display = "block"; 61 | tab.nav.querySelector("a")?.classList.add("is-active"); 62 | } 63 | 64 | public async add(tab: Tab): Promise { 65 | if (!this.wrapper || !this.nav) { 66 | throw new Error("Cannot find wrapper or nav"); 67 | } 68 | 69 | const target = document.createElement("div"); 70 | target.id = `baha-anime-tab-${tab.name}`; 71 | target.classList.add("ani-tabs__item"); 72 | this.wrapper.appendChild(target); 73 | 74 | const nav = document.createElement("div"); 75 | nav.classList.add("ani-tab-nav"); 76 | 77 | const t = { data: tab, target, nav }; 78 | 79 | const link = document.createElement("a"); 80 | link.href = `#baha-anime-tab-${tab.name}`; 81 | link.classList.add("ani-tabs-link"); 82 | link.innerText = tab.name; 83 | link.addEventListener("click", (evt) => { 84 | evt.preventDefault(); 85 | this.hide_all(); 86 | this.show(t); 87 | }); 88 | nav.appendChild(link); 89 | this.nav.appendChild(nav); 90 | 91 | this.tabs.push(t); 92 | await tab.mount(target); 93 | } 94 | 95 | public async remove(tab: Tab): Promise { 96 | if (!this.wrapper || !this.nav) { 97 | throw new Error("Cannot find wrapper or nav"); 98 | } 99 | 100 | const index = this.tabs.findIndex((t) => t.data === tab); 101 | if (index === -1) { 102 | throw new Error("Tab not found"); 103 | } 104 | 105 | const { target, nav } = this.tabs[index]; 106 | await tab.unmount(); 107 | this.wrapper.removeChild(target); 108 | this.nav.removeChild(nav); 109 | this.tabs.splice(index, 1); 110 | } 111 | 112 | static attachable(): boolean { 113 | const ok = 114 | !!document.querySelector(".ani-tabs") && !!document.querySelector(".ani-tab-content"); 115 | return ok; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/content/mount.ts: -------------------------------------------------------------------------------- 1 | import { wait } from "wait-elm"; 2 | import SkipButton from "../components/SkipButton.svelte"; 3 | import SkipTab from "../components/SkipTab.svelte"; 4 | import { log as base_log } from "../log"; 5 | import { storage } from "../storage"; 6 | 7 | const log = base_log.extend("mount"); 8 | log.enabled = true; 9 | 10 | export async function mount(target: HTMLDivElement): Promise { 11 | new SkipTab({ target }); 12 | log("mounted skip tab"); 13 | 14 | const endpoints = (await storage.get()).endpoints; 15 | 16 | const video = await wait("video"); 17 | if (!video) { 18 | throw new Error("Cannot find video element"); 19 | } 20 | 21 | const sn = new URLSearchParams(window.location.search).get("sn"); 22 | if (!sn) { 23 | throw new Error("Cannot find sn in query string"); 24 | } 25 | 26 | try { 27 | const data = fetch_data(sn, endpoints); 28 | 29 | const config = { attributes: true, attributeFilter: ["src"] }; 30 | const observer = new MutationObserver((mutations) => { 31 | mutations.forEach((mutation) => { 32 | if (mutation.attributeName === "src") { 33 | video.addEventListener("loadedmetadata", () => { 34 | const videojs = document.querySelector("video-js"); 35 | 36 | if (videojs) { 37 | const button = document.createElement("div"); 38 | button.style.display = "contents"; 39 | videojs.appendChild(button); 40 | 41 | data.then((raw) => { 42 | log("data", raw); 43 | 44 | const data = Object.entries(raw).map( 45 | ([chapter, [start, duration]]) => ({ 46 | chapter, 47 | start, 48 | end: start + duration, 49 | }), 50 | ); 51 | 52 | if (data.length === 0) { 53 | data.push({ chapter: "NEVT", start: 0, end: 3 }); 54 | } 55 | 56 | new SkipButton({ 57 | target: button, 58 | props: { data, video }, 59 | }); 60 | }); 61 | } 62 | }); 63 | } 64 | }); 65 | }); 66 | observer.observe(video, config); 67 | } catch (err) { 68 | log(err); 69 | } 70 | } 71 | 72 | async function fetch_data( 73 | sn: string, 74 | endpoints: string[], 75 | ): Promise> { 76 | log("fetching data", { sn, endpoints }); 77 | for (const endpoint of endpoints) { 78 | try { 79 | const url = `${endpoint}${sn}.json`; 80 | const res = await fetch(url, { redirect: "follow" }); 81 | const data = await res.json(); 82 | 83 | return data; 84 | } catch (err) { 85 | log(`[Not Found] ${endpoint} ${err}`); 86 | } 87 | } 88 | 89 | throw new Error("All endpoints do not have this data."); 90 | } 91 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/content/utils.ts: -------------------------------------------------------------------------------- 1 | export function create_report_url(): string { 2 | const title = document.querySelector(".anime_name > h1")?.textContent; 3 | const sn = new URLSearchParams(location.search).get("sn"); 4 | 5 | const url = new URL("https://github.com/JacobLinCool/baha-anime-skip/issues/new"); 6 | 7 | if (title && sn) { 8 | url.searchParams.set("title", `[資料錯誤或遺失] ${title} (${sn})`); 9 | 10 | const body = [ 11 | `[動畫瘋連結](https://ani.gamer.com.tw/animeVideo.php?sn=${sn})`, 12 | "", 13 | `# 問題描述`, 14 | ``, 15 | "", 16 | `# 補充資料`, 17 | ``, 18 | "", 19 | ].join("\n"); 20 | url.searchParams.set("body", body); 21 | } 22 | 23 | return url.toString(); 24 | } 25 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/log.ts: -------------------------------------------------------------------------------- 1 | import debug from "debug"; 2 | 3 | export const log = debug("anime-skip"); 4 | log.enabled = true; 5 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/manifest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineManifest } from "@crxjs/vite-plugin"; 2 | import package_json from "../package.json"; 3 | 4 | const { version, displayName, description } = package_json; 5 | 6 | export default defineManifest(async () => ({ 7 | manifest_version: 3, 8 | name: displayName, 9 | description: description, 10 | version: version, 11 | version_name: version, 12 | icons: { 13 | "16": "src/assets/icons/icon-16.png", 14 | "32": "src/assets/icons/icon-32.png", 15 | "48": "src/assets/icons/icon-48.png", 16 | "128": "src/assets/icons/icon-128.png", 17 | }, 18 | content_scripts: [ 19 | { 20 | matches: ["https://ani.gamer.com.tw/animeVideo.php?*"], 21 | js: ["src/content/index.ts"], 22 | }, 23 | ], 24 | background: { 25 | service_worker: "src/background/index.ts", 26 | }, 27 | permissions: ["storage"] as chrome.runtime.ManifestPermissions[], 28 | })); 29 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/storage.ts: -------------------------------------------------------------------------------- 1 | import { log as base_log } from "./log"; 2 | 3 | const log = base_log.extend("storage"); 4 | log.enabled = true; 5 | 6 | export interface SkipStorage { 7 | endpoints: string[]; 8 | } 9 | 10 | const default_storage: SkipStorage = { 11 | endpoints: [ 12 | "https://jacoblincool.github.io/baha-anime-skip/", 13 | "https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/data/", 14 | ], 15 | }; 16 | 17 | export const storage = { 18 | get: async (): Promise => { 19 | log("getting storage"); 20 | const storage = (await chrome.storage.sync.get(default_storage)) as Promise; 21 | log("got storage", storage); 22 | return storage; 23 | }, 24 | set: async (value: Partial): Promise => { 25 | log("setting storage", value); 26 | await chrome.storage.sync.set(value); 27 | log("set storage"); 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/styles.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/svelte.config.js: -------------------------------------------------------------------------------- 1 | import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; 2 | 3 | export default { 4 | // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 5 | // for more information about preprocessors 6 | preprocess: vitePreprocess(), 7 | }; 8 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | 3 | /** @type {import('tailwindcss').Config} */ 4 | export default { 5 | content: ["./src/**/*.{svelte,css,ts}"], 6 | theme: { 7 | extend: {}, 8 | }, 9 | plugins: [require("@tailwindcss/typography"), require("daisyui")], 10 | prefix: "tw-", 11 | daisyui: { 12 | themes: [ 13 | { 14 | bahamut: { 15 | primary: "#00b4d8", 16 | "primary-focus": "#59d3eb", 17 | "primary-content": "#fff", 18 | secondary: "#e67600", 19 | "secondary-focus": "#f68b19", 20 | "secondary-content": "#fff", 21 | accent: "#ea7b94", 22 | "accent-focus": "#f58ba3", 23 | "accent-content": "#fff", 24 | neutral: "#000", 25 | }, 26 | }, 27 | ], 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/svelte/tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ESNext", 5 | "useDefineForClassFields": true, 6 | "module": "ESNext", 7 | "resolveJsonModule": true, 8 | "moduleResolution": "bundler", 9 | /** 10 | * Typecheck JS in `.svelte` and `.js` files by default. 11 | * Disable checkJs if you'd like to use dynamic types in JS. 12 | * Note that setting allowJs false does not prevent the use 13 | * of JS in `.svelte` files. 14 | */ 15 | "allowJs": true, 16 | "checkJs": true, 17 | "isolatedModules": true 18 | }, 19 | "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | // vite tsconfig 2 | { 3 | "compilerOptions": { 4 | "composite": true, 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler" 8 | }, 9 | "include": ["vite.config.ts", "src/manifest.config.ts", "package.json"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/baha-anime-skip-ext/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { crx } from "@crxjs/vite-plugin"; 2 | import { svelte } from "@sveltejs/vite-plugin-svelte"; 3 | import { defineConfig } from "vite"; 4 | import manifest from "./src/manifest.config"; 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [svelte(), crx({ manifest })], 9 | // HACK: https://github.com/crxjs/chrome-extension-tools/issues/696 10 | // https://github.com/crxjs/chrome-extension-tools/issues/746 11 | server: { 12 | port: 5173, 13 | strictPort: true, 14 | hmr: { 15 | clientPort: 5173, 16 | }, 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /packages/baha-anime-skip/README.md: -------------------------------------------------------------------------------- 1 | # baha-anime-skip 2 | -------------------------------------------------------------------------------- /packages/baha-anime-skip/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baha-anime-skip", 3 | "version": "0.2.1", 4 | "description": "Skip OP or other things on Bahamut Anime.", 5 | "keywords": [], 6 | "author": "JacobLinCool (https://github.com/JacobLinCool)", 7 | "license": "MIT", 8 | "type": "module", 9 | "main": "dist/index.user.js", 10 | "files": [ 11 | "dist" 12 | ], 13 | "scripts": { 14 | "build": "tsup" 15 | }, 16 | "dependencies": { 17 | "baha-anime-skip-db": "workspace:*", 18 | "wait-elm": "^0.1.0" 19 | }, 20 | "devDependencies": { 21 | "tsup": "^7.2.0", 22 | "tsx": "^3.13.0", 23 | "typedoc": "^0.25.1", 24 | "typescript": "^5.2.2", 25 | "zod": "^3.22.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/baha-anime-skip/src/button.ts: -------------------------------------------------------------------------------- 1 | export const button = create_button(); 2 | 3 | export function create_button(): HTMLButtonElement { 4 | const button = document.createElement("button"); 5 | 6 | Object.assign(button.style, { 7 | opacity: "0", 8 | transition: "opacity 0.3s", 9 | position: "absolute", 10 | bottom: "50px", 11 | right: "0px", 12 | margin: "20px", 13 | width: "120px", 14 | height: "40px", 15 | border: "1px solid lightgray", 16 | borderRadius: "4px", 17 | backgroundColor: "rgba(0, 0, 0, 0.5)", 18 | color: "white", 19 | fontSize: "16px", 20 | zIndex: "9", 21 | justifyContent: "center", 22 | alignItems: "center", 23 | cursor: "pointer", 24 | pointerEvents: "auto", 25 | overflow: "hidden", 26 | } as CSSStyleDeclaration); 27 | 28 | return button; 29 | } 30 | -------------------------------------------------------------------------------- /packages/baha-anime-skip/src/config.ts: -------------------------------------------------------------------------------- 1 | const PREFIX = "bas-"; 2 | 3 | const config = { 4 | get(key: string): unknown | null { 5 | try { 6 | return JSON.parse(localStorage.getItem(PREFIX + key) || ""); 7 | } catch { 8 | return localStorage.getItem(PREFIX + key); 9 | } 10 | }, 11 | set(key: string, value: unknown): void { 12 | if (typeof value === "string") { 13 | localStorage.setItem(PREFIX + key, value); 14 | } else { 15 | localStorage.setItem(PREFIX + key, JSON.stringify(value)); 16 | } 17 | }, 18 | }; 19 | 20 | if (config.get("endpoints") === null) { 21 | config.set("endpoints", [ 22 | "https://jacoblin.cool/baha-anime-skip/", 23 | "https://jacoblincool.github.io/baha-anime-skip/", 24 | "https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/data/", 25 | ]); 26 | } 27 | 28 | export { config }; 29 | -------------------------------------------------------------------------------- /packages/baha-anime-skip/src/index.ts: -------------------------------------------------------------------------------- 1 | import { wait } from "wait-elm"; 2 | import { button } from "./button"; 3 | import { config } from "./config"; 4 | import { prefetch_all, prefetch_check, prefetch_ui } from "./prefetch"; 5 | import { add_tab } from "./tab"; 6 | import { Event } from "./types"; 7 | import { debug, get_data } from "./utils"; 8 | 9 | (async () => { 10 | attach() 11 | .catch((err) => { 12 | debug(err.toString()); 13 | }) 14 | .then(() => { 15 | if (config.get("prefetch") === "1" && config.get("cache") === "1") { 16 | prefetch_ui(); 17 | prefetch_all().then(() => { 18 | prefetch_check(); 19 | }); 20 | } 21 | }); 22 | 23 | async function attach() { 24 | await add_tab(); 25 | 26 | const target = await wait("video"); 27 | if (!target) { 28 | throw new Error("Cannot find video element"); 29 | } 30 | 31 | const sn = new URLSearchParams(window.location.search).get("sn"); 32 | if (!sn) { 33 | throw new Error("Cannot find sn in query string"); 34 | } 35 | 36 | const config = { attributes: true, attributeFilter: ["src"] }; 37 | const observer = new MutationObserver((mutations) => { 38 | mutations.forEach((mutation) => { 39 | if (mutation.attributeName === "src") { 40 | target.addEventListener("loadedmetadata", () => { 41 | const videojs = document.querySelector("video-js"); 42 | 43 | if (videojs) { 44 | videojs.appendChild(button); 45 | } 46 | }); 47 | } 48 | }); 49 | }); 50 | observer.observe(target, config); 51 | 52 | const data: Event[] = Object.entries(await get_data(sn).catch(() => ({}))).map( 53 | ([chapter, [start, duration]]) => ({ chapter, start, end: start + duration }), 54 | ); 55 | debug("Chapters", JSON.stringify(data, null, 4)); 56 | 57 | if (data.length === 0) { 58 | data.push({ chapter: "NEVT", start: 0, end: 3 }); 59 | } 60 | 61 | let prev_event: Event | null = null; 62 | let temp_disabled_event: Event | null = null; 63 | 64 | const none = 65 | (type = "Skip button") => 66 | () => 67 | debug(`${type} clicked`); 68 | target.addEventListener("timeupdate", () => { 69 | const time = target.currentTime; 70 | 71 | let curr_event: Event | null = null; 72 | for (let i = 0; i < data.length; i++) { 73 | if (data[i].start <= time && time <= data[i].end) { 74 | curr_event = data[i]; 75 | break; 76 | } 77 | } 78 | 79 | if (curr_event === null && prev_event !== null) { 80 | debug(`Leaving ${prev_event.chapter}`); 81 | button.style.opacity = "0"; 82 | button.style.pointerEvents = "none"; 83 | button.onclick = none(); 84 | button.oncontextmenu = none("Context menu"); 85 | prev_event = null; 86 | temp_disabled_event = null; 87 | } else if ( 88 | curr_event && 89 | curr_event !== prev_event && 90 | curr_event !== temp_disabled_event 91 | ) { 92 | const event = curr_event; 93 | debug(`Entering ${event.chapter}`); 94 | 95 | button.style.opacity = "0.85"; 96 | button.style.pointerEvents = "auto"; 97 | button.innerHTML = `Skip ${event.chapter}`; 98 | 99 | button.onclick = () => { 100 | target.currentTime = event.end; 101 | button.onclick = none(); 102 | button.oncontextmenu = none("Context menu"); 103 | debug(`Skip ${event.chapter} clicked, go to ${event.end}`); 104 | }; 105 | 106 | button.oncontextmenu = () => { 107 | debug(`Hiding ${event.chapter}`); 108 | temp_disabled_event = event; 109 | button.style.opacity = "0"; 110 | button.style.pointerEvents = "none"; 111 | button.onclick = none(); 112 | button.oncontextmenu = none("Context menu"); 113 | }; 114 | 115 | if (event.chapter === "NEVT") { 116 | button.innerHTML = "貢獻 OP 資訊"; 117 | button.onclick = () => { 118 | window.open( 119 | "https://github.com/JacobLinCool/baha-anime-skip#readme", 120 | "_blank", 121 | ); 122 | }; 123 | } 124 | 125 | prev_event = event; 126 | } 127 | }); 128 | } 129 | })(); 130 | -------------------------------------------------------------------------------- /packages/baha-anime-skip/src/prefetch.ts: -------------------------------------------------------------------------------- 1 | import { config } from "./config"; 2 | import { get_data } from "./utils"; 3 | 4 | export function prefetch_ui(): void { 5 | if (!document.querySelector("#bas-style")) { 6 | const style = document.createElement("style"); 7 | style.id = "bas-style"; 8 | style.innerHTML = `.season ul li a.bas-cached:after { content: "v"; color: orange; position: absolute; top: 0; left: 0; padding: 0 4px; }`; 9 | document.head.appendChild(style); 10 | } 11 | } 12 | 13 | export async function prefetch_all(): Promise { 14 | await Promise.all( 15 | Array.from(document.querySelectorAll(".season ul li a")).map( 16 | async (elm) => { 17 | const sn = elm.href.match(/sn=(\d+)/)?.[1]; 18 | if (sn && !config.get(`cache-${sn}`)) { 19 | try { 20 | await get_data(sn); 21 | } catch (err) { 22 | console.error(err); 23 | } 24 | } 25 | }, 26 | ), 27 | ); 28 | } 29 | 30 | export function prefetch_check(): void { 31 | Array.from(document.querySelectorAll(".season ul li a")).map((elm) => { 32 | const sn = elm.href.match(/sn=(\d+)/)?.[1]; 33 | if (sn && config.get(`cache-${sn}`)) { 34 | elm.classList.add("bas-cached"); 35 | } 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /packages/baha-anime-skip/src/tab.ts: -------------------------------------------------------------------------------- 1 | import { wait } from "wait-elm"; 2 | import { config } from "./config"; 3 | import { debug } from "./utils"; 4 | 5 | export async function add_tab(): Promise { 6 | const tabs = await wait(".sub_top.ani-tabs"); 7 | const contents = await wait(".ani-tab-content"); 8 | 9 | const CONTENT_ID = "baha-anime-skip-content"; 10 | 11 | const tab = ` 12 | 17 | `; 18 | 19 | const tab_elm = document.createElement("div"); 20 | tab_elm.innerHTML = tab; 21 | tabs.appendChild(tab_elm); 22 | 23 | document.querySelector(`a[href="#${CONTENT_ID}"]`)?.addEventListener("click", (e) => { 24 | document.querySelector(".ani-tabs-link.is-active")?.classList.remove("is-active"); 25 | (e.target as HTMLDivElement).classList.add("is-active"); 26 | document.querySelectorAll(".ani-tab-content__item").forEach((item) => { 27 | item.style.display = "none"; 28 | }); 29 | 30 | const content = document.querySelector(`#${CONTENT_ID}`); 31 | if (content) { 32 | content.style.display = "block"; 33 | } 34 | e.preventDefault(); 35 | }); 36 | 37 | const issue_title = `[資料錯誤或遺失] ${ 38 | document.title.match(/(.+?\[.+?\])/)?.[1] 39 | } (${new URLSearchParams(location.search).get("sn")})`; 40 | const issue_body = `[動畫瘋連結](${location.href})\n\n# 問題描述\n\n\n# 補充資料\n\n`; 41 | 42 | const endpoints = config.get("endpoints") as string[]; 43 | 44 | const content = ` 45 | 110 | `; 111 | 112 | const dummy = document.createElement("div"); 113 | dummy.innerHTML = content; 114 | const elm = dummy.firstElementChild; 115 | if (elm) { 116 | contents.appendChild(elm); 117 | } 118 | 119 | if (config.get("cache") === "1") { 120 | document.querySelector("#bas-use-cache")?.setAttribute("checked", ""); 121 | } 122 | document.querySelector("#bas-use-cache")?.addEventListener("change", (e) => { 123 | config.set("cache", (e.target as HTMLInputElement).checked ? "1" : "0"); 124 | if ((e.target as HTMLInputElement).checked === false) { 125 | Object.keys(localStorage) 126 | .filter((key) => key.startsWith("bas-cache-")) 127 | .forEach((key) => localStorage.removeItem(key)); 128 | } 129 | }); 130 | 131 | if (config.get("prefetch") === "1") { 132 | document.querySelector("#bas-use-prefetch")?.setAttribute("checked", ""); 133 | } 134 | document.querySelector("#bas-use-prefetch")?.addEventListener("change", (e) => { 135 | config.set("prefetch", (e.target as HTMLInputElement).checked ? "1" : "0"); 136 | }); 137 | 138 | document.querySelector("#bas-endpoint-save")?.addEventListener("click", (e) => { 139 | const content = document.querySelector("#bas-endpoint")?.value; 140 | const new_endpoints = 141 | content 142 | ?.split(",") 143 | .map((e) => e.trim()) 144 | .filter((e) => e.length > 0) ?? []; 145 | const old_endpoints = config.get("endpoints") as string[]; 146 | if (new_endpoints.length && new_endpoints.join() !== old_endpoints.join()) { 147 | config.set("endpoints", new_endpoints); 148 | debug(`Endpoint changed from ${old_endpoints} to ${new_endpoints}`); 149 | } 150 | e.preventDefault(); 151 | }); 152 | } 153 | -------------------------------------------------------------------------------- /packages/baha-anime-skip/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface Event { 2 | chapter: string; 3 | start: number; 4 | end: number; 5 | } 6 | -------------------------------------------------------------------------------- /packages/baha-anime-skip/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { config } from "./config"; 2 | 3 | export function debug(...contents: string[]): void { 4 | console.log(...contents); 5 | const elm = document.querySelector("#baha-anime-skip-debug-console"); 6 | if (elm) { 7 | elm.value += contents.join(" ").toString() + "\n"; 8 | } 9 | } 10 | 11 | export async function get_data(sn: string): Promise> { 12 | if (config.get("cache") === "1" && config.get(`cache-${sn}`)) { 13 | return JSON.parse(config.get(`cache-${sn}`) as string); 14 | } 15 | 16 | const endpoints = config.get("endpoints") as string[]; 17 | for (const endpoint of endpoints) { 18 | try { 19 | const url = `${endpoint}${sn}.json`; 20 | const res = await fetch(url); 21 | const data = await res.json(); 22 | 23 | if (config.get("cache") === "1") { 24 | config.set(`cache-${sn}`, JSON.stringify(data)); 25 | } 26 | 27 | return data; 28 | } catch (err) { 29 | debug(`[Not Found] ${err}`); 30 | } 31 | } 32 | 33 | throw new Error("All endpoints do not have this data."); 34 | } 35 | -------------------------------------------------------------------------------- /packages/baha-anime-skip/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | import PACKAGE from "./package.json"; 3 | 4 | const banner = `// ==UserScript== 5 | // @name Baha Anime Skip 6 | // @version ${PACKAGE.version} 7 | // @description ${PACKAGE.description} 8 | // @author JacobLinCool (https://github.com/JacobLinCool) 9 | // @license MIT 10 | // @homepage https://github.com/JacobLinCool/baha-anime-skip#readme 11 | // @supportURL https://github.com/JacobLinCool/baha-anime-skip/issues 12 | // @updateURL https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/dist/index.user.js 13 | // @downloadURL https://raw.githubusercontent.com/JacobLinCool/baha-anime-skip/dist/index.user.js 14 | // @namespace http://tampermonkey.net/ 15 | // @match https://ani.gamer.com.tw/animeVideo.php?sn=* 16 | // @icon https://www.google.com/s2/favicons?domain=gamer.com.tw 17 | // @grant none 18 | // ==/UserScript== 19 | `; 20 | 21 | export default defineConfig(() => ({ 22 | entry: ["src/index.ts"], 23 | outDir: "dist", 24 | target: "node16", 25 | platform: "browser", 26 | format: ["esm"], 27 | clean: true, 28 | splitting: false, 29 | noExternal: ["wait-elm"], 30 | banner: () => ({ 31 | js: banner, 32 | }), 33 | outExtension: () => { 34 | return { js: ".user.js" }; 35 | }, 36 | })); 37 | -------------------------------------------------------------------------------- /packages/marker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "marker", 4 | "version": "0.1.0", 5 | "description": "", 6 | "keywords": [], 7 | "author": "JacobLinCool (https://github.com/JacobLinCool)", 8 | "license": "MIT", 9 | "type": "module", 10 | "scripts": { 11 | "build": "tsup src/app.ts --clean --format esm", 12 | "start": "node dist/app.js", 13 | "recent": "node dist/app.js -k recent && node dist/app.js -l 80 -u 100 -r 1200,1800 -n ED --last recent", 14 | "rolling": "node dist/app.js rolling" 15 | }, 16 | "dependencies": { 17 | "baha-anime-crawler": "^0.1.1", 18 | "baha-anime-dl": "^0.0.4", 19 | "baha-anime-dl-ext": "^0.0.4", 20 | "bahamut-anime": "^1.2.0", 21 | "commander": "^11.0.0", 22 | "debug": "^4.3.4", 23 | "file-mapping": "^0.2.1", 24 | "lcsb": "^0.1.3", 25 | "log-update": "^5.0.1", 26 | "node-fetch": "^3.3.2", 27 | "ora": "^7.0.1" 28 | }, 29 | "devDependencies": { 30 | "@types/debug": "^4.1.9", 31 | "@types/node-fetch": "^2.6.6", 32 | "tsup": "^7.2.0", 33 | "tsx": "^3.13.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/marker/src/app.ts: -------------------------------------------------------------------------------- 1 | import { program } from "commander"; 2 | import os from "node:os"; 3 | import { no_matched_cache } from "./cache"; 4 | import { data } from "./data"; 5 | import { create_recent_list, create_rolling_list, create_series_list } from "./list"; 6 | import { run } from "./run"; 7 | import { Options } from "./types"; 8 | 9 | const defaults = { 10 | pool: "1200,2400,4800,9600,19200", 11 | lower: 84, 12 | upper: 92, 13 | range: "0,360", 14 | concurrency: Number(process.env.MARKER_CONCURRENCY) || os.cpus().length, 15 | keep: false, 16 | name: "OP", 17 | last: false, 18 | }; 19 | 20 | program 21 | .option("-p, --pool ", "pool size", defaults.pool) 22 | .option("-l, --lower ", "lower bound", Number, defaults.lower) 23 | .option("-u, --upper ", "upper bound", Number, defaults.upper) 24 | .option("-r, --range ", "range", defaults.range) 25 | .option("-c, --concurrency ", "concurrency", Number, defaults.concurrency) 26 | .option("-k, --keep", "do not cleanup", defaults.keep) 27 | .option("-n, --name ", "chapter name", defaults.name) 28 | .option("--last", "use last-first strategy"); 29 | 30 | program.command("recent").action(async () => { 31 | const opt = parse_options(program.opts()); 32 | console.log(JSON.stringify(opt)); 33 | 34 | const list = await create_recent_list(); 35 | const items = list.filter( 36 | (item) => !data[item.sn]?.[opt.name] && !no_matched_cache[opt.name]?.includes(item.sn), 37 | ); 38 | await run(items, opt); 39 | }); 40 | 41 | program 42 | .command("rolling") 43 | .option("-y, --year ", "rolling year", Number, new Date().getFullYear()) 44 | .option("-m, --month ", "rolling month", Number, new Date().getMonth() + 1) 45 | .option("--limit ", "rolling limit", Number, 12 * 100) 46 | .action(async ({ year, month, limit }: { year: number; month: number; limit: number }) => { 47 | const opt = parse_options(program.opts()); 48 | console.log(JSON.stringify(opt)); 49 | 50 | const list = await create_rolling_list(year, month, limit); 51 | const items = list.filter( 52 | (item) => !data[item.sn]?.[opt.name] && !no_matched_cache[opt.name]?.includes(item.sn), 53 | ); 54 | await run(items, opt); 55 | }); 56 | 57 | program.command("single ").action(async (sn: string) => { 58 | const opt = parse_options(program.opts()); 59 | console.log(JSON.stringify(opt)); 60 | 61 | const list = [{ sn }]; 62 | if (data[sn]?.[opt.name]) { 63 | console.log(`skip ${sn} ${opt.name}`); 64 | return; 65 | } 66 | await run(list, opt); 67 | }); 68 | 69 | program.command("series ").action(async (sn: string) => { 70 | const opt = parse_options(program.opts()); 71 | console.log(JSON.stringify(opt)); 72 | 73 | const list = await create_series_list(sn); 74 | const items = list.filter( 75 | (item) => !data[item.sn]?.[opt.name] && !no_matched_cache[opt.name]?.includes(item.sn), 76 | ); 77 | 78 | await run(items, opt); 79 | }); 80 | 81 | program.parse(); 82 | 83 | function parse_options(opt: typeof defaults): Options { 84 | const pool = opt.pool.split(",").map((x) => Number(x)); 85 | const [from, to] = opt.range.split(",").map((x) => Number(x)); 86 | const { lower, upper, concurrency, keep, name, last } = opt; 87 | 88 | return { pool, from, to, lower, upper, concurrency, keep, name, last }; 89 | } 90 | -------------------------------------------------------------------------------- /packages/marker/src/cache.ts: -------------------------------------------------------------------------------- 1 | import { mapping } from "file-mapping"; 2 | 3 | const NO_MATCHED_CACHE = "./no-matched.cache"; 4 | const FAILED_CACHE = "./failed.cache"; 5 | export const no_matched_cache: Record = mapping(NO_MATCHED_CACHE, {}); 6 | export const failed_cache: Record = mapping(FAILED_CACHE, {}); 7 | -------------------------------------------------------------------------------- /packages/marker/src/data.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs"; 2 | 3 | export const FILE = "../baha-anime-skip-db/data.json"; 4 | export const data = JSON.parse(fs.readFileSync(FILE, "utf-8")) as Record< 5 | string, 6 | Record 7 | >; 8 | -------------------------------------------------------------------------------- /packages/marker/src/list.ts: -------------------------------------------------------------------------------- 1 | import { DetailCrawler, ListCrawler } from "baha-anime-crawler"; 2 | import { Anime } from "bahamut-anime"; 3 | import fetch from "node-fetch"; 4 | import fs from "node:fs"; 5 | import ora from "ora"; 6 | 7 | export async function create_recent_list(): Promise<{ sn: string }[]> { 8 | const INDEX = "https://api.gamer.com.tw/mobile_app/anime/v3/index.php"; 9 | 10 | const items: { title: string; sn: string; ignore: boolean }[] = await fetch(INDEX) 11 | .then((res) => res.json() as Promise) 12 | .then((data) => 13 | data.data.newAnime.date.map((item) => ({ 14 | title: item.title, 15 | sn: item.videoSn, 16 | ignore: item.volume === "電影" || !!item.highlightTag.vipTime, 17 | })), 18 | ); 19 | 20 | return items.filter((item) => !item.ignore).map((item) => ({ sn: item.sn })); 21 | } 22 | 23 | export async function create_rolling_list( 24 | year: number, 25 | month: number, 26 | limit = 12 * 100, 27 | ): Promise<{ sn: string }[]> { 28 | const CACHE_FILE = "rolling-list.cache"; 29 | 30 | if (!fs.existsSync(CACHE_FILE)) { 31 | const spinner = ora("Fetching list").start(); 32 | const list_crawler = new ListCrawler(); 33 | list_crawler.on("progress", (current, total) => { 34 | spinner.text = `Fetching list: ${current} / ${total}`; 35 | }); 36 | const list = await list_crawler.crawl(); 37 | 38 | spinner.text = "Fetching details"; 39 | const detail_crawler = new DetailCrawler( 40 | list.filter( 41 | (item) => 42 | !item.r18 && 43 | !item.premium && 44 | ((item.date.year === year && item.date.month <= month) || 45 | item.date.year < year), 46 | ), 47 | ); 48 | detail_crawler.on("progress", (current, total) => { 49 | spinner.text = `Fetching details: ${current} / ${total}`; 50 | }); 51 | const details = (await detail_crawler.crawl()).sort( 52 | (a, b) => b.date.year - a.date.year || b.date.month - a.date.month, 53 | ); 54 | fs.writeFileSync( 55 | CACHE_FILE, 56 | JSON.stringify( 57 | details 58 | .map((item) => Object.values(item.episodes)) 59 | .flat() 60 | .slice(0, limit), 61 | ), 62 | ); 63 | spinner.succeed("Done"); 64 | } 65 | 66 | const details = JSON.parse(fs.readFileSync(CACHE_FILE, "utf-8")) as number[]; 67 | 68 | return details.map((sn) => ({ sn: sn.toString() })); 69 | } 70 | 71 | export async function create_series_list(sn: string): Promise<{ sn: string }[]> { 72 | const anime = new Anime(+sn); 73 | const episodes = Object.values(await anime.episodes()).flat(); 74 | return episodes.map(({ sn }) => ({ sn: sn.toString() })); 75 | } 76 | 77 | export interface IndexData { 78 | data: { 79 | announce: string; 80 | newAnime: NewAnime; 81 | newAnimeSchedule: NewAnimeSchedule; 82 | aniChannel: AniChannel[]; 83 | hotAnime: HotAnime[]; 84 | newAdded: NewAdded[]; 85 | category: Category[]; 86 | gnnList: GnnList[]; 87 | forumList: ForumList[]; 88 | ad: unknown[]; 89 | lastAniUpTime: number; 90 | }; 91 | } 92 | 93 | export interface NewAnime { 94 | date: Date[]; 95 | popular: Popular[]; 96 | } 97 | 98 | export interface Date { 99 | acgSn: string; 100 | videoSn: string; 101 | animeSn: string; 102 | title: string; 103 | dcC1: string; 104 | dcC2: string; 105 | week: string; 106 | favorite: boolean; 107 | cover: string; 108 | upTime: string; 109 | upTimeHours: string; 110 | volume: string; 111 | popular: string; 112 | highlightTag: HighlightTag; 113 | } 114 | 115 | export interface HighlightTag { 116 | bilingual: boolean; 117 | edition: string; 118 | vipTime: string; 119 | } 120 | 121 | export interface Popular { 122 | acgSn: string; 123 | videoSn: string; 124 | animeSn: string; 125 | title: string; 126 | dcC1: string; 127 | dcC2: string; 128 | week: string; 129 | favorite: boolean; 130 | cover: string; 131 | upTime: string; 132 | upTimeHours: string; 133 | volume: string; 134 | popular: string; 135 | highlightTag: HighlightTag; 136 | } 137 | 138 | export interface NewAnimeSchedule { 139 | "1": DailySchedule[]; 140 | "2": DailySchedule[]; 141 | "3": DailySchedule[]; 142 | "4": DailySchedule[]; 143 | "5": DailySchedule[]; 144 | "6": DailySchedule[]; 145 | "7": DailySchedule[]; 146 | } 147 | 148 | export interface DailySchedule { 149 | videoSn: string; 150 | title: string; 151 | scheduleTime: string; 152 | volumeString: string; 153 | } 154 | 155 | export interface AniChannel { 156 | title: string; 157 | status: number; 158 | uploadTime: string; 159 | img: string; 160 | } 161 | 162 | export interface HotAnime { 163 | acgSn: string; 164 | animeSn: string; 165 | title: string; 166 | dcC1: string; 167 | dcC2: string; 168 | favorite: boolean; 169 | flag: string; 170 | cover: string; 171 | info: string; 172 | popular: string; 173 | highlightTag: HighlightTag; 174 | } 175 | 176 | export interface HighlightTag { 177 | bilingual: boolean; 178 | edition: string; 179 | vipTime: string; 180 | } 181 | 182 | export interface NewAdded { 183 | acgSn: string; 184 | animeSn: string; 185 | title: string; 186 | dcC1: string; 187 | dcC2: string; 188 | favorite: boolean; 189 | flag: string; 190 | cover: string; 191 | info: string; 192 | popular: string; 193 | highlightTag: HighlightTag; 194 | } 195 | 196 | export interface Category { 197 | title: string; 198 | intro: string; 199 | list: List[]; 200 | } 201 | 202 | export interface List { 203 | acgSn: string; 204 | animeSn: string; 205 | videoSn: string; 206 | title: string; 207 | dcC1: string; 208 | dcC2: string; 209 | favorite: boolean; 210 | flag: string; 211 | cover: string; 212 | info: string; 213 | popular: string; 214 | highlightTag: HighlightTag; 215 | } 216 | 217 | export interface GnnList { 218 | url: string; 219 | title: string; 220 | pic: string; 221 | } 222 | 223 | export interface ForumList { 224 | url: string; 225 | title: string; 226 | pic: string; 227 | } 228 | -------------------------------------------------------------------------------- /packages/marker/src/marker.ts: -------------------------------------------------------------------------------- 1 | import { AnimeDetailInfo, DetailCrawler, RateLimiter } from "baha-anime-crawler"; 2 | import { Downloader, default_config } from "baha-anime-dl"; 3 | import { merge } from "baha-anime-dl-ext"; 4 | import debug from "debug"; 5 | import { partition } from "lcsb"; 6 | import { exec } from "node:child_process"; 7 | import fs from "node:fs"; 8 | import os from "node:os"; 9 | import path from "node:path"; 10 | 11 | debug.enable("baha-anime-dl*"); 12 | 13 | export async function marker( 14 | sn: string[], 15 | { 16 | pool = 4800, 17 | lower = 75, 18 | upper = 95, 19 | before = 6 * 60, 20 | after = 0 * 60, 21 | concurrency = os.cpus().length, 22 | keep = false, 23 | ref = false, 24 | raise = false, 25 | chapter = "OP", 26 | priority = 1, 27 | }: { 28 | ref?: boolean; 29 | pool?: number; 30 | lower?: number; 31 | upper?: number; 32 | before?: number; 33 | after?: number; 34 | concurrency?: number; 35 | keep?: boolean; 36 | raise?: boolean; 37 | chapter?: string; 38 | priority?: 1 | 2; 39 | } = {}, 40 | ): Promise>> { 41 | if (sn.length === 0) { 42 | console.log("Too few arguments"); 43 | process.exit(1); 44 | } 45 | 46 | const sn_list = ref ? await get_sn(sn[0]) : sn.map((item) => +item); 47 | sn_list.sort((a, b) => a - b); 48 | const limiter = new RateLimiter({ concurrent: concurrency }); 49 | 50 | const temp = path.join(os.tmpdir(), "waves-tmp"); 51 | if (!fs.existsSync(temp)) { 52 | fs.mkdirSync(temp, { recursive: true }); 53 | } 54 | 55 | await Promise.all( 56 | sn_list.map(async (sn) => { 57 | await limiter.lock(); 58 | try { 59 | await download(sn, temp, keep); 60 | } catch { 61 | limiter.unlock(); 62 | if (raise) { 63 | throw new Error("Failed to download"); 64 | } 65 | } 66 | limiter.unlock(); 67 | }), 68 | ); 69 | 70 | const availables = sn_list.filter((sn) => fs.existsSync(path.join(temp, `${sn}.wav`))); 71 | const waves = availables.sort((a, b) => a - b).map((sn) => `${sn}.wav`); 72 | const blocks = waves 73 | .map((file) => fs.readFileSync(path.join(temp, file))) 74 | .map((buffer) => 75 | partition(buffer, { pool, lower, upper }) 76 | .filter((b) => b.start < before && b.end > after) 77 | .map((b) => { 78 | b.duration = +b.duration.toFixed(2); 79 | return b; 80 | }), 81 | ); 82 | 83 | for (let i = 0; i < blocks.length; i++) { 84 | console.log(`${availables[i]} ${JSON.stringify(blocks[i])}`); 85 | } 86 | 87 | const result = availables.reduce( 88 | (dict, sn, idx) => { 89 | if (priority === 2) { 90 | blocks.reverse(); 91 | } 92 | 93 | const block = blocks[idx].find( 94 | (b) => 95 | b.start < before && b.end > after && b.duration >= lower && b.duration <= upper, 96 | ); 97 | if (block) { 98 | dict[sn] = { 99 | [chapter]: [+block.start.toFixed(2), +block.duration.toFixed(2)], 100 | }; 101 | } 102 | return dict; 103 | }, 104 | {} as Record>, 105 | ); 106 | 107 | waves.forEach((wav) => (keep ? null : fs.rmSync(path.join(temp, wav), { recursive: true }))); 108 | 109 | return result; 110 | } 111 | 112 | async function get_sn(ref: string) { 113 | const crawler = new DetailCrawler([{ ref: +ref } as AnimeDetailInfo]); 114 | const db = await crawler.crawl(); 115 | 116 | const target = db.find((item) => item.ref === +ref); 117 | if (!target) { 118 | throw new Error("Not found"); 119 | } 120 | 121 | return Object.values(target.episodes); 122 | } 123 | 124 | async function download(sn: number, dir: string, keep: boolean) { 125 | const tmp = path.join(dir, sn.toString()); 126 | const mp4 = path.join(tmp, `${sn}.mp4`); 127 | const wav = path.join(dir, `${sn}.wav`); 128 | 129 | fs.mkdirSync(tmp, { recursive: true }); 130 | 131 | if (!fs.existsSync(mp4)) { 132 | const downloader = new Downloader({ 133 | ...default_config(), 134 | concurrency: 2, 135 | }); 136 | await downloader.init(); 137 | 138 | const download = downloader.download(sn); 139 | download.meta.catch(() => {}); 140 | const merged = await merge(download); 141 | 142 | fs.writeFileSync(mp4, Buffer.from(merged)); 143 | } 144 | 145 | if (!fs.existsSync(wav) && fs.existsSync(mp4)) { 146 | const ffmpeg_cmd = `ffmpeg -i ${mp4} -acodec pcm_s16le -ac 1 ${wav}`; 147 | const ffmpeg_process = exec(ffmpeg_cmd, (error, stdout, stderr) => { 148 | if (error) { 149 | console.error(`exec error: ${error}`); 150 | return; 151 | } 152 | console.log(`stdout: ${stdout}`); 153 | console.error(`stderr: ${stderr}`); 154 | }); 155 | 156 | await new Promise((resolve) => { 157 | ffmpeg_process.on("exit", resolve); 158 | }); 159 | } 160 | 161 | if (!keep) { 162 | fs.rmSync(tmp, { recursive: true }); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /packages/marker/src/run.ts: -------------------------------------------------------------------------------- 1 | import { RateLimiter } from "baha-anime-crawler"; 2 | import fs from "node:fs"; 3 | import { failed_cache, no_matched_cache } from "./cache"; 4 | import { FILE, data } from "./data"; 5 | import { marker } from "./marker"; 6 | import { Options } from "./types"; 7 | 8 | export async function run(items: { sn: string }[], opt: Options): Promise { 9 | const limiter = new RateLimiter({ concurrent: opt.concurrency }); 10 | 11 | let count = 0; 12 | const tasks: Promise[] = []; 13 | 14 | for (const item of items) { 15 | tasks.push( 16 | (async () => { 17 | await limiter.lock(); 18 | console.log(`start ${item.sn} ${opt.name}`); 19 | 20 | try { 21 | for (const pool of opt.pool) { 22 | const results = await marker([item.sn], { 23 | pool, 24 | lower: opt.lower, 25 | upper: opt.upper, 26 | after: opt.from, 27 | before: opt.to, 28 | keep: true, 29 | raise: true, 30 | chapter: opt.name, 31 | priority: opt.last ? 2 : 1, 32 | }); 33 | 34 | if (!results[item.sn] || Object.keys(results[item.sn]).length === 0) { 35 | if (pool === opt.pool[opt.pool.length - 1]) { 36 | if (!no_matched_cache[opt.name]) { 37 | no_matched_cache[opt.name] = []; 38 | } 39 | no_matched_cache[opt.name].push(item.sn); 40 | } 41 | continue; 42 | } 43 | 44 | console.log(`${item.sn} ${JSON.stringify(results)}`); 45 | 46 | for (const [name, result] of Object.entries(results[item.sn])) { 47 | if (!data[item.sn]) { 48 | data[item.sn] = {}; 49 | } 50 | data[item.sn][name] = result; 51 | } 52 | 53 | if (++count >= 5) { 54 | fs.writeFileSync(FILE, JSON.stringify(data)); 55 | count = 0; 56 | } 57 | 58 | if (opt.keep === false) { 59 | await marker([item.sn], { 60 | lower: 9999, 61 | after: 0, 62 | before: 0, 63 | keep: opt.keep, 64 | chapter: opt.name, 65 | }); 66 | } 67 | 68 | break; 69 | } 70 | } catch (err) { 71 | if (!failed_cache[opt.name]) { 72 | failed_cache[opt.name] = []; 73 | } 74 | failed_cache[opt.name].push(item.sn); 75 | console.error((err as Error).toString()); 76 | } 77 | 78 | limiter.unlock(); 79 | })(), 80 | ); 81 | } 82 | 83 | while ((await Promise.all(tasks)).length !== tasks.length) { 84 | // keep waiting for all tasks to finish 85 | } 86 | 87 | if (count > 0) { 88 | fs.writeFileSync(FILE, JSON.stringify(data)); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /packages/marker/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface Options { 2 | pool: number[]; 3 | from: number; 4 | to: number; 5 | lower: number; 6 | upper: number; 7 | concurrency: number; 8 | keep: boolean; 9 | name: string; 10 | last: boolean; 11 | } 12 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:base", ":preserveSemverRanges"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["lib", "src/_tests", "**/tsup.config.ts"], 3 | "compilerOptions": { 4 | "target": "es2020", 5 | "lib": ["es2020", "DOM"], 6 | "module": "ES2022", 7 | "moduleResolution": "node", 8 | "outDir": "./lib", 9 | "declaration": true, 10 | "resolveJsonModule": true, 11 | "noEmitOnError": true, 12 | "esModuleInterop": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "strict": true, 15 | "skipLibCheck": true 16 | } 17 | } 18 | --------------------------------------------------------------------------------