diff --git a/.gitignore b/.gitignore index ff04496..9e22e82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ dist +public/videos .solid .output .vercel diff --git a/bun.lock b/bun.lock index 93e2cbe..3e3ad73 100644 --- a/bun.lock +++ b/bun.lock @@ -9,6 +9,7 @@ "@solidjs/meta": "^0.29.4", "@solidjs/router": "^0.15.3", "@solidjs/start": "^1.1.3", + "better-auth": "^1.2.6", "open-props": "^1.7.14", "sitemap": "^8.0.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=="], + "@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=="], "@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=="], + "@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=="], "@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=="], + "@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=="], "@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=="], + "@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.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=="], + "@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=="], "@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=="], + "@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/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/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/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/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/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=="], + "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=="], "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=="], + "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=="], "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=="], + "jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], + "js-levenshtein": ["js-levenshtein@1.1.6", "", {}, "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g=="], "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=="], + "kysely": ["kysely@0.27.6", "", {}, "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ=="], + "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=="], @@ -870,6 +911,8 @@ "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=="], "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=="], + "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=="], "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=="], + "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=="], "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=="], + "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], + "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=="], diff --git a/package.json b/package.json index 2c9590d..ff30cbf 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@solidjs/meta": "^0.29.4", "@solidjs/router": "^0.15.3", "@solidjs/start": "^1.1.3", + "better-auth": "^1.2.6", "open-props": "^1.7.14", "sitemap": "^8.0.0", "solid-icons": "^1.1.0", diff --git a/src/auth.ts b/src/auth.ts new file mode 100644 index 0000000..031fbef --- /dev/null +++ b/src/auth.ts @@ -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()], +}); diff --git a/src/features/player/SampleVideo_1280x720_10mb.captions.vtt b/src/features/player/SampleVideo_1280x720_10mb.captions.vtt new file mode 100644 index 0000000..9b3f0fd --- /dev/null +++ b/src/features/player/SampleVideo_1280x720_10mb.captions.vtt @@ -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 diff --git a/src/features/player/SampleVideo_1280x720_10mb.mp4 b/src/features/player/SampleVideo_1280x720_10mb.mp4 new file mode 100644 index 0000000..3ce062e Binary files /dev/null and b/src/features/player/SampleVideo_1280x720_10mb.mp4 differ diff --git a/src/features/player/SampleVideo_1280x720_10mb.thumbnails.vtt b/src/features/player/SampleVideo_1280x720_10mb.thumbnails.vtt new file mode 100644 index 0000000..38e9e84 --- /dev/null +++ b/src/features/player/SampleVideo_1280x720_10mb.thumbnails.vtt @@ -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 diff --git a/src/features/player/controls/volume.module.css b/src/features/player/controls/volume.module.css new file mode 100644 index 0000000..bffc843 --- /dev/null +++ b/src/features/player/controls/volume.module.css @@ -0,0 +1,3 @@ +.container { + display: block grid; +} diff --git a/src/features/player/controls/volume.tsx b/src/features/player/controls/volume.tsx new file mode 100644 index 0000000..1647997 --- /dev/null +++ b/src/features/player/controls/volume.tsx @@ -0,0 +1,17 @@ +import { Component, createSignal } from "solid-js"; +import css from "./volume.module.css"; + +interface VolumeProps { + value: number; +} + +export const Volume: Component = (props) => { + const [volume, setVolume] = createSignal(props.value); + + return ( +
+ + +
+ ); +}; diff --git a/src/features/player/overview.jpg b/src/features/player/overview.jpg new file mode 100644 index 0000000..85efcc6 Binary files /dev/null and b/src/features/player/overview.jpg differ diff --git a/src/features/player/player.module.css b/src/features/player/player.module.css index e69de29..1623fd5 100644 --- a/src/features/player/player.module.css +++ b/src/features/player/player.module.css @@ -0,0 +1,5 @@ +.player { + & > video::cue { + font-size: 1.5rem; + } +} diff --git a/src/features/player/player.tsx b/src/features/player/player.tsx index 93b5558..d158a0e 100644 --- a/src/features/player/player.tsx +++ b/src/features/player/player.tsx @@ -12,22 +12,90 @@ import { onMount, untrack, } 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 { id: string; } export const Player: Component = (props) => { - const [video, setVideo] = createSignal(undefined as unknown as HTMLVideoElement); + const [video, setVideo] = createSignal( + 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'); - const onTimeUpdate = createEventSignal(video, 'timeupdate'); + return captions !== undefined + ? 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(() => { onDurationChange(); - onTimeUpdate(); - return video()?.duration ?? 100; + return video()?.duration ?? 0; }); const currentTime = createMemo(() => { @@ -36,10 +104,6 @@ export const Player: Component = (props) => { return video()?.currentTime ?? 0; }); - createEffect(() => { - console.log(duration(), currentTime()); - }); - createEventListenerMap(() => video()!, { durationchange(e) { console.log("durationchange", e); @@ -60,7 +124,11 @@ export const Player: Component = (props) => { console.log("seeking", 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) { @@ -107,17 +175,52 @@ export const Player: Component = (props) => { }; return ( - <> +

{props.id}

-
); }; + +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(":"); +}; diff --git a/src/features/shell/top.tsx b/src/features/shell/top.tsx index 2b9a335..a95b1e8 100644 --- a/src/features/shell/top.tsx +++ b/src/features/shell/top.tsx @@ -1,10 +1,64 @@ -import { Component } from "solid-js"; +import { Component, createEffect, createMemo, Show } from "solid-js"; import { ColorSchemePicker } from "../theme"; +import { signIn, signOut, useSession } from "~/auth"; +import { hash } from "~/utilities"; import css from "./top.module.css"; 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 ( ); diff --git a/src/features/theme/picker.tsx b/src/features/theme/picker.tsx index 0acce5a..c7ff342 100644 --- a/src/features/theme/picker.tsx +++ b/src/features/theme/picker.tsx @@ -1,43 +1,69 @@ -import { WiMoonAltFirstQuarter, WiMoonAltFull, WiMoonAltNew } from "solid-icons/wi"; -import { Component, createEffect, For, Match, on, Setter, Switch } from "solid-js"; +import { + WiMoonAltFirstQuarter, + WiMoonAltFull, + WiMoonAltNew, +} from "solid-icons/wi"; +import { + Component, + createEffect, + For, + Match, + on, + Setter, + Switch, +} from "solid-js"; import { ColorScheme, useTheme } from "./context"; -import css from './picker.module.css'; +import css from "./picker.module.css"; import { Select } from "~/components/select"; -const colorSchemes: Record = Object.fromEntries(Object.entries(ColorScheme).map(([k, v]) => [v, k])) as any; +const colorSchemes: Record = + Object.fromEntries( + Object.entries(ColorScheme).map(([k, v]) => [v, k]), + ) as any; export const ColorSchemePicker: Component = (props) => { - const themeContext = useTheme(); + const themeContext = useTheme(); - const setScheme: Setter = (next) => { + const setScheme: Setter = (next) => { + if (typeof next === "function") { + next = next(); + } - if (typeof next === 'function') { - next = next(); - } + themeContext.setColorScheme(next); + }; - themeContext.setColorScheme(next); - }; + return ( + <> + - createEffect(on(() => themeContext.theme.colorScheme, (colorScheme) => { - console.log(colorScheme); - })); - - return <> - - - {/*