1+ const { app, BrowserWindow, ipcMain, dialog } = require ( 'electron' ) ;
2+ const path = require ( 'path' ) ;
3+ const fs = require ( 'fs-extra' ) ;
4+ const pdfParse = require ( 'pdf-parse' ) ;
5+
6+ // import { app, BrowserWindow, ipcMain, dialog } from 'electron';
7+ // import path from 'path';
8+ // import fs from 'fs-extra';
9+ // import * as mupdfjs from 'mupdf/mupdfjs';
10+ // console.log("Encoding:", process.stdout.getEncoding());
11+
12+ process . stdout . setDefaultEncoding ( 'utf-8' ) ;
13+
14+ let mainWindow ;
15+
16+ function createWindow ( ) {
17+ mainWindow = new BrowserWindow ( {
18+ icon : path . join ( __dirname , 'logo.png' ) ,
19+ width : 800 ,
20+ height : 600 ,
21+ webPreferences : {
22+ nodeIntegration : true ,
23+ contextIsolation : false
24+ }
25+ } ) ;
26+
27+ mainWindow . loadFile ( 'index.html' ) ;
28+ }
29+
30+ app . whenReady ( ) . then ( createWindow ) ;
31+
32+ app . on ( 'window-all-closed' , ( ) => {
33+ if ( process . platform !== 'darwin' ) {
34+ app . quit ( ) ;
35+ }
36+ } ) ;
37+
38+ app . on ( 'activate' , ( ) => {
39+ if ( BrowserWindow . getAllWindows ( ) . length === 0 ) {
40+ createWindow ( ) ;
41+ }
42+ } ) ;
43+
44+ ipcMain . handle ( 'select-directory' , async ( ) => {
45+ const result = await dialog . showOpenDialog ( mainWindow , {
46+ properties : [ 'openDirectory' ]
47+ } ) ;
48+ return result . filePaths ;
49+ } ) ;
50+
51+
52+ function isValidLine ( line ) {
53+ // Skip if line is empty
54+ if ( ! line || line . length === 0 ) return false ;
55+
56+ // Skip if line is too short (less than 5 characters)
57+ if ( line . length < 5 ) return false ;
58+
59+ // Skip if line is just numbers (including dots and spaces)
60+ if ( / ^ [ \d \s . ] + $ / . test ( line ) ) return false ;
61+
62+ // Skip if line contains common page number patterns
63+ // Including "page 78" and "- 78 -"
64+ if ( / ^ p a g e \s * \d + $ / i. test ( line ) || / ^ - \s * \d + \s * - $ / . test ( line ) ) return false ;
65+
66+ // Skip if line is mostly special characters (allow Korean characters)
67+ const specialCharRatio = ( line . match ( / [ ^ a - z A - Z 0 - 9 가 - 힣 \s ] / g) || [ ] ) . length / line . length ;
68+ if ( specialCharRatio > 0.5 ) return false ;
69+
70+ return true ;
71+ }
72+
73+
74+ ipcMain . handle ( 'process-files' , async ( event , dirPath ) => {
75+ try {
76+ const outputDir = path . join ( dirPath , 'renamed_files' ) ;
77+ await fs . ensureDir ( outputDir ) ;
78+
79+ const files = await fs . readdir ( dirPath ) ;
80+ const results = [ ] ;
81+
82+ for ( const file of files ) {
83+ const filePath = path . join ( dirPath , file ) ;
84+ const stats = await fs . stat ( filePath ) ;
85+
86+ if ( stats . isFile ( ) ) {
87+ try {
88+ let firstLine = '' ;
89+ const fileExt = path . extname ( file ) . toLowerCase ( ) ;
90+
91+ if ( fileExt === '.pdf' ) {
92+
93+ // let doc = mupdfjs.PDFDocument.openDocument(fs.readFileSync(filePath), "application/pdf");
94+ // let page = new mupdfjs.PDFPage(doc, 0); // returns the first page of the document
95+ // let extractedText = page.getText()
96+
97+ // // cleanup
98+ // doc.destroy()
99+ // page.destroy()
100+
101+ const dataBuffer = await fs . readFile ( filePath ) ;
102+ const pdfData = await pdfParse ( dataBuffer ) ;
103+ extractedText = pdfData . text
104+
105+ console . log ( extractedText )
106+ // Get all lines and find the first non-empty one
107+ const lines = extractedText . split ( '\n' )
108+ . map ( line => line . trim ( ) )
109+ . filter ( line => line . length > 0 ) ;
110+
111+ // Find first valid line
112+ firstLine = '' ;
113+ for ( const line of lines ) {
114+ if ( isValidLine ( line ) ) {
115+ firstLine = line . substring ( 0 , 100 ) ; // Get first 100 characters
116+ break ;
117+ }
118+ }
119+
120+ } else {
121+ const content = await fs . readFile ( filePath , 'utf8' ) ;
122+ const lines = content . split ( '\n' )
123+ . map ( line => line . trim ( ) )
124+ . filter ( line => line . length > 0 ) ;
125+ // Find first valid line
126+ firstLine = '' ;
127+ for ( const line of lines ) {
128+ if ( isValidLine ( line ) ) {
129+ firstLine = line . substring ( 0 , 100 ) ; // Get first 100 characters
130+ break ;
131+ }
132+ }
133+
134+ }
135+
136+ let newFileName ;
137+ if ( firstLine && firstLine . length > 0 ) {
138+ // Create safe filename from first non-empty line
139+ newFileName = firstLine
140+ . replace ( / [ ^ a - z 0 - 9 가 - 힣 ] / gi, '_' )
141+ + fileExt ;
142+ } else {
143+ // If no text found, use original filename
144+ newFileName = file ;
145+ }
146+
147+ // Handle duplicate filenames
148+ let finalNewPath = path . join ( outputDir , newFileName ) ;
149+ // let counter = 1;
150+ // while (await fs.pathExists(finalNewPath)) {
151+ // const nameWithoutExt = newFileName.slice(0, -fileExt.length);
152+ // newFileName = `${nameWithoutExt}_${counter}${fileExt}`;
153+ // finalNewPath = path.join(outputDir, newFileName);
154+ // counter++;
155+ // }
156+
157+ await fs . copy ( filePath , finalNewPath ) ;
158+
159+ results . push ( {
160+ originalName : file ,
161+ newName : newFileName ,
162+ success : true ,
163+ noTextFound : ! firstLine
164+ } ) ;
165+ } catch ( err ) {
166+ // Handle PDF parsing errors (common with scanned PDFs)
167+ if ( err . message . includes ( 'PDF' ) ) {
168+ // If PDF parsing fails, use original filename
169+ const newPath = path . join ( outputDir , file ) ;
170+ await fs . copy ( filePath , newPath ) ;
171+ results . push ( {
172+ originalName : file ,
173+ newName : file ,
174+ success : true ,
175+ noTextFound : true
176+ } ) ;
177+ } else {
178+ results . push ( {
179+ originalName : file ,
180+ error : err . message ,
181+ success : false
182+ } ) ;
183+ }
184+ }
185+ }
186+ }
187+
188+ return results ;
189+ } catch ( err ) {
190+ throw err ;
191+ }
192+ } ) ;
0 commit comments