@@ -47,6 +47,9 @@ const API_URL = "https://api.launcherhub.net/giveMeTheList";
4747const DEVICES_API_URL = "https://api.launcherhub.net/devices" ;
4848const CDN_COVER = "https://m5burner-cdn.m5stack.com/cover/" ;
4949const CDN_FIRMWARE = "https://m5burner-cdn.m5stack.com/firmware/" ;
50+ const CORS_PROXY = "https://launcher-proxy.bmorcelli.workers.dev/?url=" ;
51+
52+ const proxiedUrl = ( url : string ) => `${ CORS_PROXY } ${ encodeURIComponent ( url ) } ` ;
5053
5154const SAMPLE_CARDPUTER_COVER =
5255 "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='200'%3E%3Crect width='320' height='200' fill='%2300dd00'/%3E%3Ctext x='160' y='110' font-family='Inter,Arial,sans-serif' font-size='32' fill='%2301110b' text-anchor='middle'%3ENo Image%3C/text%3E%3C/svg%3E" ;
@@ -117,12 +120,10 @@ const makeDownloadName = (entry: FirmwareEntry, versionLabel: string) => {
117120 . replace ( / ^ - + | - + $ / g, "" )
118121 . toLowerCase ( ) ;
119122
120- const parts = [ entry . name , entry . author , versionLabel ]
121- . filter ( Boolean )
122- . map ( ( part ) => normalize ( part ?? "" ) ) ;
123+ const name = normalize ( entry . name ) || "launcher-firmware" ;
124+ const version = normalize ( versionLabel ) ;
123125
124- const base = parts . filter ( ( part ) => part . length > 0 ) . join ( "-" ) ;
125- return `${ base || "launcher-firmware" } .bin` ;
126+ return version ? `${ name } .${ version } .bin` : `${ name } .bin` ;
126127} ;
127128
128129const formatPublishedDate = ( value : string | undefined ) => {
@@ -410,22 +411,44 @@ document.addEventListener("DOMContentLoaded", () => {
410411 select . disabled = true ;
411412 }
412413
413- const downloadButton = document . createElement ( "a" ) ;
414+ const downloadButton = document . createElement ( "button" ) ;
415+ downloadButton . type = "button" ;
414416 downloadButton . className = "button button--ghost" ;
415417 downloadButton . textContent = "Download firmware" ;
416- downloadButton . target = "_blank" ;
417- downloadButton . rel = "noopener" ;
418- downloadButton . href = select . value || "#" ;
419- downloadButton . toggleAttribute ( "aria-disabled" , select . value . length === 0 ) ;
420- const initialVersionLabel =
421- select . selectedOptions [ 0 ] ?. dataset . versionLabel ?? select . options [ 0 ] ?. dataset . versionLabel ?? "" ;
422- downloadButton . download = makeDownloadName ( entry , initialVersionLabel ) ;
418+ downloadButton . disabled = select . value . length === 0 ;
423419
424- select . addEventListener ( "change" , ( ) => {
425- downloadButton . href = select . value || "#" ;
426- downloadButton . toggleAttribute ( "aria-disabled" , select . value . length === 0 ) ;
420+ const getSelectedFilename = ( ) => {
427421 const versionLabel = select . selectedOptions [ 0 ] ?. dataset . versionLabel ?? "" ;
428- downloadButton . download = makeDownloadName ( entry , versionLabel ) ;
422+ return makeDownloadName ( entry , versionLabel ) ;
423+ } ;
424+
425+ downloadButton . addEventListener ( "click" , async ( ) => {
426+ const url = select . value ;
427+ if ( ! url ) return ;
428+ const filename = getSelectedFilename ( ) ;
429+ const originalText = downloadButton . textContent ;
430+ downloadButton . disabled = true ;
431+ downloadButton . textContent = "Downloading…" ;
432+ try {
433+ const response = await fetch ( proxiedUrl ( url ) ) ;
434+ if ( ! response . ok ) throw new Error ( `HTTP ${ response . status } ` ) ;
435+ const blob = await response . blob ( ) ;
436+ const blobUrl = URL . createObjectURL ( blob ) ;
437+ const link = document . createElement ( "a" ) ;
438+ link . href = blobUrl ;
439+ link . download = filename ;
440+ link . click ( ) ;
441+ URL . revokeObjectURL ( blobUrl ) ;
442+ } catch {
443+ window . open ( url , "_blank" ) ;
444+ } finally {
445+ downloadButton . textContent = originalText ;
446+ downloadButton . disabled = select . value . length === 0 ;
447+ }
448+ } ) ;
449+
450+ select . addEventListener ( "change" , ( ) => {
451+ downloadButton . disabled = select . value . length === 0 ;
429452 } ) ;
430453
431454 controls . append ( select , downloadButton ) ;
0 commit comments