mirror of
https://github.com/FoxxMD/multi-scrobbler.git
synced 2026-09-03 05:10:00 +03:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f61988597a |
@@ -11,7 +11,7 @@ services:
|
||||
# context: .
|
||||
# dockerfile: .devcontainer/Dockerfile
|
||||
|
||||
image: mcr.microsoft.com/devcontainers/javascript-node:24-bookworm
|
||||
image: mcr.microsoft.com/devcontainers/javascript-node:1-20-bookworm
|
||||
|
||||
volumes:
|
||||
# Update this to wherever you want VS Code to mount the folder of your project
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"forwardPorts": [9078,3000],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": ".devcontainer/postCreate.sh",
|
||||
"postCreateCommand": "npm install",
|
||||
|
||||
// Configure tool-specific properties.
|
||||
"customizations": {
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo 'Adding node_modules to path'
|
||||
echo 'export PATH=/workspaces/node_modules/.bin:/workspaces/docsite/node_modules/.bin:$PATH' >> /home/node/.bashrc
|
||||
|
||||
echo 'Updating npm...'
|
||||
npm install -g npm@11.12.1
|
||||
|
||||
echo 'Installing concurrently...'
|
||||
npm install -g concurrently
|
||||
|
||||
echo 'If you have freshly cloned this project or node_modules folder does not exist then you should run "npm run install:parallel" now'
|
||||
+1
-3
@@ -30,6 +30,4 @@ tmp-*
|
||||
.env
|
||||
*.env
|
||||
.storybook
|
||||
.stories
|
||||
*.db
|
||||
*.db-*
|
||||
.stories
|
||||
@@ -1,19 +0,0 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm" # See documentation for possible values
|
||||
directories:
|
||||
- "/"
|
||||
- "/docsite"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "docker"
|
||||
# Look for a `Dockerfile` in the `root` directory
|
||||
directory: "/"
|
||||
# Check for updates once a week
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -151,6 +151,3 @@ tmp-*
|
||||
|
||||
*storybook.log
|
||||
storybook-static
|
||||
|
||||
*.db
|
||||
*.db-*
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"extends": "@istanbuljs/nyc-config-typescript",
|
||||
"exclude": [
|
||||
"node_modules/",
|
||||
"**/src/backend/common/schema/**",
|
||||
"**/src/backend/tests/**",
|
||||
"register.js",
|
||||
"**/src/server/**/*.d.ts",
|
||||
"**/src/client/**"
|
||||
],
|
||||
"include": [
|
||||
"**/src/backend/**/*.ts",
|
||||
"**/src/**/backend/*.js",
|
||||
"**/src/**/backend/*.js.map"
|
||||
],
|
||||
"extension": [
|
||||
".ts"
|
||||
],
|
||||
"reporter": [
|
||||
"text-summary",
|
||||
"html"
|
||||
],
|
||||
"report-dir": "./coverage"
|
||||
}
|
||||
+2
-2
@@ -9,10 +9,10 @@ export default defineMain({
|
||||
],
|
||||
"addons": [
|
||||
"@chromatic-com/storybook",
|
||||
// "@storybook/addon-vitest",
|
||||
"@storybook/addon-vitest",
|
||||
"@storybook/addon-a11y",
|
||||
"@storybook/addon-docs",
|
||||
// "@storybook/addon-onboarding"
|
||||
"@storybook/addon-onboarding"
|
||||
],
|
||||
features: {
|
||||
// https://github.com/storybookjs/storybook/discussions/33279
|
||||
|
||||
+1
-3
@@ -1,7 +1,7 @@
|
||||
FROM ghcr.io/linuxserver/baseimage-debian:bookworm AS base
|
||||
|
||||
ENV TZ=Etc/GMT
|
||||
ENV NODE_VERSION=24.14.0
|
||||
ENV NODE_VERSION=20.18.1
|
||||
|
||||
# borrowing openssl header removal trick from offical docker-node
|
||||
# https://github.com/nodejs/docker-node/blob/main/18/bookworm-slim/Dockerfile#L8
|
||||
@@ -49,8 +49,6 @@ RUN \
|
||||
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
RUN echo "Node: $(node -v)\nNPM: $(npm -v)"
|
||||
|
||||
RUN npm install -g concurrently
|
||||
|
||||
ARG data_dir=/config
|
||||
|
||||
Generated
+247
-264
@@ -40,7 +40,7 @@
|
||||
"typescript": "~5.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.18.1"
|
||||
"node": ">=18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/autocomplete-core": {
|
||||
@@ -6191,6 +6191,15 @@
|
||||
"node": ">=14.16"
|
||||
}
|
||||
},
|
||||
"node_modules/@trysound/sax": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
|
||||
"integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tybys/wasm-util": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz",
|
||||
@@ -6274,10 +6283,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"license": "MIT"
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="
|
||||
},
|
||||
"node_modules/@types/estree-jsx": {
|
||||
"version": "1.0.5",
|
||||
@@ -6785,10 +6793,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.16.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
|
||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||
"license": "MIT",
|
||||
"version": "8.14.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
||||
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -6796,18 +6803,6 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-import-phases": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
|
||||
"integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"acorn": "^8.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-jsx": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
||||
@@ -7210,18 +7205,6 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.10.13",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.13.tgz",
|
||||
"integrity": "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"baseline-browser-mapping": "dist/cli.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/batch": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
|
||||
@@ -7249,23 +7232,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.4",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz",
|
||||
"integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==",
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "~3.1.2",
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "~1.2.0",
|
||||
"http-errors": "~2.0.1",
|
||||
"iconv-lite": "~0.4.24",
|
||||
"on-finished": "~2.4.1",
|
||||
"qs": "~6.14.0",
|
||||
"raw-body": "~2.5.3",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.13.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "~1.0.0"
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
@@ -7334,10 +7317,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"license": "MIT",
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -7355,9 +7337,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.28.2",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
|
||||
"integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
|
||||
"version": "4.25.1",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz",
|
||||
"integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -7374,11 +7356,10 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.10.12",
|
||||
"caniuse-lite": "^1.0.30001782",
|
||||
"electron-to-chromium": "^1.5.328",
|
||||
"node-releases": "^2.0.36",
|
||||
"update-browserslist-db": "^1.2.3"
|
||||
"caniuse-lite": "^1.0.30001726",
|
||||
"electron-to-chromium": "^1.5.173",
|
||||
"node-releases": "^2.0.19",
|
||||
"update-browserslist-db": "^1.1.3"
|
||||
},
|
||||
"bin": {
|
||||
"browserslist": "cli.js"
|
||||
@@ -7519,9 +7500,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001782",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001782.tgz",
|
||||
"integrity": "sha512-dZcaJLJeDMh4rELYFw1tvSn1bhZWYFOt468FcbHHxx/Z/dFidd1I6ciyFdi3iwfQCyOjqo9upF6lGQYtMiJWxw==",
|
||||
"version": "1.0.30001727",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz",
|
||||
"integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -7943,16 +7924,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/compression": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
|
||||
"integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz",
|
||||
"integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"compressible": "~2.0.18",
|
||||
"debug": "2.6.9",
|
||||
"negotiator": "~0.6.4",
|
||||
"on-headers": "~1.1.0",
|
||||
"on-headers": "~1.0.2",
|
||||
"safe-buffer": "5.2.1",
|
||||
"vary": "~1.1.2"
|
||||
},
|
||||
@@ -8088,9 +8069,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
|
||||
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
@@ -9110,9 +9091,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.329",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.329.tgz",
|
||||
"integrity": "sha512-/4t+AS1l4S3ZC0Ja7PHFIWeBIxGA3QGqV8/yKsP36v7NcyUCl+bIcmw6s5zVuMIECWwBrAK/6QLzTmbJChBboQ==",
|
||||
"version": "1.5.182",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.182.tgz",
|
||||
"integrity": "sha512-Lv65Btwv9W4J9pyODI6EWpdnhfvrve/us5h1WspW8B2Fb0366REPtY3hX7ounk1CkV/TBjWCEvCBBbYbmV0qCA==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
@@ -9178,13 +9159,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.20.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz",
|
||||
"integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==",
|
||||
"license": "MIT",
|
||||
"version": "5.18.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz",
|
||||
"integrity": "sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.3.0"
|
||||
"tapable": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
@@ -9229,10 +9209,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
|
||||
"integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
|
||||
"license": "MIT"
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
|
||||
"integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ=="
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
@@ -9554,39 +9533,39 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
|
||||
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
|
||||
"version": "4.21.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "~1.20.3",
|
||||
"content-disposition": "~0.5.4",
|
||||
"body-parser": "1.20.3",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "~0.7.1",
|
||||
"cookie-signature": "~1.0.6",
|
||||
"cookie": "0.7.1",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "~1.3.1",
|
||||
"fresh": "~0.5.2",
|
||||
"http-errors": "~2.0.0",
|
||||
"finalhandler": "1.3.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"merge-descriptors": "1.0.3",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "~2.4.1",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "~0.1.12",
|
||||
"path-to-regexp": "0.1.12",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "~6.14.0",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "~0.19.0",
|
||||
"serve-static": "~1.16.2",
|
||||
"send": "0.19.0",
|
||||
"serve-static": "1.16.2",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "~2.0.1",
|
||||
"statuses": "2.0.1",
|
||||
"type-is": "~1.6.18",
|
||||
"utils-merge": "1.0.1",
|
||||
"vary": "~1.1.2"
|
||||
@@ -9627,9 +9606,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/express/node_modules/path-to-regexp": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz",
|
||||
"integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==",
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/express/node_modules/range-parser": {
|
||||
@@ -10143,8 +10122,7 @@
|
||||
"node_modules/glob-to-regexp": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
|
||||
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
|
||||
"license": "BSD-2-Clause"
|
||||
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
|
||||
},
|
||||
"node_modules/global-dirs": {
|
||||
"version": "3.0.1",
|
||||
@@ -10257,10 +10235,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/gray-matter/node_modules/js-yaml": {
|
||||
"version": "3.14.2",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||
"license": "MIT",
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
||||
"dependencies": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
@@ -10781,30 +10758,17 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/http-errors": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
|
||||
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
||||
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"depd": "~2.0.0",
|
||||
"inherits": "~2.0.4",
|
||||
"setprototypeof": "~1.2.0",
|
||||
"statuses": "~2.0.2",
|
||||
"toidentifier": "~1.0.1"
|
||||
"depd": "2.0.0",
|
||||
"inherits": "2.0.4",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"toidentifier": "1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/http-errors/node_modules/statuses": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
@@ -10937,9 +10901,9 @@
|
||||
"integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q=="
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz",
|
||||
"integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==",
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
|
||||
"integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/immutable-json-patch": {
|
||||
@@ -11418,10 +11382,9 @@
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||
"license": "MIT",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
@@ -11883,16 +11846,11 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loader-runner": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz",
|
||||
"integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==",
|
||||
"license": "MIT",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
|
||||
"integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
|
||||
"engines": {
|
||||
"node": ">=6.11.5"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/loader-utils": {
|
||||
@@ -11930,10 +11888,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.18.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.0.tgz",
|
||||
"integrity": "sha512-l1mfj2atMqndAHI3ls7XqPxEjV2J9ZkcNyHpoZA3r2T1LLwDB69jgkMWh71YKwhBbK0G2f4WSn05ahmQXVxupA==",
|
||||
"license": "MIT"
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.23",
|
||||
@@ -12413,10 +12370,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-to-hast": {
|
||||
"version": "13.2.1",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz",
|
||||
"integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",
|
||||
"license": "MIT",
|
||||
"version": "13.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz",
|
||||
"integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/mdast": "^4.0.0",
|
||||
@@ -14341,10 +14297,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"license": "ISC",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
@@ -14471,19 +14426,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-forge": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz",
|
||||
"integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
|
||||
"license": "(BSD-3-Clause OR GPL-2.0)",
|
||||
"engines": {
|
||||
"node": ">= 6.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.36",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz",
|
||||
"integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==",
|
||||
"license": "MIT"
|
||||
"version": "2.0.19",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
||||
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
@@ -14680,9 +14634,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/on-headers": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
|
||||
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
|
||||
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
@@ -15111,10 +15065,9 @@
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||
"license": "MIT",
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
@@ -16721,12 +16674,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
||||
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
@@ -16784,15 +16737,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.3",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz",
|
||||
"integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "~3.1.2",
|
||||
"http-errors": "~2.0.1",
|
||||
"iconv-lite": "~0.4.24",
|
||||
"unpipe": "~1.0.0"
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
@@ -17791,13 +17744,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz",
|
||||
"integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=11.0.0"
|
||||
}
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
|
||||
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.26.0",
|
||||
@@ -17812,10 +17762,9 @@
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/schema-utils": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
|
||||
"integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
|
||||
"license": "MIT",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
|
||||
"integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"ajv": "^8.9.0",
|
||||
@@ -17913,24 +17862,24 @@
|
||||
}
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
|
||||
"integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==",
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"encodeurl": "~2.0.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"fresh": "~0.5.2",
|
||||
"http-errors": "~2.0.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"mime": "1.6.0",
|
||||
"ms": "2.1.3",
|
||||
"on-finished": "~2.4.1",
|
||||
"on-finished": "2.4.1",
|
||||
"range-parser": "~1.2.1",
|
||||
"statuses": "~2.0.2"
|
||||
"statuses": "2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
@@ -17951,6 +17900,15 @@
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/send/node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
@@ -17960,15 +17918,6 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/statuses": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/serialize-javascript": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
||||
@@ -17978,15 +17927,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/serve-handler": {
|
||||
"version": "6.1.7",
|
||||
"resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.7.tgz",
|
||||
"integrity": "sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==",
|
||||
"version": "6.1.6",
|
||||
"resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz",
|
||||
"integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "3.0.0",
|
||||
"content-disposition": "0.5.2",
|
||||
"mime-types": "2.1.18",
|
||||
"minimatch": "3.1.5",
|
||||
"minimatch": "3.1.2",
|
||||
"path-is-inside": "1.0.2",
|
||||
"path-to-regexp": "3.3.0",
|
||||
"range-parser": "1.2.0"
|
||||
@@ -18077,15 +18026,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.16.3",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz",
|
||||
"integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==",
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "~0.19.1"
|
||||
"send": "0.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
@@ -18647,18 +18596,18 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/svgo": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz",
|
||||
"integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz",
|
||||
"integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@trysound/sax": "0.2.0",
|
||||
"commander": "^7.2.0",
|
||||
"css-select": "^5.1.0",
|
||||
"css-tree": "^2.3.1",
|
||||
"css-what": "^6.1.0",
|
||||
"csso": "^5.0.5",
|
||||
"picocolors": "^1.0.0",
|
||||
"sax": "^1.5.0"
|
||||
"picocolors": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"svgo": "bin/svgo"
|
||||
@@ -18700,16 +18649,11 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz",
|
||||
"integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==",
|
||||
"license": "MIT",
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
@@ -18730,14 +18674,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser-webpack-plugin": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz",
|
||||
"integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==",
|
||||
"license": "MIT",
|
||||
"version": "5.3.11",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz",
|
||||
"integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==",
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"jest-worker": "^27.4.5",
|
||||
"schema-utils": "^4.3.0",
|
||||
"serialize-javascript": "^6.0.2",
|
||||
"terser": "^5.31.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -18949,10 +18893,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.24.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz",
|
||||
"integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==",
|
||||
"license": "MIT",
|
||||
"version": "6.21.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz",
|
||||
"integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==",
|
||||
"engines": {
|
||||
"node": ">=18.17"
|
||||
}
|
||||
@@ -19137,9 +19080,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
|
||||
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
|
||||
"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -19522,10 +19465,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz",
|
||||
"integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==",
|
||||
"license": "MIT",
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
|
||||
"integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
|
||||
"dependencies": {
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.1.2"
|
||||
@@ -19554,36 +19496,33 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.105.4",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz",
|
||||
"integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==",
|
||||
"license": "MIT",
|
||||
"version": "5.97.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz",
|
||||
"integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.7",
|
||||
"@types/estree": "^1.0.8",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/estree": "^1.0.6",
|
||||
"@webassemblyjs/ast": "^1.14.1",
|
||||
"@webassemblyjs/wasm-edit": "^1.14.1",
|
||||
"@webassemblyjs/wasm-parser": "^1.14.1",
|
||||
"acorn": "^8.16.0",
|
||||
"acorn-import-phases": "^1.0.3",
|
||||
"browserslist": "^4.28.1",
|
||||
"acorn": "^8.14.0",
|
||||
"browserslist": "^4.24.0",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.20.0",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"enhanced-resolve": "^5.17.1",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.2.11",
|
||||
"json-parse-even-better-errors": "^2.3.1",
|
||||
"loader-runner": "^4.3.1",
|
||||
"loader-runner": "^4.2.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^4.3.3",
|
||||
"tapable": "^2.3.0",
|
||||
"terser-webpack-plugin": "^5.3.17",
|
||||
"watchpack": "^2.5.1",
|
||||
"webpack-sources": "^3.3.4"
|
||||
"schema-utils": "^3.2.0",
|
||||
"tapable": "^2.1.1",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"watchpack": "^2.4.1",
|
||||
"webpack-sources": "^3.2.3"
|
||||
},
|
||||
"bin": {
|
||||
"webpack": "bin/webpack.js"
|
||||
@@ -19784,14 +19723,41 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-sources": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz",
|
||||
"integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==",
|
||||
"license": "MIT",
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
||||
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||
"peerDependencies": {
|
||||
"ajv": "^6.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
},
|
||||
"node_modules/webpack/node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
@@ -19811,6 +19777,23 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/schema-utils": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
|
||||
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.8",
|
||||
"ajv": "^6.12.5",
|
||||
"ajv-keywords": "^3.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/webpackbar": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-6.0.1.tgz",
|
||||
@@ -20103,9 +20086,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
|
||||
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
|
||||
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.14.0",
|
||||
"npm": ">=11.12.1"
|
||||
"node": ">=18.0"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+8132
-1572
File diff suppressed because it is too large
Load Diff
+25
-18
@@ -33,8 +33,8 @@
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.14.0",
|
||||
"npm": ">=11.12.1"
|
||||
"node": ">=18.19.1",
|
||||
"npm": ">=9.1.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -79,12 +79,12 @@
|
||||
"@types/express-serve-static-core": "^4.19.6",
|
||||
"@xhayper/discord-rpc": "^1.3.0",
|
||||
"address": "^1.2.2",
|
||||
"ajv": "^8.18.0",
|
||||
"ajv": "^8.12.0",
|
||||
"ajv-formats": "^3.0.1",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"avahi-browse": "^1.1.4",
|
||||
"better-sse": "^0.8.0",
|
||||
"body-parser": "^2.2.2",
|
||||
"body-parser": "^1.19.0",
|
||||
"cacheable": "^1.10.4",
|
||||
"castv2": "^0.1.10",
|
||||
"clone": "^2.1.2",
|
||||
@@ -95,15 +95,15 @@
|
||||
"cors": "^2.8.5",
|
||||
"dayjs": "^1.10.4",
|
||||
"dbus-ts": "^0.0.7",
|
||||
"discord.js": "^14.26.0",
|
||||
"discord.js": "^14.25.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"express": "^4.22.1",
|
||||
"express-session": "^1.19.0",
|
||||
"express": "^4.17.1",
|
||||
"express-session": "^1.17.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fixed-size-list": "^0.3.0",
|
||||
"flat-cache": "^6.1.13",
|
||||
"formidable": "^3.5",
|
||||
"glob": "^11.1.0",
|
||||
"glob": "^11.0.0",
|
||||
"google-auth-library": "^9.15.0",
|
||||
"gotify": "^1.1.0",
|
||||
"http-cookie-agent": "^7.0.1",
|
||||
@@ -116,7 +116,6 @@
|
||||
"jsondiffpatch-react": "^1.0.8",
|
||||
"keyv": "^5.5.0",
|
||||
"kodi-api": "^0.2.1",
|
||||
"kysely-node-native-sqlite": "^1.1.0",
|
||||
"lastfm-ts-api": "^2.6.0",
|
||||
"merge-error-cause": "^5.0.2",
|
||||
"mopidy": "^1.3.0",
|
||||
@@ -126,20 +125,20 @@
|
||||
"next-themes": "^0.4.6",
|
||||
"node-object-hash": "^3.1.1",
|
||||
"normalize-url": "^8.0.1",
|
||||
"ntfy": "^1.15.2",
|
||||
"ntfy": "^1.7.6",
|
||||
"p-event": "^4.2.0",
|
||||
"p-map": "^7.0.4",
|
||||
"p-retry": "^7.1.1",
|
||||
"passport": "^0.6.0",
|
||||
"passport-deezer": "^0.2.0",
|
||||
"patch-package": "^8.0.1",
|
||||
"patch-package": "^8.0.0",
|
||||
"prom-client": "^15.1.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^6.1.1",
|
||||
"react-icons": "^5.6.0",
|
||||
"react-redux": "^8.1.2",
|
||||
"react-router-dom": "^6.30.3",
|
||||
"react-router-dom": "^6.15.0",
|
||||
"react-virtuoso": "^4.18.3",
|
||||
"round-robin-js": "^3.0.10",
|
||||
"sass": "^1.93.3",
|
||||
@@ -154,11 +153,10 @@
|
||||
"tsx": "^4.7.0",
|
||||
"typeson": "^9.0.4",
|
||||
"typeson-registry": "^11.1.1",
|
||||
"undici": "7.24.6",
|
||||
"undici": "7.10.0",
|
||||
"vite-express": "^0.16.0",
|
||||
"vlc-client": "^1.1.1",
|
||||
"workmatic": "github:FoxxMD/workmatic#testDist",
|
||||
"xml2js": "0.6.2",
|
||||
"xml2js": "0.6.1",
|
||||
"youtubei.js": "^15.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -167,9 +165,15 @@
|
||||
"@eslint/js": "^8.56.0",
|
||||
"@faker-js/faker": "^9.0.1",
|
||||
"@gr2m/net-interceptor": "^1.0.0",
|
||||
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
||||
"@storybook/addon-a11y": "10.1.11",
|
||||
"@storybook/addon-docs": "10.1.11",
|
||||
"@storybook/addon-onboarding": "10.1.11",
|
||||
"@storybook/addon-vitest": "10.1.11",
|
||||
"@storybook/react-vite": "10.1.11",
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@tsconfig/node18": "^1.0.1",
|
||||
"@types/chai": "^4.3.0",
|
||||
"@types/chai-as-promised": "^7.1.5",
|
||||
@@ -183,7 +187,7 @@
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/jscodeshift": "^0.11.6",
|
||||
"@types/mocha": "^9.1.0",
|
||||
"@types/node": "^24.1.0",
|
||||
"@types/node": "^20.19.2",
|
||||
"@types/object-hash": "^3.0.0",
|
||||
"@types/passport": "^1.0.12",
|
||||
"@types/react": "^18.2.18",
|
||||
@@ -194,6 +198,8 @@
|
||||
"@types/superagent": "^8.1.9",
|
||||
"@types/xml2js": "^0.4.11",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"@vitest/browser-playwright": "^4.1.0",
|
||||
"@vitest/coverage-v8": "^4.1.0",
|
||||
"chai": "^4.3.6",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"eslint": "^8.56.0",
|
||||
@@ -207,11 +213,12 @@
|
||||
"nodemon": "^3.0.3",
|
||||
"playwright": "^1.58.2",
|
||||
"sinon": "^21.0.2",
|
||||
"storybook": "10.2.0",
|
||||
"storybook": "^10.2.0",
|
||||
"ts-essentials": "^10.1.1",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^7.0.1",
|
||||
"vite": "^5.4.21",
|
||||
"vite": "^5.2.12",
|
||||
"vitest": "^4.1.0",
|
||||
"with-local-tmp-dir": "^6.0.0"
|
||||
},
|
||||
"browserslist": {
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
diff --git a/node_modules/kysely-node-native-sqlite/dist/index.cjs b/node_modules/kysely-node-native-sqlite/dist/index.cjs
|
||||
index 1015da7..0679a95 100644
|
||||
--- a/node_modules/kysely-node-native-sqlite/dist/index.cjs
|
||||
+++ b/node_modules/kysely-node-native-sqlite/dist/index.cjs
|
||||
@@ -55,7 +55,11 @@ var import_node_sqlite = require("node:sqlite");
|
||||
var NodeNativeSqliteConnection = class {
|
||||
#db;
|
||||
constructor(...args) {
|
||||
- this.#db = new import_node_sqlite.DatabaseSync(...args);
|
||||
+ if (args[0] instanceof import_node_sqlite.DatabaseSync) {
|
||||
+ this.#db = args[0];
|
||||
+ } else {
|
||||
+ this.#db = new import_node_sqlite.DatabaseSync(...args);
|
||||
+ }
|
||||
}
|
||||
[Symbol.dispose]() {
|
||||
this.#db.close();
|
||||
diff --git a/node_modules/kysely-node-native-sqlite/dist/index.d.cts b/node_modules/kysely-node-native-sqlite/dist/index.d.cts
|
||||
index 72366bb..32e8464 100644
|
||||
--- a/node_modules/kysely-node-native-sqlite/dist/index.d.cts
|
||||
+++ b/node_modules/kysely-node-native-sqlite/dist/index.d.cts
|
||||
@@ -3,7 +3,7 @@ import { Dialect, SqliteAdapter, Driver, Kysely, DatabaseIntrospector, SqliteQue
|
||||
|
||||
declare class NodeNativeSqliteDialect implements Dialect {
|
||||
#private;
|
||||
- constructor(...args: ConstructorParameters<typeof DatabaseSync>);
|
||||
+ constructor(...args: ConstructorParameters<typeof DatabaseSync> | [DatabaseSync]);
|
||||
createAdapter(): SqliteAdapter;
|
||||
createDriver(): Driver;
|
||||
createIntrospector(db: Kysely<unknown>): DatabaseIntrospector;
|
||||
diff --git a/node_modules/kysely-node-native-sqlite/dist/index.d.ts b/node_modules/kysely-node-native-sqlite/dist/index.d.ts
|
||||
index 72366bb..32e8464 100644
|
||||
--- a/node_modules/kysely-node-native-sqlite/dist/index.d.ts
|
||||
+++ b/node_modules/kysely-node-native-sqlite/dist/index.d.ts
|
||||
@@ -3,7 +3,7 @@ import { Dialect, SqliteAdapter, Driver, Kysely, DatabaseIntrospector, SqliteQue
|
||||
|
||||
declare class NodeNativeSqliteDialect implements Dialect {
|
||||
#private;
|
||||
- constructor(...args: ConstructorParameters<typeof DatabaseSync>);
|
||||
+ constructor(...args: ConstructorParameters<typeof DatabaseSync> | [DatabaseSync]);
|
||||
createAdapter(): SqliteAdapter;
|
||||
createDriver(): Driver;
|
||||
createIntrospector(db: Kysely<unknown>): DatabaseIntrospector;
|
||||
diff --git a/node_modules/kysely-node-native-sqlite/dist/index.js b/node_modules/kysely-node-native-sqlite/dist/index.js
|
||||
index 8c2b8cf..17b7eb1 100644
|
||||
--- a/node_modules/kysely-node-native-sqlite/dist/index.js
|
||||
+++ b/node_modules/kysely-node-native-sqlite/dist/index.js
|
||||
@@ -32,7 +32,11 @@ import { DatabaseSync } from "node:sqlite";
|
||||
var NodeNativeSqliteConnection = class {
|
||||
#db;
|
||||
constructor(...args) {
|
||||
- this.#db = new DatabaseSync(...args);
|
||||
+ if (args[0] instanceof DatabaseSync) {
|
||||
+ this.#db = args[0];
|
||||
+ } else {
|
||||
+ this.#db = new DatabaseSync(...args);
|
||||
+ }
|
||||
}
|
||||
[Symbol.dispose]() {
|
||||
this.#db.close();
|
||||
@@ -1,20 +0,0 @@
|
||||
import { createDatabase, WorkmaticDb } from 'workmatic';
|
||||
import { DatabaseSync } from 'node:sqlite';
|
||||
import { configDir } from '../index.js';
|
||||
import * as path from 'path';
|
||||
|
||||
export const getJobsDb = (dbName: string = ':memory:'): [WorkmaticDb, DatabaseSync] => {
|
||||
let dbPath: string;
|
||||
if(dbName === ':memory') {
|
||||
dbPath = dbName;
|
||||
} else {
|
||||
dbPath = path.resolve(configDir, `${dbName}.db`);
|
||||
}
|
||||
|
||||
const database = new DatabaseSync(dbPath);
|
||||
const db = createDatabase({ db: database });
|
||||
database.exec(`CREATE INDEX IF NOT EXISTS playdate ON workmatic_jobs((payload->>'$.data.playDate'))`);
|
||||
database.exec(`CREATE INDEX IF NOT EXISTS seenAt ON workmatic_jobs((payload->>'$.meta.seenAt'))`);
|
||||
|
||||
return [db, database];
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { MusicBrainzApi } from 'musicbrainz-api';
|
||||
import { SourceType } from './config/source/sources.js';
|
||||
import { ClientType, clientTypes } from './config/client/clients.js';
|
||||
import assert, { AssertionError } from 'assert';
|
||||
import { SimpleError } from '../errors/MSErrors.js';
|
||||
|
||||
export const lowGranularitySources: SourceType[] = ['subsonic', 'ytmusic'];
|
||||
|
||||
@@ -268,7 +269,7 @@ export const asCacheConfig = (val: Record<string, any>): val is CacheConfigType
|
||||
if(asCacheConnectableConfig(val) || asCacheEphemeralConfig(val)) {
|
||||
return true;
|
||||
}
|
||||
throw new Error(`${val.provider} must have a connection property that is a string`);
|
||||
throw new SimpleError(`${val.provider} must have a connection property that is a string`);
|
||||
}
|
||||
export const asCacheMetadataProvider = (val: any): val is CacheScrobbleProvider => asCacheProvider(val);
|
||||
export type CacheScrobbleProvider = CacheProvider;
|
||||
|
||||
@@ -94,7 +94,6 @@ export default abstract class AbstractScrobbleClient extends AbstractComponent i
|
||||
|
||||
scrobbleDelay: number = 1000;
|
||||
scrobbleSleep: number = 2000;
|
||||
scrobbleWaitStopInterval: number = 2000;
|
||||
scrobbleRetries: number = 0;
|
||||
scrobbling: boolean = false;
|
||||
userScrobblingStopSignal: undefined | any;
|
||||
@@ -199,18 +198,6 @@ export default abstract class AbstractScrobbleClient extends AbstractComponent i
|
||||
this.existingScrobble = (playObjPre: PlayObject, existingScrobbles: PlayObject[], log?: boolean) => existingScrobble(playObjPre, existingScrobbles, existingScrobbleOpts, log);
|
||||
}
|
||||
|
||||
[Symbol.dispose]() {
|
||||
this.scheduler.stop();
|
||||
for(const job of this.scheduler.getAllJobs()) {
|
||||
this.scheduler.removeById(job.id);
|
||||
}
|
||||
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
this[Symbol.dispose]();
|
||||
await this.tryStopScrobbling();
|
||||
}
|
||||
|
||||
protected async postCache(): Promise<void> {
|
||||
await super.postCache();
|
||||
this.generateStaggerMappers();
|
||||
@@ -627,11 +614,11 @@ export default abstract class AbstractScrobbleClient extends AbstractComponent i
|
||||
return;
|
||||
}
|
||||
this.userScrobblingStopSignal = true;
|
||||
let timePasssed = 0;
|
||||
while(this.userScrobblingStopSignal !== undefined && timePasssed < (this.scrobbleWaitStopInterval * 10)) {
|
||||
await sleep(this.scrobbleWaitStopInterval);
|
||||
timePasssed += this.scrobbleWaitStopInterval;
|
||||
this.logger.verbose(`Waiting for scrobble processing stop signal to be acknowledged (waited ${timePasssed}ms)`);
|
||||
let secsPassed = 0;
|
||||
while(this.userScrobblingStopSignal !== undefined && secsPassed < 10) {
|
||||
await sleep(2000);
|
||||
secsPassed += 2;
|
||||
this.logger.verbose(`Waiting for scrobble processing stop signal to be acknowledged (waited ${secsPassed}s)`);
|
||||
}
|
||||
if(this.userScrobblingStopSignal !== undefined) {
|
||||
this.logger.warn('Could not stop scrobble processing! Or signal was lost :(');
|
||||
|
||||
@@ -117,12 +117,6 @@ export default abstract class AbstractSource extends AbstractComponent implement
|
||||
this.discoveredCounter = getRoot().items.sourceMetics.discovered;
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
if(this.canPoll) {
|
||||
await this.tryStopPolling();
|
||||
}
|
||||
}
|
||||
|
||||
protected async postCache(): Promise<void> {
|
||||
await super.postCache();
|
||||
this.generateStaggerMappers();
|
||||
|
||||
@@ -71,25 +71,6 @@ export default class MemorySource extends AbstractSource {
|
||||
})));
|
||||
}
|
||||
|
||||
[Symbol.dispose]() {
|
||||
this.scheduler.stop();
|
||||
for(const job of this.scheduler.getAllJobs()) {
|
||||
this.scheduler.removeById(job.id);
|
||||
}
|
||||
for(const p of this.players.keys()) {
|
||||
this.deletePlayer(p);
|
||||
}
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await super[Symbol.asyncDispose]();
|
||||
this.scheduler.stop();
|
||||
for(const job of this.scheduler.getAllJobs()) {
|
||||
this.scheduler.removeById(job.id);
|
||||
}
|
||||
this[Symbol.dispose]();
|
||||
}
|
||||
|
||||
cleanupPlayers = () => {
|
||||
for (const key of this.players.keys()) {
|
||||
this.cleanupPlayer(key);
|
||||
@@ -207,8 +188,6 @@ export default class MemorySource extends AbstractSource {
|
||||
if(reason !== undefined) {
|
||||
this.players.get(id)?.logger.debug(reason);
|
||||
}
|
||||
using player = this.players.get(id);
|
||||
player[Symbol.dispose]();
|
||||
this.players.delete(id);
|
||||
this.playerState.delete(id);
|
||||
this.emitEvent('playerDelete', {platformId: id});
|
||||
|
||||
@@ -99,15 +99,6 @@ export abstract class AbstractPlayerState {
|
||||
this.stateIntervalOptions = {staleInterval, orphanedInterval: orphanedInterval};
|
||||
}
|
||||
|
||||
[Symbol.dispose]() {
|
||||
if(this.currentListenRange !== undefined) {
|
||||
this.currentListenRange[Symbol.dispose]();
|
||||
}
|
||||
for(const lr of this.listenRanges) {
|
||||
lr[Symbol.dispose]();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract newListenProgress(data?: Partial<PlayProgress>): ListenProgress;
|
||||
protected abstract newListenRange(start?: ListenProgress, end?: ListenProgress, options?: object): ListenRange;
|
||||
|
||||
|
||||
@@ -15,10 +15,6 @@ export abstract class ListenRange {
|
||||
this.end = e;
|
||||
}
|
||||
|
||||
[Symbol.dispose]() {
|
||||
|
||||
}
|
||||
|
||||
public abstract isPositional(): boolean;
|
||||
public abstract isInitial(): boolean;
|
||||
public abstract seeked(position?: number, reportedTS?: Dayjs): [boolean, Second?];
|
||||
@@ -104,11 +100,6 @@ export class ListenRangePositional extends ListenRange {
|
||||
this.finalized = false;
|
||||
}
|
||||
|
||||
[Symbol.dispose]() {
|
||||
super[Symbol.dispose]()
|
||||
this.rtPlayer[Symbol.dispose]();
|
||||
}
|
||||
|
||||
isPositional(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { Logger } from "@foxxmd/logging";
|
||||
import { CALCULATED_PLAYER_STATUSES, PlayPlatformId, REPORTED_PLAYER_STATUSES } from "../../common/infrastructure/Atomic.js";
|
||||
import { AbstractPlayerState, PlayerStateOptions } from "./AbstractPlayerState.js";
|
||||
import { PlayProgressPositional, Second } from "../../../core/Atomic.js";
|
||||
import { GenericPlayerState } from "./GenericPlayerState.js";
|
||||
import { GenericRealtimePlayer, RealtimePlayer } from "./RealtimePlayer.js";
|
||||
import { PlayProgress, PlayProgressPositional, Second } from "../../../core/Atomic.js";
|
||||
import { Dayjs } from "dayjs";
|
||||
import { ListenProgressPositional } from "./ListenProgress.js";
|
||||
import { ListenRangePositional } from "./ListenRange.js";
|
||||
import { ListenProgress, ListenProgressPositional } from "./ListenProgress.js";
|
||||
import { ListenRange, ListenRangePositional } from "./ListenRange.js";
|
||||
|
||||
export class PositionalPlayerState extends AbstractPlayerState {
|
||||
|
||||
|
||||
@@ -33,13 +33,6 @@ export abstract class RealtimePlayer {
|
||||
this.scheduler.stop();
|
||||
}
|
||||
|
||||
[Symbol.dispose]() {
|
||||
this.scheduler.stop();
|
||||
for(const job of this.scheduler.getAllJobs()) {
|
||||
this.scheduler.removeById(job.id);
|
||||
}
|
||||
}
|
||||
|
||||
public play(position?: number) {
|
||||
if (position !== undefined) {
|
||||
this.position = position;
|
||||
|
||||
+6
-3
@@ -4,8 +4,9 @@ import asPromised from 'chai-as-promised';
|
||||
import { after, before, describe, it } from 'mocha';
|
||||
import dayjs from "dayjs";
|
||||
import withLocalTmpDir from 'with-local-tmp-dir';
|
||||
import path from 'path';
|
||||
import { initFileCache, initMemoryCache, initValkeyCache, MSCache } from "../../common/Cache.js";
|
||||
import { generatePlays } from "../../../core/PlayTestUtils.js";
|
||||
import { generatePlay, generatePlayerStateData, generatePlays, normalizePlays } from "../../../core/PlayTestUtils.js";
|
||||
import { ListenProgressPositional, ListenProgressTS } from "../../sources/PlayerState/ListenProgress.js";
|
||||
import { isPortReachableConnect } from "../../utils/NetworkUtils.js";
|
||||
import { getRoot } from "../../ioc.js";
|
||||
@@ -164,7 +165,7 @@ describe('#Caching', function () {
|
||||
const root = getRoot();
|
||||
root.upsert({ cache: () => () => new MSCache(loggerTest, { scrobble: { provider: 'file', connection: process.cwd(), persistInterval: 100 } }) });
|
||||
|
||||
await using test = new TestScrobbler();
|
||||
const test = new TestScrobbler();
|
||||
await test.initialize();
|
||||
const plays = generatePlays(100);
|
||||
await test.queueScrobble(plays, 'testSource');
|
||||
@@ -173,11 +174,13 @@ describe('#Caching', function () {
|
||||
const dirContents = await promises.readdir('.');
|
||||
const hasCache = dirContents.some(x => x === 'ms-scrobble.cache');
|
||||
expect(hasCache).is.true;
|
||||
test.scheduler.stop();
|
||||
|
||||
await using newTest = new TestScrobbler();
|
||||
const newTest = new TestScrobbler();
|
||||
await newTest.initialize();
|
||||
expect(newTest.queuedScrobbles.length).to.eq(plays.length);
|
||||
expect(newTest.queuedScrobbles[0].play.data.track).to.eq(queued[0].data.track);
|
||||
newTest.scheduler.stop();
|
||||
|
||||
}, { unsafeCleanup: true });
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import chai, { assert, expect } from 'chai';
|
||||
import asPromised from 'chai-as-promised';
|
||||
import { after, before, describe, it } from 'mocha';
|
||||
import { createDatabase, createClient, createWorker } from 'workmatic';
|
||||
import { DatabaseSync } from 'node:sqlite';
|
||||
import { getJobsDb } from '../../common/database/JobDb.js';
|
||||
import { generatePlay } from '../../../core/PlayTestUtils.js';
|
||||
|
||||
chai.use(asPromised);
|
||||
|
||||
it('does stuff', async function () {
|
||||
|
||||
const [db, nodeDb] = getJobsDb(':memory:');
|
||||
const client = createClient({ db, queue: 'scrobble' });
|
||||
|
||||
const { id } = await client.add(generatePlay());
|
||||
console.log(`Job created: ${id}`);
|
||||
expect(true).to.eq(true);
|
||||
});
|
||||
@@ -21,7 +21,6 @@ export class TestScrobbler extends AbstractScrobbleClient {
|
||||
this.getScrobblesForTimeRange = async (_) => this.testRecentScrobbles;
|
||||
this.scrobbleDelay = 10;
|
||||
this.scrobbleSleep = 20;
|
||||
this.scrobbleWaitStopInterval = 20;
|
||||
}
|
||||
|
||||
doScrobble(playObj: PlayObject) {
|
||||
|
||||
@@ -50,6 +50,8 @@ const generateTestScrobbler = () => {
|
||||
return testScrobbler;
|
||||
}
|
||||
|
||||
let testScrobbler: TestScrobbler = generateTestScrobbler()
|
||||
|
||||
describe('Networking', function () {
|
||||
|
||||
describe('Authentication', function () {
|
||||
@@ -116,9 +118,12 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
|
||||
describe('When scrobble is unique', function () {
|
||||
|
||||
beforeEach(function() {
|
||||
testScrobbler = generateTestScrobbler();
|
||||
});
|
||||
|
||||
it('It is not detected as duplicate when play date is newer than most recent', async function () {
|
||||
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
|
||||
const newScrobble = generatePlay({
|
||||
@@ -131,7 +136,6 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
|
||||
it('It is not detected as duplicate when play date is close to an existing scrobble', async function () {
|
||||
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
|
||||
const newScrobble = generatePlay({
|
||||
@@ -143,7 +147,6 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
|
||||
it('It handles unique detection when no existing scrobble matches above a score of 0', async function () {
|
||||
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
|
||||
const uniquePlay = generatePlay({
|
||||
@@ -162,9 +165,12 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
|
||||
describe('When scrobble track/artist/album matches existing but is a new scrobble', function () {
|
||||
|
||||
beforeEach(function() {
|
||||
testScrobbler = generateTestScrobbler();
|
||||
});
|
||||
|
||||
it('Is not detected as duplicate when artist is same, time is similar, but track is different', async function () {
|
||||
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
|
||||
const diffPlay = clone(normalizedWithMixedDur[1]);
|
||||
@@ -176,7 +182,6 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
|
||||
it('Is not detected as duplicate when track is same, time is similar, but artist is different', async function () {
|
||||
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
|
||||
const diffPlay = clone(normalizedWithMixedDur[1]);
|
||||
@@ -189,7 +194,6 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
|
||||
it('Is not detected as duplicate when play date is different by more than 10 seconds (high granularity source)', async function () {
|
||||
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
|
||||
const timeOffPos = clone(normalizedWithMixedDur[normalizedWithMixedDur.length - 1]);
|
||||
@@ -208,7 +212,6 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
initialDate: firstPlayDate,
|
||||
defaultMeta: {source: 'subsonic'}
|
||||
});
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = recent;
|
||||
|
||||
const timeOffPos = clone(recent[recent.length - 1]);
|
||||
@@ -223,9 +226,12 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
|
||||
describe('When existing has duration', function () {
|
||||
|
||||
beforeEach(function() {
|
||||
testScrobbler = generateTestScrobbler();
|
||||
});
|
||||
|
||||
it('A track with continuity to the previous track is not detected as a duplicate', async function () {
|
||||
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithDur;
|
||||
|
||||
const brickPt1 = normalizedWithDur.find(x => x.data.track.includes('Another Brick'));
|
||||
@@ -255,7 +261,6 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
initialDate: firstPlayDate,
|
||||
defaultMeta: {source: 'jellyfin'}
|
||||
});
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = recent;
|
||||
|
||||
const repeatPlay = clone(recent[recent.length - 1]);
|
||||
@@ -276,7 +281,6 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
playDate: dayjs().subtract(179, 's'),
|
||||
duration: 179
|
||||
});
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = [play];
|
||||
|
||||
const newPlay = clone(play);
|
||||
@@ -292,14 +296,16 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
|
||||
describe('When scrobble is a duplicate (title/artists/album)', function () {
|
||||
|
||||
beforeEach(function() {
|
||||
testScrobbler = generateTestScrobbler();
|
||||
});
|
||||
|
||||
it('Is detected as duplicate when an exact match', async function () {
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
assert.isTrue((await testScrobbler.alreadyScrobbled(normalizedWithMixedDur[normalizedWithMixedDur.length - 1]))[0]);
|
||||
});
|
||||
|
||||
it('Is detected as duplicate when artist/title differences are whitespace or case', async function () {
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
const ref = normalizedWithMixedDur[3];
|
||||
|
||||
@@ -324,7 +330,6 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
});
|
||||
|
||||
it('Is detected as duplicate when artist/title differences are from unicode normalization', async function () {
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
const ref = normalizedWithMixedDur.find(x => x.data.track === 'Jimbó');
|
||||
|
||||
@@ -336,7 +341,6 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
|
||||
it('Is detected as duplicate when play date is off by 10 seconds or less (high granularity source)', async function () {
|
||||
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
|
||||
const timeOffPos = clone(normalizedWithMixedDur[normalizedWithMixedDur.length - 1]);
|
||||
@@ -366,7 +370,6 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
initialDate: firstPlayDate,
|
||||
defaultMeta: {source: 'subsonic'}
|
||||
});
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = recent;
|
||||
|
||||
const timeOffPos = clone(recent[recent.length - 1]);
|
||||
@@ -380,7 +383,6 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
});
|
||||
|
||||
it('Is detected as duplicate when title is exact, artist is similar, and time is similar', async function () {
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
const ref = normalizedWithMixedDur[3];
|
||||
|
||||
@@ -425,7 +427,7 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
lifecycle: defaultLifecycle()
|
||||
}
|
||||
}
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDurOlder.concat(ref);
|
||||
|
||||
assert.isTrue((await testScrobbler.alreadyScrobbled(spotifyPlay))[0]);
|
||||
@@ -433,9 +435,12 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
|
||||
describe('When at least one play has duration', function () {
|
||||
|
||||
beforeEach(function() {
|
||||
testScrobbler = generateTestScrobbler();
|
||||
});
|
||||
|
||||
it('Is detected as duplicate when play date is close to the end of an existing scrobble', async function () {
|
||||
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithDur;
|
||||
|
||||
const timeEnd = clone(normalizedWithDur[normalizedWithMixedDur.length - 2]);
|
||||
@@ -460,13 +465,16 @@ describe('Detects duplicate and unique scrobbles from client recent history', fu
|
||||
|
||||
describe('Detects duplicate and unique scrobbles using actively tracked scrobbles', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
});
|
||||
|
||||
it('Detects a unique play', async function() {
|
||||
const newScrobble = generatePlay({
|
||||
playDate: normalizedWithMixedDur[normalizedWithMixedDur.length - 3].data.playDate.add(3, 'seconds')
|
||||
});
|
||||
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
const [matchedPlay, matchedData] = await testScrobbler.findExistingSubmittedPlayObj(newScrobble);
|
||||
|
||||
assert.isUndefined(matchedPlay);
|
||||
@@ -477,8 +485,6 @@ describe('Detects duplicate and unique scrobbles using actively tracked scrobble
|
||||
const newScrobble = generatePlay({
|
||||
playDate: normalizedWithMixedDur[normalizedWithMixedDur.length - 3].data.playDate.add(3, 'seconds')
|
||||
});
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
testScrobbler.addScrobbledTrack(newScrobble, newScrobble);
|
||||
|
||||
const [matchedPlay, matchedData] = await testScrobbler.findExistingSubmittedPlayObj(newScrobble);
|
||||
@@ -491,8 +497,6 @@ describe('Detects duplicate and unique scrobbles using actively tracked scrobble
|
||||
const newScrobble = generatePlay({
|
||||
playDate: normalizedWithMixedDur[normalizedWithMixedDur.length - 3].data.playDate.add(3, 'seconds')
|
||||
});
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
testScrobbler.addScrobbledTrack(newScrobble, newScrobble);
|
||||
|
||||
const dupScrobble = clone(newScrobble);
|
||||
@@ -515,7 +519,7 @@ describe('Upstream Scrobbles', function() {
|
||||
|
||||
it('Calls timerange func to get SOT scrobbles when none exists', async function() {
|
||||
const existingPlays = normalizePlays(generatePlays(3), {initialDate: dayjs().subtract(1, 'hour')});
|
||||
await using scrobbler = generateTestScrobbler();
|
||||
const scrobbler = generateTestScrobbler();
|
||||
scrobbler.testRecentScrobbles = [];
|
||||
await scrobbler.tryInitialize();
|
||||
scrobbler.testRecentScrobbles = existingPlays;
|
||||
@@ -529,12 +533,11 @@ describe('Upstream Scrobbles', function() {
|
||||
await emptied;
|
||||
scrobbler.tryStopScrobbling().then(() => null);
|
||||
expect(sp.called).is.true;
|
||||
return;
|
||||
});
|
||||
|
||||
it('Uses cached timerange for closely grouped scrobbles', async function() {
|
||||
const existingPlays = normalizePlays(generatePlays(3), {initialDate: dayjs().subtract(1, 'hour')});
|
||||
await using scrobbler = generateTestScrobbler();
|
||||
const scrobbler = generateTestScrobbler();
|
||||
scrobbler.testRecentScrobbles = [];
|
||||
await scrobbler.tryInitialize();
|
||||
scrobbler.testRecentScrobbles = existingPlays;
|
||||
@@ -549,12 +552,11 @@ describe('Upstream Scrobbles', function() {
|
||||
await emptied;
|
||||
scrobbler.tryStopScrobbling().then(() => null);
|
||||
expect(sp.callCount).to.eq(1);
|
||||
return;
|
||||
});
|
||||
|
||||
it('Uses separate timerange calls when scrobbles are not closely grouped', async function() {
|
||||
const existingPlays = normalizePlays(generatePlays(3), {initialDate: dayjs().subtract(1, 'hour')});
|
||||
await using scrobbler = generateTestScrobbler();
|
||||
const scrobbler = generateTestScrobbler();
|
||||
scrobbler.testRecentScrobbles = [];
|
||||
await scrobbler.tryInitialize();
|
||||
scrobbler.testRecentScrobbles = existingPlays;
|
||||
@@ -570,12 +572,11 @@ describe('Upstream Scrobbles', function() {
|
||||
await emptied;
|
||||
scrobbler.tryStopScrobbling().then(() => null);
|
||||
expect(sp.callCount).to.eq(2);
|
||||
return;
|
||||
});
|
||||
|
||||
it('Gets fresh timerange if TTL of staleAfter has passed', async function() {
|
||||
const existingPlays = normalizePlays(generatePlays(3), {initialDate: dayjs().subtract(1, 'hour')});
|
||||
await using scrobbler = generateTestScrobbler();
|
||||
const scrobbler = generateTestScrobbler();
|
||||
scrobbler.testRecentScrobbles = [];
|
||||
await scrobbler.tryInitialize();
|
||||
scrobbler.testRecentScrobbles = existingPlays;
|
||||
@@ -596,7 +597,6 @@ describe('Upstream Scrobbles', function() {
|
||||
await emptied2;
|
||||
scrobbler.tryStopScrobbling().then(() => null);
|
||||
expect(sp.calledTwice).is.true;
|
||||
return;
|
||||
});
|
||||
|
||||
});
|
||||
@@ -604,7 +604,7 @@ describe('Upstream Scrobbles', function() {
|
||||
describe('Dead Scrobbles', function() {
|
||||
|
||||
it('Processes all dead scrobbles', async function () {
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
testScrobbler = generateTestScrobbler();
|
||||
await testScrobbler.initialize();
|
||||
testScrobbler.testRecentScrobbles = [];
|
||||
|
||||
@@ -619,19 +619,21 @@ describe('Dead Scrobbles', function() {
|
||||
|
||||
});
|
||||
|
||||
const normalizedScrobbler = async () => {
|
||||
await using testScrobbler = generateTestScrobbler();
|
||||
await testScrobbler.initialize();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
testScrobbler.scrobbleSleep = 500;
|
||||
testScrobbler.scrobbleDelay = 0;
|
||||
//testScrobbler.lastScrobbleCheck = dayjs().subtract(60, 'seconds');
|
||||
testScrobbler.config.options = {};
|
||||
return testScrobbler;
|
||||
}
|
||||
|
||||
|
||||
describe('Scrobble client uses transform plays correctly', function() {
|
||||
|
||||
beforeEach(async function() {
|
||||
testScrobbler = generateTestScrobbler();
|
||||
await testScrobbler.initialize();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
testScrobbler.scrobbleSleep = 500;
|
||||
testScrobbler.scrobbleDelay = 0;
|
||||
//testScrobbler.lastScrobbleCheck = dayjs().subtract(60, 'seconds');
|
||||
testScrobbler.config.options = {};
|
||||
//testScrobbler.initScrobbleMonitoring().catch(console.error);
|
||||
});
|
||||
|
||||
// TODO need to find a better way to detect this
|
||||
// since we are now doing it in the processing loop instead of before queue
|
||||
|
||||
@@ -654,7 +656,6 @@ describe('Scrobble client uses transform plays correctly', function() {
|
||||
// });
|
||||
|
||||
it('Transforms play on scrobble when postCompare is present', async function() {
|
||||
await using testScrobbler = await normalizedScrobbler();
|
||||
testScrobbler.config.options = {
|
||||
playTransform: {
|
||||
postCompare: {
|
||||
@@ -678,7 +679,6 @@ describe('Scrobble client uses transform plays correctly', function() {
|
||||
});
|
||||
|
||||
it('Transforms candidate play on comparison', async function() {
|
||||
await using testScrobbler = await normalizedScrobbler();
|
||||
testScrobbler.config.options = {
|
||||
playTransform: {
|
||||
compare: {
|
||||
@@ -701,7 +701,6 @@ describe('Scrobble client uses transform plays correctly', function() {
|
||||
});
|
||||
|
||||
it('Transforms existing play on comparison', async function() {
|
||||
await using testScrobbler = await normalizedScrobbler();
|
||||
testScrobbler.config.options = {
|
||||
playTransform: {
|
||||
compare: {
|
||||
@@ -725,25 +724,24 @@ describe('Scrobble client uses transform plays correctly', function() {
|
||||
|
||||
afterEach(async function () {
|
||||
this.timeout(3500);
|
||||
//await testScrobbler.tryStopScrobbling()
|
||||
await testScrobbler.tryStopScrobbling()
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
const normalizedMonitoringScrobbler = async () => {
|
||||
const testScrobbler = generateTestScrobbler();
|
||||
await testScrobbler.initialize();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
testScrobbler.scrobbleSleep = 100;
|
||||
testScrobbler.scrobbleDelay = 0;
|
||||
testScrobbler.initScrobbleMonitoring().catch(console.error);
|
||||
return testScrobbler;
|
||||
}
|
||||
|
||||
describe('Manages scrobble queue', function() {
|
||||
|
||||
beforeEach(async function() {
|
||||
testScrobbler = generateTestScrobbler();
|
||||
await testScrobbler.initialize();
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
testScrobbler.testRecentScrobbles = normalizedWithMixedDur;
|
||||
testScrobbler.scrobbleSleep = 500;
|
||||
testScrobbler.scrobbleDelay = 0;
|
||||
testScrobbler.initScrobbleMonitoring().catch(console.error);
|
||||
});
|
||||
|
||||
it('Scrobbles a uniquely queued play', async function() {
|
||||
await using testScrobbler = await normalizedMonitoringScrobbler();
|
||||
const newScrobble = generatePlay({
|
||||
playDate: normalizedWithMixedDur[normalizedWithMixedDur.length - 3].data.playDate.add(3, 'seconds')
|
||||
});
|
||||
@@ -755,7 +753,6 @@ describe('Manages scrobble queue', function() {
|
||||
});
|
||||
|
||||
it('Does not Scrobble a duplicate play queued after original is scrobbled', async function() {
|
||||
await using testScrobbler = await normalizedMonitoringScrobbler();
|
||||
this.timeout(20000);
|
||||
|
||||
const newScrobble = generatePlay({
|
||||
@@ -777,7 +774,6 @@ describe('Manages scrobble queue', function() {
|
||||
});
|
||||
|
||||
it('Does not Scrobble a duplicate play queued before original is scrobbled', async function() {
|
||||
await using testScrobbler = await normalizedMonitoringScrobbler();
|
||||
this.timeout(3500);
|
||||
|
||||
const newScrobble = generatePlay({
|
||||
@@ -799,7 +795,6 @@ describe('Manages scrobble queue', function() {
|
||||
});
|
||||
|
||||
it('Delays scrobbles when many are queued', async function () {
|
||||
await using testScrobbler = await normalizedMonitoringScrobbler();
|
||||
this.timeout(3500);
|
||||
|
||||
const newScrobble1 = generatePlay({
|
||||
@@ -828,6 +823,7 @@ describe('Manages scrobble queue', function() {
|
||||
|
||||
after(async function () {
|
||||
this.timeout(3500);
|
||||
await testScrobbler.tryStopScrobbling()
|
||||
});
|
||||
});
|
||||
|
||||
@@ -837,7 +833,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('When no Now Playing exists, chooses play based on sorted platform id', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler();
|
||||
const npScrobbler = new NowPlayingScrobbler();
|
||||
await npScrobbler.initialize();
|
||||
|
||||
const firstPlatform: PlayPlatformId = ['aaa', 'NO_USER'];
|
||||
@@ -856,7 +852,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('When Now Playing platform does not exist in queued plays, chooses play based on sorted platform id', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler();
|
||||
const npScrobbler = new NowPlayingScrobbler();
|
||||
await npScrobbler.initialize();
|
||||
|
||||
const firstPlatform: PlayPlatformId = ['aaa', 'NO_USER'];
|
||||
@@ -877,7 +873,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('Chooses play based on existing Now Playing', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler();
|
||||
const npScrobbler = new NowPlayingScrobbler();
|
||||
await npScrobbler.initialize();
|
||||
|
||||
const firstPlatform: PlayPlatformId = ['aaa', 'NO_USER'];
|
||||
@@ -901,7 +897,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('Sorts Sources alphabetically when using default Source sorting', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler();
|
||||
const npScrobbler = new NowPlayingScrobbler();
|
||||
await npScrobbler.initialize();
|
||||
|
||||
const a = generateSourcePlayerObj({play:generatePlay({}, {deviceId: genGroupIdStr(generatePlayPlatformId())})});
|
||||
@@ -918,7 +914,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('Sorts Sources based on user config', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler({name: 'test', options: {nowPlaying: ['btest', 'atest']}});
|
||||
const npScrobbler = new NowPlayingScrobbler({name: 'test', options: {nowPlaying: ['btest', 'atest']}});
|
||||
await npScrobbler.initialize();
|
||||
|
||||
const a = generateSourcePlayerObj({play:generatePlay({}, {deviceId: genGroupIdStr(generatePlayPlatformId())})});
|
||||
@@ -935,7 +931,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('Does not report if source is not in user config', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler({name: 'test', options: {nowPlaying: ['btest', 'atest']}});
|
||||
const npScrobbler = new NowPlayingScrobbler({name: 'test', options: {nowPlaying: ['btest', 'atest']}});
|
||||
await npScrobbler.initialize();
|
||||
|
||||
const c = generateSourcePlayerObj({play:generatePlay({}, {deviceId: genGroupIdStr(generatePlayPlatformId())})});
|
||||
@@ -953,7 +949,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('Should update if no existing Now Playing', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler();
|
||||
const npScrobbler = new NowPlayingScrobbler();
|
||||
await npScrobbler.initialize();
|
||||
|
||||
const res = npScrobbler.shouldUpdatePlayingNow(generateSourcePlayerObj({play:generatePlay({}, {deviceId: genGroupIdStr(generatePlayPlatformId())})}));
|
||||
@@ -962,7 +958,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('Should update if previous Now Playing matches updated and last updated diff is greater than upper limit', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler();
|
||||
const npScrobbler = new NowPlayingScrobbler();
|
||||
await npScrobbler.initialize();
|
||||
|
||||
const lastUpdate = generateSourcePlayerObj({play:generatePlay({}, {deviceId: genGroupIdStr(generatePlayPlatformId())})});
|
||||
@@ -975,7 +971,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('Should NOT update if previous Now Playing matches updated and last updated diff is less than upper limit', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler();
|
||||
const npScrobbler = new NowPlayingScrobbler();
|
||||
await npScrobbler.initialize();
|
||||
|
||||
const lastUpdate = generateSourcePlayerObj({play:generatePlay({}, {deviceId: genGroupIdStr(generatePlayPlatformId())})});
|
||||
@@ -988,7 +984,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('Should update if previous Now Playing does NOT match updated and last updated diff is greater than lower limit', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler();
|
||||
const npScrobbler = new NowPlayingScrobbler();
|
||||
await npScrobbler.initialize();
|
||||
|
||||
const lastUpdate = generateSourcePlayerObj({play:generatePlay({}, {deviceId: genGroupIdStr(generatePlayPlatformId())})});
|
||||
@@ -1001,7 +997,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('Should NOT update if previous Now Playing does NOT match updated and last updated diff is less than than lower limit', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler();
|
||||
const npScrobbler = new NowPlayingScrobbler();
|
||||
await npScrobbler.initialize();
|
||||
|
||||
const lastUpdate = generateSourcePlayerObj({play:generatePlay({}, {deviceId: genGroupIdStr(generatePlayPlatformId())})});
|
||||
@@ -1022,7 +1018,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('Should update when no existing Now Playing', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler();
|
||||
const npScrobbler = new NowPlayingScrobbler();
|
||||
npScrobbler.nowPlayingTaskInterval = 10;
|
||||
await npScrobbler.initialize();
|
||||
npScrobbler.scheduler.startById('pn_task');
|
||||
@@ -1036,7 +1032,7 @@ describe('Now Playing', function() {
|
||||
|
||||
it('Should update when updated does not match Now Playing', async function () {
|
||||
|
||||
await using npScrobbler = new NowPlayingScrobbler();
|
||||
const npScrobbler = new NowPlayingScrobbler();
|
||||
npScrobbler.nowPlayingTaskInterval = 10;
|
||||
await npScrobbler.initialize();
|
||||
npScrobbler.scheduler.startById('pn_task');
|
||||
|
||||
@@ -27,6 +27,8 @@ const emitter = new EventEmitter();
|
||||
const generateSource = () => {
|
||||
return new TestSource('spotify', 'test', {}, {localUrl: new URL('https://example.com'), configDir: 'fake', logger: loggerTest, version: 'test'}, emitter);
|
||||
}
|
||||
let source: TestSource = generateSource();
|
||||
|
||||
const generateMemorySource = (config: SourceConfig = {}) => {
|
||||
const s = new TestMemorySource('spotify', 'test', config, {localUrl: new URL('https://example.com'), configDir: 'fake', logger: loggerTest, version: 'test'}, emitter);
|
||||
s.buildTransformRules();
|
||||
@@ -43,8 +45,11 @@ const generateMemoryPositionalSource = (config: SourceConfig = {}) => {
|
||||
|
||||
describe('Sources use transform plays correctly', function () {
|
||||
|
||||
beforeEach(function() {
|
||||
source = generateSource();
|
||||
});
|
||||
|
||||
it('Transforms play on preCompare', async function() {
|
||||
await using source = generateSource();
|
||||
source.config.options = {
|
||||
playTransform: {
|
||||
preCompare: {
|
||||
@@ -67,7 +72,6 @@ describe('Sources use transform plays correctly', function () {
|
||||
});
|
||||
|
||||
it('Transforms play on postCompare', async function() {
|
||||
await using source = generateSource();
|
||||
source.config.options = {
|
||||
playTransform: {
|
||||
postCompare: {
|
||||
@@ -96,7 +100,6 @@ describe('Sources use transform plays correctly', function () {
|
||||
});
|
||||
|
||||
it('Transforms play existing comparison', async function() {
|
||||
await using source = generateSource();
|
||||
source.config.options = {
|
||||
playTransform: {
|
||||
compare: {
|
||||
@@ -123,7 +126,6 @@ describe('Sources use transform plays correctly', function () {
|
||||
});
|
||||
|
||||
it('Transforms play candidate comparison', async function() {
|
||||
await using source = generateSource();
|
||||
source.config.options = {
|
||||
playTransform: {
|
||||
compare: {
|
||||
@@ -193,7 +195,7 @@ describe('Player Cleanup', function () {
|
||||
});
|
||||
|
||||
const cleanedUpDuration = async (generateSource: (config: SourceConfig) => MemorySource) => {
|
||||
await using source = generateSource({data: {staleAfter: 21, orphanedAfter: 40}, options: {}});
|
||||
const source = generateSource({data: {staleAfter: 21, orphanedAfter: 40}, options: {}});
|
||||
const initialDate = dayjs();
|
||||
const initialState = generatePlayerStateData({position: 0, playData: {duration: 50}, timestamp: initialDate, status: REPORTED_PLAYER_STATUSES.playing});
|
||||
expect((await source.processRecentPlays([initialState])).length).to.be.eq(0);
|
||||
@@ -237,7 +239,7 @@ describe('Player Cleanup', function () {
|
||||
|
||||
const noScrobbleRediscoveryOnActive = async (generateSource: (config: SourceConfig) => MemorySource) => {
|
||||
|
||||
await using source = generateSource({data: {staleAfter: 21, orphanedAfter: 40}, options: {}});
|
||||
const source = generateSource({data: {staleAfter: 21, orphanedAfter: 40}, options: {}});
|
||||
const initialDate = dayjs();
|
||||
const initialState = generatePlayerStateData({position: 0, playData: {duration: 50}, timestamp: initialDate, status: REPORTED_PLAYER_STATUSES.playing});
|
||||
expect((await source.processRecentPlays([initialState])).length).to.be.eq(0);
|
||||
@@ -305,7 +307,7 @@ describe('Player Cleanup', function () {
|
||||
|
||||
const noScrobbleStale = async (generateSource: (config: SourceConfig) => MemorySource) => {
|
||||
|
||||
await using source = generateSource({data: {staleAfter: 21, orphanedAfter: 40}, options: {}});
|
||||
const source = generateSource({data: {staleAfter: 21, orphanedAfter: 40}, options: {}});
|
||||
const initialDate = dayjs();
|
||||
|
||||
// if player incorrectly counted stale time then 30s of actual play + 20s of stale time > scrobble threshold of 50% of 90s
|
||||
@@ -350,7 +352,7 @@ describe('Player Cleanup', function () {
|
||||
|
||||
const scrobbleRediscoveryOnActive = async (generateSource: (config: SourceConfig) => MemorySource) => {
|
||||
|
||||
await using source = generateSource({data: {staleAfter: 21, orphanedAfter: 40}, options: {}});
|
||||
const source = generateSource({data: {staleAfter: 21, orphanedAfter: 40}, options: {}});
|
||||
const initialDate = dayjs();
|
||||
|
||||
// if player incorrectly counted stale time then 30s of actual play + 20s of stale time > scrobble threshold of 50% of 90s
|
||||
@@ -455,7 +457,7 @@ describe('Deezer Internal Source', function() {
|
||||
const fuzzyPlay = clone(targetPlay);
|
||||
fuzzyPlay.data.playDate = targetPlay.data.playDate.add(targetPlay.data.duration, 's');
|
||||
|
||||
await using source = generateDeezerSource({fuzzyDiscoveryIgnore: true});
|
||||
const source = generateDeezerSource({fuzzyDiscoveryIgnore: true});
|
||||
await source.discover([...normalizedPlays, interimPlay]);
|
||||
|
||||
const discovered = await source.discover([fuzzyPlay]);
|
||||
@@ -468,7 +470,7 @@ describe('Deezer Internal Source', function() {
|
||||
const fuzzyPlay = clone(targetPlay);
|
||||
fuzzyPlay.data.playDate = targetPlay.data.playDate.add(targetPlay.data.duration, 's');
|
||||
|
||||
await using source = generateDeezerSource({fuzzyDiscoveryIgnore: true});
|
||||
const source = generateDeezerSource({fuzzyDiscoveryIgnore: true});
|
||||
await source.discover(normalizedPlays);
|
||||
|
||||
const discovered = await source.discover([fuzzyPlay]);
|
||||
@@ -482,7 +484,7 @@ describe('Deezer Internal Source', function() {
|
||||
fuzzyPlay.data.playDate = targetPlay.data.playDate.add(targetPlay.data.duration, 's');
|
||||
const morePlays = normalizePlays([...normalizedPlays, fuzzyPlay, ...generatePlays(2)], {initialDate: firstPlayDate});
|
||||
|
||||
await using source = generateDeezerSource({fuzzyDiscoveryIgnore: true});
|
||||
const source = generateDeezerSource({fuzzyDiscoveryIgnore: true});
|
||||
const discovered = await source.discover(morePlays);
|
||||
|
||||
expect(discovered.length).to.eq(morePlays.length);
|
||||
@@ -497,7 +499,7 @@ describe('Deezer Internal Source', function() {
|
||||
const fuzzyPlay = clone(targetPlay);
|
||||
fuzzyPlay.data.playDate = targetPlay.data.playDate.add(targetPlay.data.duration, 's');
|
||||
|
||||
await using source = generateDeezerSource({fuzzyDiscoveryIgnore: 'aggressive'});
|
||||
const source = generateDeezerSource({fuzzyDiscoveryIgnore: 'aggressive'});
|
||||
await source.discover([...normalizedPlays, interimPlay]);
|
||||
|
||||
const discovered = await source.discover([fuzzyPlay]);
|
||||
@@ -511,7 +513,7 @@ describe('Deezer Internal Source', function() {
|
||||
const duringPlay = clone(targetPlay);
|
||||
duringPlay.data.playDate = targetPlay.data.playDate.add(targetPlay.data.duration * 0.5, 's');
|
||||
|
||||
await using source = generateDeezerSource({fuzzyDiscoveryIgnore: 'aggressive'});
|
||||
const source = generateDeezerSource({fuzzyDiscoveryIgnore: 'aggressive'});
|
||||
await source.discover([...normalizedPlays, interimPlay]);
|
||||
|
||||
const discovered = await source.discover([duringPlay]);
|
||||
@@ -525,7 +527,7 @@ describe('Deezer Internal Source', function() {
|
||||
const fuzzyPlay = clone(targetPlay);
|
||||
fuzzyPlay.data.playDate = targetPlay.data.playDate.add(targetPlay.data.duration + 39, 's');
|
||||
|
||||
await using source = generateDeezerSource({fuzzyDiscoveryIgnore: 'aggressive'});
|
||||
const source = generateDeezerSource({fuzzyDiscoveryIgnore: 'aggressive'});
|
||||
await source.discover([...normalizedPlays, interimPlay]);
|
||||
|
||||
const discovered = await source.discover([fuzzyPlay]);
|
||||
@@ -538,7 +540,7 @@ describe('Deezer Internal Source', function() {
|
||||
const fuzzyPlay = clone(targetPlay);
|
||||
fuzzyPlay.data.playDate = targetPlay.data.playDate.add(targetPlay.data.duration, 's');
|
||||
|
||||
await using source = generateDeezerSource({fuzzyDiscoveryIgnore: 'aggressive'});
|
||||
const source = generateDeezerSource({fuzzyDiscoveryIgnore: 'aggressive'});
|
||||
await source.discover(normalizedPlays);
|
||||
|
||||
const discovered = await source.discover([fuzzyPlay]);
|
||||
@@ -552,7 +554,7 @@ describe('Deezer Internal Source', function() {
|
||||
fuzzyPlay.data.playDate = targetPlay.data.playDate.add(targetPlay.data.duration, 's');
|
||||
const morePlays = normalizePlays([...normalizedPlays, fuzzyPlay, ...generatePlays(2)], {initialDate: firstPlayDate});
|
||||
|
||||
await using source = generateDeezerSource({fuzzyDiscoveryIgnore: 'aggressive'});
|
||||
const source = generateDeezerSource({fuzzyDiscoveryIgnore: 'aggressive'});
|
||||
const discovered = await source.discover(morePlays);
|
||||
|
||||
expect(discovered.length).to.eq(morePlays.length - 1);
|
||||
|
||||
@@ -20,11 +20,10 @@ export const createGetScrobblesForTimeRangeFunc = <T extends PaginatedTimeRangeS
|
||||
const logger = childLogger(pLogger, ['Pagination']);
|
||||
const reqLabel = () => `Request ${requestCount}`;
|
||||
const reqLogger = childLogger(logger, [reqLabel]);
|
||||
|
||||
let plays: PlayObject[] = [];
|
||||
|
||||
if (hasPagelessTimeRangeListens(fetcher)) {
|
||||
return async (opts: PaginatedTimeRangeCommonOptions): Promise<PlayObject[]> => {
|
||||
let plays: PlayObject[] = [];
|
||||
requestCount = 0;
|
||||
let more = true;
|
||||
let currOpts = { ...opts };
|
||||
@@ -108,6 +107,7 @@ export const createGetScrobblesForTimeRangeFunc = <T extends PaginatedTimeRangeS
|
||||
}
|
||||
} else if (hasPaginatedTimeRangeListens(fetcher)) {
|
||||
return async (opts: PaginatedListensTimeRangeOptions): Promise<PlayObject[]> => {
|
||||
let plays: PlayObject[] = [];
|
||||
requestCount = 0;
|
||||
let more = true;
|
||||
let currOpts: PaginatedListensTimeRangeOptions = opts;
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="@vitest/browser-playwright" />
|
||||
Reference in New Issue
Block a user