1
0
cvsa/packages/backend/routes/song/milestone.ts

68 lines
2.0 KiB
TypeScript

import { Elysia, t } from "elysia";
import { db, bilibiliMetadata, eta } from "@core/drizzle";
import { eq, and, gte, lt } from "drizzle-orm";
import serverTiming from "@backend/middlewares/timing";
import z from "zod";
import { BiliVideoSchema } from "@backend/lib/schema";
type MileStoneType = "dendou" | "densetsu" | "shinwa";
const range = {
dendou: [0, 100000],
densetsu: [100000, 1000000],
shinwa: [1000000, 10000000]
};
export const closeMileStoneHandler = new Elysia({ prefix: "/songs" }).use(serverTiming()).get(
"/close-milestone/:type",
async ({ params, query }) => {
const type = params.type;
const offset = query.offset;
const limit = query.limit;
const min = range[type as MileStoneType][0];
const max = range[type as MileStoneType][1];
const q = db
.select()
.from(eta)
.innerJoin(bilibiliMetadata, eq(bilibiliMetadata.aid, eta.aid))
.where(and(gte(eta.currentViews, min), lt(eta.currentViews, max)))
.orderBy(eta.eta)
.$dynamic();
return q.limit(limit || 20).offset(offset || 0);
},
{
response: {
200: z.array(
z.object({
eta: z.object({
aid: z.number(),
eta: z.number(),
speed: z.number(),
currentViews: z.number(),
updatedAt: z.string()
}),
bilibili_metadata: BiliVideoSchema
})
),
404: t.Object({
message: t.String()
})
},
params: t.Object({
type: t.String({ enum: ["dendou", "densetsu", "shinwa"] })
}),
query: t.Object({
offset: t.Optional(t.Number()),
limit: t.Optional(t.Number())
}),
detail: {
summary: "Get songs close to milestones",
description:
"This endpoint retrieves songs that are approaching significant view count milestones. \
It supports three milestone types: 'dendou' (0-100k views), 'densetsu' (100k-1M views), and 'shinwa' (1M-10M views). \
For each type, it returns videos that are within the specified view range and have an estimated time to reach \
the next milestone below the threshold. Results are ordered by estimated time to milestone."
}
}
);