Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
7cdfa00af5
|
|||
35572a48e7
|
|||
3186f375e1
|
|||
3c1b7dba0e
|
|||
5591070979
|
|||
38e8b4c2ba
|
|||
260cef7b73
|
|||
c57f9ec3ea
|
|||
6874804703
|
@ -8,6 +8,7 @@ MASTODON_INSTANCE = 'metalhead.club'
|
||||
MASTODON_ACCESS_TOKEN = 'YOUR_ACCESS_TOKEN_HERE'
|
||||
BASE_URL = 'https://moshingmammut.phlaym.net'
|
||||
VERBOSE = false
|
||||
DEBUG_LOG = false
|
||||
IGNORE_USERS = @moshhead@metalhead.club
|
||||
WEBSUB_HUB = 'http://pubsubhubbub.superfeedr.com'
|
||||
|
||||
|
29
.eslintrc.cjs
Normal file
29
.eslintrc.cjs
Normal file
@ -0,0 +1,29 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
extends: ['plugin:svelte/recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
|
||||
plugins: ['@typescript-eslint'],
|
||||
ignorePatterns: ['*.cjs'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.svelte'],
|
||||
parser: 'svelte-eslint-parser',
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser'
|
||||
}
|
||||
}
|
||||
],
|
||||
settings: {
|
||||
'svelte3/typescript': () => require('typescript')
|
||||
},
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020,
|
||||
extraFileExtensions: ['.svelte']
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true
|
||||
}
|
||||
};
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,7 @@
|
||||
moshing-mammut.pid
|
||||
yt_auth_token
|
||||
spotify_auth_token
|
||||
tidal_auth_token
|
||||
*.db
|
||||
feed.xml
|
||||
playbook.yml
|
||||
|
@ -1,6 +1,5 @@
|
||||
{
|
||||
"apexskier.eslint.config.eslintConfigPath" : ".eslintrc.cjs",
|
||||
"apexskier.eslint.config.eslintPath" : "node_modules\/@eslint\/eslintrc\/dist\/eslintrc.cjs",
|
||||
"apexskier.eslint.config.eslintConfigPath" : ".eslint.cjs",
|
||||
"apexskier.eslint.config.fixOnSave" : "Enable",
|
||||
"apexskier.typescript.config.formatDocumentOnSave" : "false",
|
||||
"apexskier.typescript.config.isEnabledForJavascript" : "Enable",
|
||||
|
@ -1,14 +1,17 @@
|
||||
[Unit]
|
||||
Description=Moshing Mammut
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/home/moshing-mammut/app/start.sh
|
||||
Restart=always
|
||||
Restart=on-failure
|
||||
User=moshing-mammut
|
||||
Group=moshing-mammut
|
||||
Environment=PATH=/usr/bin:/usr/local/bin
|
||||
Environment=NODE_ENV=production
|
||||
WorkingDirectory=/home/moshing-mammut/app
|
||||
Type=forking
|
||||
PIDFile=/home/moshing-mammut/app/moshing-mammut.pid
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
457
package-lock.json
generated
457
package-lock.json
generated
@ -27,7 +27,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@zerodevx/svelte-toast": "^0.9.3",
|
||||
"eslint": "^9.11.1",
|
||||
"eslint": "^9.30.1",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-plugin-svelte": "^3.0.0",
|
||||
"globals": "^16.3.0",
|
||||
@ -36,8 +36,7 @@
|
||||
"svelte": "^5",
|
||||
"svelte-check": "^4.0.0",
|
||||
"tslib": "^2.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^6.0.0"
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
@ -80,6 +79,7 @@
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -97,6 +97,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -114,6 +115,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -131,6 +133,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -148,6 +151,7 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -165,6 +169,7 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -182,6 +187,7 @@
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -199,6 +205,7 @@
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -216,6 +223,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -233,6 +241,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -250,6 +259,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -267,6 +277,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -284,6 +295,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -301,6 +313,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -318,6 +331,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -335,6 +349,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -352,6 +367,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -369,6 +385,7 @@
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -386,6 +403,7 @@
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -403,6 +421,7 @@
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -420,6 +439,7 @@
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -437,6 +457,7 @@
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -454,6 +475,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -471,6 +493,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -488,6 +511,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@ -536,30 +560,6 @@
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array/node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-helpers": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz",
|
||||
@ -607,17 +607,6 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/globals": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||
@ -631,29 +620,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.30.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz",
|
||||
@ -1174,9 +1140,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.11",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.11.tgz",
|
||||
"integrity": "sha512-C512c1ytBTio4MrpWKlJpyFHT6+qfFL8SZ58zBzJ1OOzUEjHeF1BtjY2fH7n4x/g2OV/KiiMLAivOp1DXmiMMw==",
|
||||
"version": "0.3.12",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
|
||||
"integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1195,16 +1161,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.3.tgz",
|
||||
"integrity": "sha512-AiR5uKpFxP3PjO4R19kQGIMwxyRyPuXmKEEy301V1C0+1rVjS94EZQXf1QKZYN8Q0YM+estSPhmx5JwNftv6nw==",
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
|
||||
"integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.28",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.28.tgz",
|
||||
"integrity": "sha512-KNNHHwW3EIp4EDYOvYFGyIFfx36R2dNJYH4knnZlF8T5jdbD5Wx8xmSaQ2gP9URkJ04LGEtlcCtwArKcmFcwKw==",
|
||||
"version": "0.3.29",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz",
|
||||
"integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1380,9 +1346,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz",
|
||||
"integrity": "sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.2.tgz",
|
||||
"integrity": "sha512-g0dF8P1e2QYPOj1gu7s/3LVP6kze9A7m6x0BZ9iTdXK8N5c2V7cpBKHV3/9A4Zd8xxavdhK0t4PnqjkqVmUc9Q==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@ -1394,9 +1360,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.1.tgz",
|
||||
"integrity": "sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.2.tgz",
|
||||
"integrity": "sha512-Yt5MKrOosSbSaAK5Y4J+vSiID57sOvpBNBR6K7xAaQvk3MkcNVV0f9fE20T+41WYN8hDn6SGFlFrKudtx4EoxA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -1408,9 +1374,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.1.tgz",
|
||||
"integrity": "sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.2.tgz",
|
||||
"integrity": "sha512-EsnFot9ZieM35YNA26nhbLTJBHD0jTwWpPwmRVDzjylQT6gkar+zenfb8mHxWpRrbn+WytRRjE0WKsfaxBkVUA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -1422,9 +1388,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.1.tgz",
|
||||
"integrity": "sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.2.tgz",
|
||||
"integrity": "sha512-dv/t1t1RkCvJdWWxQ2lWOO+b7cMsVw5YFaS04oHpZRWehI1h0fV1gF4wgGCTyQHHjJDfbNpwOi6PXEafRBBezw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -1436,9 +1402,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.1.tgz",
|
||||
"integrity": "sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.2.tgz",
|
||||
"integrity": "sha512-W4tt4BLorKND4qeHElxDoim0+BsprFTwb+vriVQnFFtT/P6v/xO5I99xvYnVzKWrK6j7Hb0yp3x7V5LUbaeOMg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -1450,9 +1416,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.1.tgz",
|
||||
"integrity": "sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.2.tgz",
|
||||
"integrity": "sha512-tdT1PHopokkuBVyHjvYehnIe20fxibxFCEhQP/96MDSOcyjM/shlTkZZLOufV3qO6/FQOSiJTBebhVc12JyPTA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -1464,9 +1430,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.1.tgz",
|
||||
"integrity": "sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.2.tgz",
|
||||
"integrity": "sha512-+xmiDGGaSfIIOXMzkhJ++Oa0Gwvl9oXUeIiwarsdRXSe27HUIvjbSIpPxvnNsRebsNdUo7uAiQVgBD1hVriwSQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@ -1478,9 +1444,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.1.tgz",
|
||||
"integrity": "sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.2.tgz",
|
||||
"integrity": "sha512-bDHvhzOfORk3wt8yxIra8N4k/N0MnKInCW5OGZaeDYa/hMrdPaJzo7CSkjKZqX4JFUWjUGm88lI6QJLCM7lDrA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@ -1492,9 +1458,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.2.tgz",
|
||||
"integrity": "sha512-NMsDEsDiYghTbeZWEGnNi4F0hSbGnsuOG+VnNvxkKg0IGDvFh7UVpM/14mnMwxRxUf9AdAVJgHPvKXf6FpMB7A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -1506,9 +1472,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.1.tgz",
|
||||
"integrity": "sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.2.tgz",
|
||||
"integrity": "sha512-lb5bxXnxXglVq+7imxykIp5xMq+idehfl+wOgiiix0191av84OqbjUED+PRC5OA8eFJYj5xAGcpAZ0pF2MnW+A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -1520,9 +1486,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.2.tgz",
|
||||
"integrity": "sha512-Yl5Rdpf9pIc4GW1PmkUGHdMtbx0fBLE1//SxDmuf3X0dUC57+zMepow2LK0V21661cjXdTn8hO2tXDdAWAqE5g==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@ -1534,9 +1500,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.2.tgz",
|
||||
"integrity": "sha512-03vUDH+w55s680YYryyr78jsO1RWU9ocRMaeV2vMniJJW/6HhoTBwyyiiTPVHNWLnhsnwcQ0oH3S9JSBEKuyqw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@ -1548,9 +1514,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.2.tgz",
|
||||
"integrity": "sha512-iYtAqBg5eEMG4dEfVlkqo05xMOk6y/JXIToRca2bAWuqjrJYJlx/I7+Z+4hSrsWU8GdJDFPL4ktV3dy4yBSrzg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@ -1562,9 +1528,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.1.tgz",
|
||||
"integrity": "sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.2.tgz",
|
||||
"integrity": "sha512-e6vEbgaaqz2yEHqtkPXa28fFuBGmUJ0N2dOJK8YUfijejInt9gfCSA7YDdJ4nYlv67JfP3+PSWFX4IVw/xRIPg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@ -1576,9 +1542,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.2.tgz",
|
||||
"integrity": "sha512-evFOtkmVdY3udE+0QKrV5wBx7bKI0iHz5yEVx5WqDJkxp9YQefy4Mpx3RajIVcM6o7jxTvVd/qpC1IXUhGc1Mw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@ -1590,9 +1556,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.2.tgz",
|
||||
"integrity": "sha512-/bXb0bEsWMyEkIsUL2Yt5nFB5naLAwyOWMEviQfQY1x3l5WsLKgvZf66TM7UTfED6erckUVUJQ/jJ1FSpm3pRQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -1604,9 +1570,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.1.tgz",
|
||||
"integrity": "sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.2.tgz",
|
||||
"integrity": "sha512-3D3OB1vSSBXmkGEZR27uiMRNiwN08/RVAcBKwhUYPaiZ8bcvdeEwWPvbnXvvXHY+A/7xluzcN+kaiOFNiOZwWg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -1618,9 +1584,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.1.tgz",
|
||||
"integrity": "sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.2.tgz",
|
||||
"integrity": "sha512-VfU0fsMK+rwdK8mwODqYeM2hDrF2WiHaSmCBrS7gColkQft95/8tphyzv2EupVxn3iE0FI78wzffoULH1G+dkw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -1632,9 +1598,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.1.tgz",
|
||||
"integrity": "sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.2.tgz",
|
||||
"integrity": "sha512-+qMUrkbUurpE6DVRjiJCNGZBGo9xM4Y0FXU5cjgudWqIBWbcLkjE3XprJUsOFgC6xjBClwVa9k6O3A7K3vxb5Q==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@ -1646,9 +1612,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.1.tgz",
|
||||
"integrity": "sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.2.tgz",
|
||||
"integrity": "sha512-3+QZROYfJ25PDcxFF66UEk8jGWigHJeecZILvkPkyQN7oc5BvFo4YEXFkOs154j3FTMp9mn9Ky8RCOwastduEA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -1790,9 +1756,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.15.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.34.tgz",
|
||||
"integrity": "sha512-8Y6E5WUupYy1Dd0II32BsWAx5MWdcnRd8L84Oys3veg1YrYtNtzgO4CFhiBg6MDSjk7Ay36HYOnU7/tuOzIzcw==",
|
||||
"version": "22.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.0.tgz",
|
||||
"integrity": "sha512-B2egV9wALML1JCpv3VQoQ+yesQKAmNMBIAY7OteVrikcOcAkWm+dGL6qpeCktPjAv6N1JLnhbNiqS35UpFyBsQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1856,6 +1822,16 @@
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
|
||||
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.35.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.1.tgz",
|
||||
@ -2005,6 +1981,32 @@
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.35.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.1.tgz",
|
||||
@ -2280,13 +2282,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"dev": true,
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
@ -2621,9 +2624,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.0.0.tgz",
|
||||
"integrity": "sha512-A0BJ5lrpJVSfnMMXjmeO0xUnoxqsBHWCoqqTnGwGYVdnctqXXUEhJOO7LxmgxJon9tEZFGpe0xPRX0h2v3AANQ==",
|
||||
"version": "17.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.0.1.tgz",
|
||||
"integrity": "sha512-GLjkduuAL7IMJg/ZnOPm9AnWKJ82mSE2tzXLaJ/6hD6DhwGfZaXG77oB8qbReyiczNxnbxQKyh0OE5mXq0bAHA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@ -2682,6 +2685,7 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
@ -2730,9 +2734,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.30.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.0.tgz",
|
||||
"integrity": "sha512-iN/SiPxmQu6EVkf+m1qpBxzUhE12YqFLOSySuOyVLJLEF9nzTf+h/1AJYc1JWzCnktggeNrjvQGLngDzXirU6g==",
|
||||
"version": "9.30.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.1.tgz",
|
||||
"integrity": "sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -2742,7 +2746,7 @@
|
||||
"@eslint/config-helpers": "^0.3.0",
|
||||
"@eslint/core": "^0.14.0",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "9.30.0",
|
||||
"@eslint/js": "9.30.1",
|
||||
"@eslint/plugin-kit": "^0.3.1",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
@ -2870,30 +2874,6 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/@eslint/js": {
|
||||
"version": "9.30.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.0.tgz",
|
||||
"integrity": "sha512-Wzw3wQwPvc9sHM+NjakWTcPx11mbZyiYHuwWa/QfZ7cIRX7WK54PSk7bdyXDaoaopUcMatv1zaQvOAAO8hCdww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://eslint.org/donate"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/eslint-visitor-keys": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||
@ -2907,29 +2887,6 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/esm-env": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
|
||||
@ -2982,9 +2939,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esrap": {
|
||||
"version": "1.4.9",
|
||||
"resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.9.tgz",
|
||||
"integrity": "sha512-3OMlcd0a03UGuZpPeUC1HxR3nA23l+HEyCiZw3b3FumJIN9KphoGzDJKMXI1S72jVS1dsenDyQC0kJlO1U9E1g==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.0.tgz",
|
||||
"integrity": "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -3311,30 +3268,6 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/glob/node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/glob/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz",
|
||||
@ -3472,9 +3405,9 @@
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
|
||||
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -3882,19 +3815,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"devOptional": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
@ -4693,9 +4623,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.1.tgz",
|
||||
"integrity": "sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==",
|
||||
"version": "4.44.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.2.tgz",
|
||||
"integrity": "sha512-PVoapzTwSEcelaWGth3uR66u7ZRo6qhPHc0f2uRO9fX6XDVNrIiGYS0Pj9+R8yIIYSD/mCx2b16Ws9itljKSPg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -4709,26 +4639,26 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.44.1",
|
||||
"@rollup/rollup-android-arm64": "4.44.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.44.1",
|
||||
"@rollup/rollup-darwin-x64": "4.44.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.44.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.44.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.44.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.44.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.44.1",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.44.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.44.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.44.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.44.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.44.1",
|
||||
"@rollup/rollup-android-arm-eabi": "4.44.2",
|
||||
"@rollup/rollup-android-arm64": "4.44.2",
|
||||
"@rollup/rollup-darwin-arm64": "4.44.2",
|
||||
"@rollup/rollup-darwin-x64": "4.44.2",
|
||||
"@rollup/rollup-freebsd-arm64": "4.44.2",
|
||||
"@rollup/rollup-freebsd-x64": "4.44.2",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.44.2",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.44.2",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.44.2",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.44.2",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.44.2",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.44.2",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.44.2",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.44.2",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.44.2",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.44.2",
|
||||
"@rollup/rollup-linux-x64-musl": "4.44.2",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.44.2",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.44.2",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.44.2",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
@ -5140,9 +5070,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/svelte": {
|
||||
"version": "5.34.9",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.34.9.tgz",
|
||||
"integrity": "sha512-sld35zFpooaSRSj4qw8Vl/cyyK0/sLQq9qhJ7BGZo/Kd0ggYtEnvNYLlzhhoqYsYQzA0hJqkzt3RBO/8KoTZOg==",
|
||||
"version": "5.35.2",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.35.2.tgz",
|
||||
"integrity": "sha512-uW/rRXYrhZ7Dh4UQNZ0t+oVGL1dEM+95GavCO8afAk1IY2cPq9BcZv9C3um5aLIya2y8lIeLPxLII9ASGg9Dzw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -5155,7 +5085,7 @@
|
||||
"axobject-query": "^4.1.0",
|
||||
"clsx": "^2.1.1",
|
||||
"esm-env": "^1.2.1",
|
||||
"esrap": "^1.4.8",
|
||||
"esrap": "^2.1.0",
|
||||
"is-reference": "^3.0.3",
|
||||
"locate-character": "^3.0.0",
|
||||
"magic-string": "^0.30.11",
|
||||
@ -5307,6 +5237,7 @@
|
||||
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2"
|
||||
@ -5449,6 +5380,7 @@
|
||||
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
@ -5519,14 +5451,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vitefu": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.7.tgz",
|
||||
"integrity": "sha512-eRWXLBbJjW3X5z5P5IHcSm2yYbYRPb2kQuc+oqsbAl99WB5kVsPbiiox+cymo8twTzifA6itvhr2CmjnaZZp0Q==",
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz",
|
||||
"integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"tests/deps/*",
|
||||
"tests/projects/*"
|
||||
"tests/projects/*",
|
||||
"tests/projects/workspace/packages/*"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0"
|
||||
|
@ -25,7 +25,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@zerodevx/svelte-toast": "^0.9.3",
|
||||
"eslint": "^9.11.1",
|
||||
"eslint": "^9.30.1",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-plugin-svelte": "^3.0.0",
|
||||
"globals": "^16.3.0",
|
||||
@ -34,8 +34,7 @@
|
||||
"svelte": "^5",
|
||||
"svelte-check": "^4.0.0",
|
||||
"tslib": "^2.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^6.0.0"
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
@ -3,15 +3,32 @@ import { TimelineReader } from '$lib/server/timeline';
|
||||
import type { Handle, HandleServerError } from '@sveltejs/kit';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import fs from 'fs/promises';
|
||||
import { close } from '$lib/server/db';
|
||||
|
||||
const logger = new Logger('App');
|
||||
|
||||
logger.log('App startup');
|
||||
if (process?.pid) {
|
||||
try {
|
||||
await fs.writeFile('moshing-mammut.pid', process.pid.toString());
|
||||
} catch (e) {
|
||||
logger.error('Could not write PID to file', e);
|
||||
}
|
||||
}
|
||||
|
||||
logger.log('App startup, PID', process?.pid);
|
||||
|
||||
logger.log('Debug log enabled', Logger.isDebugEnabled());
|
||||
TimelineReader.init();
|
||||
|
||||
export const handleError = (({ error }) => {
|
||||
if (error instanceof Error) {
|
||||
logger.error('Something went wrong: ', error.name, error.message);
|
||||
process.on('sveltekit:shutdown', (reason) => {
|
||||
close();
|
||||
logger.log('Shutting down', reason);
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
export const handleError = (({ error, status }) => {
|
||||
if (error instanceof Error && status !== 404) {
|
||||
logger.error('Something went wrong:', error.name, error.message);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -20,12 +37,6 @@ export const handleError = (({ error }) => {
|
||||
}) satisfies HandleServerError;
|
||||
|
||||
export const handle = (async ({ event, resolve }) => {
|
||||
const searchParams = event.url.searchParams;
|
||||
const authCode = searchParams.get('code');
|
||||
if (authCode) {
|
||||
logger.debug('received GET hook', event.url.searchParams);
|
||||
}
|
||||
|
||||
// Reeder *insists* on checking /feed instead of /feed.xml
|
||||
if (event.url.pathname === '/feed') {
|
||||
return new Response('', { status: 301, headers: { Location: '/feed.xml' } });
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { DEBUG_LOG } from '$env/static/private';
|
||||
import { env } from '$env/dynamic/private';
|
||||
import { isTruthy } from '$lib/truthyString';
|
||||
const { DEV } = import.meta.env;
|
||||
|
||||
export const enableVerboseLog = isTruthy(env.VERBOSE);
|
||||
export const debugLogEnv = isTruthy(DEBUG_LOG);
|
||||
|
||||
/**
|
||||
* @deprecated Use the new {@link Logger} class instead.
|
||||
@ -41,31 +43,31 @@ export class Logger {
|
||||
public constructor(private name: string) {}
|
||||
|
||||
public static isDebugEnabled(): boolean {
|
||||
return DEV || enableVerboseLog;
|
||||
return debugLogEnv || DEV || enableVerboseLog;
|
||||
}
|
||||
public verbose(...params: any[]) {
|
||||
if (!enableVerboseLog) {
|
||||
return;
|
||||
}
|
||||
console.debug(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.debug(new Date().toISOString(), '- [VRBSE]', `- ${this.name} -`, ...params);
|
||||
}
|
||||
public debug(...params: any[]) {
|
||||
if (false && !Logger.isDebugEnabled()) {
|
||||
if (!Logger.isDebugEnabled()) {
|
||||
return;
|
||||
}
|
||||
console.debug(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.debug(new Date().toISOString(), '- [DEBUG]', `- ${this.name} -`, ...params);
|
||||
}
|
||||
public log(...params: any[]) {
|
||||
console.log(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.log(new Date().toISOString(), '- [ LOG ]', `- ${this.name} -`, ...params);
|
||||
}
|
||||
public info(...params: any[]) {
|
||||
console.info(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.info(new Date().toISOString(), '- [INFO ]', `- ${this.name} -`, ...params);
|
||||
}
|
||||
public warn(...params: any[]) {
|
||||
console.warn(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.warn(new Date().toISOString(), '- [WARN ]', `- ${this.name} -`, ...params);
|
||||
}
|
||||
public error(...params: any[]) {
|
||||
console.error(new Date().toISOString(), `- ${this.name} -`, ...params);
|
||||
console.error(new Date().toISOString(), '- [ERROR]', `- ${this.name} -`, ...params);
|
||||
}
|
||||
|
||||
public static error(...params: any[]) {
|
||||
|
@ -5,6 +5,7 @@ export type SongInfo = {
|
||||
youtubeUrl?: string;
|
||||
spotifyUrl?: string;
|
||||
spotifyUri?: string;
|
||||
tidalUri?: string;
|
||||
type: 'song' | 'album';
|
||||
title?: string;
|
||||
artistName?: string;
|
||||
|
@ -68,6 +68,15 @@ type Migration = {
|
||||
};
|
||||
|
||||
const db: sqlite3.Database = new sqlite3.Database('moshingmammut.db');
|
||||
|
||||
export function close() {
|
||||
try {
|
||||
db.close();
|
||||
} catch (e) {
|
||||
logger.error('Could not close DB');
|
||||
}
|
||||
}
|
||||
|
||||
// for the local masto instance, the instance name is *not* saved
|
||||
// as part of the username or acct, so it needs to be stripped
|
||||
const ignoredUsers: string[] =
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { BASE_URL } from '$env/static/private';
|
||||
import { Logger } from '$lib/log';
|
||||
import type { OauthResponse } from '$lib/mastodon/response';
|
||||
import fs from 'fs/promises';
|
||||
@ -6,6 +7,7 @@ export abstract class OauthPlaylistAdder {
|
||||
/// How many minutes before expiry the token will be refreshed
|
||||
protected refresh_time: number = 15;
|
||||
protected logger: Logger = new Logger('OauthPlaylistAdder');
|
||||
protected redirectUri?: URL;
|
||||
|
||||
protected constructor(
|
||||
protected apiBase: string,
|
||||
@ -22,6 +24,12 @@ export abstract class OauthPlaylistAdder {
|
||||
}
|
||||
}
|
||||
|
||||
protected getRedirectUri(suffix: string): URL {
|
||||
const uri = this.redirectUri ?? new URL(`${BASE_URL}/${suffix}`);
|
||||
this.logger.debug('getRedirectUri', uri);
|
||||
return uri;
|
||||
}
|
||||
|
||||
protected constructAuthUrlInternal(
|
||||
endpointUrl: string,
|
||||
clientId: string,
|
||||
@ -46,7 +54,8 @@ export abstract class OauthPlaylistAdder {
|
||||
code: string,
|
||||
redirectUri: URL,
|
||||
client_secret?: string,
|
||||
customHeader?: HeadersInit
|
||||
customHeader?: HeadersInit,
|
||||
code_verifier?: string
|
||||
) {
|
||||
this.logger.debug('received code');
|
||||
const params = new URLSearchParams();
|
||||
@ -57,6 +66,9 @@ export abstract class OauthPlaylistAdder {
|
||||
if (client_secret) {
|
||||
params.append('client_secret', client_secret);
|
||||
}
|
||||
if (code_verifier) {
|
||||
params.append('code_verifier', code_verifier);
|
||||
}
|
||||
this.logger.debug('sending token req', params);
|
||||
const resp: OauthResponse = await fetch(tokenUrl, {
|
||||
method: 'POST',
|
||||
@ -90,12 +102,22 @@ export abstract class OauthPlaylistAdder {
|
||||
protected async shouldRefreshToken(): Promise<{ token: OauthResponse; refresh: boolean } | null> {
|
||||
const token = await this.auth();
|
||||
if (token == null || !token?.expires) {
|
||||
this.logger.warn('Cannot check if token should be refreshed. Token expiry is unreadablle');
|
||||
return null;
|
||||
}
|
||||
let refreshAt = new Date();
|
||||
if (token.error) {
|
||||
this.logger.error('Access token is invalid, should refresh');
|
||||
return {
|
||||
token: token,
|
||||
refresh: true
|
||||
};
|
||||
}
|
||||
let refreshAt = new Date(token.expires);
|
||||
// Refresh token this.refresh_time minutes before it expires
|
||||
refreshAt.setTime(refreshAt.getTime() - this.refresh_time * 60 * 1000);
|
||||
this.logger.info('token expiry', token.expires, 'vs refresh @', refreshAt);
|
||||
if (token.expires.getTime() > refreshAt.getTime()) {
|
||||
|
||||
this.logger.info('refresh @', refreshAt, 'token expires', token.expires);
|
||||
if (refreshAt.getTime() > new Date().getTime()) {
|
||||
return {
|
||||
token: token,
|
||||
refresh: false
|
||||
@ -106,7 +128,7 @@ export abstract class OauthPlaylistAdder {
|
||||
'Token expires',
|
||||
token.expires,
|
||||
token.expires.getTime(),
|
||||
`which is after the refresh time`,
|
||||
`so it should be refreshed before or at`,
|
||||
refreshAt,
|
||||
refreshAt.getTime()
|
||||
);
|
||||
|
187
src/lib/server/playlist/tidalPlaylistAdder.ts
Normal file
187
src/lib/server/playlist/tidalPlaylistAdder.ts
Normal file
@ -0,0 +1,187 @@
|
||||
import { TIDAL_PLAYLIST_ID, TIDAL_CLIENT_ID, TIDAL_CLIENT_SECRET } from '$env/static/private';
|
||||
import { Logger } from '$lib/log';
|
||||
import type { OauthResponse } from '$lib/mastodon/response';
|
||||
import type { SongInfo } from '$lib/odesliResponse';
|
||||
import { createHash } from 'crypto';
|
||||
import { OauthPlaylistAdder } from './oauthPlaylistAdder';
|
||||
import type { PlaylistAdder } from './playlistAdder';
|
||||
import type { TidalAddToPlaylistResponse } from './tidalResponse';
|
||||
|
||||
export class TidalPlaylistAdder extends OauthPlaylistAdder implements PlaylistAdder {
|
||||
private static code_verifier?: string;
|
||||
|
||||
public constructor() {
|
||||
super('https://openapi.tidal.com/v2', 'tidal_auth_token');
|
||||
//super('https://api.tidal.com/v2', 'tidal_auth_token');
|
||||
this.logger = new Logger('TidalPlaylistAdder');
|
||||
}
|
||||
|
||||
public constructAuthUrl(redirectUri: URL): URL {
|
||||
const endpoint = 'https://login.tidal.com/authorize';
|
||||
const verifier = Buffer.from(crypto.getRandomValues(new Uint8Array(100)).toString(), 'ascii')
|
||||
.toString('base64url')
|
||||
.slice(0, 128);
|
||||
const code_challenge = createHash('sha256').update(verifier).digest('base64url');
|
||||
TidalPlaylistAdder.code_verifier = verifier;
|
||||
|
||||
let additionalParameters = new Map([
|
||||
['code_challenge_method', 'S256'],
|
||||
['code_challenge', code_challenge]
|
||||
]);
|
||||
return this.constructAuthUrlInternal(
|
||||
endpoint,
|
||||
TIDAL_CLIENT_ID,
|
||||
'playlists.write playlists.read user.read', //r_usr w_usr
|
||||
redirectUri,
|
||||
additionalParameters
|
||||
);
|
||||
}
|
||||
|
||||
public async receivedAuthCode(code: string, url: URL) {
|
||||
this.logger.debug('received code');
|
||||
const tokenUrl = new URL('https://auth.tidal.com/v1/oauth2/token');
|
||||
await this.receivedAuthCodeInternal(
|
||||
tokenUrl,
|
||||
TIDAL_CLIENT_ID,
|
||||
code,
|
||||
url,
|
||||
TIDAL_CLIENT_SECRET,
|
||||
undefined,
|
||||
TidalPlaylistAdder.code_verifier
|
||||
);
|
||||
}
|
||||
|
||||
private async refreshToken(force: boolean = false): Promise<OauthResponse | null> {
|
||||
const tokenInfo = await this.shouldRefreshToken();
|
||||
if (tokenInfo == null) {
|
||||
return null;
|
||||
}
|
||||
let token = tokenInfo.token;
|
||||
if (!tokenInfo.refresh && !force) {
|
||||
return token;
|
||||
}
|
||||
|
||||
if (!token.refresh_token) {
|
||||
this.logger.error('Need to refresh access token, but no refresh token provided');
|
||||
return null;
|
||||
}
|
||||
|
||||
const tokenUrl = new URL('https://auth.tidal.com/v1/oauth2/token');
|
||||
return await this.requestRefreshToken(tokenUrl, TIDAL_CLIENT_ID, token.refresh_token);
|
||||
}
|
||||
|
||||
private async addToPlaylistRetry(song: SongInfo, remaning: number = 3) {
|
||||
if (remaning < 0) {
|
||||
this.logger.error('max retries reached, song will not be added to playlist');
|
||||
}
|
||||
this.logger.debug('addToTidalPlaylist', remaning);
|
||||
const token = await this.refreshToken();
|
||||
if (token == null) {
|
||||
return;
|
||||
}
|
||||
this.logger.debug('token check successful');
|
||||
|
||||
if (!TIDAL_PLAYLIST_ID || TIDAL_PLAYLIST_ID === 'CHANGE_ME') {
|
||||
this.logger.debug('no playlist ID configured');
|
||||
return;
|
||||
}
|
||||
if (!song.tidalUri) {
|
||||
this.logger.info('Skip adding song to playlist, no Uri', song);
|
||||
return;
|
||||
}
|
||||
|
||||
// This would be API v2, but that's still in beta and only allows adding an item *before* another one
|
||||
const options: RequestInit = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `${token.token_type} ${token.access_token}`,
|
||||
'Content-Type': 'application/vnd.api+json',
|
||||
Accept: 'application/vnd.api+json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
data: [
|
||||
{
|
||||
id: song.tidalUri,
|
||||
type: 'tracks'
|
||||
}
|
||||
],
|
||||
meta: {
|
||||
positionBefore: 'ffb6286e-237a-4dfc-bbf1-2fb0eb004ed5' // Hardcoded last element of list
|
||||
}
|
||||
})
|
||||
};
|
||||
const apiUrl = new URL(`${this.apiBase}/playlists/${TIDAL_PLAYLIST_ID}/relationships/items`);
|
||||
const request = new Request(apiUrl, options);
|
||||
this.logger.debug('Adding to playlist request', request);
|
||||
|
||||
// This would be API v1 (or api v2, but *not* the OpenAPI v2),
|
||||
// but that requires r_usr and w_usr permission scopes which are impossible to request
|
||||
/*
|
||||
const options: RequestInit = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `${token.token_type} ${token.access_token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
onArtifactNotFound: 'SKIP',
|
||||
trackIds: song.tidalUri,
|
||||
//toIndex: -1
|
||||
onDupes: 'SKIP'
|
||||
})
|
||||
};
|
||||
const apiUrl = new URL(`${this.apiBase}/playlists/${TIDAL_PLAYLIST_ID}/items`);
|
||||
try {
|
||||
const r = await fetch(new URL(`${this.apiBase}/playlists/${TIDAL_PLAYLIST_ID}`), {
|
||||
headers: {
|
||||
Authorization: `${token.token_type} ${token.access_token}`
|
||||
}
|
||||
});
|
||||
const txt = await r.text();
|
||||
this.logger.debug('playlist', r.status, txt);
|
||||
const rj = JSON.parse(txt);
|
||||
this.logger.debug('playlist', rj);
|
||||
} catch (e) {
|
||||
this.logger.error('playlist fetch failed', e);
|
||||
}
|
||||
|
||||
const request = new Request(apiUrl, options);
|
||||
this.logger.debug('Adding to playlist request', request);
|
||||
*/
|
||||
|
||||
let resp: Response | null = null;
|
||||
try {
|
||||
resp = await fetch(request);
|
||||
let respObj: TidalAddToPlaylistResponse | null = null;
|
||||
// If the request was successful, a 201 with no content is received
|
||||
// Errors will have content and a different status code
|
||||
if (resp.status !== 201) {
|
||||
respObj = await resp.json();
|
||||
}
|
||||
if (respObj !== null && respObj.errors) {
|
||||
this.logger.error('Add to playlist failed', song.tidalUri, resp.status, respObj.errors);
|
||||
if (respObj.errors.some((x) => x.status === 401)) {
|
||||
const token = await this.refreshToken(true);
|
||||
if (token == null) {
|
||||
return;
|
||||
}
|
||||
this.addToPlaylistRetry(song, remaning--);
|
||||
}
|
||||
} else if (respObj === null && resp.status === 201) {
|
||||
this.logger.info('Added to playlist', song.tidalUri, song.title);
|
||||
} else {
|
||||
this.logger.info(
|
||||
'Add to playlist result is neither 201 nor error',
|
||||
song.tidalUri,
|
||||
song.title,
|
||||
respObj
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.error('Add to playlist request failed', resp?.status, e);
|
||||
}
|
||||
}
|
||||
public async addToPlaylist(song: SongInfo) {
|
||||
await this.addToPlaylistRetry(song);
|
||||
}
|
||||
}
|
28
src/lib/server/playlist/tidalResponse.ts
Normal file
28
src/lib/server/playlist/tidalResponse.ts
Normal file
@ -0,0 +1,28 @@
|
||||
export type TidalAddToPlaylistResponse = {
|
||||
errors: TidalAddToPlaylistError[];
|
||||
};
|
||||
|
||||
export type TidalAddToPlaylistError = {
|
||||
id: string;
|
||||
status: number;
|
||||
code: TidalErrorCode;
|
||||
detail: string;
|
||||
source: TidalAddToPlaylistErrorSource;
|
||||
meta: TidalAddToPlaylistErrorMeta;
|
||||
};
|
||||
|
||||
export type TidalAddToPlaylistErrorSource = {
|
||||
parameter: string;
|
||||
};
|
||||
export type TidalAddToPlaylistErrorMeta = {
|
||||
category: string;
|
||||
};
|
||||
export type TidalErrorCode =
|
||||
| 'INVALID_ENUM_VALUE'
|
||||
| 'VALUE_REGEX_MISMATCH'
|
||||
| 'NOT_FOUND'
|
||||
| 'METHOD_NOT_SUPPORTED'
|
||||
| 'NOT_ACCEPTABLE'
|
||||
| 'UNSUPPORTED_MEDIA_TYPE'
|
||||
| 'UNAVAILABLE_FOR_LEGAL_REASONS_RESPONSE'
|
||||
| 'INTERNAL_SERVER_ERROR';
|
@ -1,9 +1,4 @@
|
||||
import {
|
||||
BASE_URL,
|
||||
YOUTUBE_CLIENT_ID,
|
||||
YOUTUBE_CLIENT_SECRET,
|
||||
YOUTUBE_PLAYLIST_ID
|
||||
} from '$env/static/private';
|
||||
import { YOUTUBE_CLIENT_ID, YOUTUBE_CLIENT_SECRET, YOUTUBE_PLAYLIST_ID } from '$env/static/private';
|
||||
import { Logger } from '$lib/log';
|
||||
import type { OauthResponse } from '$lib/mastodon/response';
|
||||
import type { SongInfo } from '$lib/odesliResponse';
|
||||
@ -17,6 +12,7 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
||||
}
|
||||
|
||||
public constructAuthUrl(redirectUri: URL): URL {
|
||||
this.redirectUri = redirectUri;
|
||||
let additionalParameters = new Map([
|
||||
['access_type', 'offline'],
|
||||
['include_granted_scopes', 'false']
|
||||
@ -33,6 +29,7 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
||||
|
||||
public async receivedAuthCode(code: string, url: URL) {
|
||||
this.logger.debug('received code');
|
||||
this.redirectUri = url;
|
||||
const tokenUrl = new URL('https://oauth2.googleapis.com/token');
|
||||
await this.receivedAuthCodeInternal(
|
||||
tokenUrl,
|
||||
@ -41,15 +38,29 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
||||
url,
|
||||
YOUTUBE_CLIENT_SECRET
|
||||
);
|
||||
const token = await this.refreshToken();
|
||||
if (token == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.logger.debug('Checking authorized token');
|
||||
const res = await fetch(this.apiBase + '/channels?part=id&mine=true', {
|
||||
method: 'GET',
|
||||
headers: { Authorization: `${token.token_type} ${token.access_token}` }
|
||||
}).then((r) => r.json());
|
||||
this.logger.debug('Checked authorized token', res);
|
||||
} catch (e) {
|
||||
this.logger.debug('Error checking authorized token', e);
|
||||
}
|
||||
}
|
||||
|
||||
private async refreshToken(): Promise<OauthResponse | null> {
|
||||
private async refreshToken(force: boolean = false): Promise<OauthResponse | null> {
|
||||
const tokenInfo = await this.shouldRefreshToken();
|
||||
if (tokenInfo == null) {
|
||||
return null;
|
||||
}
|
||||
let token = tokenInfo.token;
|
||||
if (!tokenInfo.refresh) {
|
||||
if (!tokenInfo.refresh && !force) {
|
||||
return token;
|
||||
}
|
||||
if (!token.refresh_token) {
|
||||
@ -62,12 +73,19 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
||||
tokenUrl,
|
||||
YOUTUBE_CLIENT_ID,
|
||||
token.refresh_token,
|
||||
`${BASE_URL}/ytauth`,
|
||||
this.getRedirectUri('ytauth').toString(),
|
||||
YOUTUBE_CLIENT_SECRET
|
||||
);
|
||||
}
|
||||
|
||||
public async addToPlaylist(song: SongInfo) {
|
||||
await this.addToPlaylistRetry(song);
|
||||
}
|
||||
|
||||
private async addToPlaylistRetry(song: SongInfo, remaning: number = 3) {
|
||||
if (remaning < 0) {
|
||||
this.logger.error('max retries reached, song will not be added to spotify playlist');
|
||||
}
|
||||
this.logger.debug('addToYoutubePlaylist');
|
||||
const token = await this.refreshToken();
|
||||
if (token == null) {
|
||||
@ -125,7 +143,15 @@ export class YoutubePlaylistAdder extends OauthPlaylistAdder implements Playlist
|
||||
const respObj = await resp.json();
|
||||
this.logger.info('Added to playlist', youtubeId, song.title);
|
||||
if (respObj.error) {
|
||||
this.logger.debug('Add to playlist failed', respObj.error.errors);
|
||||
this.logger.error('Add to playlist failed', respObj.error.errors);
|
||||
if (respObj.error.errors && respObj.error.errors[0].reason === 'authError') {
|
||||
this.logger.info('Refreshing auth token');
|
||||
const token = await this.refreshToken(true);
|
||||
if (token == null) {
|
||||
return;
|
||||
}
|
||||
this.addToPlaylistRetry(song, remaning--);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,12 +54,16 @@ export async function saveAtomFeed(feed: Feed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.append('hub.mode', 'publish');
|
||||
params.append('hub.url', `${BASE_URL}/feed.xml`);
|
||||
const param = new FormData();
|
||||
param.append('hub.mode', 'publish');
|
||||
param.append('hub.url', `${BASE_URL}/feed.xml`);
|
||||
//const params = new URLSearchParams();
|
||||
//params.append('hub.mode', 'publish');
|
||||
//params.append('hub.url', `${BASE_URL}/feed.xml`);
|
||||
await fetch(WEBSUB_HUB, {
|
||||
method: 'POST',
|
||||
body: params
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: param
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error('Failed to update WebSub hub', e);
|
||||
|
@ -2,6 +2,7 @@ import {
|
||||
HASHTAG_FILTER,
|
||||
MASTODON_ACCESS_TOKEN,
|
||||
MASTODON_INSTANCE,
|
||||
IGNORE_USERS,
|
||||
ODESLI_API_KEY,
|
||||
YOUTUBE_API_KEY
|
||||
} from '$env/static/private';
|
||||
@ -36,6 +37,7 @@ import sharp from 'sharp';
|
||||
import { URL, URLSearchParams } from 'url';
|
||||
import { WebSocket } from 'ws';
|
||||
import type { PlaylistAdder } from './playlist/playlistAdder';
|
||||
import { TidalPlaylistAdder } from './playlist/tidalPlaylistAdder';
|
||||
|
||||
const URL_REGEX = new RegExp(/href="(?<postUrl>[^>]+?)" target="_blank"/gm);
|
||||
const INVIDIOUS_REGEX = new RegExp(/invidious.*?watch.*?v=(?<videoId>[a-zA-Z_0-9-]+)/gm);
|
||||
@ -48,6 +50,7 @@ export class TimelineReader {
|
||||
private lastPosts: string[] = [];
|
||||
private playlistAdders: PlaylistAdder[];
|
||||
private logger: Logger;
|
||||
private ignoredUsers: string[];
|
||||
|
||||
private async isMusicVideo(videoId: string) {
|
||||
if (!YOUTUBE_API_KEY || YOUTUBE_API_KEY === 'CHANGE_ME') {
|
||||
@ -174,22 +177,24 @@ export class TimelineReader {
|
||||
}
|
||||
const isMusic = await this.isMusicVideo(youtubeId);
|
||||
if (!isMusic) {
|
||||
this.logger.debug('Probably not a music video', youtubeId, url);
|
||||
this.logger.debug('Probably not a music video', youtubeId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const spotify: Platform = 'spotify';
|
||||
const tidal: Platform = 'tidal';
|
||||
const tidalId = odesliInfo.linksByPlatform[tidal]?.entityUniqueId;
|
||||
const tidalUri = tidalId ? odesliInfo.entitiesByUniqueId[tidalId].id : undefined;
|
||||
|
||||
const songInfo = {
|
||||
...info,
|
||||
pageUrl: odesliInfo.pageUrl,
|
||||
youtubeUrl: odesliInfo.linksByPlatform[platform]?.url,
|
||||
spotifyUrl: odesliInfo.linksByPlatform[spotify]?.url,
|
||||
spotifyUri: odesliInfo.linksByPlatform[spotify]?.nativeAppUriDesktop,
|
||||
tidalUri: tidalUri,
|
||||
postedUrl: url.toString()
|
||||
} as SongInfo;
|
||||
if (songInfo.youtubeUrl && !songInfo.spotifyUrl) {
|
||||
this.logger.warn('SongInfo with YT, but no spotify URL', odesliInfo);
|
||||
}
|
||||
return songInfo;
|
||||
} catch (e) {
|
||||
if (e instanceof Error && e.cause === 429) {
|
||||
@ -372,6 +377,18 @@ export class TimelineReader {
|
||||
}
|
||||
|
||||
private async checkAndSavePost(post: Post) {
|
||||
const isIgnored = this.ignoredUsers.includes(post.account.acct);
|
||||
if (isIgnored) {
|
||||
this.logger.info(
|
||||
'Ignoring post by ignored user',
|
||||
post.account.acct,
|
||||
'is ignored',
|
||||
this.ignoredUsers,
|
||||
isIgnored
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const hashttags: string[] = HASHTAG_FILTER.split(',');
|
||||
const found_tags: Tag[] = post.tags.filter((t: Tag) => hashttags.includes(t.name));
|
||||
|
||||
@ -405,11 +422,42 @@ export class TimelineReader {
|
||||
const socket = new WebSocket(
|
||||
`wss://${MASTODON_INSTANCE}/api/v1/streaming?type=subscribe&stream=public:local&access_token=${MASTODON_ACCESS_TOKEN}`
|
||||
);
|
||||
|
||||
// Sometimes, the app just stops receiving WS updates.
|
||||
// Regularly check if it is necessary to reset it
|
||||
const wsTimeout = 5;
|
||||
let timeoutId = setTimeout(
|
||||
() => {
|
||||
socketLogger.warn(
|
||||
'Websocket has not received a new post in',
|
||||
wsTimeout,
|
||||
'hours. Resetting, it might be stuck'
|
||||
);
|
||||
socket.close();
|
||||
this.startWebsocket();
|
||||
},
|
||||
1000 * 60 * 60 * wsTimeout
|
||||
); // 5 hours
|
||||
socket.onopen = () => {
|
||||
socketLogger.log('Connected to WS');
|
||||
};
|
||||
socket.onmessage = async (event) => {
|
||||
try {
|
||||
// Reset timer
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(
|
||||
() => {
|
||||
socketLogger.warn(
|
||||
'Websocket has not received a new post in',
|
||||
wsTimeout,
|
||||
'hours. Resetting, it might be stuck'
|
||||
);
|
||||
socket.close();
|
||||
this.startWebsocket();
|
||||
},
|
||||
1000 * 60 * 60 * wsTimeout
|
||||
);
|
||||
|
||||
const data: TimelineEvent = JSON.parse(event.data.toString());
|
||||
socketLogger.debug('ES event', data.event);
|
||||
if (data.event !== 'update') {
|
||||
@ -479,7 +527,21 @@ export class TimelineReader {
|
||||
private constructor() {
|
||||
this.logger = new Logger('Timeline');
|
||||
this.logger.log('Constructing timeline object');
|
||||
this.playlistAdders = [new YoutubePlaylistAdder(), new SpotifyPlaylistAdder()];
|
||||
this.playlistAdders = [
|
||||
new YoutubePlaylistAdder(),
|
||||
new SpotifyPlaylistAdder(),
|
||||
new TidalPlaylistAdder()
|
||||
];
|
||||
this.ignoredUsers =
|
||||
IGNORE_USERS === undefined || IGNORE_USERS === 'CHANGE_ME' || !!IGNORE_USERS
|
||||
? []
|
||||
: IGNORE_USERS.split(',')
|
||||
.map((u) => (u.startsWith('@') ? u.substring(1) : u))
|
||||
.map((u) =>
|
||||
u.endsWith('@' + MASTODON_INSTANCE)
|
||||
? u.substring(0, u.length - ('@' + MASTODON_INSTANCE).length)
|
||||
: u
|
||||
);
|
||||
this.startWebsocket();
|
||||
|
||||
this.loadPostsSinceLastRun()
|
||||
|
@ -1,4 +1,7 @@
|
||||
export function isTruthy(value: string | number | boolean | null | undefined): boolean {
|
||||
if (value === null || value === undefined) {
|
||||
return false;
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
return value.toLowerCase() === 'true' || !!+value; // here we parse to number first
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
import type { Post } from '$lib/mastodon/response';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load = (async ({ fetch }) => {
|
||||
export const load = (async ({ fetch, setHeaders }) => {
|
||||
const p = await fetch('/');
|
||||
setHeaders({
|
||||
'cache-control': 'public,max-age=60'
|
||||
});
|
||||
return {
|
||||
posts: (await p.json()) as Post[]
|
||||
};
|
||||
|
@ -1,5 +1,8 @@
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
export const GET = (async ({ fetch }) => {
|
||||
export const GET = (async ({ fetch, setHeaders }) => {
|
||||
setHeaders({
|
||||
'cache-control': 'max-age=10'
|
||||
});
|
||||
return await fetch('api/posts');
|
||||
}) satisfies RequestHandler;
|
||||
|
@ -7,9 +7,19 @@ const { DEV } = import.meta.env;
|
||||
|
||||
const logger = new Logger('SpotifyAuth');
|
||||
|
||||
export const load: PageServerLoad = async ({ url }) => {
|
||||
export const load: PageServerLoad = async ({ url, request }) => {
|
||||
const forwardedHost = request.headers.get('X-Forwarded-Host');
|
||||
let redirect_base;
|
||||
if (DEV) {
|
||||
redirect_base = url.origin;
|
||||
} else if (forwardedHost) {
|
||||
redirect_base = `${url.protocol}//${forwardedHost}`;
|
||||
} else {
|
||||
redirect_base = BASE_URL;
|
||||
}
|
||||
const redirect_uri = new URL(`${redirect_base}${url.pathname}`);
|
||||
|
||||
const adder = new SpotifyPlaylistAdder();
|
||||
let redirect_uri = new URL(`${BASE_URL}/spotifyAuth`);
|
||||
if (url.hostname === 'localhost' && DEV) {
|
||||
redirect_uri.hostname = '127.0.0.1';
|
||||
}
|
||||
|
39
src/routes/tidalAuth/+page.server.ts
Normal file
39
src/routes/tidalAuth/+page.server.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { BASE_URL } from '$env/static/private';
|
||||
import { Logger } from '$lib/log';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { TidalPlaylistAdder } from '$lib/server/playlist/tidalPlaylistAdder';
|
||||
import { URL } from 'node:url';
|
||||
const { DEV } = import.meta.env;
|
||||
|
||||
const logger = new Logger('TidalAuth');
|
||||
|
||||
export const load: PageServerLoad = async ({ url, request }) => {
|
||||
const forwardedHost = request.headers.get('X-Forwarded-Host');
|
||||
let redirect_base;
|
||||
if (DEV) {
|
||||
redirect_base = url.origin;
|
||||
} else if (forwardedHost) {
|
||||
redirect_base = `${url.protocol}//${forwardedHost}`;
|
||||
} else {
|
||||
redirect_base = BASE_URL;
|
||||
}
|
||||
const redirect_uri = new URL(`${redirect_base}${url.pathname}`);
|
||||
const adder = new TidalPlaylistAdder();
|
||||
logger.debug(url.searchParams, url.hostname, redirect_uri);
|
||||
if (url.searchParams.has('code')) {
|
||||
await adder.receivedAuthCode(url.searchParams.get('code') || '', redirect_uri);
|
||||
redirect(307, '/');
|
||||
} else if (url.searchParams.has('error')) {
|
||||
logger.error('received error', url.searchParams.get('error'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (await adder.authCodeExists()) {
|
||||
redirect(307, '/');
|
||||
}
|
||||
|
||||
const authUrl = adder.constructAuthUrl(redirect_uri);
|
||||
logger.debug('+page.server.ts', authUrl.toString());
|
||||
redirect(307, authUrl);
|
||||
};
|
1
src/routes/tidalAuth/+page.svelte
Normal file
1
src/routes/tidalAuth/+page.svelte
Normal file
@ -0,0 +1 @@
|
||||
<h1>Something went wrong</h1>
|
@ -3,12 +3,24 @@ import { Logger } from '$lib/log';
|
||||
import { YoutubePlaylistAdder } from '$lib/server/playlist/ytPlaylistAdder';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
const { DEV } = import.meta.env;
|
||||
|
||||
const logger = new Logger('YT Auth');
|
||||
|
||||
export const load: PageServerLoad = async ({ url }) => {
|
||||
export const load: PageServerLoad = async ({ url, request }) => {
|
||||
const forwardedHost = request.headers.get('X-Forwarded-Host');
|
||||
let redirect_base;
|
||||
if (DEV) {
|
||||
redirect_base = url.origin;
|
||||
} else if (forwardedHost) {
|
||||
redirect_base = `${url.protocol}//${forwardedHost}`;
|
||||
} else {
|
||||
redirect_base = BASE_URL;
|
||||
}
|
||||
const redirect_uri = new URL(`${redirect_base}${url.pathname}`);
|
||||
|
||||
const adder = new YoutubePlaylistAdder();
|
||||
const redirect_uri = new URL(`${BASE_URL}/ytauth`);
|
||||
logger.debug('redirect URL', redirect_uri);
|
||||
if (url.searchParams.has('code')) {
|
||||
logger.debug(url.searchParams);
|
||||
await adder.receivedAuthCode(url.searchParams.get('code') || '', redirect_uri);
|
||||
|
@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
. /home/moshing-mammut/.nvm/nvm.sh
|
||||
node -r dotenv/config build
|
||||
node -r dotenv/config build &
|
Reference in New Issue
Block a user