diff --git a/lib/nonGameTerms.json b/lib/nonGameTerms.json index b1f45bc..e5088f4 100644 --- a/lib/nonGameTerms.json +++ b/lib/nonGameTerms.json @@ -18,6 +18,7 @@ "editor", "emulator", "expansion", + "figurine", "firmware", "guide", "hack", @@ -26,6 +27,7 @@ "installer", "intro", "json", + "jpg", "manual", "mod", "movie", @@ -44,6 +46,7 @@ "sdk", "setup", "soundtrack", + "sqlite", "terms", "tool", "trainer", @@ -51,7 +54,8 @@ "update", "utility", "video", - "Virtual Console", - "wallpaper" + "virtual console", + "wallpaper", + "xml" ] } \ No newline at end of file diff --git a/lib/services/elasticsearch.js b/lib/services/elasticsearch.js index 9373e13..7a4200b 100644 --- a/lib/services/elasticsearch.js +++ b/lib/services/elasticsearch.js @@ -1,6 +1,9 @@ import { Client } from '@elastic/elasticsearch'; import debugPrint from '../debugprint.js'; import { File } from '../models/index.js'; +import { readFileSync } from 'fs'; +import { fileURLToPath } from 'url'; +import { dirname, resolve } from 'path'; const client = new Client({ node: process.env.ELASTICSEARCH_URL || 'http://localhost:9200' @@ -8,6 +11,23 @@ const client = new Client({ const INDEX_NAME = 'myrient_files'; +// Cache for nonGameTerms +let nonGameTermsCache = null; + +function getNonGameTerms() { + if (nonGameTermsCache) { + return nonGameTermsCache; + } + + const __filename = fileURLToPath(import.meta.url); + const __dirname = dirname(__filename); + + const nonGameTermsPath = resolve(__dirname, '../../lib/nonGameTerms.json'); + nonGameTermsCache = JSON.parse(readFileSync(nonGameTermsPath, 'utf8')); + + return nonGameTermsCache; +} + export async function initElasticsearch() { try { const indexExists = await client.indices.exists({ index: INDEX_NAME }); @@ -111,7 +131,7 @@ export async function search(query, options) { const searchQuery = { index: INDEX_NAME, body: { - size: 1000, + size: 1500, query: { bool: { must: buildMustClauses(query, options), @@ -132,7 +152,6 @@ export async function search(query, options) { try { const startTime = process.hrtime(); const response = await client.search(searchQuery); - const elapsed = parseHrtimeToSeconds(process.hrtime(startTime)); // Fetch full records from PostgreSQL for the search results const ids = response.hits.hits.map(hit => hit._id); @@ -146,13 +165,28 @@ export async function search(query, options) { return map; }, {}); - // Combine Elasticsearch results with full PostgreSQL records + // Build results with full PostgreSQL records + let results = response.hits.hits.map(hit => ({ + ...recordMap[hit._id].dataValues, + score: hit._score, + highlights: hit.highlight + })); + + // Apply non-game content filtering in JavaScript if the option is enabled + if (options.hideNonGame) { + const nonGameTerms = getNonGameTerms(); + const termPatterns = nonGameTerms.terms.map(term => new RegExp(term, 'i')); + + // Filter results in JavaScript (much faster than complex Elasticsearch queries) + results = results.filter(item => { + // Check if filename contains any of the non-game terms + return !termPatterns.some(pattern => pattern.test(item.filename)); + }); + } + + const elapsed = parseHrtimeToSeconds(process.hrtime(startTime)); return { - items: response.hits.hits.map(hit => ({ - ...recordMap[hit._id].dataValues, - score: hit._score, - highlights: hit.highlight - })), + items: results, elapsed }; } catch (error) { diff --git a/server.js b/server.js index 5d6a662..0657367 100644 --- a/server.js +++ b/server.js @@ -44,6 +44,7 @@ let defaultSettings = { fields: searchFields, fuzzy: 0, prefix: true, + hideNonGame: true, }; //programmatically set the default boosts while reducing overhead when adding another search field @@ -79,7 +80,9 @@ let defaultOptions = { fileCount: fileCount, termCount: 0, generateAsciiArt: generateAsciiArt, - isEmulatorCompatible: isEmulatorCompatible + isEmulatorCompatible: isEmulatorCompatible, + isNonGameContent: isNonGameContent, + nonGameTerms: nonGameTerms }; function updateDefaults(){ @@ -143,7 +146,8 @@ app.get("/search", async function (req, res) { results: results, pageNum: pageNum, indexing: search.indexing, - urlPrefix: urlPrefix + urlPrefix: urlPrefix, + settings: settings }; let page = "results"; options = buildOptions(page, options); diff --git a/views/pages/results.ejs b/views/pages/results.ejs index 5e7c386..7351fc2 100644 --- a/views/pages/results.ejs +++ b/views/pages/results.ejs @@ -30,7 +30,14 @@ -

Found <%= results.items.length %> result<%= results.items.length != 1 ? 's': '' %> in <%= results.elapsed %> seconds. <%= indexing ? "Indexing in progress, if the list is missing something please try reloading in a few minutes" : "" %>

+

Found <%= results.items.length %> result<%= results.items.length != 1 ? 's': '' %> in <%= results.elapsed %> seconds. <%= indexing ? "Indexing in progress, if the list is missing something please try reloading in a few minutes" : "" %> + <% if (settings.hideNonGame) { %> + + Non-game content filter is active + + + <% } %> +

@@ -165,4 +172,9 @@ "bottomStart": '' } }); + + // Initialize tooltips + $(function () { + $('[data-toggle="tooltip"]').tooltip() + }); \ No newline at end of file diff --git a/views/pages/settings.ejs b/views/pages/settings.ejs index e8979e7..cca5d6c 100644 --- a/views/pages/settings.ejs +++ b/views/pages/settings.ejs @@ -49,6 +49,10 @@ Match All Words +
@@ -96,9 +100,11 @@ if(typeof settings.combineWith == 'undefined') {settings.combineWith = defaults.combineWith} if(typeof settings.fuzzy == 'undefined') {settings.fuzzy = defaults.fuzzy} if(typeof settings.prefix == 'undefined') {settings.prefix = defaults.prefix} + if(typeof settings.hideNonGame == 'undefined') {settings.hideNonGame = defaults.hideNonGame} document.getElementById('combineWith').checked = settings.combineWith ? true : false document.getElementById('fuzzy').value = settings.fuzzy document.getElementById('prefix').checked = settings.prefix + document.getElementById('hideNonGame').checked = settings.hideNonGame } function saveSettings(){ @@ -112,6 +118,7 @@ settings.combineWith = document.getElementById('combineWith').checked ? 'AND' : '' settings.fuzzy = parseFloat (document.getElementById('fuzzy').value) settings.prefix = document.getElementById('prefix').checked + settings.hideNonGame = document.getElementById('hideNonGame').checked localStorage.setItem('settings', JSON.stringify(settings)) window.location.href = '/' }