mirror of
https://github.com/Drop-OSS/drop.git
synced 2025-11-10 04:22:09 +10:00
feat: version hiding
This commit is contained in:
@ -308,8 +308,10 @@
|
|||||||
"umuLauncherId": "UMU Launcher ID",
|
"umuLauncherId": "UMU Launcher ID",
|
||||||
"umuOverride": "Override UMU Launcher Game 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.",
|
"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.",
|
"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"
|
"version": "Select version to import"
|
||||||
},
|
},
|
||||||
"withoutMetadata": "Import without metadata"
|
"withoutMetadata": "Import without metadata"
|
||||||
|
|||||||
@ -398,6 +398,36 @@
|
|||||||
/>
|
/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</SwitchGroup>
|
</SwitchGroup>
|
||||||
|
<!-- setup mode -->
|
||||||
|
<SwitchGroup as="div" class="flex items-center justify-between">
|
||||||
|
<span class="flex flex-grow flex-col">
|
||||||
|
<SwitchLabel
|
||||||
|
as="span"
|
||||||
|
class="text-sm font-medium leading-6 text-zinc-100"
|
||||||
|
passive
|
||||||
|
>{{ $t("library.admin.import.version.hide") }}</SwitchLabel
|
||||||
|
>
|
||||||
|
<SwitchDescription as="span" class="text-sm text-zinc-400">{{
|
||||||
|
$t("library.admin.import.version.hideDesc")
|
||||||
|
}}</SwitchDescription>
|
||||||
|
</span>
|
||||||
|
<Switch
|
||||||
|
v-model="versionSettings.hide"
|
||||||
|
:class="[
|
||||||
|
versionSettings.hide ? 'bg-blue-600' : 'bg-zinc-800',
|
||||||
|
'relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
:class="[
|
||||||
|
versionSettings.hide ? 'translate-x-5' : 'translate-x-0',
|
||||||
|
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out',
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</Switch>
|
||||||
|
</SwitchGroup>
|
||||||
|
|
||||||
<Disclosure v-slot="{ open }" as="div" class="py-2">
|
<Disclosure v-slot="{ open }" as="div" class="py-2">
|
||||||
<dt>
|
<dt>
|
||||||
<DisclosureButton
|
<DisclosureButton
|
||||||
@ -548,6 +578,7 @@ import {
|
|||||||
import { XCircleIcon } from "@heroicons/vue/16/solid";
|
import { XCircleIcon } from "@heroicons/vue/16/solid";
|
||||||
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
|
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
|
||||||
import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/vue/24/solid";
|
import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/vue/24/solid";
|
||||||
|
import type { ImportVersion } from "~/server/api/v1/admin/import/version/index.post";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: "admin",
|
layout: "admin",
|
||||||
@ -561,18 +592,7 @@ const versions = await $dropFetch(
|
|||||||
`/api/v1/admin/import/version?id=${encodeURIComponent(gameId)}`,
|
`/api/v1/admin/import/version?id=${encodeURIComponent(gameId)}`,
|
||||||
);
|
);
|
||||||
const currentlySelectedVersion = ref(-1);
|
const currentlySelectedVersion = ref(-1);
|
||||||
const versionSettings = ref<{
|
const versionSettings = ref<Partial<typeof ImportVersion.infer>>({
|
||||||
platform: PlatformClient | undefined;
|
|
||||||
|
|
||||||
onlySetup: boolean;
|
|
||||||
launch: string;
|
|
||||||
launchArgs: string;
|
|
||||||
setup: string;
|
|
||||||
setupArgs: string;
|
|
||||||
|
|
||||||
delta: boolean;
|
|
||||||
umuId: string;
|
|
||||||
}>({
|
|
||||||
platform: undefined,
|
platform: undefined,
|
||||||
launch: "",
|
launch: "",
|
||||||
launchArgs: "",
|
launchArgs: "",
|
||||||
@ -581,6 +601,7 @@ const versionSettings = ref<{
|
|||||||
delta: false,
|
delta: false,
|
||||||
onlySetup: false,
|
onlySetup: false,
|
||||||
umuId: "",
|
umuId: "",
|
||||||
|
hide: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const versionGuesses =
|
const versionGuesses =
|
||||||
|
|||||||
@ -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));
|
||||||
@ -56,12 +56,11 @@ model GameTag {
|
|||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
name String @unique
|
name String @unique
|
||||||
|
|
||||||
games Game[]
|
games Game[]
|
||||||
|
|
||||||
@@index([name(ops: raw("gist_trgm_ops(siglen=32)"))], type: Gist)
|
@@index([name(ops: raw("gist_trgm_ops(siglen=32)"))], type: Gist)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
model GameRating {
|
model GameRating {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
|
|
||||||
@ -95,6 +94,7 @@ model GameVersion {
|
|||||||
setupCommand String @default("") // Command to setup game (dependencies and such)
|
setupCommand String @default("") // Command to setup game (dependencies and such)
|
||||||
setupArgs String[]
|
setupArgs String[]
|
||||||
onlySetup Boolean @default(false)
|
onlySetup Boolean @default(false)
|
||||||
|
hidden Boolean @default(false)
|
||||||
|
|
||||||
umuIdOverride String?
|
umuIdOverride String?
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +1,25 @@
|
|||||||
import { type } from "arktype";
|
import { type } from "arktype";
|
||||||
|
import { PlatformClient } from "~/composables/types";
|
||||||
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
|
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
|
||||||
import aclManager from "~/server/internal/acls";
|
import aclManager from "~/server/internal/acls";
|
||||||
import prisma from "~/server/internal/db/database";
|
import prisma from "~/server/internal/db/database";
|
||||||
import libraryManager from "~/server/internal/library";
|
import libraryManager from "~/server/internal/library";
|
||||||
import { parsePlatform } from "~/server/internal/utils/parseplatform";
|
|
||||||
|
|
||||||
const ImportVersion = type({
|
export const ImportVersion = type({
|
||||||
id: "string",
|
id: "string",
|
||||||
version: "string",
|
version: "string",
|
||||||
|
|
||||||
platform: "string",
|
platform: type.valueOf(PlatformClient),
|
||||||
|
|
||||||
launch: "string = ''",
|
launch: "string = ''",
|
||||||
launchArgs: "string = ''",
|
launchArgs: "string = ''",
|
||||||
|
|
||||||
setup: "string = ''",
|
setup: "string = ''",
|
||||||
setupArgs: "string = ''",
|
setupArgs: "string = ''",
|
||||||
|
|
||||||
onlySetup: "boolean = false",
|
onlySetup: "boolean = false",
|
||||||
|
hide: "boolean = false",
|
||||||
|
|
||||||
delta: "boolean = false",
|
delta: "boolean = false",
|
||||||
umuId: "string = ''",
|
umuId: "string = ''",
|
||||||
}).configure(throwingArktype);
|
}).configure(throwingArktype);
|
||||||
@ -34,15 +39,12 @@ export default defineEventHandler(async (h3) => {
|
|||||||
onlySetup,
|
onlySetup,
|
||||||
delta,
|
delta,
|
||||||
umuId,
|
umuId,
|
||||||
|
hide,
|
||||||
} = await readDropValidatedBody(h3, ImportVersion);
|
} = await readDropValidatedBody(h3, ImportVersion);
|
||||||
|
|
||||||
const platformParsed = parsePlatform(platform);
|
|
||||||
if (!platformParsed)
|
|
||||||
throw createError({ statusCode: 400, statusMessage: "Invalid platform." });
|
|
||||||
|
|
||||||
if (delta) {
|
if (delta) {
|
||||||
const validOverlayVersions = await prisma.gameVersion.count({
|
const validOverlayVersions = await prisma.gameVersion.count({
|
||||||
where: { gameId: id, platform: platformParsed, delta: false },
|
where: { gameId: id, platform, delta: false },
|
||||||
});
|
});
|
||||||
if (validOverlayVersions == 0)
|
if (validOverlayVersions == 0)
|
||||||
throw createError({
|
throw createError({
|
||||||
@ -75,6 +77,7 @@ export default defineEventHandler(async (h3) => {
|
|||||||
launchArgs,
|
launchArgs,
|
||||||
setup,
|
setup,
|
||||||
setupArgs,
|
setupArgs,
|
||||||
|
hide,
|
||||||
|
|
||||||
umuId,
|
umuId,
|
||||||
delta,
|
delta,
|
||||||
|
|||||||
@ -17,6 +17,7 @@ export default defineClientEventHandler(async (h3) => {
|
|||||||
gameId: id,
|
gameId: id,
|
||||||
versionName: version,
|
versionName: version,
|
||||||
},
|
},
|
||||||
|
hidden: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ export default defineClientEventHandler(async (h3) => {
|
|||||||
const versions = await prisma.gameVersion.findMany({
|
const versions = await prisma.gameVersion.findMany({
|
||||||
where: {
|
where: {
|
||||||
gameId: id,
|
gameId: id,
|
||||||
|
hidden: false,
|
||||||
},
|
},
|
||||||
orderBy: {
|
orderBy: {
|
||||||
versionIndex: "desc", // Latest one first
|
versionIndex: "desc", // Latest one first
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import { GameNotFoundError, type LibraryProvider } from "./provider";
|
|||||||
import { logger } from "../logging";
|
import { logger } from "../logging";
|
||||||
import type { GameModel } from "~/prisma/client/models";
|
import type { GameModel } from "~/prisma/client/models";
|
||||||
import { createHash } from "node:crypto";
|
import { createHash } from "node:crypto";
|
||||||
|
import type { ImportVersion } from "~/server/api/v1/admin/import/version/index.post";
|
||||||
|
|
||||||
export function createGameImportTaskId(libraryId: string, libraryPath: string) {
|
export function createGameImportTaskId(libraryId: string, libraryPath: string) {
|
||||||
return createHash("md5")
|
return createHash("md5")
|
||||||
@ -231,18 +232,7 @@ class LibraryManager {
|
|||||||
async importVersion(
|
async importVersion(
|
||||||
gameId: string,
|
gameId: string,
|
||||||
versionName: string,
|
versionName: string,
|
||||||
metadata: {
|
metadata: Omit<typeof ImportVersion.infer, "id" | "version">,
|
||||||
platform: string;
|
|
||||||
onlySetup: boolean;
|
|
||||||
|
|
||||||
setup: string;
|
|
||||||
setupArgs: string;
|
|
||||||
launch: string;
|
|
||||||
launchArgs: string;
|
|
||||||
delta: boolean;
|
|
||||||
|
|
||||||
umuId: string;
|
|
||||||
},
|
|
||||||
) {
|
) {
|
||||||
const taskId = createVersionImportTaskId(gameId, versionName);
|
const taskId = createVersionImportTaskId(gameId, versionName);
|
||||||
|
|
||||||
@ -286,41 +276,24 @@ class LibraryManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Then, create the database object
|
// Then, create the database object
|
||||||
if (metadata.onlySetup) {
|
await prisma.gameVersion.create({
|
||||||
await prisma.gameVersion.create({
|
data: {
|
||||||
data: {
|
gameId: gameId,
|
||||||
gameId: gameId,
|
versionName: versionName,
|
||||||
versionName: versionName,
|
dropletManifest: manifest,
|
||||||
dropletManifest: manifest,
|
versionIndex: currentIndex,
|
||||||
versionIndex: currentIndex,
|
delta: metadata.delta,
|
||||||
delta: metadata.delta,
|
umuIdOverride: metadata.umuId,
|
||||||
umuIdOverride: metadata.umuId,
|
platform: platform,
|
||||||
platform: platform,
|
|
||||||
|
|
||||||
onlySetup: true,
|
hidden: metadata.hide,
|
||||||
setupCommand: metadata.setup,
|
onlySetup: metadata.onlySetup,
|
||||||
setupArgs: metadata.setupArgs.split(" "),
|
setupCommand: metadata.setup,
|
||||||
},
|
setupArgs: metadata.setupArgs.split(" "),
|
||||||
});
|
launchCommand: metadata.launch,
|
||||||
} else {
|
launchArgs: metadata.launchArgs.split(" "),
|
||||||
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(" "),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Successfully created version!");
|
logger.info("Successfully created version!");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user