fix: improve fuzzy handling
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<style>
|
||||
body {
|
||||
@@ -35,10 +34,9 @@
|
||||
background: #000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="bar">
|
||||
<button id="refresh">refresh</button>
|
||||
<label>
|
||||
@@ -51,11 +49,12 @@
|
||||
</label>
|
||||
<label>
|
||||
threshold
|
||||
<input id="threshold" type="range" min="0" max="120" value="85">
|
||||
<input id="threshold" type="range" min="0" max="120" value="85" />
|
||||
<span id="thresholdText">85</span>
|
||||
</label>
|
||||
<label>
|
||||
time: <span id="timingText">Loading...</span><span style="color: gray;">(image load complete in browser)</span>
|
||||
time: <span id="timingText">Loading...</span
|
||||
><span style="color: gray">(image load complete in browser)</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -63,10 +62,10 @@
|
||||
|
||||
<script>
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const type = urlParams.get('type');
|
||||
const type = urlParams.get("type");
|
||||
|
||||
let MINE, ORIG, W, H;
|
||||
if (type === 'list') {
|
||||
if (type === "list") {
|
||||
MINE = "/v1/card/genshin/775956514";
|
||||
ORIG = "/v1/card/genshin/diff/listoriginal.webp";
|
||||
W = 1200;
|
||||
@@ -91,7 +90,9 @@
|
||||
const thresholdText = document.getElementById("thresholdText");
|
||||
const timingText = document.getElementById("timingText");
|
||||
|
||||
let mineData, origData, refreshing = false;
|
||||
let mineData,
|
||||
origData,
|
||||
refreshing = false;
|
||||
|
||||
function loadImage(src) {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -99,7 +100,8 @@
|
||||
img.crossOrigin = "anonymous";
|
||||
img.onload = () => resolve(img);
|
||||
img.onerror = reject;
|
||||
img.src = src + (src.includes("?") ? "&" : "?") + "cacheBust=" + Date.now();
|
||||
img.src =
|
||||
src + (src.includes("?") ? "&" : "?") + "cacheBust=" + Date.now();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -127,7 +129,9 @@
|
||||
|
||||
const start = Date.now();
|
||||
const [mineImg, origImg] = await Promise.all([
|
||||
loadImage(MINE).finally(() => timingText.innerText = `${Date.now() - start}ms`),
|
||||
loadImage(MINE).finally(
|
||||
() => (timingText.innerText = `${Date.now() - start}ms`),
|
||||
),
|
||||
loadImage(ORIG),
|
||||
]);
|
||||
|
||||
@@ -200,9 +204,7 @@
|
||||
} else {
|
||||
o[i + 3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else if (mode.value === "diff") {
|
||||
} else if (mode.value === "diff") {
|
||||
const dr = Math.abs(m[i] - r[i]);
|
||||
const dg = Math.abs(m[i + 1] - r[i + 1]);
|
||||
const db = Math.abs(m[i + 2] - r[i + 2]);
|
||||
@@ -212,9 +214,7 @@
|
||||
o[i + 1] = diff;
|
||||
o[i + 2] = diff;
|
||||
o[i + 3] = diff > t ? 255 : 0;
|
||||
}
|
||||
|
||||
else {
|
||||
} else {
|
||||
o[i] = m[i]; // mine red-ish
|
||||
o[i + 1] = r[i + 1]; // original green-ish
|
||||
o[i + 2] = 0;
|
||||
@@ -230,14 +230,17 @@
|
||||
mode.oninput = render;
|
||||
threshold.oninput = render;
|
||||
|
||||
refresh().catch(err => {
|
||||
refresh().catch((err) => {
|
||||
console.error(err);
|
||||
ctx.fillStyle = "red";
|
||||
ctx.fillText(String(err), 20, 30);
|
||||
});
|
||||
|
||||
window.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter" && !["INPUT", "SELECT"].includes(e.target.tagName)) {
|
||||
if (
|
||||
e.key === "Enter" &&
|
||||
!["INPUT", "SELECT"].includes(e.target.tagName)
|
||||
) {
|
||||
e.preventDefault();
|
||||
refresh();
|
||||
}
|
||||
@@ -247,7 +250,5 @@
|
||||
// refresh();
|
||||
// });
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -55,7 +55,8 @@ export function endfieldCard(app: App) {
|
||||
params: t.Object({ uid: t.String() }),
|
||||
detail: {
|
||||
tags: ["Endfield"],
|
||||
description: "Preload data required to render an Endfield template card.",
|
||||
description:
|
||||
"Preload data required to render an Endfield template card.",
|
||||
},
|
||||
afterResponse: ({ log }) => log`Data preload complete`,
|
||||
},
|
||||
@@ -121,7 +122,8 @@ export function endfieldCard(app: App) {
|
||||
{ http: "http", card: "card" },
|
||||
{
|
||||
default: "http",
|
||||
description: "Type of error to return when card fails to render.",
|
||||
description:
|
||||
"Type of error to return when card fails to render.",
|
||||
},
|
||||
),
|
||||
debug: t.Boolean({
|
||||
@@ -134,7 +136,8 @@ export function endfieldCard(app: App) {
|
||||
),
|
||||
detail: {
|
||||
tags: ["Endfield"],
|
||||
description: "Generate a placeholder Endfield profile card image from a UID.",
|
||||
description:
|
||||
"Generate a placeholder Endfield profile card image from a UID.",
|
||||
},
|
||||
afterResponse: ({ log }) => log`Rendering completed`,
|
||||
},
|
||||
|
||||
@@ -61,7 +61,9 @@ export function EndfieldTemplate({
|
||||
<div tw="text-[1.55em] leading-[1.15] font-semibold">
|
||||
Route + Card Shell
|
||||
</div>
|
||||
<div tw="text-white/60 mt-[.35em]">Ready for game-specific layout work</div>
|
||||
<div tw="text-white/60 mt-[.35em]">
|
||||
Ready for game-specific layout work
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div tw="rounded-[1em] border border-white/10 bg-black/20 p-[1.2em]">
|
||||
@@ -71,7 +73,9 @@ export function EndfieldTemplate({
|
||||
<div tw="text-[1.55em] leading-[1.15] font-semibold">
|
||||
Character Grid
|
||||
</div>
|
||||
<div tw="text-white/60 mt-[.35em]">Replace placeholder sections with Endfield data</div>
|
||||
<div tw="text-white/60 mt-[.35em]">
|
||||
Replace placeholder sections with Endfield data
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -80,7 +84,8 @@ export function EndfieldTemplate({
|
||||
Signature
|
||||
</div>
|
||||
<div tw="text-[1.05em] leading-[1.45] text-white/82 whitespace-pre-wrap">
|
||||
{signature?.trim() || "No signature available in the fetched payload yet."}
|
||||
{signature?.trim() ||
|
||||
"No signature available in the fetched payload yet."}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { mkdir, readdir, rm } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { file, hash, write } from "bun";
|
||||
import type { ResolvedPlayerInfo} from "enka.ts";
|
||||
import type { ResolvedPlayerInfo } from "enka.ts";
|
||||
import { TTLCache } from "enka.ts";
|
||||
|
||||
import type {
|
||||
@@ -13,11 +13,9 @@ import type {
|
||||
EnkaNamecards,
|
||||
EnkaPfps,
|
||||
RelicStore,
|
||||
WeaponStore} from "@/games/genshin/types/enka";
|
||||
import {
|
||||
ElementList
|
||||
WeaponStore,
|
||||
} from "@/games/genshin/types/enka";
|
||||
|
||||
import { ElementList } from "@/games/genshin/types/enka";
|
||||
import { Deduplicator } from "@/lib/dedupe";
|
||||
import { createLogger } from "@/lib/logger";
|
||||
|
||||
@@ -210,10 +208,11 @@ export async function getEnkaStore<K extends keyof StoreTypeMap>(
|
||||
return data;
|
||||
}
|
||||
|
||||
// DEPRECATED: No longer needed
|
||||
export function getAvatar(
|
||||
store: AvatarStore,
|
||||
playerInfo: ResolvedPlayerInfo,
|
||||
id: number,
|
||||
id: string | number,
|
||||
) {
|
||||
return (
|
||||
Object.entries(store).find(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { BaseAvatar } from "enka.ts";
|
||||
import { distance } from "fastest-levenshtein";
|
||||
|
||||
function shortAvatarId(id: number) {
|
||||
function shortAvatarId(id: string | number) {
|
||||
// 10000120 -> 120
|
||||
return String(id).replace(/^10*/, "");
|
||||
return String(id).replace(/^10*/, "").replace(/^-\d+/, "");
|
||||
}
|
||||
|
||||
function norm(s: string) {
|
||||
@@ -60,5 +60,8 @@ function fuzzyNameMatch<T extends { avatar: BaseAvatar }>(
|
||||
}
|
||||
|
||||
function avatarAliases(name: string) {
|
||||
return [name, ...name.split(" ")];
|
||||
const aliases: Record<string, string[]> = {
|
||||
Traveler: ["Aether", "Lumine"],
|
||||
};
|
||||
return [name, ...name.split(" "), ...(aliases[name] ?? [])];
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ import type { ResolvedAvatarInfo } from "enka.ts";
|
||||
import { AvatarElement } from "enka.ts";
|
||||
|
||||
import type { EnkaLocsLanguage } from "@/games/genshin/types/enka";
|
||||
import { FightPropMapEnum, PercentageFightProp } from "@/games/genshin/types/fightPropMap";
|
||||
import {
|
||||
FightPropMapEnum,
|
||||
PercentageFightProp,
|
||||
} from "@/games/genshin/types/fightPropMap";
|
||||
|
||||
// Types
|
||||
interface DisplayRow {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import type { Affix } from "@/games/genshin/types/enka";
|
||||
import { FightPropMapEnum, PercentageFightProp } from "@/games/genshin/types/fightPropMap";
|
||||
import {
|
||||
FightPropMapEnum,
|
||||
PercentageFightProp,
|
||||
} from "@/games/genshin/types/fightPropMap";
|
||||
|
||||
export type RollSummary = {
|
||||
id: string;
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
} from "@/games/genshin/types/enka";
|
||||
import type { Logger } from "@/lib/logger";
|
||||
import { arrRandom } from "@/lib/util";
|
||||
|
||||
import { CardResponse } from "@/v1/response";
|
||||
|
||||
export async function ListPage(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { t } from "elysia";
|
||||
|
||||
export type AvatarStore = Record<number, Avatar>;
|
||||
export type AvatarStore = Record<string | number, Avatar>;
|
||||
|
||||
export interface Avatar {
|
||||
Element: ElementType;
|
||||
|
||||
+1
-1
@@ -1,3 +1,4 @@
|
||||
import { cors } from "@elysia/cors";
|
||||
import openapi from "@elysiajs/openapi";
|
||||
import { Elysia, t } from "elysia";
|
||||
|
||||
@@ -5,7 +6,6 @@ import { version } from "../package.json";
|
||||
import { pm } from "./lib/auth";
|
||||
import { createLogger } from "./lib/logger";
|
||||
import { v1routes } from "./v1";
|
||||
import { cors } from '@elysia/cors'
|
||||
|
||||
const log = createLogger("APP");
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { feature } from "bun:bundle";
|
||||
import type { InspectColor} from "node:util";
|
||||
import type { InspectColor } from "node:util";
|
||||
import { styleText } from "node:util";
|
||||
|
||||
import { inspect } from "bun";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { join } from "node:path";
|
||||
|
||||
import type { MaybePromise} from "bun";
|
||||
import type { MaybePromise } from "bun";
|
||||
import { $, write } from "bun";
|
||||
|
||||
import { createLogger } from "@/lib/logger";
|
||||
|
||||
Reference in New Issue
Block a user