@@ -3,7 +3,7 @@ import path from 'path'
33import fs from 'fs'
44import http from 'http'
55import https from 'https'
6- import { URL } from 'url'
6+ import { URL , pathToFileURL } from 'url'
77import { OsrSerialManager } from './osrSerial'
88import { SCRIPT_AXIS_DEFINITIONS , inferAxisIdFromStem , stripKnownAxisSuffix } from '../src/services/multiaxis'
99import { getVideoSubtitleMatchScore , parseSubtitleFile } from '../src/services/subtitles'
@@ -43,6 +43,7 @@ const SUBTITLE_DIR_KEYWORDS = [
4343const MAX_SUBTITLE_SEARCH_DEPTH = 2
4444const MAX_SCAN_SUBTITLE_VALIDATION_CANDIDATES = 3
4545const SCAN_YIELD_INTERVAL = 25
46+ const NATURAL_SORTER = new Intl . Collator ( undefined , { numeric : true , sensitivity : 'base' } )
4647
4748let mainWindow : BrowserWindow | null = null
4849const subtitleCandidateCache = new Map < string , string [ ] > ( )
@@ -198,7 +199,7 @@ ipcMain.handle('fs:readDir', async (_event, dirPath: string) => {
198199 }
199200
200201 await scanDir ( dirPath , '' )
201- return files . sort ( ( a , b ) => a . relativePath . localeCompare ( b . relativePath ) )
202+ return files . sort ( ( a , b ) => NATURAL_SORTER . compare ( a . relativePath , b . relativePath ) )
202203 } catch {
203204 return [ ]
204205 }
@@ -226,8 +227,8 @@ ipcMain.handle('fs:saveFunscript', async (_event, videoPath: string, data: strin
226227} )
227228
228229ipcMain . handle ( 'fs:getVideoUrl' , async ( _event , filePath : string ) => {
229- // Return a file:// URL that the renderer can use
230- return `file:/// ${ filePath . replace ( / \\ / g , '/' ) } `
230+ // Encode reserved URL characters such as "#" in Windows file names.
231+ return pathToFileURL ( filePath ) . toString ( )
231232} )
232233
233234ipcMain . handle ( 'fs:findArtwork' , async ( _event , mediaPath : string ) => {
0 commit comments