feat: Implemented a radial virtual gamepad keyboard. fix: Fixed shortcuts for file explorer
184 lines
No EOL
7.9 KiB
TypeScript
184 lines
No EOL
7.9 KiB
TypeScript
import Elysia, { status } from "elysia";
|
|
import z from "zod";
|
|
import { and, count, eq, getTableColumns, not, notExists, or } from "drizzle-orm";
|
|
import { config, db, plugins } from "../app";
|
|
import * as schema from "@schema/app";
|
|
import { findPlatform } from "./services/utils";
|
|
|
|
export default new Elysia()
|
|
.get('/platforms', async () =>
|
|
{
|
|
const localPlatforms = await db.select({ ...getTableColumns(schema.platforms), game_count: count(schema.games.id) })
|
|
.from(schema.platforms)
|
|
.leftJoin(schema.games, eq(schema.games.platform_id, schema.platforms.id))
|
|
.groupBy(schema.platforms.id);
|
|
|
|
const localPlatformSet = new Set(localPlatforms.filter(p => p.game_count > 0).map(p => p.slug));
|
|
|
|
const remotePlatforms: FrontEndPlatformType[] = [];
|
|
|
|
await plugins.hooks.games.fetchPlatforms.promise({ platforms: remotePlatforms });
|
|
|
|
await Promise.all(remotePlatforms.map(async p =>
|
|
{
|
|
p.hasLocal = localPlatformSet.has(p.slug);
|
|
|
|
if (p.paths_screenshots.length <= 0)
|
|
{
|
|
const localScreenshots = await db.select({ id: schema.screenshots.id }).from(schema.games).leftJoin(schema.platforms, eq(schema.platforms.id, schema.games.platform_id)).where(eq(schema.platforms.slug, p.slug)).leftJoin(schema.screenshots, eq(schema.screenshots.game_id, schema.games.id)).limit(1);
|
|
|
|
if (localScreenshots)
|
|
p.paths_screenshots.push(...localScreenshots.map(s => `/api/romm/screenshot/${s.id}`));
|
|
}
|
|
|
|
const localGames = await db.select({ id: schema.games.id, source: schema.games.source, souceId: schema.games.source_id }).from(schema.games).leftJoin(schema.platforms, eq(schema.platforms.id, schema.games.platform_id)).where(and(eq(schema.platforms.slug, p.slug), not(eq(schema.games.source, 'romm')))).groupBy(schema.games.id);
|
|
p.game_count += localGames.length;
|
|
}));
|
|
|
|
const platformSlugSet = new Set(remotePlatforms.map(p => p.slug));
|
|
|
|
const platforms: FrontEndPlatformType[] = [];
|
|
platforms.push(...remotePlatforms);
|
|
platforms.push(...await Promise.all(localPlatforms.filter(p => !platformSlugSet?.has(p.slug)).map(async p =>
|
|
{
|
|
const game = await db.query.games.findFirst({ where: eq(schema.games.platform_id, p.id) });
|
|
let screenshots: { id: number; }[] = [];
|
|
if (game)
|
|
{
|
|
screenshots = await db.query.screenshots.findMany({ where: eq(schema.screenshots.game_id, game.id), columns: { id: true } });
|
|
}
|
|
|
|
const platform: FrontEndPlatformType = {
|
|
slug: p.slug,
|
|
name: p.name,
|
|
family_name: p.family_name,
|
|
path_cover: `/api/romm/platform/local/${p.id}/cover`,
|
|
game_count: p.game_count,
|
|
updated_at: p.created_at,
|
|
id: { source: 'local', id: String(p.id) },
|
|
hasLocal: true,
|
|
paths_screenshots: screenshots?.map(s => `/api/romm/screenshot/${s.id}`) ?? []
|
|
|
|
};
|
|
|
|
return platform;
|
|
})));
|
|
|
|
return { platforms };
|
|
}).get('/platforms/:source/:id', async ({ params: { source, id } }) =>
|
|
{
|
|
if (source === 'local')
|
|
{
|
|
const localPlatform = await db.query.platforms.findFirst({ where: eq(schema.platforms.id, Number(id)) });
|
|
if (localPlatform)
|
|
{
|
|
const platform: FrontEndPlatformType = {
|
|
slug: localPlatform.slug,
|
|
name: localPlatform.name,
|
|
family_name: localPlatform.family_name,
|
|
path_cover: `/api/romm/platform/local/${localPlatform.id}/cover`,
|
|
game_count: 0,
|
|
updated_at: localPlatform.created_at,
|
|
id: { source: 'local', id: String(localPlatform.id) },
|
|
hasLocal: true,
|
|
paths_screenshots: []
|
|
};
|
|
|
|
return platform;
|
|
}
|
|
|
|
return status("Not Found");
|
|
} else
|
|
{
|
|
const remotePlatform = await plugins.hooks.games.fetchPlatform.promise({ source, id });
|
|
if (!remotePlatform) return status("Not Found");
|
|
const local = await db.query.platforms.findFirst({ where: or(eq(schema.platforms.slug, remotePlatform?.slug), eq(schema.platforms.name, remotePlatform?.name)) });
|
|
return { ...remotePlatform, hasLocal: !!local };
|
|
}
|
|
}, { params: z.object({ source: z.string(), id: z.string() }) })
|
|
.get('/platform/local/:id/cover', async ({ params: { id }, set }) =>
|
|
{
|
|
set.headers["cross-origin-resource-policy"] = 'cross-origin';
|
|
|
|
const coverBlob = await db.query.platforms.findFirst({
|
|
columns: {
|
|
cover: true, cover_type: true
|
|
|
|
}, where: eq(schema.platforms.id, id)
|
|
});
|
|
if (!coverBlob || !coverBlob.cover)
|
|
{
|
|
return status(404);
|
|
}
|
|
if (coverBlob.cover_type)
|
|
{
|
|
set.headers["content-type"] = coverBlob.cover_type;
|
|
}
|
|
return status(200, coverBlob.cover);
|
|
}, { response: { 200: z.instanceof(Buffer<ArrayBufferLike>), 404: z.any() }, params: z.object({ id: z.coerce.number() }) })
|
|
.post('/platform/:source/:id/update', async ({ params: { source, id } }) =>
|
|
{
|
|
const where: any[] = [];
|
|
if (source === 'local')
|
|
{
|
|
where.push(eq(schema.platforms.id, Number(id)));
|
|
} else
|
|
{
|
|
const remotePlatform = await plugins.hooks.games.fetchPlatform.promise({ source, id });
|
|
if (remotePlatform)
|
|
{
|
|
where.push(eq(schema.platforms.slug, remotePlatform.slug));
|
|
}
|
|
}
|
|
|
|
const localPlatform = await db.query.platforms.findFirst({
|
|
where: or(...where)
|
|
|
|
});
|
|
if (!localPlatform) return status("Not Found");
|
|
|
|
const platformLookup = await plugins.hooks.games.platformLookup.promise({
|
|
slug: localPlatform.slug
|
|
});
|
|
let platformCover = await fetch(`${config.get('rommAddress') ?? 'https://demo.romm.app'}/assets/platforms/${localPlatform.slug}.svg`);
|
|
if (!platformCover.ok && platformLookup?.url_logo)
|
|
{
|
|
platformCover = await fetch(platformLookup.url_logo);
|
|
}
|
|
|
|
await db.update(schema.platforms).set({
|
|
name: platformLookup?.name,
|
|
cover: Buffer.from(await platformCover.arrayBuffer()),
|
|
cover_type: platformCover.headers.get('content-type'),
|
|
}).where(eq(schema.platforms.id, localPlatform.id));
|
|
})
|
|
.delete('/platform/local/:id', async ({ params: { id } }) =>
|
|
{
|
|
const deleted = await db.delete(schema.platforms).where(and(eq(schema.platforms.id, Number(id)),
|
|
notExists(
|
|
db
|
|
.select()
|
|
.from(schema.games)
|
|
.where(eq(schema.games.platform_id, Number(id)))
|
|
))).returning();
|
|
if (deleted.length <= 0) return status("Not Found");
|
|
})
|
|
.get('/platform/lookup/match/:source/:id', async ({ params: { source, id } }) =>
|
|
{
|
|
const platformLookup = await plugins.hooks.games.platformLookup.promise({ source, id });
|
|
if (!platformLookup) return status("Not Found");
|
|
const match = await findPlatform({
|
|
system_slug: platformLookup.slug,
|
|
platform: {
|
|
source_slug: platformLookup.slug,
|
|
source_id: Number(id),
|
|
source: source,
|
|
name: platformLookup.name
|
|
}
|
|
});
|
|
return { details: platformLookup, match };
|
|
}, {
|
|
detail: {
|
|
description: "Find matches of remote platform lookups. Returns the operations for each platform if it were to be imported. If platform locally exists. Will a new local platform be created from say romm. Unknown is returned if no match is found."
|
|
}
|
|
}); |