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;
}
function openJellyfinSetupWindow(): void {
if (appState.jellyfinSetupWindow) {
appState.jellyfinSetupWindow.focus();
return;
}
const setupWindow = new BrowserWindow({
width: 520,
height: 560,
title: 'Jellyfin Setup',
show: true,
autoHideMenuBar: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
},
});
const defaults = getResolvedJellyfinConfig();
const defaultServer = defaults.serverUrl || 'http://127.0.0.1:8096';
const defaultUser = defaults.username || '';
const formHtml = `