move sonora to lbry apps - #143
Conversation
Code Review: Move Sonora to LBRY AppsOverviewThis PR moves the Sonora audio app into the LBRY apps section, adds a proper SVG logo, wires up TanStack Router file-based routes, and introduces six new page components (Browse, Record, Upload, Archive/Collection, Studio, Market). The scope is reasonable and the overall structure follows the patterns already established by Emporium. Bugs / Correctness Issues1. Memory leaks in
// RecordPage.tsx — in stopRecording / discard handler
if (recordedUrl) URL.revokeObjectURL(recordedUrl);Similarly, when a new file is selected in 2. MediaStream not cleaned up on unmount in If the user navigates away while recording, useEffect(() => {
return () => {
streamRef.current?.getTracks().forEach(t => t.stop());
if (timerRef.current) clearInterval(timerRef.current);
};
}, []);3.
Code Quality4. alert("Please select an audio file");Using 5. This pure helper doesn't close over any component state: // Currently inside BrowsePage — recreated on every render
const convertToAudio = (arweaveAudio: ArweaveAudio): Audio => { ... }Move it outside the component (or to a shared utils file) so it isn't recreated each render. 6. Stale/missing dependency in useEffect(() => {
refreshMarketAudioNFTs(1, 8, false);
}, []); // ← refreshMarketAudioNFTs missingESLint's 7. Navigation inconsistency in The tab bar exposes four routes: Browse, Record, Collection, Shop. But two additional routes ( 8. JSX indentation inconsistency
Performance9. useEffect(() => {
if (audios.length === 0 && !loading && !error) {
dispatch(fetchAudios({ reset: true }));
}
}, [dispatch, audios.length, loading, error]);This re-evaluates whenever const initialised = useRef(false);
useEffect(() => {
if (!initialised.current) {
initialised.current = true;
dispatch(fetchAudios({ reset: true }));
}
}, [dispatch]);What's Good
SummaryThe main blockers are the memory leak / missing stream cleanup in RecordPage (items 1–2) and the unimplemented |
Code Review — PR #143: Move Sonora to LBRY AppsOverviewThis PR migrates Sonora out of the core app into the LBRY apps structure, adds a proper layout with navigation tabs, introduces five new pages (Browse, Archive, Market, Record, Studio, Upload), adds owner profile links from AudioCards, and swaps the placeholder Picsum logo for a real SVG. The structure mirrors the existing Emporium pattern and is generally clean. Potential Bugs1. Likely infinite re-render in
// ArchivePage.tsx
useEffect(() => {
if (targetPrincipal) {
refreshAudioNFTs(targetPrincipal, 1, false);
}
}, [targetPrincipal, refreshAudioNFTs]); // refreshAudioNFTs re-created every render → infinite loop
2. MediaRecorder compatibility — Safari/iOS will silently fail // RecordPage.tsx
const mediaRecorder = new MediaRecorder(stream);
// ...
const blob = new Blob(chunks, { type: "audio/webm" });
const mimeType = ['audio/webm', 'audio/ogg', 'audio/mp4'].find(t => MediaRecorder.isTypeSupported(t)) ?? '';
const mediaRecorder = new MediaRecorder(stream, mimeType ? { mimeType } : {});3. Pagination condition inconsistency
Code Quality4. Mutation of converted object in const audioItem = convertToAudio(arweaveAudio);
audioItem.size = formatFileSize(audioItem.size); // mutates immediately after constructionThis is fragile. Either 5. Drag-and-drop flickering in const handleDragLeave = (e: React.DragEvent) => {
e.preventDefault();
setIsDragging(false); // fires when dragging over a child element
};
const handleDragLeave = (e: React.DragEvent) => {
e.preventDefault();
if (!e.currentTarget.contains(e.relatedTarget as Node)) {
setIsDragging(false);
}
};6. useEffect(() => {
if (audios.length === 0 && !loading && !error) {
dispatch(fetchAudios({ reset: true }));
}
}, [dispatch, audios.length, loading, error]);If the user genuinely has zero results (no audio on Arweave), this will re-dispatch every time the component mounts. A dedicated Minor / Style7. Hardcoded gateway URL const arweaveUrl = `https://arweave.net/${transactionId}`;Appears in both 8. Upload route not in navigation tabs
9. {...("exact" in tab && tab.exact ? { activeOptions: { exact: true } } : {})}Since only the Browse tab has activeOptions={tab.exact ? { exact: true } : undefined}SecurityNo concerns identified. Principal values travel through TanStack Router's typed params (no raw interpolation). The Summary
The overall approach is solid and consistent with the existing Emporium app pattern. The three bugs above are worth fixing before merge, especially the potential infinite loop in |
Summary