Extensions are now lazy loaded to prevent

long wait times to use the app.
This commit is contained in:
2025-11-20 09:30:19 -05:00
parent 2a453c40a8
commit 6ddc45b989
4 changed files with 93 additions and 55 deletions

51
main.js
View File

@@ -7,9 +7,6 @@ const initDatabase = require('./src/database/db-init');
const { initDiscordRPC } = require('./src/discord-rpc'); const { initDiscordRPC } = require('./src/discord-rpc');
const headlessBrowser = require('./src/utils/headless-browser'); const headlessBrowser = require('./src/utils/headless-browser');
const fetchPath = require.resolve('node-fetch');
const cheerioPath = require.resolve('cheerio');
const waifuBoardsPath = path.join(app.getPath('home'), 'WaifuBoards'); const waifuBoardsPath = path.join(app.getPath('home'), 'WaifuBoards');
const pluginsPath = path.join(waifuBoardsPath, 'extensions'); const pluginsPath = path.join(waifuBoardsPath, 'extensions');
const dbPath = path.join(waifuBoardsPath, 'favorites.db'); const dbPath = path.join(waifuBoardsPath, 'favorites.db');
@@ -25,44 +22,34 @@ try {
console.error('Failed to create directories:', error); console.error('Failed to create directories:', error);
} }
const loadedScrapers = {}; const availableScrapers = {};
function loadScrapers() { function loadScrapers() {
console.log('Loading scrapers...'); console.log('Scanning for plugins...');
console.log(`Checking for plugins in: ${pluginsPath}`);
const files = fs.readdirSync(pluginsPath); let files = [];
files
.filter((file) => file.endsWith('.js'))
.forEach((file) => {
const filePath = path.join(pluginsPath, file);
try { try {
const scraperModule = require(filePath); files = fs.readdirSync(pluginsPath).filter((file) => file.endsWith('.js'));
const className = Object.keys(scraperModule)[0]; } catch (e) {
const ScraperClass = scraperModule[className]; console.error("Failed to read plugins directory", e);
return;
}
if ( files.forEach((file) => {
typeof ScraperClass === 'function' && const name = file.replace('.js', '');
ScraperClass.prototype.fetchSearchResult const filePath = path.join(pluginsPath, file);
) {
const instance = new ScraperClass(fetchPath, cheerioPath, headlessBrowser);
loadedScrapers[className] = { availableScrapers[name] = {
instance: instance, name: name,
baseUrl: instance.baseUrl, path: filePath,
instance: null
}; };
console.log(
`Successfully loaded scraper: ${className} from ${instance.baseUrl}`
);
} else {
console.warn(`File ${file} does not export a valid scraper class.`);
}
} catch (error) {
console.error(`Failed to load scraper from ${file}:`, error);
}
}); });
console.log(`Found ${files.length} plugins. (Lazy Loaded)`);
} }
loadScrapers(); loadScrapers();
const db = initDatabase(dbPath); const db = initDatabase(dbPath);
@@ -100,7 +87,7 @@ app.on('window-all-closed', function () {
} }
}); });
const apiHandlers = require('./src/ipc/api-handlers')(loadedScrapers); const apiHandlers = require('./src/ipc/api-handlers')(availableScrapers, headlessBrowser);
const dbHandlers = require('./src/ipc/db-handlers')(db); const dbHandlers = require('./src/ipc/db-handlers')(db);
ipcMain.handle('api:getSources', apiHandlers.getSources); ipcMain.handle('api:getSources', apiHandlers.getSources);

View File

@@ -1,6 +1,6 @@
{ {
"name": "waifu-board", "name": "waifu-board",
"version": "v1.3.0", "version": "v1.3.1",
"description": "An image board app to store and browse your favorite waifus!", "description": "An image board app to store and browse your favorite waifus!",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {

View File

@@ -1,29 +1,80 @@
module.exports = function (loadedScrapers) { const fs = require('fs');
const fetchPath = require.resolve('node-fetch');
const cheerioPath = require.resolve('cheerio');
function peekBaseUrl(filePath) {
try {
const content = fs.readFileSync(filePath, 'utf-8');
const match = content.match(/baseUrl\s*=\s*["']([^"']+)["']/);
return match ? match[1] : null;
} catch (e) {
return null;
}
}
module.exports = function (availableScrapers, headlessBrowser) {
Object.keys(availableScrapers).forEach(name => {
const scraper = availableScrapers[name];
if (!scraper.url) {
const url = peekBaseUrl(scraper.path);
if (url) {
scraper.url = url;
}
}
});
return { return {
getSources: () => { getSources: () => {
return Object.keys(loadedScrapers).map((name) => { return Object.keys(availableScrapers).map((name) => {
const scraper = availableScrapers[name];
return { return {
name: name, name: name,
url: loadedScrapers[name].baseUrl, url: scraper.url || name
}; };
}); });
}, },
search: async (event, source, query, page) => { search: async (event, source, query, page) => {
const scraperData = availableScrapers[source];
if (!scraperData) {
return { success: false, error: `Source ${source} not found.` };
}
if (!scraperData.instance) {
console.log(`[LazyLoad] Initializing scraper: ${source}...`);
try { try {
if (loadedScrapers[source] && loadedScrapers[source].instance) { const scraperModule = require(scraperData.path);
const results = await loadedScrapers[source].instance.fetchSearchResult(
query, const className = Object.keys(scraperModule)[0];
page const ScraperClass = scraperModule[className];
);
if (!ScraperClass || typeof ScraperClass !== 'function') {
throw new Error(`File ${scraperData.path} does not export a valid class.`);
}
const instance = new ScraperClass(fetchPath, cheerioPath, headlessBrowser);
scraperData.instance = instance;
if (instance.baseUrl) {
scraperData.url = instance.baseUrl;
}
} catch (err) {
console.error(`Failed to lazy load ${source}:`, err);
return { success: false, error: `Failed to load extension: ${err.message}` };
}
}
try {
const results = await scraperData.instance.fetchSearchResult(query, page);
return { success: true, data: results }; return { success: true, data: results };
} else { } catch (err) {
throw new Error(`Unknown source or source failed to load: ${source}`); console.error(`Error during search in ${source}:`, err);
return { success: false, error: err.message };
} }
} catch (error) {
console.error(`Error searching ${source}:`, error);
return { success: false, error: error.message };
} }
},
}; };
}; };

View File

@@ -1,6 +1,6 @@
const GITHUB_OWNER = 'ItsSkaiya'; const GITHUB_OWNER = 'ItsSkaiya';
const GITHUB_REPO = 'WaifuBoard'; const GITHUB_REPO = 'WaifuBoard';
const CURRENT_VERSION = 'v1.3.0'; const CURRENT_VERSION = 'v1.3.1';
const UPDATE_CHECK_INTERVAL = 5 * 60 * 1000; const UPDATE_CHECK_INTERVAL = 5 * 60 * 1000;
let currentVersionDisplay; let currentVersionDisplay;