[READ-ONLY] Mirror of https://github.com/flo-bit/skywatched. review movies and tv shows, based on at proto skywatched.app
0

Configure Feed

Select the types of activity you want to include in your feed.

fly deploy, page transitions, some cleanup

Florian (Dec 21, 2024, 3:35 AM +0100) 8386c90b 4e31978b

+579 -363
+24
.dockerignore
··· 1 + node_modules 2 + 3 + # Output 4 + .output 5 + .vercel 6 + /.svelte-kit 7 + /build 8 + 9 + # OS 10 + .DS_Store 11 + Thumbs.db 12 + 13 + # Env 14 + .env 15 + .env.* 16 + !.env.example 17 + !.env.test 18 + 19 + # Vite 20 + vite.config.js.timestamp-* 21 + vite.config.ts.timestamp-* 22 + 23 + # SQLite 24 + *.db
+2
.env.example
··· 10 10 # A random key for encrypting the session 11 11 # on unix systems you can generate one with `openssl rand -base64 32` 12 12 NYX_PASSWORD="" 13 + 14 + BACKEND_URL="https://skywatched-jetstream.fly.dev"
+18
.github/workflows/fly-deploy.yml
··· 1 + # See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/ 2 + 3 + name: Fly Deploy 4 + on: 5 + push: 6 + branches: 7 + - main 8 + jobs: 9 + deploy: 10 + name: Deploy app 11 + runs-on: ubuntu-latest 12 + concurrency: deploy-group # optional: ensure only one action runs at a time 13 + steps: 14 + - uses: actions/checkout@v4 15 + - uses: superfly/flyctl-actions/setup-flyctl@master 16 + - run: flyctl deploy --remote-only 17 + env: 18 + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
+50
Dockerfile
··· 1 + # syntax = docker/dockerfile:1 2 + 3 + # Adjust NODE_VERSION as desired 4 + ARG NODE_VERSION=20.9.0 5 + FROM node:${NODE_VERSION}-slim as base 6 + 7 + LABEL fly_launch_runtime="SvelteKit" 8 + 9 + # SvelteKit app lives here 10 + WORKDIR /app 11 + 12 + # Set production environment 13 + ENV NODE_ENV="production" 14 + 15 + # Throw-away build stage to reduce size of final image 16 + FROM base as build 17 + 18 + # set env variables 19 + ENV DATABASE_URL=file:local.db 20 + ENV DATABASE_AUTH_TOKEN=a 21 + 22 + # Install packages needed to build node modules 23 + RUN apt-get update -qq && \ 24 + apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3 25 + 26 + # Install node modules 27 + COPY .npmrc package-lock.json package.json ./ 28 + RUN npm ci --include=dev 29 + 30 + # Copy application code 31 + COPY . . 32 + 33 + # Build application 34 + RUN npm run build 35 + 36 + # Remove development dependencies 37 + RUN npm prune --omit=dev 38 + 39 + 40 + # Final stage for app image 41 + FROM base 42 + 43 + # Copy built application 44 + COPY --from=build /app/build /app/build 45 + COPY --from=build /app/node_modules /app/node_modules 46 + COPY --from=build /app/package.json /app 47 + 48 + # Start the server by default, this can be overwritten at runtime 49 + EXPOSE 3000 50 + CMD [ "npm", "run", "start" ]
+2 -7
README.md
··· 18 18 19 19 - `TMDB_API_KEY` (get one [here](https://www.themoviedb.org/settings/api)) 20 20 - `NYX_PASSWORD` (can be generated on unix systems with `openssl rand -base64 32`) 21 + - `BACKEND_URL` (the url of the backend server) 21 22 22 23 2. install the dependencies: 23 24 ··· 25 26 npm install 26 27 ``` 27 28 28 - 3. run the database migrations: 29 - 30 - ```bash 31 - npm run db:migrate 32 - ``` 33 - 34 - 4. run the development server: 29 + 3. run the development server: 35 30 36 31 ```bash 37 32 npm run dev
-26
drizzle/0000_dazzling_wong.sql
··· 1 - CREATE TABLE `movies` ( 2 - `id` integer PRIMARY KEY NOT NULL, 3 - `username` text NOT NULL, 4 - `watched` integer NOT NULL, 5 - `rating` integer, 6 - `rating_text` text, 7 - `poster_path` text, 8 - `original_title` text NOT NULL, 9 - FOREIGN KEY (`username`) REFERENCES `user`(`username`) ON UPDATE no action ON DELETE no action 10 - ); 11 - --> statement-breakpoint 12 - CREATE TABLE `session` ( 13 - `id` text PRIMARY KEY NOT NULL, 14 - `user_id` text NOT NULL, 15 - `expires_at` integer NOT NULL, 16 - FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action 17 - ); 18 - --> statement-breakpoint 19 - CREATE TABLE `user` ( 20 - `id` text PRIMARY KEY NOT NULL, 21 - `age` integer, 22 - `username` text NOT NULL, 23 - `password_hash` text NOT NULL 24 - ); 25 - --> statement-breakpoint 26 - CREATE UNIQUE INDEX `user_username_unique` ON `user` (`username`);
-168
drizzle/meta/0000_snapshot.json
··· 1 - { 2 - "version": "6", 3 - "dialect": "sqlite", 4 - "id": "1725baa2-c420-4b7f-932d-47e7e6293695", 5 - "prevId": "00000000-0000-0000-0000-000000000000", 6 - "tables": { 7 - "movies": { 8 - "name": "movies", 9 - "columns": { 10 - "id": { 11 - "name": "id", 12 - "type": "integer", 13 - "primaryKey": true, 14 - "notNull": true, 15 - "autoincrement": false 16 - }, 17 - "username": { 18 - "name": "username", 19 - "type": "text", 20 - "primaryKey": false, 21 - "notNull": true, 22 - "autoincrement": false 23 - }, 24 - "watched": { 25 - "name": "watched", 26 - "type": "integer", 27 - "primaryKey": false, 28 - "notNull": true, 29 - "autoincrement": false 30 - }, 31 - "rating": { 32 - "name": "rating", 33 - "type": "integer", 34 - "primaryKey": false, 35 - "notNull": false, 36 - "autoincrement": false 37 - }, 38 - "rating_text": { 39 - "name": "rating_text", 40 - "type": "text", 41 - "primaryKey": false, 42 - "notNull": false, 43 - "autoincrement": false 44 - }, 45 - "poster_path": { 46 - "name": "poster_path", 47 - "type": "text", 48 - "primaryKey": false, 49 - "notNull": false, 50 - "autoincrement": false 51 - }, 52 - "original_title": { 53 - "name": "original_title", 54 - "type": "text", 55 - "primaryKey": false, 56 - "notNull": true, 57 - "autoincrement": false 58 - } 59 - }, 60 - "indexes": {}, 61 - "foreignKeys": { 62 - "movies_username_user_username_fk": { 63 - "name": "movies_username_user_username_fk", 64 - "tableFrom": "movies", 65 - "tableTo": "user", 66 - "columnsFrom": ["username"], 67 - "columnsTo": ["username"], 68 - "onDelete": "no action", 69 - "onUpdate": "no action" 70 - } 71 - }, 72 - "compositePrimaryKeys": {}, 73 - "uniqueConstraints": {} 74 - }, 75 - "session": { 76 - "name": "session", 77 - "columns": { 78 - "id": { 79 - "name": "id", 80 - "type": "text", 81 - "primaryKey": true, 82 - "notNull": true, 83 - "autoincrement": false 84 - }, 85 - "user_id": { 86 - "name": "user_id", 87 - "type": "text", 88 - "primaryKey": false, 89 - "notNull": true, 90 - "autoincrement": false 91 - }, 92 - "expires_at": { 93 - "name": "expires_at", 94 - "type": "integer", 95 - "primaryKey": false, 96 - "notNull": true, 97 - "autoincrement": false 98 - } 99 - }, 100 - "indexes": {}, 101 - "foreignKeys": { 102 - "session_user_id_user_id_fk": { 103 - "name": "session_user_id_user_id_fk", 104 - "tableFrom": "session", 105 - "tableTo": "user", 106 - "columnsFrom": ["user_id"], 107 - "columnsTo": ["id"], 108 - "onDelete": "no action", 109 - "onUpdate": "no action" 110 - } 111 - }, 112 - "compositePrimaryKeys": {}, 113 - "uniqueConstraints": {} 114 - }, 115 - "user": { 116 - "name": "user", 117 - "columns": { 118 - "id": { 119 - "name": "id", 120 - "type": "text", 121 - "primaryKey": true, 122 - "notNull": true, 123 - "autoincrement": false 124 - }, 125 - "age": { 126 - "name": "age", 127 - "type": "integer", 128 - "primaryKey": false, 129 - "notNull": false, 130 - "autoincrement": false 131 - }, 132 - "username": { 133 - "name": "username", 134 - "type": "text", 135 - "primaryKey": false, 136 - "notNull": true, 137 - "autoincrement": false 138 - }, 139 - "password_hash": { 140 - "name": "password_hash", 141 - "type": "text", 142 - "primaryKey": false, 143 - "notNull": true, 144 - "autoincrement": false 145 - } 146 - }, 147 - "indexes": { 148 - "user_username_unique": { 149 - "name": "user_username_unique", 150 - "columns": ["username"], 151 - "isUnique": true 152 - } 153 - }, 154 - "foreignKeys": {}, 155 - "compositePrimaryKeys": {}, 156 - "uniqueConstraints": {} 157 - } 158 - }, 159 - "enums": {}, 160 - "_meta": { 161 - "schemas": {}, 162 - "tables": {}, 163 - "columns": {} 164 - }, 165 - "internal": { 166 - "indexes": {} 167 - } 168 - }
-13
drizzle/meta/_journal.json
··· 1 - { 2 - "version": "7", 3 - "dialect": "sqlite", 4 - "entries": [ 5 - { 6 - "idx": 0, 7 - "version": "6", 8 - "when": 1732126290956, 9 - "tag": "0000_dazzling_wong", 10 - "breakpoints": true 11 - } 12 - ] 13 - }
+22
fly.toml
··· 1 + # fly.toml app configuration file generated for skywatched on 2024-12-21T02:44:48+01:00 2 + # 3 + # See https://fly.io/docs/reference/configuration/ for information about how to use this file. 4 + # 5 + 6 + app = 'skywatched' 7 + primary_region = 'lax' 8 + 9 + [build] 10 + 11 + [http_service] 12 + internal_port = 3000 13 + force_https = true 14 + auto_stop_machines = 'stop' 15 + auto_start_machines = true 16 + min_machines_running = 0 17 + processes = ['app'] 18 + 19 + [[vm]] 20 + memory = '512mb' 21 + cpu_kind = 'shared' 22 + cpus = 1
+395 -6
package-lock.json
··· 16 16 "@node-rs/argon2": "^1.1.0", 17 17 "@oslojs/crypto": "^1.0.1", 18 18 "@oslojs/encoding": "^1.1.0", 19 + "@sveltejs/adapter-node": "^5.2.11", 19 20 "@sveltejs/adapter-vercel": "^5.5.2", 20 21 "clsx": "^2.1.1", 21 22 "dotenv": "^16.4.5", ··· 25 26 "tailwind-merge": "^2.5.4" 26 27 }, 27 28 "devDependencies": { 29 + "@flydotio/dockerfile": "^0.5.9", 28 30 "@melt-ui/pp": "^0.3.2", 29 31 "@melt-ui/svelte": "^0.86.2", 30 32 "@sveltejs/adapter-auto": "^3.0.0", ··· 1386 1388 "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", 1387 1389 "dev": true 1388 1390 }, 1391 + "node_modules/@flydotio/dockerfile": { 1392 + "version": "0.5.9", 1393 + "resolved": "https://registry.npmjs.org/@flydotio/dockerfile/-/dockerfile-0.5.9.tgz", 1394 + "integrity": "sha512-ZPvMw9ABrE6W4nc92NL5Jy4XdAehldsU4LZ6pJP+H0sAqHqw3Bk9qKbMcjKJN1aM5AuKqfWm/I4ABGnkDjcqEw==", 1395 + "dev": true, 1396 + "dependencies": { 1397 + "chalk": "^5.3.0", 1398 + "diff": "^5.1.0", 1399 + "ejs": "^3.1.9", 1400 + "shell-quote": "^1.8.1", 1401 + "yargs": "^17.7.2" 1402 + }, 1403 + "bin": { 1404 + "dockerfile": "index.js" 1405 + }, 1406 + "engines": { 1407 + "node": ">=16.0.0" 1408 + } 1409 + }, 1410 + "node_modules/@flydotio/dockerfile/node_modules/chalk": { 1411 + "version": "5.4.0", 1412 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.0.tgz", 1413 + "integrity": "sha512-ZkD35Mx92acjB2yNJgziGqT9oKHEOxjTBTDRpOsRWtdecL/0jM3z5kM/CTzHWvHIen1GvkM85p6TuFfDGfc8/Q==", 1414 + "dev": true, 1415 + "engines": { 1416 + "node": "^12.17.0 || ^14.13 || >=16.0.0" 1417 + }, 1418 + "funding": { 1419 + "url": "https://github.com/chalk/chalk?sponsor=1" 1420 + } 1421 + }, 1389 1422 "node_modules/@humanfs/core": { 1390 1423 "version": "0.19.1", 1391 1424 "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", ··· 2123 2156 "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", 2124 2157 "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==" 2125 2158 }, 2159 + "node_modules/@rollup/plugin-commonjs": { 2160 + "version": "28.0.2", 2161 + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.2.tgz", 2162 + "integrity": "sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==", 2163 + "dependencies": { 2164 + "@rollup/pluginutils": "^5.0.1", 2165 + "commondir": "^1.0.1", 2166 + "estree-walker": "^2.0.2", 2167 + "fdir": "^6.2.0", 2168 + "is-reference": "1.2.1", 2169 + "magic-string": "^0.30.3", 2170 + "picomatch": "^4.0.2" 2171 + }, 2172 + "engines": { 2173 + "node": ">=16.0.0 || 14 >= 14.17" 2174 + }, 2175 + "peerDependencies": { 2176 + "rollup": "^2.68.0||^3.0.0||^4.0.0" 2177 + }, 2178 + "peerDependenciesMeta": { 2179 + "rollup": { 2180 + "optional": true 2181 + } 2182 + } 2183 + }, 2184 + "node_modules/@rollup/plugin-commonjs/node_modules/is-reference": { 2185 + "version": "1.2.1", 2186 + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", 2187 + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", 2188 + "dependencies": { 2189 + "@types/estree": "*" 2190 + } 2191 + }, 2192 + "node_modules/@rollup/plugin-json": { 2193 + "version": "6.1.0", 2194 + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", 2195 + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", 2196 + "dependencies": { 2197 + "@rollup/pluginutils": "^5.1.0" 2198 + }, 2199 + "engines": { 2200 + "node": ">=14.0.0" 2201 + }, 2202 + "peerDependencies": { 2203 + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" 2204 + }, 2205 + "peerDependenciesMeta": { 2206 + "rollup": { 2207 + "optional": true 2208 + } 2209 + } 2210 + }, 2211 + "node_modules/@rollup/plugin-node-resolve": { 2212 + "version": "16.0.0", 2213 + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.0.tgz", 2214 + "integrity": "sha512-0FPvAeVUT/zdWoO0jnb/V5BlBsUSNfkIOtFHzMO4H9MOklrmQFY6FduVHKucNb/aTFxvnGhj4MNj/T1oNdDfNg==", 2215 + "dependencies": { 2216 + "@rollup/pluginutils": "^5.0.1", 2217 + "@types/resolve": "1.20.2", 2218 + "deepmerge": "^4.2.2", 2219 + "is-module": "^1.0.0", 2220 + "resolve": "^1.22.1" 2221 + }, 2222 + "engines": { 2223 + "node": ">=14.0.0" 2224 + }, 2225 + "peerDependencies": { 2226 + "rollup": "^2.78.0||^3.0.0||^4.0.0" 2227 + }, 2228 + "peerDependenciesMeta": { 2229 + "rollup": { 2230 + "optional": true 2231 + } 2232 + } 2233 + }, 2126 2234 "node_modules/@rollup/pluginutils": { 2127 2235 "version": "5.1.3", 2128 2236 "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", ··· 2384 2492 "@sveltejs/kit": "^2.0.0" 2385 2493 } 2386 2494 }, 2495 + "node_modules/@sveltejs/adapter-node": { 2496 + "version": "5.2.11", 2497 + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.2.11.tgz", 2498 + "integrity": "sha512-lR7/dfUaKFf3aI408KRDy/BVDYoqUws7zNOJz2Hl4JoshlTnMgdha3brXBRFXB+cWtYvJjjPhvmq3xqpbioi4w==", 2499 + "dependencies": { 2500 + "@rollup/plugin-commonjs": "^28.0.1", 2501 + "@rollup/plugin-json": "^6.1.0", 2502 + "@rollup/plugin-node-resolve": "^16.0.0", 2503 + "rollup": "^4.9.5" 2504 + }, 2505 + "peerDependencies": { 2506 + "@sveltejs/kit": "^2.4.0" 2507 + } 2508 + }, 2387 2509 "node_modules/@sveltejs/adapter-vercel": { 2388 2510 "version": "5.5.2", 2389 2511 "resolved": "https://registry.npmjs.org/@sveltejs/adapter-vercel/-/adapter-vercel-5.5.2.tgz", ··· 2592 2714 "undici-types": "~6.20.0" 2593 2715 } 2594 2716 }, 2717 + "node_modules/@types/resolve": { 2718 + "version": "1.20.2", 2719 + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", 2720 + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==" 2721 + }, 2595 2722 "node_modules/@types/ws": { 2596 2723 "version": "8.5.13", 2597 2724 "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", ··· 2992 3119 "version": "1.1.1", 2993 3120 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 2994 3121 "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 3122 + }, 3123 + "node_modules/async": { 3124 + "version": "3.2.6", 3125 + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", 3126 + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", 3127 + "dev": true 2995 3128 }, 2996 3129 "node_modules/async-sema": { 2997 3130 "version": "3.1.1", ··· 3382 3515 "node": ">=18" 3383 3516 } 3384 3517 }, 3518 + "node_modules/cliui": { 3519 + "version": "8.0.1", 3520 + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", 3521 + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", 3522 + "dev": true, 3523 + "dependencies": { 3524 + "string-width": "^4.2.0", 3525 + "strip-ansi": "^6.0.1", 3526 + "wrap-ansi": "^7.0.0" 3527 + }, 3528 + "engines": { 3529 + "node": ">=12" 3530 + } 3531 + }, 3532 + "node_modules/cliui/node_modules/ansi-regex": { 3533 + "version": "5.0.1", 3534 + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 3535 + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 3536 + "dev": true, 3537 + "engines": { 3538 + "node": ">=8" 3539 + } 3540 + }, 3541 + "node_modules/cliui/node_modules/emoji-regex": { 3542 + "version": "8.0.0", 3543 + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 3544 + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 3545 + "dev": true 3546 + }, 3547 + "node_modules/cliui/node_modules/string-width": { 3548 + "version": "4.2.3", 3549 + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 3550 + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 3551 + "dev": true, 3552 + "dependencies": { 3553 + "emoji-regex": "^8.0.0", 3554 + "is-fullwidth-code-point": "^3.0.0", 3555 + "strip-ansi": "^6.0.1" 3556 + }, 3557 + "engines": { 3558 + "node": ">=8" 3559 + } 3560 + }, 3561 + "node_modules/cliui/node_modules/strip-ansi": { 3562 + "version": "6.0.1", 3563 + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 3564 + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 3565 + "dev": true, 3566 + "dependencies": { 3567 + "ansi-regex": "^5.0.1" 3568 + }, 3569 + "engines": { 3570 + "node": ">=8" 3571 + } 3572 + }, 3573 + "node_modules/cliui/node_modules/wrap-ansi": { 3574 + "version": "7.0.0", 3575 + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 3576 + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 3577 + "dev": true, 3578 + "dependencies": { 3579 + "ansi-styles": "^4.0.0", 3580 + "string-width": "^4.1.0", 3581 + "strip-ansi": "^6.0.0" 3582 + }, 3583 + "engines": { 3584 + "node": ">=10" 3585 + }, 3586 + "funding": { 3587 + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 3588 + } 3589 + }, 3385 3590 "node_modules/clsx": { 3386 3591 "version": "2.1.1", 3387 3592 "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", ··· 3419 3624 "engines": { 3420 3625 "node": ">= 6" 3421 3626 } 3627 + }, 3628 + "node_modules/commondir": { 3629 + "version": "1.0.1", 3630 + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", 3631 + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" 3422 3632 }, 3423 3633 "node_modules/concat-map": { 3424 3634 "version": "0.0.1", ··· 3603 3813 "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", 3604 3814 "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", 3605 3815 "dev": true 3816 + }, 3817 + "node_modules/diff": { 3818 + "version": "5.2.0", 3819 + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", 3820 + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", 3821 + "dev": true, 3822 + "engines": { 3823 + "node": ">=0.3.1" 3824 + } 3606 3825 }, 3607 3826 "node_modules/dlv": { 3608 3827 "version": "1.1.3", ··· 4184 4403 "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 4185 4404 "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 4186 4405 }, 4406 + "node_modules/ejs": { 4407 + "version": "3.1.10", 4408 + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", 4409 + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", 4410 + "dev": true, 4411 + "dependencies": { 4412 + "jake": "^10.8.5" 4413 + }, 4414 + "bin": { 4415 + "ejs": "bin/cli.js" 4416 + }, 4417 + "engines": { 4418 + "node": ">=0.10.0" 4419 + } 4420 + }, 4187 4421 "node_modules/electron-to-chromium": { 4188 4422 "version": "1.5.73", 4189 4423 "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.73.tgz", ··· 4699 4933 "version": "6.4.2", 4700 4934 "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz", 4701 4935 "integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==", 4702 - "dev": true, 4703 4936 "peerDependencies": { 4704 4937 "picomatch": "^3 || ^4" 4705 4938 }, ··· 4748 4981 "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 4749 4982 "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" 4750 4983 }, 4984 + "node_modules/filelist": { 4985 + "version": "1.0.4", 4986 + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", 4987 + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", 4988 + "dev": true, 4989 + "dependencies": { 4990 + "minimatch": "^5.0.1" 4991 + } 4992 + }, 4993 + "node_modules/filelist/node_modules/brace-expansion": { 4994 + "version": "2.0.1", 4995 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 4996 + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 4997 + "dev": true, 4998 + "dependencies": { 4999 + "balanced-match": "^1.0.0" 5000 + } 5001 + }, 5002 + "node_modules/filelist/node_modules/minimatch": { 5003 + "version": "5.1.6", 5004 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", 5005 + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", 5006 + "dev": true, 5007 + "dependencies": { 5008 + "brace-expansion": "^2.0.1" 5009 + }, 5010 + "engines": { 5011 + "node": ">=10" 5012 + } 5013 + }, 4751 5014 "node_modules/fill-range": { 4752 5015 "version": "7.1.1", 4753 5016 "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", ··· 4912 5175 "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 4913 5176 "funding": { 4914 5177 "url": "https://github.com/sponsors/ljharb" 5178 + } 5179 + }, 5180 + "node_modules/get-caller-file": { 5181 + "version": "2.0.5", 5182 + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 5183 + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 5184 + "dev": true, 5185 + "engines": { 5186 + "node": "6.* || 8.* || >= 10.*" 4915 5187 } 4916 5188 }, 4917 5189 "node_modules/get-intrinsic": { ··· 5213 5485 "version": "2.15.1", 5214 5486 "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", 5215 5487 "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", 5216 - "dev": true, 5217 5488 "dependencies": { 5218 5489 "hasown": "^2.0.2" 5219 5490 }, ··· 5250 5521 "engines": { 5251 5522 "node": ">=0.10.0" 5252 5523 } 5524 + }, 5525 + "node_modules/is-module": { 5526 + "version": "1.0.0", 5527 + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", 5528 + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" 5253 5529 }, 5254 5530 "node_modules/is-number": { 5255 5531 "version": "7.0.0", ··· 5289 5565 }, 5290 5566 "optionalDependencies": { 5291 5567 "@pkgjs/parseargs": "^0.11.0" 5568 + } 5569 + }, 5570 + "node_modules/jake": { 5571 + "version": "10.9.2", 5572 + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", 5573 + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", 5574 + "dev": true, 5575 + "dependencies": { 5576 + "async": "^3.2.3", 5577 + "chalk": "^4.0.2", 5578 + "filelist": "^1.0.4", 5579 + "minimatch": "^3.1.2" 5580 + }, 5581 + "bin": { 5582 + "jake": "bin/cli.js" 5583 + }, 5584 + "engines": { 5585 + "node": ">=10" 5292 5586 } 5293 5587 }, 5294 5588 "node_modules/jiti": { ··· 5959 6253 "node_modules/path-parse": { 5960 6254 "version": "1.0.7", 5961 6255 "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 5962 - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 5963 - "dev": true 6256 + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" 5964 6257 }, 5965 6258 "node_modules/path-scurry": { 5966 6259 "version": "1.11.1", ··· 6537 6830 "node": ">= 12.13.0" 6538 6831 } 6539 6832 }, 6833 + "node_modules/require-directory": { 6834 + "version": "2.1.1", 6835 + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 6836 + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 6837 + "dev": true, 6838 + "engines": { 6839 + "node": ">=0.10.0" 6840 + } 6841 + }, 6540 6842 "node_modules/resolve": { 6541 6843 "version": "1.22.8", 6542 6844 "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", 6543 6845 "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", 6544 - "dev": true, 6545 6846 "dependencies": { 6546 6847 "is-core-module": "^2.13.0", 6547 6848 "path-parse": "^1.0.7", ··· 6849 7150 "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 6850 7151 "engines": { 6851 7152 "node": ">=8" 7153 + } 7154 + }, 7155 + "node_modules/shell-quote": { 7156 + "version": "1.8.2", 7157 + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", 7158 + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", 7159 + "dev": true, 7160 + "engines": { 7161 + "node": ">= 0.4" 7162 + }, 7163 + "funding": { 7164 + "url": "https://github.com/sponsors/ljharb" 6852 7165 } 6853 7166 }, 6854 7167 "node_modules/side-channel": { ··· 7183 7496 "version": "1.0.0", 7184 7497 "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 7185 7498 "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 7186 - "dev": true, 7187 7499 "engines": { 7188 7500 "node": ">= 0.4" 7189 7501 }, ··· 8386 8698 } 8387 8699 } 8388 8700 }, 8701 + "node_modules/y18n": { 8702 + "version": "5.0.8", 8703 + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 8704 + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 8705 + "dev": true, 8706 + "engines": { 8707 + "node": ">=10" 8708 + } 8709 + }, 8389 8710 "node_modules/yallist": { 8390 8711 "version": "5.0.0", 8391 8712 "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", ··· 8401 8722 "dev": true, 8402 8723 "engines": { 8403 8724 "node": ">= 6" 8725 + } 8726 + }, 8727 + "node_modules/yargs": { 8728 + "version": "17.7.2", 8729 + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", 8730 + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", 8731 + "dev": true, 8732 + "dependencies": { 8733 + "cliui": "^8.0.1", 8734 + "escalade": "^3.1.1", 8735 + "get-caller-file": "^2.0.5", 8736 + "require-directory": "^2.1.1", 8737 + "string-width": "^4.2.3", 8738 + "y18n": "^5.0.5", 8739 + "yargs-parser": "^21.1.1" 8740 + }, 8741 + "engines": { 8742 + "node": ">=12" 8743 + } 8744 + }, 8745 + "node_modules/yargs-parser": { 8746 + "version": "21.1.1", 8747 + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 8748 + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 8749 + "dev": true, 8750 + "engines": { 8751 + "node": ">=12" 8752 + } 8753 + }, 8754 + "node_modules/yargs/node_modules/ansi-regex": { 8755 + "version": "5.0.1", 8756 + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 8757 + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 8758 + "dev": true, 8759 + "engines": { 8760 + "node": ">=8" 8761 + } 8762 + }, 8763 + "node_modules/yargs/node_modules/emoji-regex": { 8764 + "version": "8.0.0", 8765 + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 8766 + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 8767 + "dev": true 8768 + }, 8769 + "node_modules/yargs/node_modules/string-width": { 8770 + "version": "4.2.3", 8771 + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 8772 + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 8773 + "dev": true, 8774 + "dependencies": { 8775 + "emoji-regex": "^8.0.0", 8776 + "is-fullwidth-code-point": "^3.0.0", 8777 + "strip-ansi": "^6.0.1" 8778 + }, 8779 + "engines": { 8780 + "node": ">=8" 8781 + } 8782 + }, 8783 + "node_modules/yargs/node_modules/strip-ansi": { 8784 + "version": "6.0.1", 8785 + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 8786 + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 8787 + "dev": true, 8788 + "dependencies": { 8789 + "ansi-regex": "^5.0.1" 8790 + }, 8791 + "engines": { 8792 + "node": ">=8" 8404 8793 } 8405 8794 }, 8406 8795 "node_modules/yesno": {
+3
package.json
··· 3 3 "version": "0.0.1", 4 4 "type": "module", 5 5 "scripts": { 6 + "start": "node build", 6 7 "dev": "vite dev --host", 7 8 "build": "vite build", 8 9 "preview": "vite preview", ··· 15 16 "db:studio": "drizzle-kit studio" 16 17 }, 17 18 "devDependencies": { 19 + "@flydotio/dockerfile": "^0.5.9", 18 20 "@melt-ui/pp": "^0.3.2", 19 21 "@melt-ui/svelte": "^0.86.2", 20 22 "@sveltejs/adapter-auto": "^3.0.0", ··· 49 51 "@node-rs/argon2": "^1.1.0", 50 52 "@oslojs/crypto": "^1.0.1", 51 53 "@oslojs/encoding": "^1.1.0", 54 + "@sveltejs/adapter-node": "^5.2.11", 52 55 "@sveltejs/adapter-vercel": "^5.5.2", 53 56 "clsx": "^2.1.1", 54 57 "dotenv": "^16.4.5",
+8
src/app.css
··· 21 21 ::-webkit-scrollbar-thumb { 22 22 @apply bg-base-600 hover:bg-accent-500 transition-colors duration-150; 23 23 border-radius: 5px; 24 + } 25 + 26 + .poster { 27 + view-transition-name: var(--name); 28 + } 29 + 30 + .title { 31 + view-transition-name: var(--name); 24 32 }
+8 -51
src/app.html
··· 1 1 <!doctype html> 2 - <html lang="en" class="h-full dark"> 3 - <script> 4 - !(function (t, e) { 5 - var o, n, p, r; 6 - e.__SV || 7 - ((window.posthog = e), 8 - (e._i = []), 9 - (e.init = function (i, s, a) { 10 - function g(t, e) { 11 - var o = e.split('.'); 12 - 2 == o.length && ((t = t[o[0]]), (e = o[1])), 13 - (t[e] = function () { 14 - t.push([e].concat(Array.prototype.slice.call(arguments, 0))); 15 - }); 16 - } 17 - ((p = t.createElement('script')).type = 'text/javascript'), 18 - (p.async = !0), 19 - (p.src = 20 - s.api_host.replace('.i.posthog.com', '-assets.i.posthog.com') + '/static/array.js'), 21 - (r = t.getElementsByTagName('script')[0]).parentNode.insertBefore(p, r); 22 - var u = e; 23 - for ( 24 - void 0 !== a ? (u = e[a] = []) : (a = 'posthog'), 25 - u.people = u.people || [], 26 - u.toString = function (t) { 27 - var e = 'posthog'; 28 - return 'posthog' !== a && (e += '.' + a), t || (e += ' (stub)'), e; 29 - }, 30 - u.people.toString = function () { 31 - return u.toString(1) + '.people (stub)'; 32 - }, 33 - o = 34 - 'capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId'.split( 35 - ' ' 36 - ), 37 - n = 0; 38 - n < o.length; 39 - n++ 40 - ) 41 - g(u, o[n]); 42 - e._i.push([i, s, a]); 43 - }), 44 - (e.__SV = 1)); 45 - })(document, window.posthog || []); 46 - posthog.init('phc_1Q4q6SdTwvStnxFWbmdOIusLc5ve0u6Fk7WpsHPoAlD', { 47 - api_host: 'https://eu.i.posthog.com', 48 - person_profiles: 'identified_only', 49 - persistence: 'memory' 50 - }); 51 - </script> 52 - 2 + <html lang="en" class="dark h-full"> 53 3 <head> 54 4 <meta charset="utf-8" /> 55 5 <link rel="icon" href="%sveltekit.assets%/favicon.svg" /> ··· 58 8 <meta name="viewport" content="width=device-width, initial-scale=1" /> 59 9 %sveltekit.head% 60 10 <link rel="stylesheet" href="https://cdn.plyr.io/3.7.8/plyr.css" /> 11 + 12 + <script 13 + defer 14 + src="https://umami-wispy-dream-8048.fly.dev/script.js" 15 + data-website-id="a372b43f-99c8-4f8e-a1bf-0ea1f726df8a" 16 + data-domains="skywatched.app" 17 + ></script> 61 18 </head> 62 19 <body data-sveltekit-preload-data="hover" class="h-full bg-black text-white"> 63 20 <div style="display: contents">%sveltekit.body%</div>
+2 -2
src/hooks.server.ts
··· 5 5 import { decodeBase64, decodeBase64urlIgnorePadding } from '@oslojs/encoding'; 6 6 7 7 import type { Handle } from '@sveltejs/kit'; 8 - import { NYX_PASSWORD } from '$env/static/private'; 8 + import { env } from '$env/dynamic/private'; 9 9 10 10 export const handle: Handle = async ({ event, resolve }) => { 11 11 const sid = event.cookies.get('sid'); ··· 15 15 return resolve(event); 16 16 } 17 17 const decoded = decodeBase64urlIgnorePadding(sid); 18 - const key = decodeBase64(NYX_PASSWORD); 18 + const key = decodeBase64(env.NYX_PASSWORD || ''); 19 19 const decrypted = await decryptToString(key, decoded); 20 20 const oauthSession = await atclient.restore(decrypted); 21 21
+1 -1
src/lib/Components/ItemCard.svelte
··· 27 27 <img 28 28 src="https://image.tmdb.org/t/p/w342{item.poster_path}" 29 29 alt="movie poster for {item.title ?? item.name}" 30 - class="size-full object-cover object-center lg:size-full" 30 + class="size-full object-cover object-center lg:size-full poster" 31 31 loading="lazy" 32 32 /> 33 33 {/if}
+5 -3
src/lib/Components/ReviewCard.svelte
··· 20 20 <img 21 21 src="https://image.tmdb.org/t/p/w154{data.record.metadata.poster_path}" 22 22 alt="movie poster for {data.record.metadata.title}" 23 - class="size-full object-cover object-center lg:size-full" 24 - /> 23 + class="poster size-full object-cover object-center lg:size-full" 24 + style:--name={`poster-${data.record.item.value}`} 25 + /> 25 26 {/if} 26 27 <span class="sr-only">View {data.record.metadata?.title}</span> 27 28 </a> ··· 48 49 href={data.record.item.ref === 'tmdb:m' 49 50 ? `/movie/${data.record.item.value}` 50 51 : `/tv/${data.record.item.value}`} 51 - class="text-2xl font-bold hover:text-accent-200" 52 + class="title text-2xl font-bold hover:text-accent-200" 53 + style:--name={`title-${data.record.item.value}`} 52 54 > 53 55 {data.record.metadata?.title} 54 56 </a>
+7 -1
src/lib/Components/Sidebar.svelte
··· 55 55 {#key $page.url.pathname} 56 56 <div 57 57 class={cn( 58 - 'fixed bottom-2 left-0 top-2 z-50 w-[4.5rem] py-2 transition-transform duration-300', 58 + 'sidebar fixed bottom-2 left-0 top-2 z-50 w-[4.5rem] py-2 transition-transform duration-300', 59 59 showSidebar.value ? 'translate-x-0' : '-translate-x-20 md:translate-x-0' 60 60 )} 61 61 > ··· 126 126 </svg> 127 127 </button> 128 128 {/if} 129 + 130 + <style> 131 + .sidebar { 132 + view-transition-name: sidebar; 133 + } 134 + </style>
+6 -6
src/lib/db.ts
··· 1 + import { env } from '$env/dynamic/private'; 2 + 1 3 export type MainRecord = { 2 4 uri: string; 3 5 cid: string; ··· 44 46 }; 45 47 46 48 export async function getRecentRecordOfUser({ did }: { did: string }): Promise<MainRecord[]> { 47 - const response = await fetch( 48 - `https://skywatched-jetstream.fly.dev/api/recent-records-by-user?did=${did}` 49 - ); 49 + const response = await fetch(`${env.BACKEND_URL}/api/recent-records-by-user?did=${did}`); 50 50 const data = await response.json(); 51 51 return data; 52 52 } 53 53 54 54 export async function getRecentRecords(): Promise<MainRecord[]> { 55 - const response = await fetch(`https://skywatched-jetstream.fly.dev/api/most-recent-records`); 55 + const response = await fetch(`${env.BACKEND_URL}/api/most-recent-records?limit=10`); 56 56 const data = await response.json(); 57 57 return data; 58 58 } ··· 65 65 value: string; 66 66 }): Promise<MainRecord[]> { 67 67 const response = await fetch( 68 - `https://skywatched-jetstream.fly.dev/api/recent-records-by-item?ref=${ref}&value=${value}` 68 + `${env.BACKEND_URL}/api/recent-records-by-item?ref=${ref}&value=${value}` 69 69 ); 70 70 const data = await response.json(); 71 71 return data; 72 72 } 73 73 74 74 export async function getRecordByUri({ uri }: { uri: string }): Promise<MainRecord> { 75 - const response = await fetch(`https://skywatched-jetstream.fly.dev/api/record?uri=${uri}`); 75 + const response = await fetch(`${env.BACKEND_URL}/api/record?uri=${uri}`); 76 76 const data = await response.json(); 77 77 return data; 78 78 }
+10 -2
src/lib/server/db/index.ts
··· 1 - import { dev } from '$app/environment'; 2 1 import { drizzle } from 'drizzle-orm/libsql'; 3 2 import { createClient } from '@libsql/client'; 4 3 import { env } from '$env/dynamic/private'; 5 4 import * as schema from './schema'; 6 5 7 6 if (!env.DATABASE_URL) throw new Error('DATABASE_URL is not set'); 8 - if (!dev && !env.DATABASE_AUTH_TOKEN) throw new Error('DATABASE_AUTH_TOKEN is not set'); 9 7 const client = createClient({ url: env.DATABASE_URL, authToken: env.DATABASE_AUTH_TOKEN }); 10 8 export const db = drizzle(client, { schema: schema }); 9 + 10 + client.execute(`CREATE TABLE IF NOT EXISTS auth_state ( 11 + key TEXT PRIMARY KEY UNIQUE, 12 + state TEXT NOT NULL 13 + );`); 14 + 15 + client.execute(`CREATE TABLE IF NOT EXISTS auth_session ( 16 + key TEXT PRIMARY KEY UNIQUE, 17 + session TEXT NOT NULL 18 + );`);
+1 -16
src/lib/server/db/schema.ts
··· 1 - import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'; 1 + import { sqliteTable, text } from 'drizzle-orm/sqlite-core'; 2 2 3 3 export const AuthSession = sqliteTable('auth_session', { 4 4 key: text('key', { mode: 'text' }).primaryKey().unique(), ··· 9 9 key: text('key', { mode: 'text' }).primaryKey().unique(), 10 10 state: text('state', { mode: 'json' }).notNull() 11 11 }); 12 - 13 - export const items = sqliteTable('items', { 14 - id: text('id').primaryKey(), 15 - movieId: integer('movie_id'), 16 - showId: integer('show_id'), 17 - did: text('did').notNull(), 18 - watched: integer('watched').notNull(), 19 - rating: integer('rating'), 20 - ratingText: text('rating_text'), 21 - posterPath: text('poster_path'), 22 - originalTitle: text('original_title').notNull(), 23 - timestamp: integer('timestamp', { mode: 'timestamp' }).notNull() 24 - }); 25 - 26 - export type Movies = typeof items.$inferSelect;
+1 -45
src/lib/server/movies.ts
··· 1 1 import { env } from '$env/dynamic/private'; 2 - import { db } from './db'; 3 - import * as table from '$lib/server/db/schema'; 4 - import { eq, and } from 'drizzle-orm'; 2 + 5 3 import type { Agent } from '@atproto/api'; 6 4 7 5 export type Kind = 'movie' | 'tv'; ··· 96 94 const data = await response.json(); 97 95 98 96 return data.results; 99 - } 100 - 101 - export async function checkWatched(id: number, did: string, kind: Kind): Promise<boolean | number> { 102 - const movie = await db 103 - .select() 104 - .from(table.items) 105 - .where( 106 - and( 107 - eq(kind === 'movie' ? table.items.movieId : table.items.showId, id), 108 - eq(table.items.did, did) 109 - ) 110 - ); 111 - 112 - if (movie.length > 0) return movie[0].watched; 113 - 114 - return false; 115 - } 116 - 117 - export async function getWatchedMoviesIds(did: string) { 118 - const movies = await db 119 - .select({ 120 - movieId: table.items.movieId, 121 - rating: table.items.rating, 122 - ratingText: table.items.ratingText 123 - }) 124 - .from(table.items) 125 - .where(and(eq(table.items.did, did), eq(table.items.watched, 1))); 126 - 127 - return new Map(movies.map((movie) => [movie.movieId ?? 0, movie.rating ?? 0])); 128 - } 129 - 130 - export async function getWatchedShowsIds(did: string) { 131 - const shows = await db 132 - .select({ 133 - showId: table.items.showId, 134 - rating: table.items.rating, 135 - ratingText: table.items.ratingText 136 - }) 137 - .from(table.items) 138 - .where(and(eq(table.items.did, did), eq(table.items.watched, 1))); 139 - 140 - return new Map(shows.map((show) => [show.showId ?? 0, show.rating ?? 0])); 141 97 } 142 98 143 99 export async function getWatchedMoviesIdsFromPDS(agent: Agent, did: string) {
+8 -3
src/routes/+layout.svelte
··· 31 31 32 32 function useCachedRatedItems() { 33 33 try { 34 + // if no version number is set or it's not 1, clear the cache 35 + const version = localStorage.getItem('skywatched-version'); 36 + if (!version || version !== '1') { 37 + localStorage.clear(); 38 + return false; 39 + } 40 + 34 41 const cachedRatedItems = localStorage.getItem(`ratedItems-${data.user.did}`); 35 42 const lastUpdate = localStorage.getItem(`ratedItems-${data.user.did}-lastUpdate`); 36 43 if ( ··· 45 52 JSON.parse(cachedRatedItems).shows.map((show: any) => [show.id, show]) 46 53 ); 47 54 48 - console.log(watchedItems.ratedMovies); 49 - console.log(watchedItems.ratedShows); 50 55 return true; 51 56 } 52 57 } catch (error) { ··· 127 132 128 133 <div 129 134 style="background-image: url(/nnnoise.svg)" 130 - class="pointer-events-none fixed inset-0 z-50 size-full opacity-70" 135 + class="pointer-events-none fixed inset-0 z-50 size-full opacity-20" 131 136 ></div> 132 137 133 138 <style>
+3 -2
src/routes/[kind]/[id]/+page.svelte
··· 73 73 <img 74 74 src="https://image.tmdb.org/t/p/w500{data.result.poster_path}" 75 75 alt="" 76 - class="h-36 w-24 shrink-0 rounded-lg border border-white/10 sm:h-64 sm:w-44" 76 + class="poster h-36 w-24 shrink-0 rounded-lg border border-white/10 sm:h-64 sm:w-44" 77 + style:--name={`poster-${data.result.id}`} 77 78 /> 78 79 <div class="flex flex-col gap-4"> 79 - <div class="max-w-xl text-2xl font-semibold text-white sm:text-4xl"> 80 + <div class="title max-w-xl text-2xl font-semibold text-white sm:text-4xl" style:--name={`title-${data.result.id}`}> 80 81 {data.result.title ?? data.result.name} 81 82 </div> 82 83
-1
src/routes/cast/[id]/+page.server.ts
··· 31 31 }; 32 32 }); 33 33 34 - console.log(combinedCredits.cast.length); 35 34 return { 36 35 combinedCredits: combinedCredits.cast, 37 36 personDetails
-4
src/routes/cast/[id]/+page.svelte
··· 20 20 return Math.abs(ageDate.getUTCFullYear() - 1970); 21 21 } 22 22 23 - onMount(() => { 24 - console.log(data.combinedCredits.length); 25 - }); 26 - 27 23 let showFullBiography = $state(false); 28 24 </script> 29 25
+2 -2
src/routes/oauth/callback/+server.ts
··· 1 1 import { atclient } from '$lib/server/client'; 2 2 import { error, redirect } from '@sveltejs/kit'; 3 3 import type { RequestEvent } from '../../$types'; 4 - import { NYX_PASSWORD } from '$env/static/private'; 4 + import { env } from '$env/dynamic/private'; 5 5 import { encryptString } from '$lib/server/crypts'; 6 6 import { decodeBase64, encodeBase64urlNoPadding } from '@oslojs/encoding'; 7 7 import { Agent } from '@atproto/api'; ··· 14 14 try { 15 15 const { session } = await atclient.callback(params); 16 16 mySession = session; 17 - const key = decodeBase64(NYX_PASSWORD); 17 + const key = decodeBase64(env.NYX_PASSWORD || ''); 18 18 const encrypted = await encryptString(key, session.did); 19 19 const encoded = encodeBase64urlNoPadding(encrypted); 20 20 cookies.set('sid', encoded, {
-3
src/routes/onboarding/+page.server.ts
··· 12 12 const formData = await request.formData(); 13 13 const crosspost = (formData.get('crosspost-enabled') ?? 'false') as string; 14 14 15 - console.log(formData); 16 - 17 15 const region = formData.get('region') as string; 18 16 const region_data = available_regions.find((r) => r.english_name === region); 19 - console.log(region_data); 20 17 21 18 await agent.com.atproto.repo.putRecord({ 22 19 repo: locals.user.did,
+1 -1
svelte.config.js
··· 1 1 import { preprocessMeltUI, sequence } from '@melt-ui/pp'; 2 - import adapter from '@sveltejs/adapter-vercel'; 2 + import adapter from '@sveltejs/adapter-node'; 3 3 import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 4 4 /** @type {import('@sveltejs/kit').Config}*/ 5 5 const config = {