Skip to content

Commit 640a49e

Browse files
committed
HOW DID THAT FIX IT
(share_target and file_handler polyfill using that work) (imagine if i break it again)
1 parent 9f37cf8 commit 640a49e

File tree

3 files changed

+80
-71
lines changed

3 files changed

+80
-71
lines changed

Build/src/helpers/filePickerHelper.tsx

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -481,20 +481,20 @@ function processFiles(files: File[]): AudioFile[] {
481481
// ---------------------
482482
export async function extractAudioMetadata(file: File): Promise<AudioMetadata> {
483483
setProcessingState(true);
484-
484+
485485
const ext = file.name.split(".").pop()?.toLowerCase();
486486

487487
// Use flo-specific extraction for .flo files
488488
if (ext === "flo") {
489489
try {
490490
const arrayBuffer = await file.arrayBuffer();
491-
const {
492-
getFloMetadata,
493-
getFloCoverArt,
494-
getFloSyncedLyrics,
495-
getFloInfo
491+
const {
492+
getFloMetadata,
493+
getFloCoverArt,
494+
getFloSyncedLyrics,
495+
getFloInfo
496496
} = await import("./floProcessor");
497-
497+
498498
// Get all flo data in parallel
499499
const [meta, cover, lyrics, info] = await Promise.all([
500500
getFloMetadata(arrayBuffer),
@@ -725,7 +725,7 @@ export function setupFileHandler(
725725
typeof window.launchQueue.setConsumer !== "function"
726726
) {
727727
console.warn("File Handling API not supported in this browser");
728-
return () => {}; // Return empty cleanup function
728+
return () => { }; // Return empty cleanup function
729729
}
730730

731731
const consumer = async (launchParams: any) => {
@@ -790,7 +790,7 @@ export function setupFileHandler(
790790
typeof window.launchQueue.setConsumer === "function"
791791
) {
792792
try {
793-
window.launchQueue.setConsumer(() => {});
793+
window.launchQueue.setConsumer(() => { });
794794
} catch (e) {
795795
console.warn("Could not clear file handler consumer:", e);
796796
}
@@ -810,21 +810,17 @@ export interface ShareTargetResult {
810810
}
811811

812812
export function handleShareTarget(): ShareTargetResult | null {
813-
// Share targets can send data via URL parameters or launch queue
814813
if (typeof window === "undefined") {
815814
return null;
816815
}
817816

818-
// Check URL parameters for share data
819817
const urlParams = new URLSearchParams(window.location.search);
820818
const title = urlParams.get("title") || undefined;
821819
const text = urlParams.get("text") || undefined;
822820
const url = urlParams.get("url") || undefined;
823821

824-
// Determine what type of share this is
825-
// Files would typically come through launch queue or POST request
826-
if (title || text) {
827-
// Text-based share - could be song info to search for
822+
if (title || text || url) {
823+
// Handle text sharing
828824
return {
829825
files: [],
830826
title,
@@ -834,12 +830,12 @@ export function handleShareTarget(): ShareTargetResult | null {
834830
};
835831
}
836832

837-
return null;
833+
// Handle files shared via Cache API
834+
return null; // Will be handled in useShareTarget
838835
}
839836

840-
// Hook to handle share targets and file shares
841837
export function useShareTarget(
842-
onShareReceived: (result: ShareTargetResult) => void,
838+
onShareReceived: (result: ShareTargetResult) => void
843839
) {
844840
const hasProcessedRef = useRef(false);
845841

@@ -848,46 +844,47 @@ export function useShareTarget(
848844

849845
async function processShare() {
850846
const urlParams = new URLSearchParams(window.location.search);
851-
852-
// Check for files in Cache (sent from Service Worker)
847+
853848
if (urlParams.get("share-received") === "true") {
854849
try {
855-
const cache = await caches.open('incoming-shares');
856-
const response = await cache.match('/shared-file');
857-
858-
if (response) {
859-
const blob = await response.blob();
860-
// Try to recover the filename from headers or default to "shared-audio"
861-
const filename = response.headers.get('x-file-name') || "shared-audio.mp3";
862-
const file = new File([blob], filename, { type: blob.type });
850+
const cache = await caches.open("incoming-shares");
851+
const keys = await cache.keys();
852+
853+
const files: File[] = [];
854+
for (const key of keys) {
855+
if (key.url.includes("/shared-file-")) {
856+
const response = await cache.match(key);
857+
const blob = await response?.blob();
858+
const fileName =
859+
response?.headers.get("x-file-name") || "unknown-file";
860+
files.push(new File([blob!], fileName, { type: blob?.type }));
861+
}
862+
}
863863

864+
if (files.length > 0) {
864865
hasProcessedRef.current = true;
865-
onShareReceived({
866-
files: [file],
867-
type: "files",
868-
});
866+
onShareReceived({ files, type: "files" });
867+
868+
// Cleanup the cache after processing
869+
for (const key of keys) {
870+
await cache.delete(key);
871+
}
869872

870-
// Cleanup
871-
await cache.delete('/shared-file');
872873
const cleanUrl = new URL(window.location.href);
873874
cleanUrl.searchParams.delete("share-received");
874875
window.history.replaceState({}, "", cleanUrl.toString());
875-
return; // Exit early if we handled files
876+
return;
876877
}
877-
} catch (e) {
878-
console.error("Failed to retrieve shared file from cache", e);
878+
} catch (error) {
879+
console.error("Failed to retrieve shared files:", error);
879880
}
880881
}
881882

882-
// Fallback to standard Text/URL share handling
883+
// Fallback to text sharing (e.g., query parameters)
883884
const shareResult = handleShareTarget();
884-
if (shareResult && shareResult.type !== "none") {
885+
if (shareResult) {
885886
hasProcessedRef.current = true;
886887
onShareReceived(shareResult);
887-
888-
const url = new URL(window.location.href);
889-
["title", "text", "url"].forEach((p) => url.searchParams.delete(p));
890-
window.history.replaceState({}, "", url.toString());
891888
}
892889
}
893890

Build/src/pages/_index.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,19 @@ export default function IndexPage() {
4444
useShareTarget((result) => {
4545
if (result.files.length > 0) {
4646
toast.success(
47-
t("shareTarget.filesReceived", { count: result.files.length }),
47+
t("shareTarget.filesReceived", { count: result.files.length })
4848
);
4949
importAudioFiles(result.files, musicPlayerHook.addSong, t);
5050
}
51-
if (result.title || result.text || result.url) {
51+
52+
if (result.type === "search" && (result.title || result.text || result.url)) {
5253
const sharedContent = result.title || result.text || result.url;
5354
if (sharedContent) {
54-
// Treat shared text as a search query
5555
musicPlayerHook.setSearchQuery(sharedContent);
5656
toast.info(t("shareTarget.searchQuery", { query: sharedContent }));
57-
58-
// Focus search input after a short delay to ensure UI is ready
5957
setTimeout(() => {
6058
const searchInput = document.querySelector(
61-
'input[type="search"], input[placeholder*="search" i]',
59+
'input[type="search"], input[placeholder*="search" i]'
6260
) as HTMLInputElement;
6361
if (searchInput) {
6462
searchInput.focus();

Build/src/workers/sw.ts

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,47 @@
1-
import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching';
2-
import { registerRoute, NavigationRoute } from 'workbox-routing';
1+
import { precacheAndRoute, createHandlerBoundToURL } from "workbox-precaching";
2+
import { registerRoute, NavigationRoute } from "workbox-routing";
33

44
// @ts-ignore
55
precacheAndRoute(self.__WB_MANIFEST);
66

7-
const handler = createHandlerBoundToURL('index.html');
7+
// Handle SPA navigation requests
8+
const handler = createHandlerBoundToURL("index.html");
89
const navigationRoute = new NavigationRoute(handler, {
9-
allowlist: [/^\/beta\/HTMLPlayer\//],
10+
allowlist: [/^\/beta\/HTMLPlayer\//],
1011
});
1112
registerRoute(navigationRoute);
1213

14+
// Handle POST requests for file sharing
1315
registerRoute(
14-
({ url, request }) => {
15-
return url.pathname === '/beta/HTMLPlayer/' && request.method === 'POST';
16-
},
17-
async ({ event }) => {
18-
try {
19-
const formData = await event.request.formData();
20-
const file = formData.get('audio');
21-
if (file) {
22-
const cache = await caches.open('incoming-shares');
23-
await cache.put('/shared-file', new Response(file));
24-
}
25-
const redirectUrl = new URL('/beta/HTMLPlayer/?share-received=true', self.location.origin);
26-
return Response.redirect(redirectUrl.href, 303);
27-
} catch (e) {
28-
// always return a response even on error
29-
return new Response('Failed to process share', { status: 400 });
16+
({ url, request }) => {
17+
return url.pathname === "/beta/HTMLPlayer/" && request.method === "POST";
18+
},
19+
async ({ event }) => {
20+
try {
21+
const formData = await event.request.formData();
22+
const cache = await caches.open("incoming-shares");
23+
24+
// Process all files in the form data
25+
const files = [];
26+
for (const [key, value] of formData.entries()) {
27+
if (value instanceof File) {
28+
files.push({ file: value, key });
29+
await cache.put(`/shared-file-${value.name}`, new Response(value, {
30+
headers: { "x-file-name": value.name, "content-type": value.type },
31+
}));
3032
}
31-
},
32-
'POST'
33+
}
34+
35+
// Redirect to the app with an indicator for file sharing
36+
const redirectUrl = new URL(
37+
`/beta/HTMLPlayer/?share-received=true&files=${files.length}`,
38+
self.location.origin
39+
);
40+
return Response.redirect(redirectUrl.href, 303);
41+
} catch (e) {
42+
// Always return a response even on error
43+
return new Response("Failed to process file share", { status: 400 });
44+
}
45+
},
46+
"POST"
3347
);

0 commit comments

Comments
 (0)