Skip to content

feat: render audio players for linked note audio - #297

Open
dergigi wants to merge 2 commits into
masterfrom
fix/issue-235
Open

feat: render audio players for linked note audio#297
dergigi wants to merge 2 commits into
masterfrom
fix/issue-235

Conversation

@dergigi

@dergigi dergigi commented Jun 19, 2026

Copy link
Copy Markdown
Owner

This renders inline audio players for note links that point to audio files, so notes like the m4a example from issue 235 no longer fall back to a generic URL preview. It also keeps ambiguous .ogg and .webm links on the video path and falls back to the audio player when the media has no video track. Build preview: example note on preview. Fixes #235.

  • add AudioPlayer plus audio URL detection in note media extraction
  • strip audio links from note text once they are rendered inline
  • preserve .ogg and .webm video previews while falling back to audio for audio-only files

Summary by CodeRabbit

  • New Features
    • Added audio player component for playing audio media files directly in the app
    • Improved media detection to recognize and extract audio URLs from content
    • Added fallback support for ambiguous media formats that could be either audio or video
    • Enhanced text processing to handle audio URLs alongside video and image URLs

@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ants Ready Ready Preview, Comment Jun 19, 2026 8:41am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds audio playback support to notes: new URL regex constants and exported helpers (extractAudioUrls, isAmbiguousAudioVideoUrl) are added to urlUtils.ts; MediaItem gains an 'audio' type and extraction; stripMediaUrls covers more audio formats; a new AudioPlayer component renders HTTP audio URLs; NoteMedia routes audio items to it; and VideoWithBlurhash falls back to AudioPlayer when metadata reveals no video dimensions.

Changes

Audio playback support

Layer / File(s) Summary
Audio URL detection and extraction utilities
src/lib/utils/urlUtils.ts
Hoists image/audio/ambiguous-audio-video/video patterns to module-level regex constants, exports extractAudioUrls and isAmbiguousAudioVideoUrl, and extends the extractNonMediaUrls filter to also exclude audio URLs.
MediaItem type extension, audio extraction, and text stripping
src/lib/utils/mediaUtils.ts, src/lib/utils/textUtils.ts
Adds 'audio' to the MediaItem.type union, appends up to two extracted audio MediaItem entries in extractMediaFromContent, and extends stripMediaUrls regexes to cover additional audio formats and query-string variants.
AudioPlayer component
src/components/AudioPlayer.tsx
New component that guards on absolute HTTP URLs, extracts the file extension for display, optionally renders a search button with propagation stopped, provides an external-link button, and renders an <audio controls preload="metadata"> element.
VideoWithBlurhash audio fallback
src/components/VideoWithBlurhash.tsx
Imports isAmbiguousAudioVideoUrl and AudioPlayer, adds renderAsAudio state reset alongside other resets, detects zero videoWidth/videoHeight on onLoadedMetadata to set renderAsAudio, and early-returns AudioPlayer when that state is true.
NoteMedia audio rendering integration
src/components/NoteMedia.tsx
Imports AudioPlayer, passes a trimmed URL to the existing VideoWithBlurhash branch, and adds a new 'audio' branch that renders AudioPlayer with a trimmed src and onClickSearch wired to the search handler.

Sequence Diagram(s)

sequenceDiagram
  participant NoteMedia
  participant VideoWithBlurhash
  participant AudioPlayer
  participant Browser as HTML audio/video

  NoteMedia->>NoteMedia: extractMediaFromContent → MediaItem[]
  alt item.type === 'video'
    NoteMedia->>VideoWithBlurhash: src=getTrimmedMediaUrl(item.src)
    VideoWithBlurhash->>Browser: render <video> element
    Browser-->>VideoWithBlurhash: onLoadedMetadata (videoWidth=0, videoHeight=0 AND allowAudioFallback)
    VideoWithBlurhash->>VideoWithBlurhash: setRenderAsAudio(true)
    VideoWithBlurhash->>AudioPlayer: render AudioPlayer(src, onClickSearch)
  else item.type === 'audio'
    NoteMedia->>AudioPlayer: src=getTrimmedMediaUrl(item.src)
  end
  AudioPlayer->>Browser: render <audio controls preload="metadata">
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 Hop hop, what's that sound?
A music note has come around!
With extractAudioUrls in paw,
I render tunes without a flaw.
m4a, mp3, even ogg—
No silent note escapes this log! 🎵

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding audio player rendering for linked note audio files, which aligns with the primary objective of implementing inline audio player functionality.
Linked Issues check ✅ Passed The implementation fully satisfies issue #235 by adding audio player support for all specified formats (m4a, mp3, ogg, wav, flac, aac, opus, webm) with proper inline rendering, URL trimming, and text stripping.
Out of Scope Changes check ✅ Passed All changes are directly aligned with adding audio player support; no out-of-scope modifications were introduced beyond the audio feature implementation.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-235

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/VideoWithBlurhash.tsx (1)

38-47: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clear stale dimensions when dim is absent on source change.

Line 44 only updates dimensions when dim is valid; otherwise previous dimensions persist across src changes and can render an incorrect aspect ratio.

Proposed fix
   useEffect(() => {
     setVideoLoaded(false);
     setVideoError(false);
     setIsPlaying(false);
     setShowControls(false);
     setRenderAsAudio(false);
     if (dim && dim.width > 0 && dim.height > 0) {
       setDimensions(dim);
+    } else {
+      setDimensions(null);
     }
   }, [src, dim]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/VideoWithBlurhash.tsx` around lines 38 - 47, The useEffect
hook in VideoWithBlurhash component only updates dimensions when dim is valid,
but fails to reset dimensions when dim is absent or invalid on source changes,
causing stale dimensions to persist and render incorrect aspect ratios. Add an
else clause after the if condition checking dim validity to explicitly clear or
reset dimensions by calling setDimensions with a default/null value when dim is
not provided or dimensions are invalid.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/utils/textUtils.ts`:
- Around line 23-24: The regex patterns in the replace calls are too broad and
strip any query parameter substring ending with media file extensions, which
corrupts unrelated URLs that contain extension-like strings in their query text.
Tighten both regex patterns to only match explicit filename-style parameters by
requiring the extension to be part of an actual filename context (such as after
an equals sign or in a filename parameter format) rather than matching any
arbitrary text followed by a media extension. This ensures that search queries
or other non-media URLs containing `.mp3` or similar in their query values are
not inadvertently corrupted.

---

Outside diff comments:
In `@src/components/VideoWithBlurhash.tsx`:
- Around line 38-47: The useEffect hook in VideoWithBlurhash component only
updates dimensions when dim is valid, but fails to reset dimensions when dim is
absent or invalid on source changes, causing stale dimensions to persist and
render incorrect aspect ratios. Add an else clause after the if condition
checking dim validity to explicitly clear or reset dimensions by calling
setDimensions with a default/null value when dim is not provided or dimensions
are invalid.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 99c911fa-349c-4f87-864e-518f0e35cbe8

📥 Commits

Reviewing files that changed from the base of the PR and between 129dbec and 8078f0f.

📒 Files selected for processing (6)
  • src/components/AudioPlayer.tsx
  • src/components/NoteMedia.tsx
  • src/components/VideoWithBlurhash.tsx
  • src/lib/utils/mediaUtils.ts
  • src/lib/utils/textUtils.ts
  • src/lib/utils/urlUtils.ts

Comment on lines +23 to +24
.replace(/\?[^\s]*\.(?:png|jpe?g|gif|gifs|apng|webp|avif|svg|m4a|mp3|wav|flac|aac|opus|mp4|webm|ogg|ogv|mov|m4v)[^\s]*/gi, '')
.replace(/\?name=[^\s]*\.(?:png|jpe?g|gif|gifs|apng|webp|avif|svg|m4a|mp3|wav|flac|aac|opus|mp4|webm|ogg|ogv|mov|m4v)[^\s]*/gi, '');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Tighten query-param stripping to avoid mutating non-media URLs.

Line 23 currently removes any query substring that ends with a media-like extension, which can corrupt unrelated links (e.g., search URLs containing .mp3 in query text). Restrict stripping to explicit filename-style params instead of any ?…ext… pattern.

Proposed fix
-    .replace(/\?[^\s]*\.(?:png|jpe?g|gif|gifs|apng|webp|avif|svg|m4a|mp3|wav|flac|aac|opus|mp4|webm|ogg|ogv|mov|m4v)[^\s]*/gi, '')
-    .replace(/\?name=[^\s]*\.(?:png|jpe?g|gif|gifs|apng|webp|avif|svg|m4a|mp3|wav|flac|aac|opus|mp4|webm|ogg|ogv|mov|m4v)[^\s]*/gi, '');
+    .replace(/\?(?:name|filename)=[^\s]*\.(?:png|jpe?g|gif|gifs|apng|webp|avif|svg|m4a|mp3|wav|flac|aac|opus|mp4|webm|ogg|ogv|mov|m4v)[^\s]*/gi, '');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.replace(/\?[^\s]*\.(?:png|jpe?g|gif|gifs|apng|webp|avif|svg|m4a|mp3|wav|flac|aac|opus|mp4|webm|ogg|ogv|mov|m4v)[^\s]*/gi, '')
.replace(/\?name=[^\s]*\.(?:png|jpe?g|gif|gifs|apng|webp|avif|svg|m4a|mp3|wav|flac|aac|opus|mp4|webm|ogg|ogv|mov|m4v)[^\s]*/gi, '');
.replace(/\?(?:name|filename)=[^\s]*\.(?:png|jpe?g|gif|gifs|apng|webp|avif|svg|m4a|mp3|wav|flac|aac|opus|mp4|webm|ogg|ogv|mov|m4v)[^\s]*/gi, '');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/utils/textUtils.ts` around lines 23 - 24, The regex patterns in the
replace calls are too broad and strip any query parameter substring ending with
media file extensions, which corrupts unrelated URLs that contain extension-like
strings in their query text. Tighten both regex patterns to only match explicit
filename-style parameters by requiring the extension to be part of an actual
filename context (such as after an equals sign or in a filename parameter
format) rather than matching any arbitrary text followed by a media extension.
This ensures that search queries or other non-media URLs containing `.mp3` or
similar in their query values are not inadvertently corrupted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: render audio player for notes with audio file links

1 participant