@@ -24,7 +24,7 @@ declare global {
2424 setConsumer : (
2525 consumer : ( launchParams : {
2626 files : FileSystemFileHandle [ ] | File [ ] ;
27- } ) => void ,
27+ } ) => void
2828 ) => void ;
2929 } ;
3030 }
@@ -71,7 +71,7 @@ export interface GaplessInfo {
7171 */
7272async function compressAlbumArt (
7373 base64 : string ,
74- maxSize = 200 ,
74+ maxSize = 200
7575) : Promise < string > {
7676 // Check if it's an animated format
7777 const isAnimatedFormat =
@@ -119,7 +119,7 @@ async function compressAlbumArt(
119119 const compressed = canvas . toDataURL ( "image/jpeg" , 0.7 ) ;
120120
121121 console . log (
122- `Album art compressed: ${ ( base64 . length / 1024 ) . toFixed ( 1 ) } KB → ${ ( compressed . length / 1024 ) . toFixed ( 1 ) } KB` ,
122+ `Album art compressed: ${ ( base64 . length / 1024 ) . toFixed ( 1 ) } KB → ${ ( compressed . length / 1024 ) . toFixed ( 1 ) } KB`
123123 ) ;
124124
125125 // Clean up the canvas to free memory
@@ -293,15 +293,15 @@ async function withTimeoutAndRetry<T>(
293293 promise : Promise < T > ,
294294 timeoutMs : number ,
295295 retries : number ,
296- errorMessage : string ,
296+ errorMessage : string
297297) : Promise < T > {
298298 let lastError : Error | null = null ;
299299 for ( let attempt = 1 ; attempt <= retries ; attempt ++ ) {
300300 try {
301301 const timeoutPromise = new Promise < T > ( ( _ , reject ) => {
302302 setTimeout (
303303 ( ) => reject ( new Error ( `Timeout: ${ errorMessage } ` ) ) ,
304- timeoutMs ,
304+ timeoutMs
305305 ) ;
306306 } ) ;
307307 return await Promise . race ( [ promise , timeoutPromise ] ) ;
@@ -339,12 +339,12 @@ export function pickAudioFiles(): Promise<AudioFile[]> {
339339 "audio/*" ,
340340 ] ,
341341 } ,
342- } ) ,
342+ } )
343343 ) ;
344344
345345 const [ open , setOpen ] = useState ( true ) ; // modal open state
346346 const [ theme , setTheme ] = useState < "light" | "dark" > (
347- document . documentElement . classList . contains ( "dark" ) ? "dark" : "light" ,
347+ document . documentElement . classList . contains ( "dark" ) ? "dark" : "light"
348348 ) ;
349349
350350 // Watch for theme changes
@@ -466,7 +466,7 @@ function processFiles(files: File[]): AudioFile[] {
466466 if ( canPlay !== "probably" && canPlay !== "maybe" ) {
467467 // TODO: i18n-ize
468468 toast . error (
469- `Skipping unsupported audio format by browser: ${ file . name } (${ file . type } )` ,
469+ `Skipping unsupported audio format by browser: ${ file . name } (${ file . type } )`
470470 ) ;
471471 continue ;
472472 }
@@ -491,6 +491,9 @@ export async function extractAudioMetadata(file: File): Promise<AudioMetadata> {
491491 const { getFloMetadata, getFloCoverArt, getFloSyncedLyrics, getFloInfo } =
492492 await import ( "./floProcessor" ) ;
493493
494+ const { getFloMetadata, getFloCoverArt, getFloSyncedLyrics, getFloInfo } =
495+ await import ( "./floProcessor" ) ;
496+
494497 // Get all flo data in parallel
495498 const [ meta , cover , lyrics , info ] = await Promise . all ( [
496499 getFloMetadata ( arrayBuffer ) ,
@@ -622,7 +625,7 @@ export async function extractAudioMetadata(file: File): Promise<AudioMetadata> {
622625 } ) ,
623626 15000 ,
624627 3 ,
625- `Metadata extraction for ${ file . name } ` ,
628+ `Metadata extraction for ${ file . name } `
626629 ) ;
627630 return result ;
628631 } catch ( e ) {
@@ -641,7 +644,7 @@ export async function extractAudioMetadata(file: File): Promise<AudioMetadata> {
641644 parseBlob ( file , { skipCovers : false , duration : true } ) ,
642645 15000 ,
643646 3 ,
644- `Fallback metadata parsing for ${ file . name } ` ,
647+ `Fallback metadata parsing for ${ file . name } `
645648 ) ;
646649
647650 if ( metadata . common ) {
@@ -716,7 +719,7 @@ export interface FileHandlerResult {
716719}
717720
718721export function setupFileHandler (
719- onFilesReceived : ( result : FileHandlerResult ) => void ,
722+ onFilesReceived : ( result : FileHandlerResult ) => void
720723) : ( ) => void {
721724 if (
722725 ! ( "launchQueue" in window ) ||
@@ -750,7 +753,7 @@ export function setupFileHandler(
750753
751754 // Check sessionStorage for processed files
752755 const processedFiles = JSON . parse (
753- sessionStorage . getItem ( "processedFiles" ) || "[]" ,
756+ sessionStorage . getItem ( "processedFiles" ) || "[]"
754757 ) ;
755758 if ( processedFiles . includes ( fileId ) ) {
756759 console . log ( "Skipping duplicate file:" , file . name ) ;
@@ -763,7 +766,7 @@ export function setupFileHandler(
763766 processedFiles . push ( fileId ) ;
764767 sessionStorage . setItem (
765768 "processedFiles" ,
766- JSON . stringify ( processedFiles ) ,
769+ JSON . stringify ( processedFiles )
767770 ) ;
768771 successCount ++ ;
769772 } else {
@@ -809,17 +812,21 @@ export interface ShareTargetResult {
809812}
810813
811814export function handleShareTarget ( ) : ShareTargetResult | null {
815+ // Share targets can send data via URL parameters or launch queue
812816 if ( typeof window === "undefined" ) {
813817 return null ;
814818 }
815819
820+ // Check URL parameters for share data
816821 const urlParams = new URLSearchParams ( window . location . search ) ;
817822 const title = urlParams . get ( "title" ) || undefined ;
818823 const text = urlParams . get ( "text" ) || undefined ;
819824 const url = urlParams . get ( "url" ) || undefined ;
820825
821- if ( title || text || url ) {
822- // Handle text sharing
826+ // Determine what type of share this is
827+ // Files would typically come through launch queue or POST request
828+ if ( title || text ) {
829+ // Text-based share - could be song info to search for
823830 return {
824831 files : [ ] ,
825832 title,
@@ -829,12 +836,12 @@ export function handleShareTarget(): ShareTargetResult | null {
829836 } ;
830837 }
831838
832- // Handle files shared via Cache API
833- return null ; // Will be handled in useShareTarget
839+ return null ;
834840}
835841
842+ // Hook to handle share targets and file shares
836843export function useShareTarget (
837- onShareReceived : ( result : ShareTargetResult ) => void ,
844+ onShareReceived : ( result : ShareTargetResult ) => void
838845) {
839846 const hasProcessedRef = useRef ( false ) ;
840847
@@ -844,6 +851,7 @@ export function useShareTarget(
844851 async function processShare ( ) {
845852 const urlParams = new URLSearchParams ( window . location . search ) ;
846853
854+ // Check for files in Cache (sent from Service Worker)
847855 if ( urlParams . get ( "share-received" ) === "true" ) {
848856 try {
849857 const cache = await caches . open ( "incoming-shares" ) ;
@@ -861,52 +869,33 @@ export function useShareTarget(
861869 }
862870
863871 if ( files . length > 0 ) {
864- // Filter out already processed files
865- const processedFiles = JSON . parse (
866- sessionStorage . getItem ( "processedFiles" ) || "[]" ,
867- ) ;
868- const newFiles = files . filter ( ( file ) => {
869- const fileId = `${ file . name } -${ file . size } -${ file . lastModified } ` ;
870- return ! processedFiles . includes ( fileId ) ;
871- } ) ;
872-
873- if ( newFiles . length > 0 ) {
874- hasProcessedRef . current = true ;
875- onShareReceived ( { files : newFiles , type : "files" } ) ;
876-
877- // Mark files as processed
878- const updatedProcessed = [
879- ...processedFiles ,
880- ...newFiles . map (
881- ( file ) => `${ file . name } -${ file . size } -${ file . lastModified } ` ,
882- ) ,
883- ] ;
884- sessionStorage . setItem (
885- "processedFiles" ,
886- JSON . stringify ( updatedProcessed ) ,
887- ) ;
888-
889- // Cleanup the cache after processing
890- for ( const key of keys ) {
891- await cache . delete ( key ) ;
892- }
872+ hasProcessedRef . current = true ;
873+ onShareReceived ( { files, type : "files" } ) ;
874+
875+ // Cleanup the cache after processing
876+ for ( const key of keys ) {
877+ await cache . delete ( key ) ;
893878 }
894879
895880 const cleanUrl = new URL ( window . location . href ) ;
896881 cleanUrl . searchParams . delete ( "share-received" ) ;
897882 window . history . replaceState ( { } , "" , cleanUrl . toString ( ) ) ;
898- return ;
883+ return ; // Exit early if we handled files
899884 }
900- } catch ( error ) {
901- console . error ( "Failed to retrieve shared files: " , error ) ;
885+ } catch ( e ) {
886+ console . error ( "Failed to retrieve shared file from cache " , e ) ;
902887 }
903888 }
904889
905- // Fallback to text sharing
890+ // Fallback to text sharing (e.g., query parameters)
906891 const shareResult = handleShareTarget ( ) ;
907- if ( shareResult ) {
892+ if ( shareResult && shareResult . type !== "none" ) {
908893 hasProcessedRef . current = true ;
909894 onShareReceived ( shareResult ) ;
895+
896+ const url = new URL ( window . location . href ) ;
897+ [ "title" , "text" , "url" ] . forEach ( ( p ) => url . searchParams . delete ( p ) ) ;
898+ window . history . replaceState ( { } , "" , url . toString ( ) ) ;
910899 }
911900 }
912901
@@ -917,7 +906,7 @@ export function useShareTarget(
917906export function useFileHandler (
918907 addSong : ( song : Song ) => Promise < void > ,
919908 t : any ,
920- isInitialized ?: boolean ,
909+ isInitialized ?: boolean
921910) {
922911 const [ isSupported , setIsSupported ] = useState ( false ) ;
923912 const processedFilesRef = useRef ( new Set < string > ( ) ) ;
@@ -940,23 +929,23 @@ export function useFileHandler(
940929 // If library is not initialized yet, queue the files
941930 if ( isInitialized === false ) {
942931 console . log (
943- "Library not initialized, queuing files for later processing" ,
932+ "Library not initialized, queuing files for later processing"
944933 ) ;
945934 pendingFilesRef . current . push ( ...result . files ) ;
946935 return ;
947936 }
948937
949938 hasProcessedFilesRef . current = true ;
950939 toast . success (
951- t ( "fileHandler.filesReceived" , { count : result . successCount } ) ,
940+ t ( "fileHandler.filesReceived" , { count : result . successCount } )
952941 ) ;
953942 await importAudioFiles ( result . files , addSong , t ) ;
954943 // Clear processed files after successful import to allow re-importing the same files
955944 processedFilesRef . current . clear ( ) ;
956945 }
957946 if ( result . errorCount > 0 ) {
958947 toast . error (
959- t ( "fileHandler.filesSkipped" , { count : result . errorCount } ) ,
948+ t ( "fileHandler.filesSkipped" , { count : result . errorCount } )
960949 ) ;
961950 }
962951 } ) ;
@@ -977,13 +966,13 @@ export function useFileHandler(
977966 hasProcessedFilesRef . current = true ;
978967 processedFilesRef . current . clear ( ) ;
979968 toast . success (
980- t ( "fileHandler.filesReceived" , { count : filesToProcess . length } ) ,
969+ t ( "fileHandler.filesReceived" , { count : filesToProcess . length } )
981970 ) ;
982971 } )
983972 . catch ( ( error ) => {
984973 console . error ( "Failed to process queued files:" , error ) ;
985974 toast . error (
986- t ( "filePicker.failedImport" , { count : filesToProcess . length } ) ,
975+ t ( "filePicker.failedImport" , { count : filesToProcess . length } )
987976 ) ;
988977 } ) ;
989978 }
0 commit comments