@@ -134,6 +134,26 @@ function extractArchive(sourcePath, destinationPath, progressCallback) {
134134 } ) ;
135135}
136136
137+ async function downloadFile ( url , outputPath , progressCallback ) {
138+ const dir = path . dirname ( outputPath ) ;
139+ if ( ! fs . existsSync ( dir ) ) await fs . promises . mkdir ( dir , { recursive : true } ) ;
140+
141+ const response = await axios ( {
142+ method : 'get' ,
143+ url : url ,
144+ responseType : 'stream' ,
145+ onDownloadProgress : progressCallback
146+ } ) . catch ( err => {
147+ console . error ( "Failed to download extractor:" , err ) ;
148+ } ) ;
149+ response . data . pipe ( fs . createWriteStream ( outputPath ) ) ;
150+ await new Promise ( ( resolve , reject ) => {
151+ response . data . once ( 'end' , resolve ) ;
152+ response . data . once ( 'error' , reject ) ;
153+ } ) ;
154+ await new Promise ( r => setTimeout ( r , 20 ) ) ;
155+ }
156+
137157async function checkForUpdates ( ) {
138158 const appPath = app . getPath ( "userData" ) ;
139159 const updaterWindow = new BrowserWindow ( {
@@ -171,110 +191,64 @@ async function checkForUpdates() {
171191 const sevenDll = "https://github.com/TheArmagan/vrckit-assets/releases/download/7z-v25.01/7z.dll" ;
172192 updateStatus ( "Downloading extractor..." ) ;
173193 updateProgress ( 0 ) ;
174- const response = await axios ( {
175- method : 'get' ,
176- url : sevenDll ,
177- responseType : 'stream' ,
178- onDownloadProgress : ( progressEvent ) => {
179- const total = progressEvent . total || 1 ; // Avoid division by zero
180- const progress = Math . round ( ( progressEvent . loaded / total ) * 50 ) ;
181- updateProgress ( progress ) ;
182- updateStatus ( `Downloading extractor... (${ ( ( progressEvent . rate / 1024 / 1024 ) || 0 ) . toFixed ( 2 ) } MB/sec)` ) ;
183- }
184- } ) . catch ( err => {
185- console . error ( "Failed to download extractor:" , err ) ;
186- } ) ;
187- response . data . pipe ( fs . createWriteStream ( sevenDllPath ) ) ;
188- await new Promise ( ( resolve , reject ) => {
189- response . data . once ( 'end' , resolve ) ;
190- response . data . once ( 'error' , reject ) ;
194+
195+ await downloadFile ( sevenDll , sevenDllPath , ( progressEvent ) => {
196+ const total = progressEvent . total || 1 ; // Avoid division by zero
197+ const progress = Math . round ( ( progressEvent . loaded / total ) * 50 ) ;
198+ updateProgress ( progress ) ;
199+ updateStatus ( `Downloading extractor... (${ ( ( progressEvent . rate / 1024 / 1024 ) || 0 ) . toFixed ( 2 ) } MB/sec)` ) ;
191200 } ) ;
201+
192202 const sevenExe = "https://github.com/TheArmagan/vrckit-assets/releases/download/7z-v25.01/7z.exe" ;
193203 updateStatus ( "Downloading extractor..." ) ;
194204 updateProgress ( 0 ) ;
195- const response2 = await axios ( {
196- method : 'get' ,
197- url : sevenExe ,
198- responseType : 'stream' ,
199- onDownloadProgress : ( progressEvent ) => {
200- const total = progressEvent . total || 1 ; // Avoid division by zero
201- const progress = Math . round ( ( progressEvent . loaded / total ) * 50 ) + 50 ;
202- updateProgress ( progress ) ;
203- updateStatus ( `Downloading extractor... (${ ( ( progressEvent . rate / 1024 / 1024 ) || 0 ) . toFixed ( 2 ) } MB/sec)` ) ;
204- }
205- } ) . catch ( err => {
206- console . error ( "Failed to download extractor:" , err ) ;
207- } ) ;
208- response2 . data . pipe ( fs . createWriteStream ( sevenExePath ) ) ;
209- await new Promise ( ( resolve , reject ) => {
210- response2 . data . once ( 'end' , resolve ) ;
211- response2 . data . once ( 'error' , reject ) ;
205+
206+ await downloadFile ( sevenExe , sevenExePath , ( progressEvent ) => {
207+ const total = progressEvent . total || 1 ; // Avoid division by zero
208+ const progress = Math . round ( ( progressEvent . loaded / total ) * 50 ) + 50 ;
209+ updateProgress ( progress ) ;
210+ updateStatus ( `Downloading extractor... (${ ( ( progressEvent . rate / 1024 / 1024 ) || 0 ) . toFixed ( 2 ) } MB/sec)` ) ;
212211 } ) ;
212+
213213 updateStatus ( "Extractor downloaded successfully." ) ;
214214 updateProgress ( 100 ) ;
215215 }
216216
217217 updateStatus ( "Checking for native updates..." ) ;
218218 updateProgress ( 5 ) ;
219- const releasesJson = await axios ( {
219+
220+ const latestRendererMetaRes = await axios ( {
220221 method : "GET" ,
221- url : "https://api.github.com/repos/thearmagan/vrckit-releases/releases/latest" ,
222- headers : {
223- "User-Agent" : `VRCKit/${ app . getVersion ( ) } https://vrckit.com/` ,
224- "Accept" : "application/vnd.github+json" ,
225- "X-GitHub-Api-Version" : "2022-11-28" ,
226- } ,
222+ url : "https://raw.githubusercontent.com/VRCKit/client/refs/heads/main/build-meta/latest/renderer.json" ,
227223 } ) ;
228224
229- if ( ! releasesJson || ! releasesJson . data || ! releasesJson . data . assets ) {
230- updateStatus ( "Failed to fetch release information." ) ;
231- updateProgress ( 100 ) ;
232- await new Promise ( resolve => setTimeout ( resolve , 1500 ) ) ;
233- process . exit ( 1 ) ;
234- }
235-
236225 const currentVersion = app . getVersion ( ) ;
237- const latestVersion = releasesJson . data . tag_name . replace ( "v" , "" ) ;
226+ const latestVersion = latestRendererMetaRes . data . version ;
238227
239228 if ( semver . lt ( currentVersion , latestVersion ) ) {
240229 updateStatus ( `Downloading native update... (v${ latestVersion } )` ) ;
241230
242- const asset = releasesJson . data . assets . find ( ( asset ) => asset . name . endsWith ( ".exe" ) ) ;
243-
244- if ( ! asset ) {
245- updateStatus ( "No compatible update found." ) ;
246- updateProgress ( 100 ) ;
247- return ( ) => updaterWindow . destroy ( ) ;
248- }
249-
231+ const assetUrl = `https://github.com/VRCKit/client/releases/download/${ latestRendererMetaRes . data . tag } /${ latestRendererMetaRes . data . filename . replaceAll ( " " , "." ) } ` ;
250232 const tempFilePath = path . join ( process . env . TEMP , `VRCKit-Latest.exe` ) ;
251- const response = await axios ( {
252- method : 'GET' ,
253- url : asset . browser_download_url ,
254- responseType : 'stream' ,
255- onDownloadProgress : ( progressEvent ) => {
256- const total = progressEvent . total || 1 ; // Avoid division by zero
257- const progress = Math . round ( ( progressEvent . loaded / total ) * 95 ) ; // 95% for download progress
258- updateStatus ( `Downloading update... (${ ( ( progressEvent . rate / 1024 / 1024 ) || 0 ) . toFixed ( 2 ) } MB/sec)` ) ;
259- updateProgress ( progress + 5 ) ; // Add 5% for the download progress
260- }
261- } ) . catch ( err => {
262- console . error ( "Failed to download update:" , err ) ;
263- } ) ;
264233
265- if ( ! response || response . status !== 200 ) {
234+ try {
235+ await downloadFile (
236+ assetUrl ,
237+ tempFilePath ,
238+ ( progressEvent ) => {
239+ const total = progressEvent . total || 1 ; // Avoid division by zero
240+ const progress = Math . round ( ( progressEvent . loaded / total ) * 95 ) ; // 95% for download progress
241+ updateStatus ( `Downloading update... (${ ( ( progressEvent . rate / 1024 / 1024 ) || 0 ) . toFixed ( 2 ) } MB/sec)` ) ;
242+ updateProgress ( progress + 5 ) ; // Add 5% for the download progress
243+ }
244+ ) ;
245+ } catch ( error ) {
246+ console . error ( "Failed to download update:" , error ) ;
266247 updateStatus ( "Failed to download update." ) ;
267248 updateProgress ( 100 ) ;
268249 return ( ) => updaterWindow . destroy ( ) ;
269250 }
270251
271- response . data . pipe ( fs . createWriteStream ( tempFilePath ) ) ;
272-
273- await new Promise ( ( resolve , reject ) => {
274- response . data . once ( 'end' , resolve ) ;
275- response . data . once ( 'error' , reject ) ;
276- } ) ;
277-
278252 updateStatus ( "Waiting for updater..." ) ;
279253 await new Promise ( r => setTimeout ( r , 500 ) ) ;
280254
@@ -291,53 +265,42 @@ async function checkForUpdates() {
291265 }
292266
293267 updateStatus ( "Checking for web updates..." ) ;
294- updateProgress ( 5 ) ;
268+ updateProgress ( 10 ) ;
295269
296270 const currentMd5Path = fs . existsSync ( path . join ( appPath , 'build/build.md5.txt' ) ) ;
297271 const currentMd5 = currentMd5Path ? await fs . promises . readFile ( path . join ( appPath , 'build/build.md5.txt' ) , 'utf8' ) : "0" ;
298272
299- const remoteMD5 = await axios . get ( 'https://api.vrckit.com/files/builds/v1/latest/build.md5.txt' )
300- . then ( res => res . data . trim ( ) )
301- . catch ( err => "0" ) ;
273+ const latestFrontendMetaRes = await axios . get ( 'https://raw.githubusercontent.com/VRCKit/client/refs/heads/main/build-meta/latest/frontend.json' ) ;
274+ const remoteMD5 = latestFrontendMetaRes . data . md5 ;
302275
303276 if ( currentMd5 === remoteMD5 ) {
304277 updateStatus ( "No updates available." ) ;
305278 updateProgress ( 100 ) ;
306279 return ( ) => updaterWindow . destroy ( ) ;
307280 }
308281
309- const remoteZipUrl = 'https://api.vrckit.com/files/builds/v1/latest/build.zip' ;
310- updateStatus ( "Downloading update..." ) ;
311-
312- const response = await axios ( {
313- method : 'get' ,
314- url : remoteZipUrl ,
315- responseType : 'stream' ,
316- onDownloadProgress : ( progressEvent ) => {
317- const total = progressEvent . total || 1 ; // Avoid division by zero
318- const progress = Math . round ( ( progressEvent . loaded / total ) * 45 ) ; // 45% for download progress
319- updateStatus ( `Downloading update... (${ ( ( progressEvent . rate / 1024 / 1024 ) || 0 ) . toFixed ( 2 ) } MB/sec)` ) ;
320- updateProgress ( progress + 5 ) ; // Add 5% for the download progress
321- }
322- } ) . catch ( err => {
323- console . error ( "Failed to download update:" , err ) ;
324- } ) ;
282+ const remoteZipUrl = `https://github.com/VRCKit/client/releases/download/${ latestFrontendMetaRes . data . tag } /build.zip` ;
283+ const tempZipPath = path . join ( appPath , 'temp_build.zip' ) ;
284+ updateStatus ( `Downloading update... (v${ latestFrontendMetaRes . data . version } )` ) ;
325285
326- if ( ! response || response . status !== 200 ) {
286+ try {
287+ await downloadFile (
288+ remoteZipUrl ,
289+ tempZipPath ,
290+ ( progressEvent ) => {
291+ const total = progressEvent . total || 1 ; // Avoid division by zero
292+ const progress = Math . round ( ( progressEvent . loaded / total ) * 40 ) ; // 40% for download progress
293+ updateStatus ( `Downloading update... (${ ( ( progressEvent . rate / 1024 / 1024 ) || 0 ) . toFixed ( 2 ) } MB/sec)` ) ;
294+ updateProgress ( progress + 10 ) ; // Add 10% for the download progress
295+ }
296+ ) ;
297+ } catch ( error ) {
298+ console . error ( "Failed to download update:" , error ) ;
327299 updateStatus ( "Failed to download update." ) ;
328300 updateProgress ( 100 ) ;
329301 return ( ) => updaterWindow . destroy ( ) ;
330302 }
331303
332- const tempZipPath = path . join ( appPath , 'temp_build.zip' ) ;
333-
334- response . data . pipe ( fs . createWriteStream ( tempZipPath ) ) ;
335-
336- await new Promise ( ( resolve , reject ) => {
337- response . data . once ( 'end' , resolve ) ;
338- response . data . once ( 'error' , reject ) ;
339- } ) ;
340-
341304 updateStatus ( "Extracting update..." ) ;
342305
343306 await extractArchive ( tempZipPath , path . join ( appPath , 'build' ) , ( progress ) => {
@@ -509,6 +472,18 @@ async function createWindow() {
509472 }
510473 ) ;
511474
475+ ipcMain . handle (
476+ "DownloadFile" ,
477+ async ( event , { url, path } ) => {
478+ try {
479+ await downloadFile ( url , path ) ;
480+ return { success : true } ;
481+ } catch ( error ) {
482+ return { error : error . message } ;
483+ }
484+ }
485+ ) ;
486+
512487 ipcMain . handle ( "ShowDialog" , async (
513488 event ,
514489 {
0 commit comments