Embedded AniList page did not render: ${reason}
We attempted to open the authorize URL in your default browser automatically.
Use one of these links to continue setup:
${authorizeUrl}
${ANILIST_DEVELOPER_SETTINGS_URL}
After login/authorization, copy the token into anilist.accessToken.
`;
void setupWindow.loadURL(
`data:text/html;charset=utf-8,${encodeURIComponent(fallbackHtml)}`,
);
}
function openAnilistSetupWindow(): void {
if (appState.anilistSetupWindow) {
appState.anilistSetupWindow.focus();
return;
}
const setupWindow = new BrowserWindow({
width: 1000,
height: 760,
title: "Anilist Setup",
show: true,
autoHideMenuBar: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
},
});
setupWindow.webContents.setWindowOpenHandler(({ url }) => {
if (!isAllowedAnilistExternalUrl(url)) {
logger.warn("Blocked unsafe AniList setup external URL", { url });
return { action: "deny" };
}
void shell.openExternal(url);
return { action: "deny" };
});
setupWindow.webContents.on("will-navigate", (event, url) => {
if (isAllowedAnilistSetupNavigationUrl(url)) {
return;
}
event.preventDefault();
logger.warn("Blocked unsafe AniList setup navigation URL", { url });
});
setupWindow.webContents.on(
"did-fail-load",
(_event, errorCode, errorDescription, validatedURL) => {
logger.error("AniList setup window failed to load", {
errorCode,
errorDescription,
validatedURL,
});
openAnilistSetupInBrowser();
if (!setupWindow.isDestroyed()) {
loadAnilistSetupFallback(
setupWindow,
`${errorDescription} (${errorCode})`,
);
}
},
);
setupWindow.webContents.on("did-finish-load", () => {
const loadedUrl = setupWindow.webContents.getURL();
if (!loadedUrl || loadedUrl === "about:blank") {
logger.warn("AniList setup loaded a blank page; using fallback");
openAnilistSetupInBrowser();
if (!setupWindow.isDestroyed()) {
loadAnilistSetupFallback(setupWindow, "blank page");
}
}
});
void setupWindow.loadURL(buildAnilistSetupUrl()).catch((error) => {
logger.error("AniList setup loadURL rejected", error);
openAnilistSetupInBrowser();
if (!setupWindow.isDestroyed()) {
loadAnilistSetupFallback(
setupWindow,
error instanceof Error ? error.message : String(error),
);
}
});
setupWindow.on("closed", () => {
appState.anilistSetupWindow = null;
appState.anilistSetupPageOpened = false;
});
appState.anilistSetupWindow = setupWindow;
appState.anilistSetupPageOpened = true;
}
async function refreshAnilistClientSecretState(options?: { force?: boolean }): Promise