This commit is contained in:
Chris Kruining 2025-04-16 00:43:31 +02:00
parent 0eb2e34e60
commit a15809f4fd
Signed by: chris
SSH key fingerprint: SHA256:nG82MUfuVdRVyCKKWqhY+pCrbz9nbX6uzUns4RKa1Pg
11 changed files with 32770 additions and 82 deletions

View file

@ -11,6 +11,7 @@
"@solidjs/start": "^1.1.3", "@solidjs/start": "^1.1.3",
"better-auth": "^1.2.6", "better-auth": "^1.2.6",
"open-props": "^1.7.14", "open-props": "^1.7.14",
"openapi-fetch": "^0.13.5",
"sitemap": "^8.0.0", "sitemap": "^8.0.0",
"solid-icons": "^1.1.0", "solid-icons": "^1.1.0",
"solid-js": "^1.9.5", "solid-js": "^1.9.5",
@ -21,6 +22,7 @@
"browserslist": "^4.24.4", "browserslist": "^4.24.4",
"bun-types": "^1.2.7", "bun-types": "^1.2.7",
"lightningcss": "^1.29.3", "lightningcss": "^1.29.3",
"openapi-typescript": "^7.6.1",
"solid-devtools": "^0.33.0", "solid-devtools": "^0.33.0",
"vite-plugin-solid-svg": "^0.8.1", "vite-plugin-solid-svg": "^0.8.1",
"vite-tsconfig-paths": "^5.1.4", "vite-tsconfig-paths": "^5.1.4",
@ -897,7 +899,7 @@
"min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="], "min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="],
"minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
@ -953,8 +955,12 @@
"open-props": ["open-props@1.7.14", "", {}, "sha512-rTsf6dGrNhlyyN5+ZAdht50s5A7vzHC/gaA56sQnSfwQU53YzWCMjdzX2hhlK+aK+3ojEwTxsvRSlk3FP8TTHA=="], "open-props": ["open-props@1.7.14", "", {}, "sha512-rTsf6dGrNhlyyN5+ZAdht50s5A7vzHC/gaA56sQnSfwQU53YzWCMjdzX2hhlK+aK+3ojEwTxsvRSlk3FP8TTHA=="],
"openapi-fetch": ["openapi-fetch@0.13.5", "", { "dependencies": { "openapi-typescript-helpers": "^0.0.15" } }, "sha512-AQK8T9GSKFREFlN1DBXTYsLjs7YV2tZcJ7zUWxbjMoQmj8dDSFRrzhLCbHPZWA1TMV3vACqfCxLEZcwf2wxV6Q=="],
"openapi-typescript": ["openapi-typescript@7.6.1", "", { "dependencies": { "@redocly/openapi-core": "^1.28.0", "ansi-colors": "^4.1.3", "change-case": "^5.4.4", "parse-json": "^8.1.0", "supports-color": "^9.4.0", "yargs-parser": "^21.1.1" }, "peerDependencies": { "typescript": "^5.x" }, "bin": { "openapi-typescript": "bin/cli.js" } }, "sha512-F7RXEeo/heF3O9lOXo2bNjCOtfp7u+D6W3a3VNEH2xE6v+fxLtn5nq0uvUcA1F5aT+CMhNeC5Uqtg5tlXFX/ag=="], "openapi-typescript": ["openapi-typescript@7.6.1", "", { "dependencies": { "@redocly/openapi-core": "^1.28.0", "ansi-colors": "^4.1.3", "change-case": "^5.4.4", "parse-json": "^8.1.0", "supports-color": "^9.4.0", "yargs-parser": "^21.1.1" }, "peerDependencies": { "typescript": "^5.x" }, "bin": { "openapi-typescript": "bin/cli.js" } }, "sha512-F7RXEeo/heF3O9lOXo2bNjCOtfp7u+D6W3a3VNEH2xE6v+fxLtn5nq0uvUcA1F5aT+CMhNeC5Uqtg5tlXFX/ag=="],
"openapi-typescript-helpers": ["openapi-typescript-helpers@0.0.15", "", {}, "sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw=="],
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
"parse-json": ["parse-json@8.2.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.0.0", "type-fest": "^4.37.0" } }, "sha512-eONBZy4hm2AgxjNFd8a4nyDJnzUAH0g34xSQAwWEVGCjdZ4ZL7dKZBfq267GWP/JaS9zW62Xs2FeAdDvpHHJGQ=="], "parse-json": ["parse-json@8.2.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.0.0", "type-fest": "^4.37.0" } }, "sha512-eONBZy4hm2AgxjNFd8a4nyDJnzUAH0g34xSQAwWEVGCjdZ4ZL7dKZBfq267GWP/JaS9zW62Xs2FeAdDvpHHJGQ=="],
@ -1143,7 +1149,7 @@
"strip-literal": ["strip-literal@3.0.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA=="], "strip-literal": ["strip-literal@3.0.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "supports-color": ["supports-color@9.4.0", "", {}, "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw=="],
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
@ -1187,7 +1193,7 @@
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="], "type-fest": ["type-fest@4.37.0", "", {}, "sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg=="],
"typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
@ -1307,8 +1313,6 @@
"@poppinss/dumper/supports-color": ["supports-color@10.0.0", "", {}, "sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ=="], "@poppinss/dumper/supports-color": ["supports-color@10.0.0", "", {}, "sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ=="],
"@redocly/openapi-core/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
"@rollup/plugin-commonjs/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], "@rollup/plugin-commonjs/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"@rollup/plugin-inject/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], "@rollup/plugin-inject/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
@ -1335,6 +1339,8 @@
"boxen/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], "boxen/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
"boxen/type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="],
"c12/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], "c12/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"c12/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], "c12/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
@ -1343,6 +1349,8 @@
"c12/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], "c12/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
"chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
@ -1357,7 +1365,7 @@
"dax-sh/undici-types": ["undici-types@5.28.4", "", {}, "sha512-3OeMF5Lyowe8VW0skf5qaIE7Or3yS9LS7fvMUI0gg4YxpIBVg0L8BxCmROw2CcYhSkpR68Epz7CGc8MPj94Uww=="], "dax-sh/undici-types": ["undici-types@5.28.4", "", {}, "sha512-3OeMF5Lyowe8VW0skf5qaIE7Or3yS9LS7fvMUI0gg4YxpIBVg0L8BxCmROw2CcYhSkpR68Epz7CGc8MPj94Uww=="],
"dot-prop/type-fest": ["type-fest@4.37.0", "", {}, "sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg=="], "glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"is-inside-container/is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], "is-inside-container/is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
@ -1397,12 +1405,6 @@
"open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], "open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
"openapi-typescript/supports-color": ["supports-color@9.4.0", "", {}, "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw=="],
"parse-json/type-fest": ["type-fest@4.37.0", "", {}, "sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg=="],
"readdir-glob/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],

View file

@ -21,6 +21,7 @@
"@solidjs/start": "^1.1.3", "@solidjs/start": "^1.1.3",
"better-auth": "^1.2.6", "better-auth": "^1.2.6",
"open-props": "^1.7.14", "open-props": "^1.7.14",
"openapi-fetch": "^0.13.5",
"sitemap": "^8.0.0", "sitemap": "^8.0.0",
"solid-icons": "^1.1.0", "solid-icons": "^1.1.0",
"solid-js": "^1.9.5", "solid-js": "^1.9.5",
@ -31,6 +32,7 @@
"browserslist": "^4.24.4", "browserslist": "^4.24.4",
"bun-types": "^1.2.7", "bun-types": "^1.2.7",
"lightningcss": "^1.29.3", "lightningcss": "^1.29.3",
"openapi-typescript": "^7.6.1",
"solid-devtools": "^0.33.0", "solid-devtools": "^0.33.0",
"vite-plugin-solid-svg": "^0.8.1", "vite-plugin-solid-svg": "^0.8.1",
"vite-tsconfig-paths": "^5.1.4", "vite-tsconfig-paths": "^5.1.4",

View file

@ -4,19 +4,33 @@ import { createAuthClient } from "better-auth/solid";
import { genericOAuthClient } from "better-auth/client/plugins"; import { genericOAuthClient } from "better-auth/client/plugins";
export const auth = betterAuth({ export const auth = betterAuth({
appName: 'Streamarr', appName: "Streamarr",
basePath: '/api/auth', basePath: "/api/auth",
advanced: { advanced: {
useSecureCookies: true, useSecureCookies: true,
crossSubDomainCookies: {
enabled: true,
},
}, },
logger: { logger: {
level: 'debug', level: "info",
}, },
onAPIError: { user: {
throw: true, additionalFields: {
name: {
type: "string",
nullable: true,
},
preferred_username: {
type: "string",
nullable: true,
},
username: {
type: "string",
nullable: true,
},
profile: {
type: "string",
nullable: true,
},
},
}, },
plugins: [ plugins: [
genericOAuth({ genericOAuth({
@ -28,7 +42,14 @@ export const auth = betterAuth({
"ZPuiW2gpVV6MGXIJFk5P3EeSW8V_ICgqduF.hJVCKkrnVmRqIQXRk0o~HSA8ZdCf8joA4m_F", "ZPuiW2gpVV6MGXIJFk5P3EeSW8V_ICgqduF.hJVCKkrnVmRqIQXRk0o~HSA8ZdCf8joA4m_F",
discoveryUrl: discoveryUrl:
"https://auth.kruining.eu/.well-known/openid-configuration", "https://auth.kruining.eu/.well-known/openid-configuration",
scopes: ["openid", "email", "picture", "profile", "groups"], scopes: [
"offline_access",
"openid",
"email",
"picture",
"profile",
"groups",
],
accessType: "offline", accessType: "offline",
pkce: true, pkce: true,
}, },

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
import createClient from "openapi-fetch";
import type { paths } from "./jellyfin.generated"; // generated by openapi-typescript
import { query } from "@solidjs/router";
import { Entry } from "../types";
const baseUrl = "http://ulmo:8096/";
const client = createClient<paths>({
baseUrl,
headers: {
Authorization: `MediaBrowser DeviceId="Streamarr", Token="b3c44db1e31f4349b19d1ff0bc487da2"`,
},
});
export const getItem = query(async (userId: string, itemId: string) => {
const { data, error } = await client.GET("/Items/{itemId}", {
params: {
path: {
itemId,
},
query: {
userId,
hasTmdbInfo: true,
recursive: true,
includeItemTypes: ["Movie", "Series"],
fields: [
"ProviderIds",
"Genres",
"DateLastMediaAdded",
"DateCreated",
"MediaSources",
],
},
},
});
return data?.Items ?? [];
}, "jellyfin.getItem");
export const getContinueWatching = query(
async (userId: string): Promise<Entry[]> => {
const { data, error } = await client.GET("/Users/{userId}/Items/Resume", {
params: {
path: {
userId,
},
query: {
mediaTypes: ["Video"],
fields: ["ProviderIds", "Genres"],
},
},
});
const items = (data?.Items ?? []).map(({ Id, Name }) => ({
id: Id,
title: Name,
thumbnail: `${baseUrl}Items/${Id}/Images/Primary`,
}));
return items;
},
"jellyfin.continueWatching",
);

View file

@ -69,3 +69,5 @@ export const getEntry = query(
}, },
"series.get", "series.get",
); );
export { getContinueWatching } from "./apis/jellyfin";

View file

@ -3,6 +3,7 @@ import { signIn, signOut } from "~/auth";
import { hash } from "~/utilities"; import { hash } from "~/utilities";
import { Avatar, Profile, User } from "../user"; import { Avatar, Profile, User } from "../user";
import css from "./top.module.css"; import css from "./top.module.css";
import { ColorSchemePicker } from "../theme";
interface TopProps { interface TopProps {
user: User | undefined; user: User | undefined;
@ -53,7 +54,7 @@ export const Top: Component<TopProps> = (props) => {
</> </>
)} )}
</Show> </Show>
{/* <ColorSchemePicker /> */} <ColorSchemePicker />
</aside> </aside>
); );
}; };

View file

@ -1,80 +1,88 @@
import { ContextProviderProps, createContextProvider } from "@solid-primitives/context"; import {
ContextProviderProps,
createContextProvider,
} from "@solid-primitives/context";
import { action, createAsyncStore, query, useAction } from "@solidjs/router"; import { action, createAsyncStore, query, useAction } from "@solidjs/router";
import { createStore } from "solid-js/store"; import { createStore } from "solid-js/store";
import { useSession } from "vinxi/http"; import { useSession } from "vinxi/http";
export enum ColorScheme { export enum ColorScheme {
Auto = 'light dark', Auto = "light dark",
Light = 'light', Light = "light",
Dark = 'dark', Dark = "dark",
} }
export interface State { export interface State {
colorScheme: ColorScheme; colorScheme: ColorScheme;
hue: number; hue: number;
} }
const getSession = async () => { const getSession = async () => {
'use server'; "use server";
return useSession<State>({ return useSession<State>({
password: process.env.SESSION_SECRET!, password: process.env.SESSION_SECRET!,
}); });
}; };
export const getState = query(async () => { export const getState = query(async () => {
'use server'; "use server";
const session = await getSession(); const session = await getSession();
if (Object.getOwnPropertyNames(session.data).length === 0) { if (Object.getOwnPropertyNames(session.data).length === 0) {
await session.update({ await session.update({
colorScheme: ColorScheme.Auto, colorScheme: ColorScheme.Auto,
hue: 0, hue: 0,
}) });
} }
return session.data; return session.data;
}, 'color-scheme'); }, "color-scheme");
const setState = action(async (state: State) => { const setState = action(async (state: State) => {
'use server'; "use server";
const session = await getSession(); const session = await getSession();
await session.update(prev => ({ ...prev, ...state })); await session.update((prev) => ({ ...prev, ...state }));
}, 'color-scheme'); }, "color-scheme");
interface ThemeContextType { interface ThemeContextType {
readonly theme: State; readonly theme: State;
setColorScheme(colorScheme: ColorScheme): void; setColorScheme(colorScheme: ColorScheme): void;
setHue(colorScheme: number): void; setHue(colorScheme: number): void;
} }
const [ThemeContextProvider, useTheme] = createContextProvider<ThemeContextType, ContextProviderProps>((props) => { const [ThemeContextProvider, useTheme] = createContextProvider<
ThemeContextType,
ContextProviderProps
>(
(props) => {
const updateState = useAction(setState); const updateState = useAction(setState);
const state = createAsyncStore(() => getState()); const state = createAsyncStore(() => getState());
return { return {
get theme() { get theme() {
return state.latest ?? { colorScheme: null }; return state.latest ?? { colorScheme: null };
}, },
setColorScheme(colorScheme) { setColorScheme(colorScheme) {
updateState({ colorScheme, hue: state.latest!.hue }); // updateState({ colorScheme, hue: state.latest!.hue });
}, },
setHue(hue) { setHue(hue) {
updateState({ hue, colorScheme: state.latest!.colorScheme }); // updateState({ hue, colorScheme: state.latest!.colorScheme });
}, },
}; };
}, { },
{
theme: { theme: {
colorScheme: ColorScheme.Auto, colorScheme: ColorScheme.Auto,
hue: 180, hue: 180,
}, },
setColorScheme(colorScheme) { }, setColorScheme(colorScheme) {},
setHue(hue) { }, setHue(hue) {},
}); },
);
export { ThemeContextProvider, useTheme }; export { ThemeContextProvider, useTheme };

View file

@ -1,4 +1,5 @@
export interface User { export interface User {
username: string;
name: string; name: string;
email: string; email: string;
image: string | null; image: string | null;

View file

@ -18,9 +18,15 @@ const load = query(async (): Promise<User | undefined> => {
return undefined; return undefined;
} }
const { name, email, image = null } = session.user; const {
preferred_username,
name,
email,
image = null,
...user
} = session.user;
return { name, email, image }; return { username: preferred_username, name, email, image };
}, "session"); }, "session");
export const route = { export const route = {

View file

@ -1,34 +1,40 @@
import { Title } from "@solidjs/meta"; import { Title } from "@solidjs/meta";
import { createAsync, query } from "@solidjs/router"; import { createAsync } from "@solidjs/router";
import { Overview } from "~/features/overview"; import { Overview } from "~/features/overview";
import { listCategories, getEntry } from "~/features/content"; import {
import { createEffect, Show } from "solid-js"; listCategories,
getEntry,
const load = query(async () => { getContinueWatching,
"use server"; } from "~/features/content";
import { Show } from "solid-js";
// const response = import { List } from "~/components/list";
}, "home.data"); import { ListItem } from "~/features/overview/list-item";
export const route = { export const route = {
preload: async () => ({ preload: async () => ({
highlight: await getEntry("14"), highlight: await getEntry("14"),
categories: await listCategories(), categories: await listCategories(),
continue: await getContinueWatching("a9c51af84bf54578a99ab4dd0ebf0763"),
}), }),
}; };
export default function Home() { export default function Home() {
const highlight = createAsync(() => getEntry("14")); const highlight = createAsync(() => getEntry("14"));
const categories = createAsync(() => listCategories()); const categories = createAsync(() => listCategories());
const continueWatching = createAsync(() =>
createEffect(() => { getContinueWatching("a9c51af84bf54578a99ab4dd0ebf0763"),
console.log(highlight(), categories()); );
});
return ( return (
<> <>
<Title>Home</Title> <Title>Home</Title>
<Show when={continueWatching()}>
<List label="Continue watching" items={continueWatching()}>
{(item) => <ListItem entry={item()} />}
</List>
</Show>
<Show when={highlight() && categories()}> <Show when={highlight() && categories()}>
<Overview highlight={highlight()!} categories={categories()!} /> <Overview highlight={highlight()!} categories={categories()!} />
</Show> </Show>