mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 01:56:16 -08:00
feat: enhance search functionality with improved LIKE pattern matching for non-ASCII characters
This commit is contained in:
1 parent
8900ee1834
commit
e04ae0e738
1 file changed
+38
-11
@@ -3,7 +3,7 @@
|
||||
* Operations for managing and searching content (streams, movies, series)
|
||||
*/
|
||||
|
||||
import { and, desc, eq, inArray, sql } from 'drizzle-orm';
|
||||
import { and, desc, eq, inArray, or, sql } from 'drizzle-orm';
|
||||
import { ipcMain } from 'electron';
|
||||
import { getDatabase } from '../../database/connection';
|
||||
import * as schema from '../../database/schema';
|
||||
@@ -16,6 +16,25 @@ function escapeLikePattern(term: string): string {
|
||||
return term.replace(/[%_\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build LIKE patterns for multiple case variants to improve non-ASCII matching
|
||||
* in SQLite (default LIKE case-insensitive behavior is ASCII-only).
|
||||
*/
|
||||
function buildLikePatterns(term: string): string[] {
|
||||
const variants = new Set<string>();
|
||||
const titleCase =
|
||||
term.length > 0
|
||||
? term.charAt(0).toLocaleUpperCase() + term.slice(1).toLocaleLowerCase()
|
||||
: term;
|
||||
|
||||
variants.add(term);
|
||||
variants.add(term.toLocaleLowerCase());
|
||||
variants.add(term.toLocaleUpperCase());
|
||||
variants.add(titleCase);
|
||||
|
||||
return [...variants].map(value => `%${escapeLikePattern(value)}%`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if content exists
|
||||
*/
|
||||
@@ -243,9 +262,11 @@ ipcMain.handle(
|
||||
async (event, playlistId: string, searchTerm: string, types: string[]) => {
|
||||
try {
|
||||
const db = await getDatabase();
|
||||
const searchTermLower = searchTerm.toLowerCase();
|
||||
const escapedTerm = escapeLikePattern(searchTerm);
|
||||
const likePattern = `%${escapedTerm}%`;
|
||||
const searchTermLower = searchTerm.toLocaleLowerCase();
|
||||
const likePatterns = buildLikePatterns(searchTerm);
|
||||
const likeConditions = likePatterns.map(
|
||||
pattern => sql`${schema.content.title} LIKE ${pattern} ESCAPE '\\'`
|
||||
);
|
||||
|
||||
// Pre-filter with SQL LIKE (case-insensitive for ASCII, handled in native C code).
|
||||
// This avoids loading the entire content table into JS memory.
|
||||
@@ -272,7 +293,7 @@ ipcMain.handle(
|
||||
schema.content.type,
|
||||
types as Array<'live' | 'movie' | 'series'>
|
||||
),
|
||||
sql`${schema.content.title} LIKE ${likePattern}`
|
||||
or(...likeConditions)
|
||||
)
|
||||
)
|
||||
.limit(200);
|
||||
@@ -280,7 +301,9 @@ ipcMain.handle(
|
||||
// Post-filter for proper Unicode case-insensitive matching
|
||||
// (SQLite LIKE is only case-insensitive for ASCII)
|
||||
const result = candidates
|
||||
.filter(item => item.title?.toLowerCase().includes(searchTermLower))
|
||||
.filter(item =>
|
||||
item.title?.toLocaleLowerCase().includes(searchTermLower)
|
||||
)
|
||||
.slice(0, 50);
|
||||
|
||||
return result;
|
||||
@@ -299,9 +322,11 @@ ipcMain.handle(
|
||||
async (event, searchTerm: string, types: string[]) => {
|
||||
try {
|
||||
const db = await getDatabase();
|
||||
const searchTermLower = searchTerm.toLowerCase();
|
||||
const escapedTerm = escapeLikePattern(searchTerm);
|
||||
const likePattern = `%${escapedTerm}%`;
|
||||
const searchTermLower = searchTerm.toLocaleLowerCase();
|
||||
const likePatterns = buildLikePatterns(searchTerm);
|
||||
const likeConditions = likePatterns.map(
|
||||
pattern => sql`${schema.content.title} LIKE ${pattern} ESCAPE '\\'`
|
||||
);
|
||||
|
||||
// Pre-filter with SQL LIKE (case-insensitive for ASCII, handled in native C code).
|
||||
// This avoids loading the entire content table into JS memory.
|
||||
@@ -335,7 +360,7 @@ ipcMain.handle(
|
||||
schema.content.type,
|
||||
types as Array<'live' | 'movie' | 'series'>
|
||||
),
|
||||
sql`${schema.content.title} LIKE ${likePattern}`
|
||||
or(...likeConditions)
|
||||
)
|
||||
)
|
||||
.orderBy(schema.content.title)
|
||||
@@ -344,7 +369,9 @@ ipcMain.handle(
|
||||
// Post-filter for proper Unicode case-insensitive matching
|
||||
// (SQLite LIKE is only case-insensitive for ASCII)
|
||||
const result = candidates
|
||||
.filter(item => item.title?.toLowerCase().includes(searchTermLower))
|
||||
.filter(item =>
|
||||
item.title?.toLocaleLowerCase().includes(searchTermLower)
|
||||
)
|
||||
.slice(0, 50);
|
||||
|
||||
return result;
|
||||
|
||||
Reference in new issue
Block a user