1- const { app, BrowserWindow, shell, ipcMain, dialog } = require ( 'electron' ) ;
1+ const { app, BrowserWindow, shell, ipcMain, dialog, globalShortcut , desktopCapturer } = require ( 'electron' ) ;
22const path = require ( 'path' ) ;
33const Store = require ( 'electron-store' ) ;
44const fs = require ( 'fs' ) ;
@@ -7,9 +7,11 @@ const extractZip = require('extract-zip');
77const { exec } = require ( 'child_process' ) ;
88
99const store = new Store ( ) ;
10+ let mainWindow = null ;
11+ let isGameRunning = false ;
1012
1113function createWindow ( ) {
12- const win = new BrowserWindow ( {
14+ mainWindow = new BrowserWindow ( {
1315 width : 1280 ,
1416 height : 720 ,
1517 minWidth : 1024 ,
@@ -27,22 +29,115 @@ function createWindow() {
2729 }
2830 } ) ;
2931
30- win . loadFile ( 'index.html' ) ;
32+ mainWindow . loadFile ( 'index.html' ) ;
3133
32- ipcMain . on ( 'window-minimize' , ( ) => win . minimize ( ) ) ;
34+ ipcMain . on ( 'window-minimize' , ( ) => mainWindow . minimize ( ) ) ;
3335 ipcMain . on ( 'window-maximize' , ( ) => {
34- if ( win . isMaximized ( ) ) {
35- win . unmaximize ( ) ;
36+ if ( mainWindow . isMaximized ( ) ) {
37+ mainWindow . unmaximize ( ) ;
3638 } else {
37- win . maximize ( ) ;
39+ mainWindow . maximize ( ) ;
3840 }
3941 } ) ;
40- ipcMain . on ( 'window-close' , ( ) => win . close ( ) ) ;
42+ ipcMain . on ( 'window-close' , ( ) => mainWindow . close ( ) ) ;
4143 ipcMain . on ( 'window-fullscreen' , ( ) => {
42- win . setFullScreen ( ! win . isFullScreen ( ) ) ;
44+ mainWindow . setFullScreen ( ! mainWindow . isFullScreen ( ) ) ;
4345 } ) ;
4446 ipcMain . on ( 'window-set-fullscreen' , ( event , enabled ) => {
45- win . setFullScreen ( Boolean ( enabled ) ) ;
47+ mainWindow . setFullScreen ( Boolean ( enabled ) ) ;
48+ } ) ;
49+
50+ ipcMain . handle ( 'take-screenshot' , async ( event ) => {
51+ try {
52+ const screenshotsDir = path . join ( app . getPath ( 'userData' ) , 'Screenshots' ) ;
53+ if ( ! fs . existsSync ( screenshotsDir ) ) {
54+ fs . mkdirSync ( screenshotsDir , { recursive : true } ) ;
55+ }
56+ const timestamp = new Date ( ) . toISOString ( ) . replace ( / [: .] / g, '-' ) ;
57+ const fileName = `screenshot-${ timestamp } .png` ;
58+ const filePath = path . join ( screenshotsDir , fileName ) ;
59+
60+ if ( isGameRunning ) {
61+ const sources = await desktopCapturer . getSources ( {
62+ types : [ 'window' , 'screen' ] ,
63+ thumbnailSize : { width : 3840 , height : 2160 } // High res for screenshot
64+ } ) ;
65+
66+ // Find Minecraft window or fallback to primary screen
67+ const source = sources . find ( s => s . name . toLowerCase ( ) . includes ( 'minecraft' ) ) ||
68+ sources . find ( s => s . id . startsWith ( 'screen' ) ) ;
69+
70+ if ( source ) {
71+ fs . writeFileSync ( filePath , source . thumbnail . toPNG ( ) ) ;
72+ return filePath ;
73+ }
74+ }
75+
76+ // Fallback to launcher capture if game isn't running or not found
77+ const win = BrowserWindow . fromWebContents ( event . sender ) || mainWindow ;
78+ if ( ! win ) throw new Error ( "Window not found" ) ;
79+ const image = await win . capturePage ( ) ;
80+ fs . writeFileSync ( filePath , image . toPNG ( ) ) ;
81+ return filePath ;
82+ } catch ( err ) {
83+ console . error ( "Screenshot capture error:" , err ) ;
84+ throw err ;
85+ }
86+ } ) ;
87+
88+ ipcMain . on ( 'game-running-state' , ( event , running ) => {
89+ isGameRunning = running ;
90+ if ( running ) {
91+ globalShortcut . register ( 'F2' , ( ) => {
92+ if ( mainWindow ) {
93+ mainWindow . webContents . send ( 'trigger-screenshot' ) ;
94+ }
95+ } ) ;
96+ } else {
97+ globalShortcut . unregister ( 'F2' ) ;
98+ }
99+ } ) ;
100+
101+ ipcMain . handle ( 'list-screenshots' , async ( ) => {
102+ const screenshotsDir = path . join ( app . getPath ( 'userData' ) , 'Screenshots' ) ;
103+ if ( ! fs . existsSync ( screenshotsDir ) ) {
104+ return [ ] ;
105+ }
106+ const files = fs . readdirSync ( screenshotsDir ) ;
107+ return files
108+ . filter ( f => f . toLowerCase ( ) . endsWith ( '.png' ) )
109+ . sort ( ( a , b ) => {
110+ try {
111+ // Extract timestamp from 'screenshot-YYYY-MM-DDTHH-mm-ss-SSSZ.png'
112+ const timeA = a . replace ( 'screenshot-' , '' ) . replace ( '.png' , '' ) . replace ( / - / g, ':' ) ;
113+ const timeB = b . replace ( 'screenshot-' , '' ) . replace ( '.png' , '' ) . replace ( / - / g, ':' ) ;
114+ return new Date ( timeB ) - new Date ( timeA ) ;
115+ } catch ( e ) {
116+ return 0 ;
117+ }
118+ } )
119+ . map ( f => ( {
120+ name : f ,
121+ path : path . join ( screenshotsDir , f ) ,
122+ url : `file://${ path . join ( screenshotsDir , f ) } `
123+ } ) ) ;
124+ } ) ;
125+
126+ ipcMain . handle ( 'delete-screenshot' , async ( event , fileName ) => {
127+ const filePath = path . join ( app . getPath ( 'userData' ) , 'Screenshots' , fileName ) ;
128+ if ( fs . existsSync ( filePath ) ) {
129+ fs . unlinkSync ( filePath ) ;
130+ return true ;
131+ }
132+ return false ;
133+ } ) ;
134+
135+ ipcMain . handle ( 'open-screenshots-dir' , async ( ) => {
136+ const screenshotsDir = path . join ( app . getPath ( 'userData' ) , 'Screenshots' ) ;
137+ if ( ! fs . existsSync ( screenshotsDir ) ) {
138+ fs . mkdirSync ( screenshotsDir , { recursive : true } ) ;
139+ }
140+ shell . openPath ( screenshotsDir ) ;
46141 } ) ;
47142
48143 ipcMain . handle ( 'store-get' , ( event , key ) => store . get ( key ) ) ;
@@ -55,10 +150,10 @@ function createWindow() {
55150 return result . filePaths [ 0 ] ;
56151 } ) ;
57152
58- win . on ( 'maximize' , ( ) => win . webContents . send ( 'window-is-maximized' , true ) ) ;
59- win . on ( 'unmaximize' , ( ) => win . webContents . send ( 'window-is-maximized' , false ) ) ;
153+ mainWindow . on ( 'maximize' , ( ) => mainWindow . webContents . send ( 'window-is-maximized' , true ) ) ;
154+ mainWindow . on ( 'unmaximize' , ( ) => mainWindow . webContents . send ( 'window-is-maximized' , false ) ) ;
60155
61- win . webContents . setWindowOpenHandler ( ( { url } ) => {
156+ mainWindow . webContents . setWindowOpenHandler ( ( { url } ) => {
62157 shell . openExternal ( url ) ;
63158 return { action : 'deny' } ;
64159 } ) ;
0 commit comments