diff --git a/i18n/locales/en_us.json b/i18n/locales/en_us.json
index 2356acb..993579e 100644
--- a/i18n/locales/en_us.json
+++ b/i18n/locales/en_us.json
@@ -308,8 +308,10 @@
"umuLauncherId": "UMU Launcher ID",
"umuOverride": "Override UMU Launcher Game ID",
"umuOverrideDesc": "By default, Drop uses a non-ID when launching with UMU Launcher. In order to get the right patches for some games, you may have to manually set this field.",
- "updateMode": "Update mode",
+ "updateMode": "Update/delta mode",
"updateModeDesc": "When enabled, these files will be installed on top of (overwriting) the previous version's. If multiple \"update modes\" are chained together, they are applied in order.",
+ "hide": "Hide version",
+ "hideDesc": "Hide version so clients cannot install it. Useful if you are using delta versions to save space, but don't want to allow users to install partial games.",
"version": "Select version to import"
},
"withoutMetadata": "Import without metadata"
diff --git a/pages/admin/library/[id]/import.vue b/pages/admin/library/[id]/import.vue
index 485a57c..11d5711 100644
--- a/pages/admin/library/[id]/import.vue
+++ b/pages/admin/library/[id]/import.vue
@@ -398,6 +398,36 @@
/>
+
+
+
+ {{ $t("library.admin.import.version.hide") }}
+ {{
+ $t("library.admin.import.version.hideDesc")
+ }}
+
+
+
+
+
+
({
+const versionSettings = ref>({
platform: undefined,
launch: "",
launchArgs: "",
@@ -581,6 +601,7 @@ const versionSettings = ref<{
delta: false,
onlySetup: false,
umuId: "",
+ hide: false,
});
const versionGuesses =
diff --git a/prisma/migrations/20250819062913_add_hidden_field_to_versions/migration.sql b/prisma/migrations/20250819062913_add_hidden_field_to_versions/migration.sql
new file mode 100644
index 0000000..24df7d6
--- /dev/null
+++ b/prisma/migrations/20250819062913_add_hidden_field_to_versions/migration.sql
@@ -0,0 +1,8 @@
+-- DropIndex
+DROP INDEX "GameTag_name_idx";
+
+-- AlterTable
+ALTER TABLE "GameVersion" ADD COLUMN "hidden" BOOLEAN NOT NULL DEFAULT false;
+
+-- CreateIndex
+CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
diff --git a/prisma/models/content.prisma b/prisma/models/content.prisma
index 3ab28be..7f00d68 100644
--- a/prisma/models/content.prisma
+++ b/prisma/models/content.prisma
@@ -56,12 +56,11 @@ model GameTag {
id String @id @default(uuid())
name String @unique
- games Game[]
+ games Game[]
@@index([name(ops: raw("gist_trgm_ops(siglen=32)"))], type: Gist)
}
-
model GameRating {
id String @id @default(uuid())
@@ -95,6 +94,7 @@ model GameVersion {
setupCommand String @default("") // Command to setup game (dependencies and such)
setupArgs String[]
onlySetup Boolean @default(false)
+ hidden Boolean @default(false)
umuIdOverride String?
diff --git a/server/api/v1/admin/import/version/index.post.ts b/server/api/v1/admin/import/version/index.post.ts
index ab9ad1c..fabf682 100644
--- a/server/api/v1/admin/import/version/index.post.ts
+++ b/server/api/v1/admin/import/version/index.post.ts
@@ -1,20 +1,25 @@
import { type } from "arktype";
+import { PlatformClient } from "~/composables/types";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import libraryManager from "~/server/internal/library";
-import { parsePlatform } from "~/server/internal/utils/parseplatform";
-const ImportVersion = type({
+export const ImportVersion = type({
id: "string",
version: "string",
- platform: "string",
+ platform: type.valueOf(PlatformClient),
+
launch: "string = ''",
launchArgs: "string = ''",
+
setup: "string = ''",
setupArgs: "string = ''",
+
onlySetup: "boolean = false",
+ hide: "boolean = false",
+
delta: "boolean = false",
umuId: "string = ''",
}).configure(throwingArktype);
@@ -34,15 +39,12 @@ export default defineEventHandler(async (h3) => {
onlySetup,
delta,
umuId,
+ hide,
} = await readDropValidatedBody(h3, ImportVersion);
- const platformParsed = parsePlatform(platform);
- if (!platformParsed)
- throw createError({ statusCode: 400, statusMessage: "Invalid platform." });
-
if (delta) {
const validOverlayVersions = await prisma.gameVersion.count({
- where: { gameId: id, platform: platformParsed, delta: false },
+ where: { gameId: id, platform, delta: false },
});
if (validOverlayVersions == 0)
throw createError({
@@ -75,6 +77,7 @@ export default defineEventHandler(async (h3) => {
launchArgs,
setup,
setupArgs,
+ hide,
umuId,
delta,
diff --git a/server/api/v1/client/game/version.get.ts b/server/api/v1/client/game/version.get.ts
index e9cf38e..37af994 100644
--- a/server/api/v1/client/game/version.get.ts
+++ b/server/api/v1/client/game/version.get.ts
@@ -17,6 +17,7 @@ export default defineClientEventHandler(async (h3) => {
gameId: id,
versionName: version,
},
+ hidden: false,
},
});
diff --git a/server/api/v1/client/game/versions.get.ts b/server/api/v1/client/game/versions.get.ts
index fab014a..1ac4b55 100644
--- a/server/api/v1/client/game/versions.get.ts
+++ b/server/api/v1/client/game/versions.get.ts
@@ -13,6 +13,7 @@ export default defineClientEventHandler(async (h3) => {
const versions = await prisma.gameVersion.findMany({
where: {
gameId: id,
+ hidden: false,
},
orderBy: {
versionIndex: "desc", // Latest one first
diff --git a/server/internal/library/index.ts b/server/internal/library/index.ts
index 0a74dfe..4285e86 100644
--- a/server/internal/library/index.ts
+++ b/server/internal/library/index.ts
@@ -15,6 +15,7 @@ import { GameNotFoundError, type LibraryProvider } from "./provider";
import { logger } from "../logging";
import type { GameModel } from "~/prisma/client/models";
import { createHash } from "node:crypto";
+import type { ImportVersion } from "~/server/api/v1/admin/import/version/index.post";
export function createGameImportTaskId(libraryId: string, libraryPath: string) {
return createHash("md5")
@@ -231,18 +232,7 @@ class LibraryManager {
async importVersion(
gameId: string,
versionName: string,
- metadata: {
- platform: string;
- onlySetup: boolean;
-
- setup: string;
- setupArgs: string;
- launch: string;
- launchArgs: string;
- delta: boolean;
-
- umuId: string;
- },
+ metadata: Omit,
) {
const taskId = createVersionImportTaskId(gameId, versionName);
@@ -286,41 +276,24 @@ class LibraryManager {
});
// Then, create the database object
- if (metadata.onlySetup) {
- await prisma.gameVersion.create({
- data: {
- gameId: gameId,
- versionName: versionName,
- dropletManifest: manifest,
- versionIndex: currentIndex,
- delta: metadata.delta,
- umuIdOverride: metadata.umuId,
- platform: platform,
+ await prisma.gameVersion.create({
+ data: {
+ gameId: gameId,
+ versionName: versionName,
+ dropletManifest: manifest,
+ versionIndex: currentIndex,
+ delta: metadata.delta,
+ umuIdOverride: metadata.umuId,
+ platform: platform,
- onlySetup: true,
- setupCommand: metadata.setup,
- setupArgs: metadata.setupArgs.split(" "),
- },
- });
- } else {
- await prisma.gameVersion.create({
- data: {
- gameId: gameId,
- versionName: versionName,
- dropletManifest: manifest,
- versionIndex: currentIndex,
- delta: metadata.delta,
- umuIdOverride: metadata.umuId,
- platform: platform,
-
- onlySetup: false,
- setupCommand: metadata.setup,
- setupArgs: metadata.setupArgs.split(" "),
- launchCommand: metadata.launch,
- launchArgs: metadata.launchArgs.split(" "),
- },
- });
- }
+ hidden: metadata.hide,
+ onlySetup: metadata.onlySetup,
+ setupCommand: metadata.setup,
+ setupArgs: metadata.setupArgs.split(" "),
+ launchCommand: metadata.launch,
+ launchArgs: metadata.launchArgs.split(" "),
+ },
+ });
logger.info("Successfully created version!");