lovely. got a couple of partial implementations....
update git ignore kaas remove large file syncy sync
This commit is contained in:
parent
89f526e9d9
commit
98cd4d630c
24 changed files with 586 additions and 76 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
dist
|
dist
|
||||||
|
public/videos
|
||||||
.solid
|
.solid
|
||||||
.output
|
.output
|
||||||
.vercel
|
.vercel
|
||||||
|
|
51
bun.lock
51
bun.lock
|
@ -9,6 +9,7 @@
|
||||||
"@solidjs/meta": "^0.29.4",
|
"@solidjs/meta": "^0.29.4",
|
||||||
"@solidjs/router": "^0.15.3",
|
"@solidjs/router": "^0.15.3",
|
||||||
"@solidjs/start": "^1.1.3",
|
"@solidjs/start": "^1.1.3",
|
||||||
|
"better-auth": "^1.2.6",
|
||||||
"open-props": "^1.7.14",
|
"open-props": "^1.7.14",
|
||||||
"sitemap": "^8.0.0",
|
"sitemap": "^8.0.0",
|
||||||
"solid-icons": "^1.1.0",
|
"solid-icons": "^1.1.0",
|
||||||
|
@ -68,6 +69,10 @@
|
||||||
|
|
||||||
"@babel/types": ["@babel/types@7.26.10", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ=="],
|
"@babel/types": ["@babel/types@7.26.10", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ=="],
|
||||||
|
|
||||||
|
"@better-auth/utils": ["@better-auth/utils@0.2.4", "", { "dependencies": { "typescript": "^5.8.2", "uncrypto": "^0.1.3" } }, "sha512-ayiX87Xd5sCHEplAdeMgwkA0FgnXsEZBgDn890XHHwSWNqqRZDYOq3uj2Ei2leTv1I2KbG5HHn60Ah1i2JWZjQ=="],
|
||||||
|
|
||||||
|
"@better-fetch/fetch": ["@better-fetch/fetch@1.1.18", "", {}, "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="],
|
||||||
|
|
||||||
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="],
|
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="],
|
||||||
|
|
||||||
"@deno/shim-deno": ["@deno/shim-deno@0.19.2", "", { "dependencies": { "@deno/shim-deno-test": "^0.5.0", "which": "^4.0.0" } }, "sha512-q3VTHl44ad8T2Tw2SpeAvghdGOjlnLPDNO2cpOxwMrBE/PVas6geWpbpIgrM+czOCH0yejp0yi8OaTuB+NU40Q=="],
|
"@deno/shim-deno": ["@deno/shim-deno@0.19.2", "", { "dependencies": { "@deno/shim-deno-test": "^0.5.0", "which": "^4.0.0" } }, "sha512-q3VTHl44ad8T2Tw2SpeAvghdGOjlnLPDNO2cpOxwMrBE/PVas6geWpbpIgrM+czOCH0yejp0yi8OaTuB+NU40Q=="],
|
||||||
|
@ -124,6 +129,8 @@
|
||||||
|
|
||||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.20.2", "", { "os": "win32", "cpu": "x64" }, "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ=="],
|
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.20.2", "", { "os": "win32", "cpu": "x64" }, "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ=="],
|
||||||
|
|
||||||
|
"@hexagon/base64": ["@hexagon/base64@1.1.28", "", {}, "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw=="],
|
||||||
|
|
||||||
"@ioredis/commands": ["@ioredis/commands@1.2.0", "", {}, "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="],
|
"@ioredis/commands": ["@ioredis/commands@1.2.0", "", {}, "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="],
|
||||||
|
|
||||||
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
|
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
|
||||||
|
@ -142,12 +149,18 @@
|
||||||
|
|
||||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
||||||
|
|
||||||
|
"@levischuck/tiny-cbor": ["@levischuck/tiny-cbor@0.2.11", "", {}, "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow=="],
|
||||||
|
|
||||||
"@mapbox/node-pre-gyp": ["@mapbox/node-pre-gyp@2.0.0", "", { "dependencies": { "consola": "^3.2.3", "detect-libc": "^2.0.0", "https-proxy-agent": "^7.0.5", "node-fetch": "^2.6.7", "nopt": "^8.0.0", "semver": "^7.5.3", "tar": "^7.4.0" }, "bin": { "node-pre-gyp": "bin/node-pre-gyp" } }, "sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg=="],
|
"@mapbox/node-pre-gyp": ["@mapbox/node-pre-gyp@2.0.0", "", { "dependencies": { "consola": "^3.2.3", "detect-libc": "^2.0.0", "https-proxy-agent": "^7.0.5", "node-fetch": "^2.6.7", "nopt": "^8.0.0", "semver": "^7.5.3", "tar": "^7.4.0" }, "bin": { "node-pre-gyp": "bin/node-pre-gyp" } }, "sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg=="],
|
||||||
|
|
||||||
"@netlify/functions": ["@netlify/functions@3.0.4", "", { "dependencies": { "@netlify/serverless-functions-api": "1.36.0" } }, "sha512-Ox8+ABI+nsLK+c4/oC5dpquXuEIjzfTlJrdQKgQijCsDQoje7inXFAtKDLvvaGvuvE+PVpMLwQcIUL6P9Ob1hQ=="],
|
"@netlify/functions": ["@netlify/functions@3.0.4", "", { "dependencies": { "@netlify/serverless-functions-api": "1.36.0" } }, "sha512-Ox8+ABI+nsLK+c4/oC5dpquXuEIjzfTlJrdQKgQijCsDQoje7inXFAtKDLvvaGvuvE+PVpMLwQcIUL6P9Ob1hQ=="],
|
||||||
|
|
||||||
"@netlify/serverless-functions-api": ["@netlify/serverless-functions-api@1.36.0", "", {}, "sha512-z6okREyK8in0486a22Oro0k+YsuyEjDXJt46FpgeOgXqKJ9ElM8QPll0iuLBkpbH33ENiNbIPLd1cuClRQnhiw=="],
|
"@netlify/serverless-functions-api": ["@netlify/serverless-functions-api@1.36.0", "", {}, "sha512-z6okREyK8in0486a22Oro0k+YsuyEjDXJt46FpgeOgXqKJ9ElM8QPll0iuLBkpbH33ENiNbIPLd1cuClRQnhiw=="],
|
||||||
|
|
||||||
|
"@noble/ciphers": ["@noble/ciphers@0.6.0", "", {}, "sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ=="],
|
||||||
|
|
||||||
|
"@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="],
|
||||||
|
|
||||||
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
||||||
|
|
||||||
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
|
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
|
||||||
|
@ -186,6 +199,16 @@
|
||||||
|
|
||||||
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="],
|
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="],
|
||||||
|
|
||||||
|
"@peculiar/asn1-android": ["@peculiar/asn1-android@2.3.16", "", { "dependencies": { "@peculiar/asn1-schema": "^2.3.15", "asn1js": "^3.0.5", "tslib": "^2.8.1" } }, "sha512-a1viIv3bIahXNssrOIkXZIlI2ePpZaNmR30d4aBL99mu2rO+mT9D6zBsp7H6eROWGtmwv0Ionp5olJurIo09dw=="],
|
||||||
|
|
||||||
|
"@peculiar/asn1-ecc": ["@peculiar/asn1-ecc@2.3.15", "", { "dependencies": { "@peculiar/asn1-schema": "^2.3.15", "@peculiar/asn1-x509": "^2.3.15", "asn1js": "^3.0.5", "tslib": "^2.8.1" } }, "sha512-/HtR91dvgog7z/WhCVdxZJ/jitJuIu8iTqiyWVgRE9Ac5imt2sT/E4obqIVGKQw7PIy+X6i8lVBoT6wC73XUgA=="],
|
||||||
|
|
||||||
|
"@peculiar/asn1-rsa": ["@peculiar/asn1-rsa@2.3.15", "", { "dependencies": { "@peculiar/asn1-schema": "^2.3.15", "@peculiar/asn1-x509": "^2.3.15", "asn1js": "^3.0.5", "tslib": "^2.8.1" } }, "sha512-p6hsanvPhexRtYSOHihLvUUgrJ8y0FtOM97N5UEpC+VifFYyZa0iZ5cXjTkZoDwxJ/TTJ1IJo3HVTB2JJTpXvg=="],
|
||||||
|
|
||||||
|
"@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.3.15", "", { "dependencies": { "asn1js": "^3.0.5", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w=="],
|
||||||
|
|
||||||
|
"@peculiar/asn1-x509": ["@peculiar/asn1-x509@2.3.15", "", { "dependencies": { "@peculiar/asn1-schema": "^2.3.15", "asn1js": "^3.0.5", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-0dK5xqTqSLaxv1FHXIcd4Q/BZNuopg+u1l23hT9rOmQ1g4dNtw0g/RnEi+TboB0gOwGtrWn269v27cMgchFIIg=="],
|
||||||
|
|
||||||
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
||||||
|
|
||||||
"@poppinss/colors": ["@poppinss/colors@4.1.4", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FA+nTU8p6OcSH4tLDY5JilGYr1bVWHpNmcLr7xmMEdbWmKHa+3QZ+DqefrXKmdjO/brHTnQZo20lLSjaO7ydog=="],
|
"@poppinss/colors": ["@poppinss/colors@4.1.4", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FA+nTU8p6OcSH4tLDY5JilGYr1bVWHpNmcLr7xmMEdbWmKHa+3QZ+DqefrXKmdjO/brHTnQZo20lLSjaO7ydog=="],
|
||||||
|
@ -270,6 +293,10 @@
|
||||||
|
|
||||||
"@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
|
"@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
|
||||||
|
|
||||||
|
"@simplewebauthn/browser": ["@simplewebauthn/browser@13.1.0", "", {}, "sha512-WuHZ/PYvyPJ9nxSzgHtOEjogBhwJfC8xzYkPC+rR/+8chl/ft4ngjiK8kSU5HtRJfczupyOh33b25TjYbvwAcg=="],
|
||||||
|
|
||||||
|
"@simplewebauthn/server": ["@simplewebauthn/server@13.1.1", "", { "dependencies": { "@hexagon/base64": "^1.1.27", "@levischuck/tiny-cbor": "^0.2.2", "@peculiar/asn1-android": "^2.3.10", "@peculiar/asn1-ecc": "^2.3.8", "@peculiar/asn1-rsa": "^2.3.8", "@peculiar/asn1-schema": "^2.3.8", "@peculiar/asn1-x509": "^2.3.8" } }, "sha512-1hsLpRHfSuMB9ee2aAdh0Htza/X3f4djhYISrggqGe3xopNjOcePiSDkDDoPzDYaaMCrbqGP1H2TYU7bgL9PmA=="],
|
||||||
|
|
||||||
"@sindresorhus/is": ["@sindresorhus/is@7.0.1", "", {}, "sha512-QWLl2P+rsCJeofkDNIT3WFmb6NrRud1SUYW8dIhXK/46XFV8Q/g7Bsvib0Askb0reRLe+WYPeeE+l5cH7SlkuQ=="],
|
"@sindresorhus/is": ["@sindresorhus/is@7.0.1", "", {}, "sha512-QWLl2P+rsCJeofkDNIT3WFmb6NrRud1SUYW8dIhXK/46XFV8Q/g7Bsvib0Askb0reRLe+WYPeeE+l5cH7SlkuQ=="],
|
||||||
|
|
||||||
"@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@2.3.0", "", {}, "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg=="],
|
"@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@2.3.0", "", {}, "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg=="],
|
||||||
|
@ -334,6 +361,8 @@
|
||||||
|
|
||||||
"@types/braces": ["@types/braces@3.0.5", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="],
|
"@types/braces": ["@types/braces@3.0.5", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="],
|
||||||
|
|
||||||
|
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
||||||
|
|
||||||
"@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
|
"@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
|
||||||
|
|
||||||
"@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
|
"@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
|
||||||
|
@ -342,6 +371,8 @@
|
||||||
|
|
||||||
"@types/micromatch": ["@types/micromatch@4.0.9", "", { "dependencies": { "@types/braces": "*" } }, "sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg=="],
|
"@types/micromatch": ["@types/micromatch@4.0.9", "", { "dependencies": { "@types/braces": "*" } }, "sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg=="],
|
||||||
|
|
||||||
|
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@22.13.14", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w=="],
|
"@types/node": ["@types/node@22.13.14", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w=="],
|
||||||
|
|
||||||
"@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
|
"@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
|
||||||
|
@ -414,6 +445,8 @@
|
||||||
|
|
||||||
"aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
|
"aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
|
||||||
|
|
||||||
|
"asn1js": ["asn1js@3.0.6", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA=="],
|
||||||
|
|
||||||
"assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
|
"assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
|
||||||
|
|
||||||
"ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="],
|
"ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="],
|
||||||
|
@ -438,6 +471,10 @@
|
||||||
|
|
||||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||||
|
|
||||||
|
"better-auth": ["better-auth@1.2.6", "", { "dependencies": { "@better-auth/utils": "0.2.4", "@better-fetch/fetch": "^1.1.18", "@noble/ciphers": "^0.6.0", "@noble/hashes": "^1.6.1", "@simplewebauthn/browser": "^13.0.0", "@simplewebauthn/server": "^13.0.0", "better-call": "^1.0.7", "defu": "^6.1.4", "jose": "^5.9.6", "kysely": "^0.27.6", "nanostores": "^0.11.3", "zod": "^3.24.1" } }, "sha512-RVy6nfNCXpohx49zP2ChUO3zN0nvz5UXuETJIhWU+dshBKpFMk4P4hAQauM3xqTJdd9hfeB5y+segmG1oYGTJQ=="],
|
||||||
|
|
||||||
|
"better-call": ["better-call@1.0.7", "", { "dependencies": { "@better-fetch/fetch": "^1.1.4", "rou3": "^0.5.1", "set-cookie-parser": "^2.7.1", "uncrypto": "^0.1.3" } }, "sha512-p5kEthErx3HsW9dCCvvEx+uuEdncn0ZrlqrOG3TkR1aVYgynpwYbTVU90nY8/UwfMhROzqZWs8vryainSQxrNg=="],
|
||||||
|
|
||||||
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
||||||
|
|
||||||
"bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="],
|
"bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="],
|
||||||
|
@ -768,6 +805,8 @@
|
||||||
|
|
||||||
"jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="],
|
"jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="],
|
||||||
|
|
||||||
|
"jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="],
|
||||||
|
|
||||||
"js-levenshtein": ["js-levenshtein@1.1.6", "", {}, "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g=="],
|
"js-levenshtein": ["js-levenshtein@1.1.6", "", {}, "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g=="],
|
||||||
|
|
||||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||||
|
@ -786,6 +825,8 @@
|
||||||
|
|
||||||
"knitwork": ["knitwork@1.2.0", "", {}, "sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg=="],
|
"knitwork": ["knitwork@1.2.0", "", {}, "sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg=="],
|
||||||
|
|
||||||
|
"kysely": ["kysely@0.27.6", "", {}, "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ=="],
|
||||||
|
|
||||||
"lazystream": ["lazystream@1.0.1", "", { "dependencies": { "readable-stream": "^2.0.5" } }, "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw=="],
|
"lazystream": ["lazystream@1.0.1", "", { "dependencies": { "readable-stream": "^2.0.5" } }, "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw=="],
|
||||||
|
|
||||||
"lightningcss": ["lightningcss@1.29.3", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.3", "lightningcss-darwin-x64": "1.29.3", "lightningcss-freebsd-x64": "1.29.3", "lightningcss-linux-arm-gnueabihf": "1.29.3", "lightningcss-linux-arm64-gnu": "1.29.3", "lightningcss-linux-arm64-musl": "1.29.3", "lightningcss-linux-x64-gnu": "1.29.3", "lightningcss-linux-x64-musl": "1.29.3", "lightningcss-win32-arm64-msvc": "1.29.3", "lightningcss-win32-x64-msvc": "1.29.3" } }, "sha512-GlOJwTIP6TMIlrTFsxTerwC0W6OpQpCGuX1ECRLBUVRh6fpJH3xTqjCjRgQHTb4ZXexH9rtHou1Lf03GKzmhhQ=="],
|
"lightningcss": ["lightningcss@1.29.3", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.3", "lightningcss-darwin-x64": "1.29.3", "lightningcss-freebsd-x64": "1.29.3", "lightningcss-linux-arm-gnueabihf": "1.29.3", "lightningcss-linux-arm64-gnu": "1.29.3", "lightningcss-linux-arm64-musl": "1.29.3", "lightningcss-linux-x64-gnu": "1.29.3", "lightningcss-linux-x64-musl": "1.29.3", "lightningcss-win32-arm64-msvc": "1.29.3", "lightningcss-win32-x64-msvc": "1.29.3" } }, "sha512-GlOJwTIP6TMIlrTFsxTerwC0W6OpQpCGuX1ECRLBUVRh6fpJH3xTqjCjRgQHTb4ZXexH9rtHou1Lf03GKzmhhQ=="],
|
||||||
|
@ -870,6 +911,8 @@
|
||||||
|
|
||||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||||
|
|
||||||
|
"nanostores": ["nanostores@0.11.4", "", {}, "sha512-k1oiVNN4hDK8NcNERSZLQiMfRzEGtfnvZvdBvey3SQbgn8Dcrk0h1I6vpxApjb10PFUflZrgJ2WEZyJQ+5v7YQ=="],
|
||||||
|
|
||||||
"nitropack": ["nitropack@2.11.7", "", { "dependencies": { "@cloudflare/kv-asset-handler": "^0.4.0", "@netlify/functions": "^3.0.2", "@rollup/plugin-alias": "^5.1.1", "@rollup/plugin-commonjs": "^28.0.3", "@rollup/plugin-inject": "^5.0.5", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-replace": "^6.0.2", "@rollup/plugin-terser": "^0.4.4", "@vercel/nft": "^0.29.2", "archiver": "^7.0.1", "c12": "^3.0.2", "chokidar": "^4.0.3", "citty": "^0.1.6", "compatx": "^0.1.8", "confbox": "^0.2.1", "consola": "^3.4.2", "cookie-es": "^2.0.0", "croner": "^9.0.0", "crossws": "^0.3.4", "db0": "^0.3.1", "defu": "^6.1.4", "destr": "^2.0.3", "dot-prop": "^9.0.0", "esbuild": "^0.25.1", "escape-string-regexp": "^5.0.0", "etag": "^1.8.1", "exsolve": "^1.0.4", "globby": "^14.1.0", "gzip-size": "^7.0.0", "h3": "^1.15.1", "hookable": "^5.5.3", "httpxy": "^0.1.7", "ioredis": "^5.6.0", "jiti": "^2.4.2", "klona": "^2.0.6", "knitwork": "^1.2.0", "listhen": "^1.9.0", "magic-string": "^0.30.17", "magicast": "^0.3.5", "mime": "^4.0.6", "mlly": "^1.7.4", "node-fetch-native": "^1.6.6", "node-mock-http": "^1.0.0", "ofetch": "^1.4.1", "ohash": "^2.0.11", "openapi-typescript": "^7.6.1", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.1.0", "pretty-bytes": "^6.1.1", "radix3": "^1.1.2", "rollup": "^4.36.0", "rollup-plugin-visualizer": "^5.14.0", "scule": "^1.3.0", "semver": "^7.7.1", "serve-placeholder": "^2.0.2", "serve-static": "^1.16.2", "source-map": "^0.7.4", "std-env": "^3.8.1", "ufo": "^1.5.4", "ultrahtml": "^1.5.3", "uncrypto": "^0.1.3", "unctx": "^2.4.1", "unenv": "^2.0.0-rc.15", "unimport": "^4.1.2", "unplugin-utils": "^0.2.4", "unstorage": "^1.15.0", "untyped": "^2.0.0", "unwasm": "^0.3.9", "youch": "^4.1.0-beta.6", "youch-core": "^0.3.2" }, "peerDependencies": { "xml2js": "^0.6.2" }, "optionalPeers": ["xml2js"], "bin": { "nitro": "dist/cli/index.mjs", "nitropack": "dist/cli/index.mjs" } }, "sha512-ghqLa3Q4X9qaQiUyspWxxoU1fY2nwfSJqhOH+COqyCp7Vgj4oM1EM1L0YNSQUF16T2tAoOWg8woXGq0EH5Y6wQ=="],
|
"nitropack": ["nitropack@2.11.7", "", { "dependencies": { "@cloudflare/kv-asset-handler": "^0.4.0", "@netlify/functions": "^3.0.2", "@rollup/plugin-alias": "^5.1.1", "@rollup/plugin-commonjs": "^28.0.3", "@rollup/plugin-inject": "^5.0.5", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-replace": "^6.0.2", "@rollup/plugin-terser": "^0.4.4", "@vercel/nft": "^0.29.2", "archiver": "^7.0.1", "c12": "^3.0.2", "chokidar": "^4.0.3", "citty": "^0.1.6", "compatx": "^0.1.8", "confbox": "^0.2.1", "consola": "^3.4.2", "cookie-es": "^2.0.0", "croner": "^9.0.0", "crossws": "^0.3.4", "db0": "^0.3.1", "defu": "^6.1.4", "destr": "^2.0.3", "dot-prop": "^9.0.0", "esbuild": "^0.25.1", "escape-string-regexp": "^5.0.0", "etag": "^1.8.1", "exsolve": "^1.0.4", "globby": "^14.1.0", "gzip-size": "^7.0.0", "h3": "^1.15.1", "hookable": "^5.5.3", "httpxy": "^0.1.7", "ioredis": "^5.6.0", "jiti": "^2.4.2", "klona": "^2.0.6", "knitwork": "^1.2.0", "listhen": "^1.9.0", "magic-string": "^0.30.17", "magicast": "^0.3.5", "mime": "^4.0.6", "mlly": "^1.7.4", "node-fetch-native": "^1.6.6", "node-mock-http": "^1.0.0", "ofetch": "^1.4.1", "ohash": "^2.0.11", "openapi-typescript": "^7.6.1", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.1.0", "pretty-bytes": "^6.1.1", "radix3": "^1.1.2", "rollup": "^4.36.0", "rollup-plugin-visualizer": "^5.14.0", "scule": "^1.3.0", "semver": "^7.7.1", "serve-placeholder": "^2.0.2", "serve-static": "^1.16.2", "source-map": "^0.7.4", "std-env": "^3.8.1", "ufo": "^1.5.4", "ultrahtml": "^1.5.3", "uncrypto": "^0.1.3", "unctx": "^2.4.1", "unenv": "^2.0.0-rc.15", "unimport": "^4.1.2", "unplugin-utils": "^0.2.4", "unstorage": "^1.15.0", "untyped": "^2.0.0", "unwasm": "^0.3.9", "youch": "^4.1.0-beta.6", "youch-core": "^0.3.2" }, "peerDependencies": { "xml2js": "^0.6.2" }, "optionalPeers": ["xml2js"], "bin": { "nitro": "dist/cli/index.mjs", "nitropack": "dist/cli/index.mjs" } }, "sha512-ghqLa3Q4X9qaQiUyspWxxoU1fY2nwfSJqhOH+COqyCp7Vgj4oM1EM1L0YNSQUF16T2tAoOWg8woXGq0EH5Y6wQ=="],
|
||||||
|
|
||||||
"node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
|
"node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
|
||||||
|
@ -954,6 +997,10 @@
|
||||||
|
|
||||||
"property-information": ["property-information@7.0.0", "", {}, "sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg=="],
|
"property-information": ["property-information@7.0.0", "", {}, "sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg=="],
|
||||||
|
|
||||||
|
"pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="],
|
||||||
|
|
||||||
|
"pvutils": ["pvutils@1.1.3", "", {}, "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ=="],
|
||||||
|
|
||||||
"quansync": ["quansync@0.2.10", "", {}, "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A=="],
|
"quansync": ["quansync@0.2.10", "", {}, "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A=="],
|
||||||
|
|
||||||
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||||
|
@ -1004,6 +1051,8 @@
|
||||||
|
|
||||||
"rollup-plugin-visualizer": ["rollup-plugin-visualizer@5.14.0", "", { "dependencies": { "open": "^8.4.0", "picomatch": "^4.0.2", "source-map": "^0.7.4", "yargs": "^17.5.1" }, "peerDependencies": { "rolldown": "1.x", "rollup": "2.x || 3.x || 4.x" }, "optionalPeers": ["rolldown", "rollup"], "bin": { "rollup-plugin-visualizer": "dist/bin/cli.js" } }, "sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA=="],
|
"rollup-plugin-visualizer": ["rollup-plugin-visualizer@5.14.0", "", { "dependencies": { "open": "^8.4.0", "picomatch": "^4.0.2", "source-map": "^0.7.4", "yargs": "^17.5.1" }, "peerDependencies": { "rolldown": "1.x", "rollup": "2.x || 3.x || 4.x" }, "optionalPeers": ["rolldown", "rollup"], "bin": { "rollup-plugin-visualizer": "dist/bin/cli.js" } }, "sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA=="],
|
||||||
|
|
||||||
|
"rou3": ["rou3@0.5.1", "", {}, "sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ=="],
|
||||||
|
|
||||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||||
|
|
||||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||||
|
@ -1026,6 +1075,8 @@
|
||||||
|
|
||||||
"serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="],
|
"serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="],
|
||||||
|
|
||||||
|
"set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="],
|
||||||
|
|
||||||
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
|
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
|
||||||
|
|
||||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
"@solidjs/meta": "^0.29.4",
|
"@solidjs/meta": "^0.29.4",
|
||||||
"@solidjs/router": "^0.15.3",
|
"@solidjs/router": "^0.15.3",
|
||||||
"@solidjs/start": "^1.1.3",
|
"@solidjs/start": "^1.1.3",
|
||||||
|
"better-auth": "^1.2.6",
|
||||||
"open-props": "^1.7.14",
|
"open-props": "^1.7.14",
|
||||||
"sitemap": "^8.0.0",
|
"sitemap": "^8.0.0",
|
||||||
"solid-icons": "^1.1.0",
|
"solid-icons": "^1.1.0",
|
||||||
|
|
29
src/auth.ts
Normal file
29
src/auth.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { betterAuth } from "better-auth";
|
||||||
|
import { genericOAuth } from "better-auth/plugins";
|
||||||
|
import { createAuthClient } from "better-auth/solid";
|
||||||
|
import { genericOAuthClient } from "better-auth/client/plugins";
|
||||||
|
|
||||||
|
export const auth = betterAuth({
|
||||||
|
plugins: [
|
||||||
|
genericOAuth({
|
||||||
|
config: [
|
||||||
|
{
|
||||||
|
providerId: "authelia",
|
||||||
|
clientId: "streamarr",
|
||||||
|
clientSecret:
|
||||||
|
"ZPuiW2gpVV6MGXIJFk5P3EeSW8V_ICgqduF.hJVCKkrnVmRqIQXRk0o~HSA8ZdCf8joA4m_F",
|
||||||
|
discoveryUrl:
|
||||||
|
"https://auth.kruining.eu/.well-known/openid-configuration",
|
||||||
|
scopes: ["openid", "email", "picture", "profile", "groups"],
|
||||||
|
accessType: "offline",
|
||||||
|
pkce: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { signIn, signOut, useSession, ...client } = createAuthClient({
|
||||||
|
baseURL: "http://localhost:3000",
|
||||||
|
plugins: [genericOAuthClient()],
|
||||||
|
});
|
39
src/features/player/SampleVideo_1280x720_10mb.captions.vtt
Normal file
39
src/features/player/SampleVideo_1280x720_10mb.captions.vtt
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
WEBVTT
|
||||||
|
|
||||||
|
00:02.170 --> 00:04.136
|
||||||
|
Emo, close your eyes
|
||||||
|
|
||||||
|
00:04.136 --> 00:05.597
|
||||||
|
Why?
|
||||||
|
NOW!
|
||||||
|
|
||||||
|
00:05.597 --> 00:07.405
|
||||||
|
Ok
|
||||||
|
|
||||||
|
00:07.405 --> 00:08.803
|
||||||
|
Good
|
||||||
|
|
||||||
|
00:08.803 --> 00:11.541
|
||||||
|
What do you see at your left side Emo?
|
||||||
|
|
||||||
|
00:11.541 --> 00:13.287
|
||||||
|
Well?
|
||||||
|
|
||||||
|
00:13.287 --> 00:16.110
|
||||||
|
Er nothing?
|
||||||
|
Really?
|
||||||
|
|
||||||
|
00:16.110 --> 00:18.514
|
||||||
|
No, nothing at all!
|
||||||
|
|
||||||
|
00:18.514 --> 00:22.669
|
||||||
|
Really? and at your right? What do you see at your right side Emo?
|
||||||
|
|
||||||
|
00:22.669 --> 00:26.111
|
||||||
|
Umm, the same Proog
|
||||||
|
|
||||||
|
00:26.111 --> 00:28.646
|
||||||
|
Exactly the same! Nothing!
|
||||||
|
|
||||||
|
00:28.646 --> 00:30.794
|
||||||
|
Great
|
BIN
src/features/player/SampleVideo_1280x720_10mb.mp4
Normal file
BIN
src/features/player/SampleVideo_1280x720_10mb.mp4
Normal file
Binary file not shown.
54
src/features/player/SampleVideo_1280x720_10mb.thumbnails.vtt
Normal file
54
src/features/player/SampleVideo_1280x720_10mb.thumbnails.vtt
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
VTT
|
||||||
|
|
||||||
|
1
|
||||||
|
00:00:00.000 --> 00:00:01.000
|
||||||
|
overview.jpg#xywh=0,0,320,180
|
||||||
|
|
||||||
|
2
|
||||||
|
00:00:01.000 --> 00:00:02.000
|
||||||
|
overview.jpg#xywh=320,0,320,180
|
||||||
|
|
||||||
|
3
|
||||||
|
00:00:02.000 --> 00:00:03.000
|
||||||
|
overview.jpg#xywh=640,0,320,180
|
||||||
|
|
||||||
|
00:00:03.000 --> 00:00:04.000
|
||||||
|
overview.jpg#xywh=960,0,320,180
|
||||||
|
|
||||||
|
00:00:04.000 --> 00:00:05.000
|
||||||
|
overview.jpg#xywh=1280,0,320,180
|
||||||
|
|
||||||
|
00:00:05.000 --> 00:00:06.000
|
||||||
|
overview.jpg#xywh=1600,0,320,180
|
||||||
|
|
||||||
|
00:00:06.000 --> 00:00:07.000
|
||||||
|
overview.jpg#xywh=1920,0,320,180
|
||||||
|
|
||||||
|
00:00:07.000 --> 00:00:08.000
|
||||||
|
overview.jpg#xywh=2240,0,320,180
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
00:00:08.000 --> 00:00:09.000
|
||||||
|
overview.jpg#xywh=0,180,320,180
|
||||||
|
|
||||||
|
00:00:09.000 --> 00:00:10.000
|
||||||
|
overview.jpg#xywh=320,180,320,180
|
||||||
|
|
||||||
|
00:00:10.000 --> 00:00:11.000
|
||||||
|
overview.jpg#xywh=640,180,320,180
|
||||||
|
|
||||||
|
00:00:11.000 --> 00:00:12.000
|
||||||
|
overview.jpg#xywh=960,180,320,180
|
||||||
|
|
||||||
|
00:00:12.000 --> 00:00:13.000
|
||||||
|
overview.jpg#xywh=1280,180,320,180
|
||||||
|
|
||||||
|
00:00:13.000 --> 00:00:14.000
|
||||||
|
overview.jpg#xywh=1600,180,320,180
|
||||||
|
|
||||||
|
00:00:14.000 --> 00:00:15.000
|
||||||
|
overview.jpg#xywh=1920,180,320,180
|
||||||
|
|
||||||
|
00:00:15.000 --> 00:00:16.000
|
||||||
|
overview.jpg#xywh=2240,180,320,180
|
3
src/features/player/controls/volume.module.css
Normal file
3
src/features/player/controls/volume.module.css
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.container {
|
||||||
|
display: block grid;
|
||||||
|
}
|
17
src/features/player/controls/volume.tsx
Normal file
17
src/features/player/controls/volume.tsx
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { Component, createSignal } from "solid-js";
|
||||||
|
import css from "./volume.module.css";
|
||||||
|
|
||||||
|
interface VolumeProps {
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Volume: Component<VolumeProps> = (props) => {
|
||||||
|
const [volume, setVolume] = createSignal(props.value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={css.container}>
|
||||||
|
<button>mute</button>
|
||||||
|
<input type="range" value={volume()} min="0" max="1" step="0.01" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
BIN
src/features/player/overview.jpg
Normal file
BIN
src/features/player/overview.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
|
@ -0,0 +1,5 @@
|
||||||
|
.player {
|
||||||
|
& > video::cue {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,22 +12,90 @@ import {
|
||||||
onMount,
|
onMount,
|
||||||
untrack,
|
untrack,
|
||||||
} from "solid-js";
|
} from "solid-js";
|
||||||
|
import css from "./player.module.css";
|
||||||
|
import { Volume } from "./controls/volume";
|
||||||
|
|
||||||
|
const metadata = query(async (id: string) => {
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
// thumbnail sprite image created with
|
||||||
|
// ```bash
|
||||||
|
// mkdir -p thumbs \
|
||||||
|
// && ffmpeg -i SampleVideo_1280x720_10mb.mp4 -r 1 -s 320x180 -f image2 thumbs/thumb-%d.jpg \
|
||||||
|
// && montage thumbs/*.jpg -geometry 320x180 -tile 8x overview.jpg \
|
||||||
|
// && rm -rf thumbs
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// 1. create thumbs directory
|
||||||
|
// 2. create image every 1 second
|
||||||
|
// 3. create sprite from images
|
||||||
|
// 4. remove thumbs
|
||||||
|
|
||||||
|
const path = `${import.meta.dirname}/SampleVideo_1280x720_10mb`;
|
||||||
|
|
||||||
|
return json({
|
||||||
|
captions: await Bun.file(`${path}.captions.vtt`).bytes(),
|
||||||
|
thumbnails: {
|
||||||
|
track: await Bun.file(`${path}.thumbnails.vtt`).text(),
|
||||||
|
image: await Bun.file(`${import.meta.dirname}/overview.jpg`).bytes(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, "player.metadata");
|
||||||
|
|
||||||
interface PlayerProps {
|
interface PlayerProps {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Player: Component<PlayerProps> = (props) => {
|
export const Player: Component<PlayerProps> = (props) => {
|
||||||
const [video, setVideo] = createSignal<HTMLVideoElement>(undefined as unknown as HTMLVideoElement);
|
const [video, setVideo] = createSignal<HTMLVideoElement>(
|
||||||
|
undefined as unknown as HTMLVideoElement,
|
||||||
|
);
|
||||||
|
const data = createAsync(() => metadata(props.id), {
|
||||||
|
deferStream: true,
|
||||||
|
initialValue: {},
|
||||||
|
});
|
||||||
|
const captionUrl = createMemo(() => {
|
||||||
|
const { captions } = data();
|
||||||
|
|
||||||
const onDurationChange = createEventSignal(video, 'durationchange');
|
return captions !== undefined
|
||||||
const onTimeUpdate = createEventSignal(video, 'timeupdate');
|
? URL.createObjectURL(new Blob([captions], { type: "text/vtt" }))
|
||||||
|
: "";
|
||||||
|
});
|
||||||
|
const thumbnails = createMemo(() => {
|
||||||
|
const { thumbnails } = data();
|
||||||
|
|
||||||
|
return thumbnails !== undefined
|
||||||
|
? URL.createObjectURL(new Blob([thumbnails.track], { type: "text/vtt" }))
|
||||||
|
: "";
|
||||||
|
});
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
const metadata = data();
|
||||||
|
const el = video();
|
||||||
|
|
||||||
|
if (metadata === undefined || el === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(metadata);
|
||||||
|
});
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
thumbnails();
|
||||||
|
|
||||||
|
console.log(video()!.textTracks.getTrackById("thumbnails")?.cues);
|
||||||
|
|
||||||
|
// const captions = el.addTextTrack("captions", "English", "en");
|
||||||
|
// captions.
|
||||||
|
});
|
||||||
|
|
||||||
|
const onDurationChange = createEventSignal(video, "durationchange");
|
||||||
|
const onTimeUpdate = createEventSignal(video, "timeupdate");
|
||||||
|
|
||||||
const duration = createMemo(() => {
|
const duration = createMemo(() => {
|
||||||
onDurationChange();
|
onDurationChange();
|
||||||
onTimeUpdate();
|
|
||||||
|
|
||||||
return video()?.duration ?? 100;
|
return video()?.duration ?? 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
const currentTime = createMemo(() => {
|
const currentTime = createMemo(() => {
|
||||||
|
@ -36,10 +104,6 @@ export const Player: Component<PlayerProps> = (props) => {
|
||||||
return video()?.currentTime ?? 0;
|
return video()?.currentTime ?? 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
console.log(duration(), currentTime());
|
|
||||||
});
|
|
||||||
|
|
||||||
createEventListenerMap(() => video()!, {
|
createEventListenerMap(() => video()!, {
|
||||||
durationchange(e) {
|
durationchange(e) {
|
||||||
console.log("durationchange", e);
|
console.log("durationchange", e);
|
||||||
|
@ -60,7 +124,11 @@ export const Player: Component<PlayerProps> = (props) => {
|
||||||
console.log("seeking", e);
|
console.log("seeking", e);
|
||||||
},
|
},
|
||||||
stalled(e) {
|
stalled(e) {
|
||||||
console.log("stalled (meaning downloading data failed)", e, video()!.error);
|
console.log(
|
||||||
|
"stalled (meaning downloading data failed)",
|
||||||
|
e,
|
||||||
|
video()!.error,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
play(e) {
|
play(e) {
|
||||||
|
@ -107,17 +175,52 @@ export const Player: Component<PlayerProps> = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<figure class={css.player}>
|
||||||
<h1>{props.id}</h1>
|
<h1>{props.id}</h1>
|
||||||
|
|
||||||
<video ref={setVideo} width="1280px" height="720px" muted src="/api/stream/video" />
|
<video
|
||||||
|
ref={setVideo}
|
||||||
|
muted
|
||||||
|
autoplay
|
||||||
|
controls
|
||||||
|
src={`/api/content/stream?id=${props.id}`}
|
||||||
|
lang="en"
|
||||||
|
>
|
||||||
|
<track
|
||||||
|
default
|
||||||
|
kind="captions"
|
||||||
|
label="English"
|
||||||
|
srclang="en"
|
||||||
|
src={captionUrl()}
|
||||||
|
/>
|
||||||
|
<track default kind="chapters" src={thumbnails()} id="thumbnails" />
|
||||||
|
{/* <track kind="captions" />
|
||||||
|
<track kind="chapters" />
|
||||||
|
<track kind="descriptions" />
|
||||||
|
<track kind="metadata" />
|
||||||
|
<track kind="subtitles" /> */}
|
||||||
|
</video>
|
||||||
|
|
||||||
|
<figcaption>
|
||||||
|
<Volume value={0.5} />
|
||||||
|
</figcaption>
|
||||||
|
|
||||||
<button onclick={toggle}>play/pause</button>
|
<button onclick={toggle}>play/pause</button>
|
||||||
|
|
||||||
<span style={{ '--duration': duration(), '--current-time': currentTime() }} />
|
<span>
|
||||||
<span data-duration={duration()} data-current-time={currentTime()} />
|
{formatTime(currentTime())} / {formatTime(duration())}
|
||||||
|
</span>
|
||||||
<progress max={duration()} value={currentTime()} />
|
<progress max={duration().toFixed(0)} value={currentTime().toFixed(0)} />
|
||||||
</>
|
</figure>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const formatTime = (subject: number) => {
|
||||||
|
const hours = Math.floor(subject / 3600);
|
||||||
|
const minutes = Math.floor((subject % 3600) / 60);
|
||||||
|
const seconds = Math.floor(subject % 60);
|
||||||
|
|
||||||
|
const sections = hours !== 0 ? [hours, minutes, seconds] : [minutes, seconds];
|
||||||
|
|
||||||
|
return sections.map((section) => String(section).padStart(2, "0")).join(":");
|
||||||
|
};
|
||||||
|
|
|
@ -1,10 +1,64 @@
|
||||||
import { Component } from "solid-js";
|
import { Component, createEffect, createMemo, Show } from "solid-js";
|
||||||
import { ColorSchemePicker } from "../theme";
|
import { ColorSchemePicker } from "../theme";
|
||||||
|
import { signIn, signOut, useSession } from "~/auth";
|
||||||
|
import { hash } from "~/utilities";
|
||||||
import css from "./top.module.css";
|
import css from "./top.module.css";
|
||||||
|
|
||||||
export const Top: Component = (props) => {
|
export const Top: Component = (props) => {
|
||||||
|
const session = useSession();
|
||||||
|
const hashedEmail = hash("SHA-256", () => session().data?.user.email);
|
||||||
|
|
||||||
|
const login = async () => {
|
||||||
|
const response = await signIn.oauth2({
|
||||||
|
providerId: "authelia",
|
||||||
|
callbackURL: "/",
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("signin response", response);
|
||||||
|
};
|
||||||
|
|
||||||
|
const logout = async () => {
|
||||||
|
const response = await signOut();
|
||||||
|
|
||||||
|
console.log("signout response", response);
|
||||||
|
};
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
console.log(hashedEmail());
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside class={css.top}>
|
<aside class={css.top}>
|
||||||
|
<Show
|
||||||
|
when={session().isPending === false && session().isRefetching === false}
|
||||||
|
>
|
||||||
|
<Show
|
||||||
|
when={session().data?.user}
|
||||||
|
fallback={
|
||||||
|
<form method="post" onSubmit={login}>
|
||||||
|
<button type="submit">Sign in</button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{(user) => (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
src={
|
||||||
|
user().image ??
|
||||||
|
`https://www.gravatar.com/avatar/${hashedEmail()}`
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<span>{user().name}</span>
|
||||||
|
<span>{user().email}</span>
|
||||||
|
</div>
|
||||||
|
<form method="post" onSubmit={logout}>
|
||||||
|
<button type="submit">Log out</button>
|
||||||
|
</form>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Show>
|
||||||
|
</Show>
|
||||||
<ColorSchemePicker />
|
<ColorSchemePicker />
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,43 +1,69 @@
|
||||||
import { WiMoonAltFirstQuarter, WiMoonAltFull, WiMoonAltNew } from "solid-icons/wi";
|
import {
|
||||||
import { Component, createEffect, For, Match, on, Setter, Switch } from "solid-js";
|
WiMoonAltFirstQuarter,
|
||||||
|
WiMoonAltFull,
|
||||||
|
WiMoonAltNew,
|
||||||
|
} from "solid-icons/wi";
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
createEffect,
|
||||||
|
For,
|
||||||
|
Match,
|
||||||
|
on,
|
||||||
|
Setter,
|
||||||
|
Switch,
|
||||||
|
} from "solid-js";
|
||||||
import { ColorScheme, useTheme } from "./context";
|
import { ColorScheme, useTheme } from "./context";
|
||||||
import css from './picker.module.css';
|
import css from "./picker.module.css";
|
||||||
import { Select } from "~/components/select";
|
import { Select } from "~/components/select";
|
||||||
|
|
||||||
const colorSchemes: Record<ColorScheme, keyof typeof ColorScheme> = Object.fromEntries(Object.entries(ColorScheme).map(([k, v]) => [v, k])) as any;
|
const colorSchemes: Record<ColorScheme, keyof typeof ColorScheme> =
|
||||||
|
Object.fromEntries(
|
||||||
|
Object.entries(ColorScheme).map(([k, v]) => [v, k]),
|
||||||
|
) as any;
|
||||||
|
|
||||||
export const ColorSchemePicker: Component = (props) => {
|
export const ColorSchemePicker: Component = (props) => {
|
||||||
const themeContext = useTheme();
|
const themeContext = useTheme();
|
||||||
|
|
||||||
const setScheme: Setter<ColorScheme> = (next) => {
|
const setScheme: Setter<ColorScheme> = (next) => {
|
||||||
|
if (typeof next === "function") {
|
||||||
|
next = next();
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof next === 'function') {
|
themeContext.setColorScheme(next);
|
||||||
next = next();
|
};
|
||||||
}
|
|
||||||
|
|
||||||
themeContext.setColorScheme(next);
|
return (
|
||||||
};
|
<>
|
||||||
|
<label aria-label="Color scheme picker">
|
||||||
|
<Select
|
||||||
|
id="color-scheme-picker"
|
||||||
|
class={css.picker}
|
||||||
|
value={themeContext.theme.colorScheme}
|
||||||
|
setValue={setScheme}
|
||||||
|
values={colorSchemes}
|
||||||
|
>
|
||||||
|
{(k, v) => (
|
||||||
|
<>
|
||||||
|
<Switch>
|
||||||
|
<Match when={k === ColorScheme.Auto}>
|
||||||
|
<WiMoonAltFirstQuarter />
|
||||||
|
</Match>
|
||||||
|
<Match when={k === ColorScheme.Light}>
|
||||||
|
<WiMoonAltNew />
|
||||||
|
</Match>
|
||||||
|
<Match when={k === ColorScheme.Dark}>
|
||||||
|
<WiMoonAltFull />
|
||||||
|
</Match>
|
||||||
|
</Switch>
|
||||||
|
{v}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
</label>
|
||||||
|
|
||||||
createEffect(on(() => themeContext.theme.colorScheme, (colorScheme) => {
|
{/* <label class={css.hue} aria-label="Hue slider">
|
||||||
console.log(colorScheme);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return <>
|
|
||||||
<label aria-label="Color scheme picker">
|
|
||||||
<Select id="color-scheme-picker" class={css.picker} value={themeContext.theme.colorScheme} setValue={setScheme} values={colorSchemes}>{
|
|
||||||
(k, v) => <>
|
|
||||||
<Switch>
|
|
||||||
<Match when={k === ColorScheme.Auto}><WiMoonAltFirstQuarter /></Match>
|
|
||||||
<Match when={k === ColorScheme.Light}><WiMoonAltNew /></Match>
|
|
||||||
<Match when={k === ColorScheme.Dark}><WiMoonAltFull /></Match>
|
|
||||||
</Switch>
|
|
||||||
{v}
|
|
||||||
</>
|
|
||||||
}</Select>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
{/* <label class={css.hue} aria-label="Hue slider">
|
|
||||||
<input type="range" min="0" max="360" value={theme.hue} onInput={e => setHue(e.target.valueAsNumber)} />
|
<input type="range" min="0" max="360" value={theme.hue} onInput={e => setHue(e.target.valueAsNumber)} />
|
||||||
</label> */}
|
</label> */}
|
||||||
</>;
|
</>
|
||||||
};
|
);
|
||||||
|
};
|
||||||
|
|
11
src/features/user/avatar.tsx
Normal file
11
src/features/user/avatar.tsx
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { Component, createMemo, Show } from "solid-js";
|
||||||
|
|
||||||
|
export const Avatar: Component = (props) => {
|
||||||
|
const src = createMemo(() => "");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Show when={src()}>
|
||||||
|
<img src={src()} />
|
||||||
|
</Show>
|
||||||
|
);
|
||||||
|
};
|
1
src/features/user/index.ts
Normal file
1
src/features/user/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export { Avatar } from "./avatar";
|
5
src/features/user/user.ts
Normal file
5
src/features/user/user.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export interface User {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
image: string;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
import { Meta } from "@solidjs/meta";
|
import { Meta } from "@solidjs/meta";
|
||||||
|
import { query, createAsync, action } from "@solidjs/router";
|
||||||
import { createEffect, on, ParentProps } from "solid-js";
|
import { createEffect, on, ParentProps } from "solid-js";
|
||||||
import { Shell } from "~/features/shell";
|
import { Shell } from "~/features/shell";
|
||||||
import { useTheme } from "~/features/theme";
|
import { useTheme } from "~/features/theme";
|
||||||
|
@ -7,13 +7,20 @@ import { useTheme } from "~/features/theme";
|
||||||
export default function ShellPage(props: ParentProps) {
|
export default function ShellPage(props: ParentProps) {
|
||||||
const themeContext = useTheme();
|
const themeContext = useTheme();
|
||||||
|
|
||||||
createEffect(on(() => themeContext.theme.colorScheme, (colorScheme) => {
|
createEffect(
|
||||||
document.documentElement.dataset.theme = colorScheme;
|
on(
|
||||||
}));
|
() => themeContext.theme.colorScheme,
|
||||||
|
(colorScheme) => {
|
||||||
|
document.documentElement.dataset.theme = colorScheme;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return <Shell>
|
return (
|
||||||
<Meta name="color-scheme" content={themeContext.theme.colorScheme} />
|
<Shell>
|
||||||
|
<Meta name="color-scheme" content={themeContext.theme.colorScheme} />
|
||||||
|
|
||||||
{props.children}
|
{props.children}
|
||||||
</Shell>;
|
</Shell>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
import { json, Params, query, redirect, RouteDefinition, useParams } from "@solidjs/router";
|
import {
|
||||||
|
json,
|
||||||
|
Params,
|
||||||
|
query,
|
||||||
|
redirect,
|
||||||
|
RouteDefinition,
|
||||||
|
useParams,
|
||||||
|
} from "@solidjs/router";
|
||||||
import { createSlug, getEntry } from "~/features/content";
|
import { createSlug, getEntry } from "~/features/content";
|
||||||
import { Player } from "~/features/player";
|
import { Player } from "~/features/player";
|
||||||
import { toSlug } from "~/utilities";
|
import { toSlug } from "~/utilities";
|
||||||
|
|
||||||
const healUrl = query(async (slug: string) => {
|
const healUrl = query(async (slug: string) => {
|
||||||
const entry = await getEntry(slug.slice(slug.lastIndexOf('-') + 1));
|
const entry = await getEntry(slug.slice(slug.lastIndexOf("-") + 1));
|
||||||
|
|
||||||
if (entry === undefined) {
|
if (entry === undefined) {
|
||||||
return json(null, { status: 404 });
|
return json(null, { status: 404 });
|
||||||
|
@ -17,11 +24,10 @@ const healUrl = query(async (slug: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
throw redirect(`/watch/${actualSlug}`);
|
throw redirect(`/watch/${actualSlug}`);
|
||||||
}, 'watch.heal');
|
}, "watch.heal");
|
||||||
|
|
||||||
interface ItemParams extends Params {
|
interface ItemParams extends Params {
|
||||||
title: string;
|
slug: string;
|
||||||
id: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const route = {
|
export const route = {
|
||||||
|
@ -31,11 +37,12 @@ export const route = {
|
||||||
} satisfies RouteDefinition;
|
} satisfies RouteDefinition;
|
||||||
|
|
||||||
export default function Item() {
|
export default function Item() {
|
||||||
const params = useParams<ItemParams>();
|
const { slug } = useParams<ItemParams>();
|
||||||
|
const id = slug.slice(slug.lastIndexOf("-") + 1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Player id={params.id} />
|
<Player id={id} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
4
src/routes/api/auth/[...action].ts
Normal file
4
src/routes/api/auth/[...action].ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import { auth } from "~/auth";
|
||||||
|
import { toSolidStartHandler } from "better-auth/solid-start";
|
||||||
|
|
||||||
|
export const { GET, POST } = toSolidStartHandler(auth);
|
BIN
src/routes/api/content/SampleVideo_1280x720_10mb.mp4
Normal file
BIN
src/routes/api/content/SampleVideo_1280x720_10mb.mp4
Normal file
Binary file not shown.
16
src/routes/api/content/metadata.ts
Normal file
16
src/routes/api/content/metadata.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { json } from "@solidjs/router";
|
||||||
|
import { APIEvent } from "@solidjs/start/server";
|
||||||
|
|
||||||
|
export const GET = async (event: APIEvent) => {
|
||||||
|
console.log(event.params);
|
||||||
|
|
||||||
|
const path = `${import.meta.dirname}/SampleVideo_1280x720_10mb`;
|
||||||
|
|
||||||
|
return json({
|
||||||
|
captions: await Bun.file(`${path}.captions.vtt`).bytes(),
|
||||||
|
thumbnails: {
|
||||||
|
track: await Bun.file(`${path}.thumbnails.vtt`).text(),
|
||||||
|
image: await Bun.file(`${import.meta.dirname}/overview.jpg`).bytes(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
45
src/routes/api/content/stream.ts
Normal file
45
src/routes/api/content/stream.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import { APIEvent } from "@solidjs/start/server";
|
||||||
|
|
||||||
|
const CHUNK_SIZE = 1 * 1e6; // 1MB
|
||||||
|
|
||||||
|
export const GET = async ({ request, ...event }: APIEvent) => {
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
const range = request.headers.get("range");
|
||||||
|
|
||||||
|
if (range === null) {
|
||||||
|
return new Response("Requires Range header", { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const file = Bun.file(
|
||||||
|
import.meta.dirname + "/SampleVideo_1280x720_10mb.mp4",
|
||||||
|
);
|
||||||
|
|
||||||
|
if ((await file.exists()) !== true) {
|
||||||
|
return new Response("File not found", { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const videoSize = file.size;
|
||||||
|
|
||||||
|
const start = Number.parseInt(range.replace(/\D/g, ""));
|
||||||
|
const end = Math.min(start + CHUNK_SIZE, videoSize - 1);
|
||||||
|
const contentLength = end - start + 1;
|
||||||
|
|
||||||
|
return new Response(file.stream());
|
||||||
|
|
||||||
|
// return new Response(video.slice(start, end).stream(), {
|
||||||
|
// status: 206,
|
||||||
|
// headers: {
|
||||||
|
// 'Accept-Ranges': 'bytes',
|
||||||
|
// 'Content-Range': `bytes ${start}-${end}/${videoSize}`,
|
||||||
|
// 'Content-Length': `${contentLength}`,
|
||||||
|
// 'Content-type': 'video/mp4',
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,15 +1,46 @@
|
||||||
export const splitAt = (subject: string, index: number): readonly [string, string] => {
|
import { Accessor, createEffect, createSignal, on } from "solid-js";
|
||||||
if (index < 0) {
|
|
||||||
return [subject, ''];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index > subject.length) {
|
export const splitAt = (
|
||||||
return [subject, ''];
|
subject: string,
|
||||||
}
|
index: number,
|
||||||
|
): readonly [string, string] => {
|
||||||
|
if (index < 0) {
|
||||||
|
return [subject, ""];
|
||||||
|
}
|
||||||
|
|
||||||
return [subject.slice(0, index), subject.slice(index + 1)];
|
if (index > subject.length) {
|
||||||
|
return [subject, ""];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [subject.slice(0, index), subject.slice(index + 1)];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const toSlug = (subject: string) => {
|
export const toSlug = (subject: string) =>
|
||||||
return subject.toLowerCase().replaceAll(' ', '-');
|
subject.toLowerCase().replaceAll(" ", "-");
|
||||||
};
|
export const toHex = (subject: number) => subject.toString(16).padStart(2, "0");
|
||||||
|
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
export const hash = (
|
||||||
|
algorithm: AlgorithmIdentifier,
|
||||||
|
subject: Accessor<string | null | undefined>,
|
||||||
|
) => {
|
||||||
|
const [hash, setHash] = createSignal<string>();
|
||||||
|
|
||||||
|
createEffect(
|
||||||
|
on(subject, async (subject) => {
|
||||||
|
if (subject === null || subject === undefined || subject.length === 0) {
|
||||||
|
setHash(undefined);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = new Uint8Array(
|
||||||
|
await crypto.subtle.digest(algorithm, encoder.encode(subject)),
|
||||||
|
);
|
||||||
|
|
||||||
|
setHash(Array.from(buffer).map(toHex).join(""));
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue