@@ -23,6 +23,7 @@ const {powerMonitor } = require('electron')
2323const { net } = require ( 'electron' )
2424const fs = require ( 'fs' ) ;
2525const fse = require ( 'fs-extra' ) ;
26+ const https = require ( 'https' ) ;
2627
2728const { powerSaveBlocker } = require ( 'electron' )
2829
@@ -1294,6 +1295,29 @@ const windows = {
12941295 this . win . webContents . send ( 'version' , data ) ;
12951296 } ,
12961297
1298+ news ( items ) {
1299+ if ( ! this . readyQ || ! this . aliveQ ) return ;
1300+ this . win . webContents . send ( 'news-items' , items ) ;
1301+ } ,
1302+
1303+ async fetchNews ( ) {
1304+ try {
1305+ const items = await getLatestNews ( ) ;
1306+ this . news ( items ) ;
1307+ console . log ( items ) ;
1308+ } catch ( error ) {
1309+ console . error ( 'Failed to load WLJS news:' , error ) ;
1310+ this . news ( [ {
1311+ source : 'WLJS news' ,
1312+ title : 'Unable to load latest news' ,
1313+ url : 'https://wljs.io' ,
1314+ summary : error . message ,
1315+ date : new Date ( ) ,
1316+ dateText : ''
1317+ } ] ) ;
1318+ }
1319+ } ,
1320+
12971321 construct ( cbk = ( ...any ) => { } ) {
12981322 let win ;
12991323
@@ -1304,7 +1328,7 @@ const windows = {
13041328
13051329 titleBarStyle : 'hiddenInset' ,
13061330 width : 600 ,
1307- height : 400 ,
1331+ height : 660 ,
13081332 resizable : false ,
13091333 title : 'Launcher' ,
13101334 contextMenu : true ,
@@ -1332,7 +1356,7 @@ const windows = {
13321356 } ,
13331357 autoHideMenuBar : true ,
13341358 width : 600 ,
1335- height : 400 ,
1359+ height : 660 ,
13361360 resizable : false ,
13371361 title : 'Launcher' ,
13381362 maximizable : false ,
@@ -1361,7 +1385,7 @@ const windows = {
13611385 } ,
13621386 autoHideMenuBar : true ,
13631387 width : 600 ,
1364- height : 400 ,
1388+ height : 660 ,
13651389 resizable : false ,
13661390 title : 'Launcher' ,
13671391 maximizable : false ,
@@ -1428,6 +1452,7 @@ const windows = {
14281452 win . once ( 'ready-to-show' , ( ) => {
14291453 self . readyQ = true ;
14301454 cbk ( win ) ;
1455+ self . fetchNews ( ) ;
14311456 } ) ;
14321457
14331458 win . on ( 'close' , ( ) => {
@@ -1494,6 +1519,86 @@ function ensureDirectoryExistence(filePath) {
14941519 fs . mkdirSync ( dirname ) ;
14951520 }
14961521
1522+ function fetchUrlText ( url ) {
1523+ return new Promise ( ( resolve , reject ) => {
1524+ const request = https . get ( url , ( res ) => {
1525+ if ( res . statusCode >= 300 && res . statusCode < 400 && res . headers . location ) {
1526+ return resolve ( fetchUrlText ( new URL ( res . headers . location , url ) . href ) ) ;
1527+ }
1528+ if ( res . statusCode < 200 || res . statusCode >= 300 ) {
1529+ return reject ( new Error ( `HTTP ${ res . statusCode } fetching ${ url } ` ) ) ;
1530+ }
1531+ let body = '' ;
1532+ res . setEncoding ( 'utf8' ) ;
1533+ res . on ( 'data' , ( chunk ) => body += chunk ) ;
1534+ res . on ( 'end' , ( ) => resolve ( body ) ) ;
1535+ } ) ;
1536+ request . on ( 'error' , reject ) ;
1537+ } ) ;
1538+ }
1539+
1540+ function stripHtml ( html ) {
1541+ return html . replace ( / < [ ^ > ] + > / g, ' ' ) . replace ( / \s + / g, ' ' ) . trim ( ) ;
1542+ }
1543+
1544+ function parseNewsItems ( html , source , pathPrefix ) {
1545+ const regex = new RegExp ( `<a[^>]+href="/${ pathPrefix } /[^"]+"[^>]*>[\\s\\S]*?</a>` , 'gi' ) ;
1546+ const items = [ ] ;
1547+ let match ;
1548+ let matchCount = 0 ;
1549+
1550+ while ( ( match = regex . exec ( html ) ) ) {
1551+ matchCount ++ ;
1552+ if ( matchCount > 50 ) break ; // safety limit
1553+
1554+ const block = match [ 0 ] ;
1555+ const hrefMatch = block . match ( / h r e f = " ( \/ [ ^ \" ] + ) " / ) ;
1556+ const titleMatch = block . match ( / < h 2 [ ^ > ] * > ( [ \s \S ] * ?) < \/ h 2 > / i) ;
1557+ const summaryMatch = block . match ( / < p [ ^ > ] * > ( [ \s \S ] * ?) < \/ p > / i) ;
1558+ const dateMatch = block . match ( / ( [ A - Z ] [ a - z ] { 2 , 8 } \s + \d { 1 , 2 } , \s + \d { 4 } ) / ) ;
1559+
1560+ const url = hrefMatch ? `https://wljs.io${ hrefMatch [ 1 ] } ` : 'https://wljs.io' ;
1561+ const title = titleMatch ? stripHtml ( titleMatch [ 1 ] ) : url ;
1562+ const summary = summaryMatch ? stripHtml ( summaryMatch [ 1 ] ) : '' ;
1563+ const dateText = dateMatch ? dateMatch [ 1 ] : '' ;
1564+ const date = dateText ? new Date ( dateText ) : new Date ( 0 ) ;
1565+
1566+ if ( title && title !== url && dateText ) {
1567+ items . push ( { source, title, url, summary, date, dateText } ) ;
1568+ }
1569+ }
1570+
1571+ console . log ( `Parsed ${ matchCount } matches for ${ source } , extracted ${ items . length } items` ) ;
1572+ return items ;
1573+ }
1574+
1575+ async function getLatestNews ( ) {
1576+ try {
1577+ console . log ( 'Fetching WLJS blog and releases...' ) ;
1578+ const [ blogHtml , releasesHtml ] = await Promise . all ( [
1579+ fetchUrlText ( 'https://wljs.io/blog' ) ,
1580+ fetchUrlText ( 'https://wljs.io/releases' )
1581+ ] ) ;
1582+
1583+ console . log ( `Blog HTML length: ${ blogHtml . length } , Releases HTML length: ${ releasesHtml . length } ` ) ;
1584+
1585+ const items = [
1586+ ...parseNewsItems ( blogHtml , 'Blog' , 'blog' ) ,
1587+ ...parseNewsItems ( releasesHtml , 'Releases' , 'releases' )
1588+ ] ;
1589+
1590+ console . log ( `Total items collected: ${ items . length } ` ) ;
1591+ items . sort ( ( a , b ) => b . date - a . date ) ;
1592+ const result = items . slice ( 0 , 8 ) ;
1593+ console . log ( `Final result: ${ result . length } items` ) ;
1594+ result . forEach ( item => console . log ( ` - ${ item . source } : ${ item . title } (${ item . dateText } )` ) ) ;
1595+ return result ;
1596+ } catch ( error ) {
1597+ console . error ( 'Error in getLatestNews:' , error ) ;
1598+ throw error ;
1599+ }
1600+ }
1601+
14971602const dumpLogs = ( cbk ) => {
14981603 const p = path . join ( appDataFolder , 'Debug' , 'System.log' ) ;
14991604 ensureDirectoryExistence ( p ) ;
0 commit comments