diff --git a/src/app/zxdb/TapeIdentifier.tsx b/src/app/zxdb/TapeIdentifier.tsx index b177c9d..e82b651 100644 --- a/src/app/zxdb/TapeIdentifier.tsx +++ b/src/app/zxdb/TapeIdentifier.tsx @@ -88,29 +88,67 @@ export default function TapeIdentifier() { {state.kind === "results" ? ( <> -

+

{state.fileName} matched {state.matches.length === 1 ? "1 entry" : `${state.matches.length} entries`}:

-
- {state.matches.map((m) => ( -
-
-
- + {state.matches.map((m) => ( +
+
+
+
+ {m.entryTitle} -
- {m.innerPath} -
-
-
-
{formatBytes(m.sizeBytes)}
-
{m.md5}
-
+ + {m.releaseYear && ( + {m.releaseYear} + )}
+ + {(m.authors.length > 0 || m.genre || m.machinetype) && ( +
+ {m.authors.length > 0 && ( + {m.authors.join(", ")} + )} + {m.genre && ( + {m.genre} + )} + {m.machinetype && ( + {m.machinetype} + )} +
+ )} + + + + + + + + + + + + + + + + + + + + +
File{m.innerPath}
Size{formatBytes(m.sizeBytes)}
MD5{m.md5}
CRC32{m.crc32}
+ + + View entry +
- ))} -
+
+ ))} ) : (

diff --git a/src/server/repo/zxdb.ts b/src/server/repo/zxdb.ts index 3c0fa79..74542c2 100644 --- a/src/server/repo/zxdb.ts +++ b/src/server/repo/zxdb.ts @@ -2633,6 +2633,11 @@ export type TapeMatch = { md5: string; crc32: string; sizeBytes: number; + machinetype: string | null; + genre: string | null; + releaseYear: number | null; + authors: string[]; + downloadLink: string; }; export async function lookupByMd5(md5: string): Promise { @@ -2645,12 +2650,46 @@ export async function lookupByMd5(md5: string): Promise { md5: softwareHashes.md5, crc32: softwareHashes.crc32, sizeBytes: softwareHashes.sizeBytes, + machinetypeName: machinetypes.name, + genreName: genretypes.name, + releaseYear: releases.releaseYear, + downloadLink: downloads.fileLink, }) .from(softwareHashes) .innerJoin(downloads, eq(downloads.id, softwareHashes.downloadId)) .innerJoin(entries, eq(entries.id, downloads.entryId)) + .leftJoin(machinetypes, eq(machinetypes.id, entries.machinetypeId)) + .leftJoin(genretypes, eq(genretypes.id, entries.genretypeId)) + .leftJoin( + releases, + and(eq(releases.entryId, downloads.entryId), eq(releases.releaseSeq, downloads.releaseSeq)) + ) .where(eq(softwareHashes.md5, md5.toLowerCase())); + // Collect unique entry IDs to fetch authors + const entryIds = [...new Set(rows.map((r) => Number(r.entryId)))]; + const authorMap = new Map(); + if (entryIds.length > 0) { + try { + const authorRows = await db + .select({ entryId: authors.entryId, name: labels.name }) + .from(authors) + .innerJoin(labels, eq(labels.id, authors.labelId)) + .where( + entryIds.length === 1 + ? eq(authors.entryId, entryIds[0]) + : sql`${authors.entryId} in (${sql.join(entryIds.map((id) => sql`${id}`), sql`, `)})` + ) + .orderBy(asc(authors.authorSeq)); + for (const a of authorRows) { + const eid = Number(a.entryId); + const existing = authorMap.get(eid); + if (existing) existing.push(a.name); + else authorMap.set(eid, [a.name]); + } + } catch {} + } + return rows.map((r) => ({ downloadId: Number(r.downloadId), entryId: Number(r.entryId), @@ -2659,5 +2698,10 @@ export async function lookupByMd5(md5: string): Promise { md5: r.md5, crc32: r.crc32, sizeBytes: Number(r.sizeBytes), + machinetype: r.machinetypeName ?? null, + genre: r.genreName ?? null, + releaseYear: r.releaseYear != null ? Number(r.releaseYear) : null, + authors: authorMap.get(Number(r.entryId)) ?? [], + downloadLink: r.downloadLink, })); }