From 43b52dee0b740c2f1e6f1434a71722064c037f80 Mon Sep 17 00:00:00 2001 From: alikia2x Date: Tue, 29 Apr 2025 06:12:44 +0800 Subject: [PATCH] add: complete docker config --- .../frontend/.dockerignore => .dockerignore | 0 .gitignore | 5 +- Dockerfile.frontend | 30 +++ package.json | 10 + packages/backend/db/db.ts | 4 +- packages/backend/db/videoSnapshot.ts | 2 +- packages/backend/register.ts | 2 +- packages/backend/videoInfo.ts | 3 +- packages/core/bun.lock | 26 +++ packages/core/db/dbNew.ts | 4 + packages/core/db/pgConfigNew.ts | 38 ++++ packages/core/deno.json | 28 +-- packages/core/net/delegate.ts | 20 +- packages/core/package.json | 4 + packages/core/tsconfig.json | 2 +- packages/frontend/Dockerfile | 27 --- .../src/db/bilibili_metadata/aidExists.ts | 8 + .../src/db/bilibili_metadata/getAidFromBV.ts | 15 ++ .../db/bilibili_metadata/getVideoMetadata.ts | 15 ++ .../src/db/snapshots/getAllSnapshots.ts | 11 + .../frontend/src/pages/song/[id]/info.astro | 189 ++++++++---------- packages/frontend/tsconfig.json | 3 +- 22 files changed, 277 insertions(+), 169 deletions(-) rename packages/frontend/.dockerignore => .dockerignore (100%) create mode 100644 Dockerfile.frontend create mode 100644 package.json create mode 100644 packages/core/db/dbNew.ts create mode 100644 packages/core/db/pgConfigNew.ts delete mode 100644 packages/frontend/Dockerfile create mode 100644 packages/frontend/src/db/bilibili_metadata/aidExists.ts create mode 100644 packages/frontend/src/db/bilibili_metadata/getAidFromBV.ts create mode 100644 packages/frontend/src/db/bilibili_metadata/getVideoMetadata.ts create mode 100644 packages/frontend/src/db/snapshots/getAllSnapshots.ts diff --git a/packages/frontend/.dockerignore b/.dockerignore similarity index 100% rename from packages/frontend/.dockerignore rename to .dockerignore diff --git a/.gitignore b/.gitignore index c990962..a4bc2db 100644 --- a/.gitignore +++ b/.gitignore @@ -91,5 +91,6 @@ model/ *.db *.sqlite *.sqlite3 -db/ -data/ \ No newline at end of file +data/ + +docker-compose.yml \ No newline at end of file diff --git a/Dockerfile.frontend b/Dockerfile.frontend new file mode 100644 index 0000000..df603ee --- /dev/null +++ b/Dockerfile.frontend @@ -0,0 +1,30 @@ +FROM oven/bun AS bun-builder + +WORKDIR /app + +COPY ./packages/core ./core + +COPY ./packages/frontend/package.json ./packages/frontend/bun.lock ./packages/frontend/tsconfig.json ./packages/frontend/astro.config.mjs ./frontend/ + +WORKDIR frontend + +RUN bun install + +COPY ./packages/frontend/ . + +RUN bun run build + +FROM node:lts-alpine + +WORKDIR /app/frontend + +COPY --from=bun-builder /app/frontend/dist ./dist +COPY --from=bun-builder /app/frontend/node_modules ./node_modules +COPY --from=bun-builder /app/frontend/package.json ./package.json + +ENV HOST=0.0.0.0 +ENV PORT=4321 + +EXPOSE 4321 + +CMD ["node", "dist/server/entry.mjs"] \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..82503e5 --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "name": "cvsa", + "version": "2.13.22", + "private": false, + "type": "module", + "workspaces": [ + "packages/frontend", + "packages/core" + ] +} diff --git a/packages/backend/db/db.ts b/packages/backend/db/db.ts index 5839327..af9d33c 100644 --- a/packages/backend/db/db.ts +++ b/packages/backend/db/db.ts @@ -1,6 +1,4 @@ import postgres from "postgres"; import { postgresConfigNpm } from "./config"; -const sql = postgres(postgresConfigNpm); - -export default sql; +export const sql = postgres(postgresConfigNpm); diff --git a/packages/backend/db/videoSnapshot.ts b/packages/backend/db/videoSnapshot.ts index 6c5ab48..d5b8fa5 100644 --- a/packages/backend/db/videoSnapshot.ts +++ b/packages/backend/db/videoSnapshot.ts @@ -1,4 +1,4 @@ -import sql from "./db"; +import { sql } from "./db"; import type { VideoSnapshotType } from "@core/db/schema.d.ts"; export async function getVideoSnapshots( diff --git a/packages/backend/register.ts b/packages/backend/register.ts index cc12324..94cbe5b 100644 --- a/packages/backend/register.ts +++ b/packages/backend/register.ts @@ -3,7 +3,7 @@ import Argon2id from "@rabbit-company/argon2id"; import { object, string, ValidationError } from "yup"; import type { Context } from "hono"; import type { Bindings, BlankEnv, BlankInput } from "hono/types"; -import sql from "./db/db.ts"; +import { sql } from "./db/db.ts"; import { ErrorResponse, StatusResponse } from "./schema"; const RegistrationBodySchema = object({ diff --git a/packages/backend/videoInfo.ts b/packages/backend/videoInfo.ts index 2583807..f560cea 100644 --- a/packages/backend/videoInfo.ts +++ b/packages/backend/videoInfo.ts @@ -34,7 +34,6 @@ async function insertVideoSnapshot(data: VideoInfoData) { } export const videoInfoHandler = createHandlers(async (c: ContextType) => { - const client = c.get("db"); try { const id = await idSchema.validate(c.req.param("id")); let videoId: string | number = id as string; @@ -64,7 +63,7 @@ export const videoInfoHandler = createHandlers(async (c: ContextType) => { await redis.setex(cacheKey, CACHE_EXPIRATION_SECONDS, JSON.stringify(result)); - await insertVideoSnapshot(client, result); + await insertVideoSnapshot(result); return c.json(result); } catch (e) { diff --git a/packages/core/bun.lock b/packages/core/bun.lock index ed464c5..754e889 100644 --- a/packages/core/bun.lock +++ b/packages/core/bun.lock @@ -4,9 +4,13 @@ "": { "dependencies": { "chalk": "^5.4.1", + "ioredis": "^5.6.1", "logform": "^2.7.0", "winston": "^3.17.0", }, + "devDependencies": { + "@types/ioredis": "^5.0.0", + }, }, }, "packages": { @@ -14,12 +18,18 @@ "@dabh/diagnostics": ["@dabh/diagnostics@2.0.3", "", { "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA=="], + "@ioredis/commands": ["@ioredis/commands@1.2.0", "", {}, "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="], + + "@types/ioredis": ["@types/ioredis@5.0.0", "", { "dependencies": { "ioredis": "*" } }, "sha512-zJbJ3FVE17CNl5KXzdeSPtdltc4tMT3TzC6fxQS0sQngkbFZ6h+0uTafsRqu+eSLIugf6Yb0Ea0SUuRr42Nk9g=="], + "@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="], "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], "chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], + "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], + "color": ["color@3.2.1", "", { "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" } }, "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA=="], "color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], @@ -30,6 +40,10 @@ "colorspace": ["colorspace@1.1.4", "", { "dependencies": { "color": "^3.1.3", "text-hex": "1.0.x" } }, "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w=="], + "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], + + "denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], + "enabled": ["enabled@2.0.0", "", {}, "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="], "fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="], @@ -38,12 +52,18 @@ "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + "ioredis": ["ioredis@5.6.1", "", { "dependencies": { "@ioredis/commands": "^1.1.1", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA=="], + "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="], "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], "kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="], + "lodash.defaults": ["lodash.defaults@4.2.0", "", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="], + + "lodash.isarguments": ["lodash.isarguments@3.1.0", "", {}, "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="], + "logform": ["logform@2.7.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], @@ -52,6 +72,10 @@ "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "redis-errors": ["redis-errors@1.2.0", "", {}, "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w=="], + + "redis-parser": ["redis-parser@3.0.0", "", { "dependencies": { "redis-errors": "^1.0.0" } }, "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], @@ -60,6 +84,8 @@ "stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="], + "standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="], + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], "text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="], diff --git a/packages/core/db/dbNew.ts b/packages/core/db/dbNew.ts new file mode 100644 index 0000000..187a7a6 --- /dev/null +++ b/packages/core/db/dbNew.ts @@ -0,0 +1,4 @@ +import postgres from "postgres"; +import { postgresConfigNpm } from "./pgConfigNew"; + +export const sql = postgres(postgresConfigNpm); diff --git a/packages/core/db/pgConfigNew.ts b/packages/core/db/pgConfigNew.ts new file mode 100644 index 0000000..d6cb437 --- /dev/null +++ b/packages/core/db/pgConfigNew.ts @@ -0,0 +1,38 @@ +const requiredEnvVars = ["DB_HOST", "DB_NAME", "DB_USER", "DB_PASSWORD", "DB_PORT", "DB_NAME_CRED"]; + +const unsetVars = requiredEnvVars.filter((key) => process.env[key] === undefined); + +if (unsetVars.length > 0) { + throw new Error(`Missing required environment variables: ${unsetVars.join(", ")}`); +} + +const databaseHost = process.env["DB_HOST"]!; +const databaseName = process.env["DB_NAME"]; +const databaseNameCred = process.env["DB_NAME_CRED"]!; +const databaseUser = process.env["DB_USER"]!; +const databasePassword = process.env["DB_PASSWORD"]!; +const databasePort = process.env["DB_PORT"]!; + +export const postgresConfig = { + hostname: databaseHost, + port: parseInt(databasePort), + database: databaseName, + user: databaseUser, + password: databasePassword +}; + +export const postgresConfigNpm = { + host: databaseHost, + port: parseInt(databasePort), + database: databaseName, + username: databaseUser, + password: databasePassword +}; + +export const postgresConfigCred = { + hostname: databaseHost, + port: parseInt(databasePort), + database: databaseNameCred, + user: databaseUser, + password: databasePassword +}; diff --git a/packages/core/deno.json b/packages/core/deno.json index 252ddba..b1027e9 100644 --- a/packages/core/deno.json +++ b/packages/core/deno.json @@ -1,15 +1,17 @@ { - "name": "@cvsa/core", - "exports": "./main.ts", - "imports": { - "ioredis": "npm:ioredis", - "log/": "./log/", - "db/": "./db/", - "$std/": "https://deno.land/std@0.216.0/", - "mq/": "./mq/", - "chalk": "npm:chalk", - "winston": "npm:winston", - "logform": "npm:logform", - "@core/": "./" - } + "name": "@cvsa/core", + "exports": "./main.ts", + "imports": { + "ioredis": "npm:ioredis", + "log/": "./log/", + "db/": "./db/", + "$std/": "https://deno.land/std@0.216.0/", + "mq/": "./mq/", + "chalk": "npm:chalk", + "winston": "npm:winston", + "logform": "npm:logform", + "@core/": "./", + "child_process": "node:child_process", + "util": "node:util" + } } diff --git a/packages/core/net/delegate.ts b/packages/core/net/delegate.ts index 153faed..d972c54 100644 --- a/packages/core/net/delegate.ts +++ b/packages/core/net/delegate.ts @@ -2,8 +2,12 @@ import logger from "log/logger.ts"; import { RateLimiter, type RateLimiterConfig } from "mq/rateLimiter.ts"; import { SlidingWindow } from "mq/slidingWindow.ts"; import { redis } from "db/redis.ts"; -import Redis from "ioredis"; -import { SECOND } from "$std/datetime/constants.ts"; +import { ReplyError } from "ioredis"; +import { SECOND } from "../const/time.ts"; +import { execFile } from 'child_process'; +import { promisify } from 'util'; + +const execAsync = promisify(execFile); interface Proxy { type: string; @@ -99,7 +103,7 @@ class NetworkDelegate { await this.providerLimiters[providerLimiterId]?.trigger(); } catch (e) { const error = e as Error; - if (e instanceof Redis.ReplyError) { + if (e instanceof ReplyError) { logger.error(error, "redis"); } logger.warn(`Unhandled error: ${error.message}`, "mq", "proxyRequest"); @@ -209,7 +213,7 @@ class NetworkDelegate { return providerAvailable && proxyAvailable; } catch (e) { const error = e as Error; - if (e instanceof Redis.ReplyError) { + if (e instanceof ReplyError) { logger.error(error, "redis"); return false; } @@ -239,8 +243,7 @@ class NetworkDelegate { private async alicloudFcRequest(url: string, region: string): Promise { try { const decoder = new TextDecoder(); - const output = await new Deno.Command("aliyun", { - args: [ + const output = await execAsync("aliyun", [ "fc", "POST", `/2023-03-30/functions/proxy-${region}/invocations`, @@ -258,9 +261,8 @@ class NetworkDelegate { "10", "--profile", `CVSA-${region}`, - ], - }).output(); - const out = decoder.decode(output.stdout); + ]) + const out = output.stdout; const rawData = JSON.parse(out); if (rawData.statusCode !== 200) { // noinspection ExceptionCaughtLocallyJS diff --git a/packages/core/package.json b/packages/core/package.json index 89931f3..c5adc11 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,11 @@ { "dependencies": { "chalk": "^5.4.1", + "ioredis": "^5.6.1", "logform": "^2.7.0", "winston": "^3.17.0" + }, + "devDependencies": { + "@types/ioredis": "^5.0.0" } } \ No newline at end of file diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 27dc7bc..3b8cd4e 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -9,7 +9,7 @@ "lib": ["ES2020", "DOM", "DOM.Iterable"], "skipLibCheck": true, "paths": { - "@core/*": ["../core/*"] + "@core/*": ["./*"] }, "allowSyntheticDefaultImports": true, "allowImportingTsExtensions": true, diff --git a/packages/frontend/Dockerfile b/packages/frontend/Dockerfile deleted file mode 100644 index 58f5940..0000000 --- a/packages/frontend/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM oven/bun AS bun-builder - -WORKDIR /app - -COPY package.json bun.lock tsconfig.json astro.config.mjs ./ - -RUN bun install - -COPY . . - -RUN bun run build - -FROM node:lts-alpine - -WORKDIR /app - -COPY --from=bun-builder /app/dist ./dist -COPY --from=bun-builder /app/node_modules ./node_modules -COPY --from=bun-builder /app/package.json ./package.json - - -ENV HOST=0.0.0.0 -ENV PORT=4321 - -EXPOSE 4321 - -CMD ["node", "dist/server/entry.mjs"] \ No newline at end of file diff --git a/packages/frontend/src/db/bilibili_metadata/aidExists.ts b/packages/frontend/src/db/bilibili_metadata/aidExists.ts new file mode 100644 index 0000000..030a1e6 --- /dev/null +++ b/packages/frontend/src/db/bilibili_metadata/aidExists.ts @@ -0,0 +1,8 @@ +import { sql } from "@core/db/dbNew"; + +export async function aidExists(aid: number) { + const res = await sql` + SELECT 1 FROM bilibili_metadata WHERE aid = ${aid} + `; + return res.length > 0; +} \ No newline at end of file diff --git a/packages/frontend/src/db/bilibili_metadata/getAidFromBV.ts b/packages/frontend/src/db/bilibili_metadata/getAidFromBV.ts new file mode 100644 index 0000000..bf937a3 --- /dev/null +++ b/packages/frontend/src/db/bilibili_metadata/getAidFromBV.ts @@ -0,0 +1,15 @@ +import { sql } from "@core/db/dbNew"; + +export async function getAidFromBV(bv: string) { + const res = await sql` + SELECT aid FROM bilibili_metadata WHERE bvid = ${bv} + ` + if (res.length <= 0) { + return null; + } + const row = res[0]; + if (row && row.aid) { + return Number(row.aid); + } + return null; +} diff --git a/packages/frontend/src/db/bilibili_metadata/getVideoMetadata.ts b/packages/frontend/src/db/bilibili_metadata/getVideoMetadata.ts new file mode 100644 index 0000000..aea2885 --- /dev/null +++ b/packages/frontend/src/db/bilibili_metadata/getVideoMetadata.ts @@ -0,0 +1,15 @@ +import { sql } from "@core/db/dbNew"; + +export async function getVideoMetadata(aid: number) { + const res = await sql` + SELECT * FROM bilibili_metadata WHERE aid = ${aid} + `; + if (res.length <= 0) { + return null; + } + const row = res[0]; + if (row) { + return row; + } + return {}; +} \ No newline at end of file diff --git a/packages/frontend/src/db/snapshots/getAllSnapshots.ts b/packages/frontend/src/db/snapshots/getAllSnapshots.ts new file mode 100644 index 0000000..3607dc2 --- /dev/null +++ b/packages/frontend/src/db/snapshots/getAllSnapshots.ts @@ -0,0 +1,11 @@ +import { sql } from "@core/db/dbNew"; + +export async function getAllSnapshots(aid: number) { + const res = await sql` + SELECT * FROM video_snapshot WHERE aid = ${aid} ORDER BY created_at DESC + `; + if (res.length <= 0) { + return null; + } + return res; +} diff --git a/packages/frontend/src/pages/song/[id]/info.astro b/packages/frontend/src/pages/song/[id]/info.astro index 89e24a0..55b73b3 100644 --- a/packages/frontend/src/pages/song/[id]/info.astro +++ b/packages/frontend/src/pages/song/[id]/info.astro @@ -1,73 +1,31 @@ --- import Layout from "@layouts/Layout.astro"; import TitleBar from "@components/TitleBar.astro"; -import pg from "pg"; -import { format } from 'date-fns'; -import { zhCN } from 'date-fns/locale'; +import { format } from "date-fns"; +import { zhCN } from "date-fns/locale"; import MetadataRow from "@components/InfoPage/MetadataRow.astro"; +import { getAllSnapshots } from "src/db/snapshots/getAllSnapshots"; +import { getAidFromBV } from "src/db/bilibili_metadata/getAidFromBV"; +import { getVideoMetadata } from "src/db/bilibili_metadata/getVideoMetadata"; +import { aidExists as idExists } from "src/db/bilibili_metadata/aidExists"; -const databaseHost = import.meta.env.DB_HOST -const databaseName = import.meta.env.DB_NAME -const databaseUser = import.meta.env.DB_USER -const databasePassword = import.meta.env.DB_PASSWORD -const databasePort = import.meta.env.DB_PORT +const databaseHost = import.meta.env.DB_HOST; +const databaseName = import.meta.env.DB_NAME; +const databaseUser = import.meta.env.DB_USER; +const databasePassword = import.meta.env.DB_PASSWORD; +const databasePort = import.meta.env.DB_PORT; const postgresConfig = { - hostname: databaseHost, - port: parseInt(databasePort!), - database: databaseName, - user: databaseUser, - password: databasePassword, + hostname: databaseHost, + port: parseInt(databasePort!), + database: databaseName, + user: databaseUser, + password: databasePassword, }; -console.log(postgresConfig) +console.log(postgresConfig); -// 路由参数 const { id } = Astro.params; -const { Client } = pg; -const client = new Client(postgresConfig); -await client.connect(); - -// 数据库查询函数 -async function getVideoMetadata(aid: number) { - const res = await client.query("SELECT * FROM bilibili_metadata WHERE aid = $1", [aid]); - if (res.rows.length <= 0) { - return null; - } - const row = res.rows[0]; - if (row) { - return row; - } - return {}; -} - -async function getVideoSnapshots(aid: number) { - const res = await client.query("SELECT * FROM video_snapshot WHERE aid = $1 ORDER BY created_at DESC", [ - aid, - ]); - if (res.rows.length <= 0) { - return null; - } - return res.rows; -} - -async function getAidFromBV(bv: string) { - const res = await client.query("SELECT aid FROM bilibili_metadata WHERE bvid = $1" + - "", [bv]); - if (res.rows.length <= 0) { - return null; - } - const row = res.rows[0]; - if (row && row.aid) { - return Number(row.aid); - } - return null; -} - -async function idExists(aid: number) { - const res = await client.query("SELECT COUNT(*) FROM bilibili_metadata WHERE aid = $1", [aid]); - return res.rows[0].count > 0; -} async function getVideoAid(id: string) { if (id.startsWith("av")) { @@ -78,27 +36,22 @@ async function getVideoAid(id: string) { return parseInt(id); } -// 获取数据 if (!id) { Astro.response.status = 404; - client.end(); return new Response(null, { status: 404 }); } const aid = await getVideoAid(id); if (!aid || isNaN(aid)) { Astro.response.status = 404; - client.end(); return new Response(null, { status: 404 }); } const aidExists = await idExists(aid); if (!aidExists) { Astro.response.status = 404; - client.end(); return new Response(null, { status: 404 }); } const videoInfo = await getVideoMetadata(aid); -const snapshots = await getVideoSnapshots(aid); -client.end(); +const snapshots = await getAllSnapshots(aid); interface Snapshot { created_at: Date; @@ -117,24 +70,36 @@ interface Snapshot {
-

视频信息: av{aid}

+

+ 视频信息: av{aid} +

基本信息

- - - - - - - - - - - + + + + + + + + + + +
@@ -142,40 +107,46 @@ interface Snapshot {

播放量历史数据

- {snapshots && snapshots.length > 0 ? ( -
- - - - - - - - - - - - - - - {snapshots.map((snapshot: Snapshot) => ( + { + snapshots && snapshots.length > 0 ? ( +
+
创建时间观看硬币点赞收藏分享弹幕评论
+ - - - - - - - - + + + + + + + + - ))} - -
{format(new Date(snapshot.created_at), 'yyyy-MM-dd HH:mm:ss', { locale: zhCN })}{snapshot.views}{snapshot.coins}{snapshot.likes}{snapshot.favorites}{snapshot.shares}{snapshot.danmakus}{snapshot.replies}创建时间观看硬币点赞收藏分享弹幕评论
-
- ) : ( -

暂无历史数据。

- )} + + + {snapshots.map((snapshot: Snapshot) => ( + + + {format(new Date(snapshot.created_at), "yyyy-MM-dd HH:mm:ss", { + locale: zhCN, + })} + + {snapshot.views} + {snapshot.coins} + {snapshot.likes} + {snapshot.favorites} + {snapshot.shares} + {snapshot.danmakus} + {snapshot.replies} + + ))} + + +
+ ) : ( +

暂无历史数据。

+ ) + }
diff --git a/packages/frontend/tsconfig.json b/packages/frontend/tsconfig.json index b8575e7..c99a382 100644 --- a/packages/frontend/tsconfig.json +++ b/packages/frontend/tsconfig.json @@ -11,6 +11,7 @@ "@assets/*": ["src/assets/*"], "@styles": ["src/styles/*"], "@core/*": ["../core/*"] - } + }, + "verbatimModuleSyntax": true } }