moved to API

This commit is contained in:
2026-03-08 22:24:34 -07:00
parent cf6b2611aa
commit 2caf566bf6
94 changed files with 1257 additions and 40930 deletions

View File

@@ -107,8 +107,6 @@
quality: 82
};
const DECK_REGISTRY_PATH = "asset/tarot deck/decks.json";
let deckManifestSources = buildDeckManifestSources();
const manifestCache = new Map();
@@ -116,6 +114,21 @@
const cardBackThumbnailCache = new Map();
let activeDeckId = DEFAULT_DECK_ID;
function getApiBaseUrl() {
return String(window.TarotDataService?.getApiBaseUrl?.() || window.TarotAppConfig?.apiBaseUrl || "")
.trim()
.replace(/\/+$/, "");
}
function rewriteBasePathForApi(basePath) {
const normalizedBasePath = String(basePath || "").trim();
if (!normalizedBasePath) {
return normalizedBasePath;
}
return window.TarotDataService?.toApiAssetUrl?.(normalizedBasePath) || normalizedBasePath;
}
function canonicalMajorName(cardName) {
return String(cardName || "")
.trim()
@@ -256,6 +269,46 @@
return /^(https?:)?\/\//i.test(String(pathValue || ""));
}
function joinAssetPath(basePath, relativePath) {
const normalizedBasePath = String(basePath || "").trim().replace(/\/+$/, "");
const normalizedRelativePath = String(relativePath || "")
.trim()
.replace(/^\.\//, "")
.replace(/^\/+/, "");
if (!normalizedBasePath) {
return normalizedRelativePath;
}
if (!normalizedRelativePath) {
return normalizedBasePath;
}
if (!isRemoteAssetPath(normalizedBasePath)) {
return `${normalizedBasePath}/${normalizedRelativePath}`;
}
try {
const url = new URL(normalizedBasePath);
const encodedRelativePath = normalizedRelativePath
.split("/")
.filter(Boolean)
.map((segment) => {
try {
return encodeURIComponent(decodeURIComponent(segment));
} catch {
return encodeURIComponent(segment);
}
})
.join("/");
url.pathname = `${url.pathname.replace(/\/+$/, "")}/${encodedRelativePath}`;
return url.toString();
} catch {
return `${normalizedBasePath}/${normalizedRelativePath}`;
}
}
function toDeckAssetPath(manifest, relativeOrAbsolutePath) {
const normalizedPath = String(relativeOrAbsolutePath || "").trim();
if (!normalizedPath) {
@@ -266,7 +319,7 @@
return normalizedPath;
}
return `${manifest.basePath}/${normalizedPath.replace(/^\.\//, "")}`;
return joinAssetPath(manifest.basePath, normalizedPath);
}
function resolveDeckCardBackPath(manifest) {
@@ -364,7 +417,7 @@
const id = String(entry?.id || "").trim().toLowerCase();
const basePath = String(entry?.basePath || "").trim().replace(/\/$/, "");
const manifestPath = String(entry?.manifestPath || "").trim();
if (!id || !basePath || !manifestPath) {
if (!id || !manifestPath) {
return;
}
@@ -382,14 +435,35 @@
}
function buildDeckManifestSources() {
const registry = readManifestJsonSync(DECK_REGISTRY_PATH);
const registryDecks = Array.isArray(registry)
? registry
: (Array.isArray(registry?.decks) ? registry.decks : null);
if (!window.TarotDataService?.isApiEnabled?.() && !getApiBaseUrl()) {
return {};
}
const registryUrl = window.TarotDataService?.buildApiUrl?.("/api/v1/decks/options") || `${getApiBaseUrl()}/api/v1/decks/options`;
if (!registryUrl) {
return {};
}
const registry = readManifestJsonSync(registryUrl);
const registryDecks = Array.isArray(registry?.decks)
? registry.decks.map((entry) => ({
id: entry?.id,
label: entry?.label,
manifestPath: window.TarotDataService?.buildApiUrl?.(`/api/v1/decks/${encodeURIComponent(String(entry?.id || "").trim().toLowerCase())}/manifest`) || `${getApiBaseUrl()}/api/v1/decks/${encodeURIComponent(String(entry?.id || "").trim().toLowerCase())}/manifest`
}))
: [];
return toDeckSourceMap(registryDecks);
}
function resetConnectionCaches() {
deckManifestSources = buildDeckManifestSources();
manifestCache.clear();
cardBackCache.clear();
cardBackThumbnailCache.clear();
setActiveDeck(activeDeckId);
}
function getDeckManifestSources(forceRefresh = false) {
if (forceRefresh || !deckManifestSources || Object.keys(deckManifestSources).length === 0) {
deckManifestSources = buildDeckManifestSources();
@@ -442,9 +516,9 @@
return {
id: source.id,
label: String(rawManifest.label || source.label || source.id),
basePath: String(source.basePath || "").replace(/\/$/, ""),
basePath: rewriteBasePathForApi(String(rawManifest.basePath || source.basePath || "").replace(/\/$/, "")),
cardBack: String(rawManifest.cardBack || "").trim(),
cardBackPath: String(source.cardBackPath || "").trim(),
cardBackPath: String(rawManifest.cardBackPath || source.cardBackPath || "").trim(),
thumbnails: normalizeThumbnailConfig(rawManifest.thumbnails, source.thumbnailRoot),
majors: rawManifest.majors || {},
minors: rawManifest.minors || {},
@@ -689,17 +763,17 @@
}
if (variant === "thumbnail") {
return resolveDeckThumbnailPath(manifest, relativePath) || `${manifest.basePath}/${relativePath}`;
return resolveDeckThumbnailPath(manifest, relativePath) || toDeckAssetPath(manifest, relativePath);
}
return `${manifest.basePath}/${relativePath}`;
return toDeckAssetPath(manifest, relativePath);
}
function resolveTarotCardImage(cardName, optionsOrDeckId) {
const { resolvedDeckId } = resolveDeckOptions(optionsOrDeckId);
const activePath = resolveWithDeck(resolvedDeckId, cardName);
if (activePath) {
return encodeURI(activePath);
return activePath;
}
return null;
@@ -709,7 +783,7 @@
const { resolvedDeckId } = resolveDeckOptions(optionsOrDeckId);
const thumbnailPath = resolveWithDeck(resolvedDeckId, cardName, "thumbnail");
if (thumbnailPath) {
return encodeURI(thumbnailPath);
return thumbnailPath;
}
return null;
@@ -720,7 +794,7 @@
if (cardBackCache.has(resolvedDeckId)) {
const cachedPath = cardBackCache.get(resolvedDeckId);
return cachedPath ? encodeURI(cachedPath) : null;
return cachedPath || null;
}
const manifest = getDeckManifest(resolvedDeckId);
@@ -728,7 +802,7 @@
cardBackCache.set(resolvedDeckId, activeBackPath || null);
if (activeBackPath) {
return encodeURI(activeBackPath);
return activeBackPath;
}
return null;
@@ -739,7 +813,7 @@
if (cardBackThumbnailCache.has(resolvedDeckId)) {
const cachedPath = cardBackThumbnailCache.get(resolvedDeckId);
return cachedPath ? encodeURI(cachedPath) : null;
return cachedPath || null;
}
const manifest = getDeckManifest(resolvedDeckId);
@@ -747,7 +821,7 @@
const thumbnailPath = resolveDeckThumbnailPath(manifest, relativeBackPath) || resolveDeckCardBackPath(manifest);
cardBackThumbnailCache.set(resolvedDeckId, thumbnailPath || null);
return thumbnailPath ? encodeURI(thumbnailPath) : null;
return thumbnailPath || null;
}
function resolveDisplayNameWithDeck(deckId, cardName, trumpNumber) {
@@ -852,6 +926,8 @@
setActiveDeck(nextDeck);
});
document.addEventListener("connection:updated", resetConnectionCaches);
window.TarotCardImages = {
resolveTarotCardImage,
resolveTarotCardThumbnail,