mirror of
https://github.com/Drop-OSS/drop.git
synced 2025-11-13 16:22:39 +10:00
feat: add ludusavi metadata import into database
WARNING: includes debug route
This commit is contained in:
@ -36,10 +36,12 @@
|
|||||||
"fast-fuzzy": "^1.12.0",
|
"fast-fuzzy": "^1.12.0",
|
||||||
"file-type-mime": "^0.4.3",
|
"file-type-mime": "^0.4.3",
|
||||||
"jdenticon": "^3.3.0",
|
"jdenticon": "^3.3.0",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
"luxon": "^3.6.1",
|
"luxon": "^3.6.1",
|
||||||
"micromark": "^4.0.1",
|
"micromark": "^4.0.1",
|
||||||
"nuxt": "^3.17.4",
|
"nuxt": "^3.17.4",
|
||||||
"nuxt-security": "2.2.0",
|
"nuxt-security": "2.2.0",
|
||||||
|
"pg-tsquery": "^8.4.2",
|
||||||
"prisma": "^6.7.0",
|
"prisma": "^6.7.0",
|
||||||
"sanitize-filename": "^1.6.3",
|
"sanitize-filename": "^1.6.3",
|
||||||
"semver": "^7.7.1",
|
"semver": "^7.7.1",
|
||||||
@ -59,6 +61,7 @@
|
|||||||
"@tailwindcss/forms": "^0.5.9",
|
"@tailwindcss/forms": "^0.5.9",
|
||||||
"@tailwindcss/typography": "^0.5.15",
|
"@tailwindcss/typography": "^0.5.15",
|
||||||
"@types/bcryptjs": "^3.0.0",
|
"@types/bcryptjs": "^3.0.0",
|
||||||
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/luxon": "^3.6.2",
|
"@types/luxon": "^3.6.2",
|
||||||
"@types/node": "^22.13.16",
|
"@types/node": "^22.13.16",
|
||||||
"@types/semver": "^7.7.0",
|
"@types/semver": "^7.7.0",
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "LudusaviEntry" (
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "LudusaviEntry_pkey" PRIMARY KEY ("name")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "LudusaviPlatformEntry" (
|
||||||
|
"ludusaviEntryName" TEXT NOT NULL,
|
||||||
|
"platform" "Platform" NOT NULL,
|
||||||
|
"files" TEXT[],
|
||||||
|
"registry" TEXT[],
|
||||||
|
|
||||||
|
CONSTRAINT "LudusaviPlatformEntry_pkey" PRIMARY KEY ("ludusaviEntryName","platform")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "LudusaviPlatformEntry" ADD CONSTRAINT "LudusaviPlatformEntry_ludusaviEntryName_fkey" FOREIGN KEY ("ludusaviEntryName") REFERENCES "LudusaviEntry"("name") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "LudusaviEntry" ADD COLUMN "steamId" TEXT;
|
||||||
18
prisma/models/ludusavi.prisma
Normal file
18
prisma/models/ludusavi.prisma
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
model LudusaviEntry {
|
||||||
|
name String @id
|
||||||
|
steamId String?
|
||||||
|
|
||||||
|
entries LudusaviPlatformEntry[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model LudusaviPlatformEntry {
|
||||||
|
ludusaviEntryName String
|
||||||
|
ludusaviEntry LudusaviEntry @relation(fields: [ludusaviEntryName], references: [name])
|
||||||
|
|
||||||
|
platform Platform
|
||||||
|
|
||||||
|
files String[]
|
||||||
|
registry String[]
|
||||||
|
|
||||||
|
@@id([ludusaviEntryName, platform])
|
||||||
|
}
|
||||||
32
server/routes/ludusavi.ts
Normal file
32
server/routes/ludusavi.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */
|
||||||
|
/* eslint-disable @typescript-eslint/no-extra-non-null-assertion */
|
||||||
|
|
||||||
|
import prisma from "../internal/db/database";
|
||||||
|
import { parsePlatform } from "../internal/utils/parseplatform";
|
||||||
|
import tsquery from "pg-tsquery";
|
||||||
|
|
||||||
|
export default defineEventHandler(async (h3) => {
|
||||||
|
const query = getQuery(h3);
|
||||||
|
const name = query.name?.toString()!!;
|
||||||
|
const platform = parsePlatform(query.platform?.toString()!!)!!;
|
||||||
|
|
||||||
|
const parser = tsquery({});
|
||||||
|
|
||||||
|
return await prisma.ludusaviEntry.findMany({
|
||||||
|
orderBy: {
|
||||||
|
_relevance: {
|
||||||
|
fields: ["name"],
|
||||||
|
search: parser(name),
|
||||||
|
sort: "desc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
entries: {
|
||||||
|
where: {
|
||||||
|
platform,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
take: 20,
|
||||||
|
});
|
||||||
|
});
|
||||||
133
server/tasks/ludusavi.ts
Normal file
133
server/tasks/ludusavi.ts
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import yaml from "js-yaml";
|
||||||
|
import prisma from "../internal/db/database";
|
||||||
|
import { Platform } from "~/prisma/client";
|
||||||
|
import type { LudusaviPlatformEntryCreateOrConnectWithoutLudusaviEntryInput } from "~/prisma/client/models";
|
||||||
|
|
||||||
|
type ConnectOrCreateShorthand =
|
||||||
|
LudusaviPlatformEntryCreateOrConnectWithoutLudusaviEntryInput;
|
||||||
|
|
||||||
|
type LudusaviModel = {
|
||||||
|
[key: string]: {
|
||||||
|
files?: {
|
||||||
|
[key: string]: {
|
||||||
|
tags?: Array<string>;
|
||||||
|
when?: Array<{ os?: string }>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
registry?: { [key: string]: { tags?: Array<string> } };
|
||||||
|
steam?: { id: number };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default defineTask({
|
||||||
|
async run(_event) {
|
||||||
|
const manifest = yaml.load(
|
||||||
|
await $fetch<string>(
|
||||||
|
"https://raw.githubusercontent.com/mtkennerly/ludusavi-manifest/refs/heads/master/data/manifest.yaml",
|
||||||
|
),
|
||||||
|
) as LudusaviModel;
|
||||||
|
|
||||||
|
for (const [name, data] of Object.entries(manifest)) {
|
||||||
|
if (!data.files && !data.registry) continue;
|
||||||
|
console.log(name);
|
||||||
|
|
||||||
|
const iterableFiles = data.files ? Object.entries(data.files) : undefined;
|
||||||
|
|
||||||
|
function findFilesForOperatingSystem(os: string) {
|
||||||
|
return iterableFiles?.filter((e) =>
|
||||||
|
e[1].when?.find((v) => v.os === os),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const connectOrCreate: ConnectOrCreateShorthand[] = [];
|
||||||
|
|
||||||
|
const windowsData = {
|
||||||
|
registry: data.registry,
|
||||||
|
files: findFilesForOperatingSystem("windows"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (windowsData.registry || windowsData.files) {
|
||||||
|
const create: ConnectOrCreateShorthand = {
|
||||||
|
where: {
|
||||||
|
ludusaviEntryName_platform: {
|
||||||
|
ludusaviEntryName: name,
|
||||||
|
platform: Platform.Windows,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
platform: Platform.Windows,
|
||||||
|
files: windowsData.files?.map((e) => e[0]) ?? [],
|
||||||
|
registry: Object.entries(windowsData.registry ?? {}).map(
|
||||||
|
(e) => e[0],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
connectOrCreate.push(create);
|
||||||
|
}
|
||||||
|
|
||||||
|
const linuxData = {
|
||||||
|
files: findFilesForOperatingSystem("linux"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (linuxData.files) {
|
||||||
|
const create: ConnectOrCreateShorthand = {
|
||||||
|
where: {
|
||||||
|
ludusaviEntryName_platform: {
|
||||||
|
ludusaviEntryName: name,
|
||||||
|
platform: Platform.Linux,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
platform: Platform.Linux,
|
||||||
|
files: linuxData.files?.map((e) => e[0]) ?? [],
|
||||||
|
registry: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
connectOrCreate.push(create);
|
||||||
|
}
|
||||||
|
|
||||||
|
const macData = {
|
||||||
|
files: findFilesForOperatingSystem("mac"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (macData.files) {
|
||||||
|
const create: ConnectOrCreateShorthand = {
|
||||||
|
where: {
|
||||||
|
ludusaviEntryName_platform: {
|
||||||
|
ludusaviEntryName: name,
|
||||||
|
platform: Platform.macOS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
platform: Platform.macOS,
|
||||||
|
files: macData.files?.map((e) => e[0]) ?? [],
|
||||||
|
registry: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
connectOrCreate.push(create);
|
||||||
|
}
|
||||||
|
|
||||||
|
const steamId = data.steam?.id.toString() ?? null;
|
||||||
|
|
||||||
|
await prisma.ludusaviEntry.upsert({
|
||||||
|
where: {
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
name,
|
||||||
|
steamId,
|
||||||
|
entries: { connectOrCreate },
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
steamId,
|
||||||
|
entries: { connectOrCreate },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { result: true };
|
||||||
|
},
|
||||||
|
});
|
||||||
10
yarn.lock
10
yarn.lock
@ -2332,6 +2332,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8"
|
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8"
|
||||||
integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==
|
integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==
|
||||||
|
|
||||||
|
"@types/js-yaml@^4.0.9":
|
||||||
|
version "4.0.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2"
|
||||||
|
integrity sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==
|
||||||
|
|
||||||
"@types/json-schema@^7.0.15":
|
"@types/json-schema@^7.0.15":
|
||||||
version "7.0.15"
|
version "7.0.15"
|
||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
||||||
@ -6982,6 +6987,11 @@ perfect-debounce@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz#9c2e8bc30b169cc984a58b7d5b28049839591d2a"
|
resolved "https://registry.yarnpkg.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz#9c2e8bc30b169cc984a58b7d5b28049839591d2a"
|
||||||
integrity sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==
|
integrity sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==
|
||||||
|
|
||||||
|
pg-tsquery@^8.4.2:
|
||||||
|
version "8.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/pg-tsquery/-/pg-tsquery-8.4.2.tgz#f28e6242f15f4d8535ac08a0f9083ce04e42e1e4"
|
||||||
|
integrity sha512-waJSlBIKE+shDhuDpuQglTH6dG5zakDhnrnxu8XB8V5c7yoDSuy4pOxY6t2dyoxTjaKMcMmlByJN7n9jx9eqMA==
|
||||||
|
|
||||||
picocolors@^1.0.0, picocolors@^1.1.1:
|
picocolors@^1.0.0, picocolors@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
|
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
|
||||||
|
|||||||
Reference in New Issue
Block a user