Skip to content

Integrate browser MP3 quick cleanse into root app#9

Merged
ChrisAdamsdevelopment merged 1 commit into
mainfrom
codex/create-new-branch-for-browser-mp3-cleanse
May 4, 2026
Merged

Integrate browser MP3 quick cleanse into root app#9
ChrisAdamsdevelopment merged 1 commit into
mainfrom
codex/create-new-branch-for-browser-mp3-cleanse

Conversation

@ChrisAdamsdevelopment
Copy link
Copy Markdown
Owner

@ChrisAdamsdevelopment ChrisAdamsdevelopment commented May 4, 2026

Motivation

  • Add an in-browser MP3 quick-cleanse path to the existing root SpectraCleanseAI application while preserving the established server cleanse and production UX.
  • Reuse MP3 metadata utilities and marker detection approach from the referenced PR Add in-browser MP3 metadata cleanse, metadata utils, and integrated frontend UI #2 as a starting point without adopting its simplified root app replacement.
  • Integrate browser-side metadata analysis into the existing queue/processing flow so users can choose between a fast local MP3 cleanse and the existing forensic server pipeline.

Description

  • Added src/utils/metadata.js (and src/utils/metadata.d.ts) exposing readFileMetadata(file) and writeMP3Metadata(file, metadata) that reuse patterns from PR Add in-browser MP3 metadata cleanse, metadata utils, and integrated frontend UI #2 for music metadata parsing and AI/provenance marker detection.
  • Integrated metadata analysis into the existing queue flow by extending QueueItem with analysis and logs, calling readFileMetadata on upload/analysis, and displaying format/title/artist/genre/provenance risk/detected markers in the UI.
  • Added a UI block with two explicit cleanse actions: Quick Cleanse (Browser) (emerald, MP3-only) which uses writeMP3Metadata and creates a Blob object URL with a manual <a download> link, and Full Server Cleanse (cyan) which uses the existing /api/process pipeline; object URLs are revoked on replace/remove/unmount.
  • Updated package.json to include browser-id3-writer@4.4.0 and music-metadata-browser@2.5.11, and preserved all existing auth/session, usage meter, plan badge, upgrade modal, Stripe checkout session flow, mock checkout banner, and server forensic report handling; no client/ folder was created or imported and the root app structure was not replaced.

Testing

  • Ran npm install and it completed successfully.
  • Ran npm run build and the TypeScript + Vite production build completed successfully.
  • Verified the root frontend entry still mounts the app through src/main.tsx and that auth /api/me, Stripe checkout-session flow, usage sync and /api/process server cleanse code paths remain present in the built source.

Reused from PR #2: metadata parsing and marker heuristics, writeMP3Metadata/readFileMetadata logic and marker list as a starting point; PR #2 is superseded by this integrated implementation and no separate client/ frontend was created or imported.


Codex Task

Summary by Sourcery

Integrate client-side MP3 metadata analysis and a browser-based quick cleanse path into the existing root app while preserving the server-based cleanse flow.

New Features:

  • Add browser-side metadata utilities to read and write MP3 tags and assess AI/provenance risk markers.
  • Extend queue items and UI to display per-track metadata analysis, provenance risk level, and detected markers.
  • Introduce Quick Cleanse (Browser) workflow that rewrites MP3 metadata locally and exposes a manual download link alongside the existing Full Server Cleanse pipeline.
  • Add AI-powered SEO payload generation for track metadata via the backend.

Enhancements:

  • Add per-item system logging to surface key lifecycle events in the UI.
  • Refine SEO defaults to derive title and tags from parsed metadata instead of raw filename when available.

Build:

  • Include browser-id3-writer and music-metadata-browser dependencies for client-side metadata parsing and tag writing.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 4, 2026

Reviewer's Guide

Adds browser-side MP3 metadata analysis and a local 'Quick Cleanse' path integrated into the existing queue flow, while preserving the full server cleanse pipeline and existing root app UX.

Sequence diagram for browser Quick Cleanse and server cleanse integration

sequenceDiagram
  actor User
  participant FrontendApp
  participant MetadataUtils
  participant BrowserURL as BrowserURLAPI
  participant BackendAPI

  User->>FrontendApp: Upload audio file
  FrontendApp->>MetadataUtils: readFileMetadata(file)
  MetadataUtils-->>FrontendApp: FileMetadataResult
  FrontendApp->>FrontendApp: updateItem analysis
  FrontendApp->>FrontendApp: addLog Reading local metadata for analysis

  User->>FrontendApp: Click Quick Cleanse (Browser)
  FrontendApp->>FrontendApp: validate MP3 extension
  FrontendApp->>FrontendApp: addLog Starting browser quick cleanse
  FrontendApp->>MetadataUtils: writeMP3Metadata(file, seo.title, analysis.artist, analysis.genre)
  MetadataUtils-->>FrontendApp: cleansedBlob
  FrontendApp->>BrowserURL: createObjectURL(cleansedBlob)
  BrowserURL-->>FrontendApp: downloadUrl
  FrontendApp->>FrontendApp: updateItem downloadUrl, downloadName, status done
  FrontendApp->>FrontendApp: addLog Browser quick cleanse complete
  User-->>FrontendApp: Click Manual Download Link

  User->>FrontendApp: Click Full Server Cleanse
  FrontendApp->>FrontendApp: addLog Starting server cleanse via /api/process
  FrontendApp->>BackendAPI: POST /api/process with file and seo
  BackendAPI-->>FrontendApp: cleansed file + report
  FrontendApp->>BrowserURL: createObjectURL(serverFile)
  BrowserURL-->>FrontendApp: downloadUrl
  FrontendApp->>FrontendApp: updateItem report, downloadUrl, status done
Loading

Sequence diagram for AI SEO payload generation using metadata analysis

sequenceDiagram
  actor User
  participant FrontendApp
  participant BackendAPI

  User->>FrontendApp: Click Generate AI SEO Payload
  FrontendApp->>FrontendApp: read activeItem.seo and analysis
  FrontendApp->>BackendAPI: POST /api/generate-seo { title, artist, genre, platform }
  BackendAPI-->>FrontendApp: { title, description, tags }
  FrontendApp->>FrontendApp: updateItem seo with response
  FrontendApp->>FrontendApp: addLog SEO payload generated
  FrontendApp-->>User: Display updated SEO fields and log
Loading

Class diagram for updated QueueItem and metadata utilities

classDiagram
  class QueueItem {
    string id
    File file
    ItemStatus status
    QueueItemSeo seo
    string downloadUrl
    string downloadName
    QueueItemReport report
    string error
    QueueItemAnalysis analysis
    string[] logs
  }

  class QueueItemSeo {
    string title
    string description
    string tags
  }

  class QueueItemReport {
    number removedCount
    string[] removedTags
    string timestamp
  }

  class QueueItemAnalysis {
    string format
    string title
    string artist
    string genre
    RiskLevel provenanceRisk
    string[] detectedMarkers
  }

  class FileMetadataResult {
    string format
    string title
    string artist
    string genre
    string[] detectedMarkers
    RiskLevel provenanceRisk
    unknown raw
  }

  class MetadataUtils {
    +readFileMetadata(file File) FileMetadataResult
    +writeMP3Metadata(file File, title string, artist string, genre string) Blob
  }

  class AppLogic {
    +addLog(id string, message string) void
    +analyzeFile(item QueueItem) QueueItemPartial
    +runBatch() void
  }

  class QueueItemPartial {
    QueueItemSeo seo
    QueueItemAnalysis analysis
  }

  QueueItem --> QueueItemSeo
  QueueItem --> QueueItemReport
  QueueItem --> QueueItemAnalysis
  QueueItem --> "*" string : logs

  MetadataUtils --> FileMetadataResult
  AppLogic --> QueueItem
  AppLogic --> MetadataUtils
  AppLogic --> QueueItemPartial
Loading

File-Level Changes

Change Details Files
Introduce shared browser metadata utilities for reading and writing MP3 tags with AI/provenance marker detection.
  • Add readFileMetadata to parse browser file metadata via music-metadata-browser and derive format/title/artist/genre plus AI marker hits and provenance risk.
  • Implement writeMP3Metadata using browser-id3-writer to rewrite ID3 tags (title/artist/genre) and stamp an encoder marker for browser quick cleanse output.
  • Define TypeScript types for metadata results and writeMP3Metadata inputs to keep the TS/Vite build type-safe.
src/utils/metadata.js
src/utils/metadata.d.ts
Integrate metadata analysis, risk markers, and a browser quick-cleanse action into the existing queue item lifecycle and UI.
  • Extend QueueItem with analysis and logs fields plus a RiskLevel type to hold local metadata analysis state and a per-item log stream.
  • Replace direct music-metadata usage with readFileMetadata, wiring analysis results into SEO defaults and a new Analysis panel that shows format, artist, genre, provenance risk, and detected markers.
  • Add a Generate AI SEO Payload button that calls /api/generate-seo with current title/analysis data and logs completion.
  • Introduce a Quick Cleanse (Browser) button that validates MP3-only, calls writeMP3Metadata, manages object URLs for the cleansed blob, and exposes a manual download link while preserving the Full Server Cleanse button wired to runBatch.
  • Add per-item logging hooks around analysis and server cleanse steps and render a System Log panel in the UI.
app.tsx
Add browser-side metadata dependencies without altering the existing build or auth/payment flows.
  • Declare browser-id3-writer and music-metadata-browser as production dependencies to support in-browser MP3 metadata operations.
  • Regenerate package-lock.json to lock versions while keeping the existing Vite/auth/Stripe setup unchanged.
package.json
package-lock.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The addLog helper closes over the queue array and then calls updateItem, which itself uses setQueue; this risks stale reads under concurrent updates, so consider updating logs via a functional setQueue/updateItem that derives from prev state rather than re-reading queue inside addLog.
  • The Quick Cleanse (Browser) path only checks for a .mp3 filename before calling writeMP3Metadata, so it may mis-handle mislabeled or unsupported files; consider validating the container/codec (e.g., via analysis.format or MIME type) before attempting to rewrite ID3 tags.
  • Since the rest of the app is in TypeScript, consider converting src/utils/metadata.js to TypeScript instead of relying on a separate metadata.d.ts, which would keep the implementation and types in sync and simplify future refactors of the metadata utilities.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `addLog` helper closes over the `queue` array and then calls `updateItem`, which itself uses `setQueue`; this risks stale reads under concurrent updates, so consider updating logs via a functional `setQueue`/`updateItem` that derives from `prev` state rather than re-reading `queue` inside `addLog`.
- The `Quick Cleanse (Browser)` path only checks for a `.mp3` filename before calling `writeMP3Metadata`, so it may mis-handle mislabeled or unsupported files; consider validating the container/codec (e.g., via `analysis.format` or MIME type) before attempting to rewrite ID3 tags.
- Since the rest of the app is in TypeScript, consider converting `src/utils/metadata.js` to TypeScript instead of relying on a separate `metadata.d.ts`, which would keep the implementation and types in sync and simplify future refactors of the metadata utilities.

## Individual Comments

### Comment 1
<location path="app.tsx" line_range="949-958" />
<code_context>
+                  <button
</code_context>
<issue_to_address>
**issue (bug_risk):** Add error handling around `writeMP3Metadata` in the Quick Cleanse handler.

Right now, failures in these async steps can throw and leave the item in a partially updated state (e.g., status updated but no download URL). Please wrap the handler body in a try/catch, set an `error` on failure, and log via `addLog` so the UI remains consistent and failures are visible.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread app.tsx
Comment on lines +949 to +958
<button
onClick={async () => {
if (!activeItem.file.name.toLowerCase().endsWith('.mp3')) { updateItem(activeItem.id, { error: 'Quick Cleanse supports MP3 only.' }); return; }
updateItem(activeItem.id, { error: null });
addLog(activeItem.id, 'Starting browser quick cleanse');
const blob = await writeMP3Metadata(activeItem.file, { title: activeItem.seo.title, artist: activeItem.analysis?.artist || '', genre: activeItem.analysis?.genre || '' });
const old = activeItem.downloadUrl;
if (old) URL.revokeObjectURL(old);
const url = URL.createObjectURL(blob);
updateItem(activeItem.id, { downloadUrl: url, downloadName: `quick_cleansed_${activeItem.file.name}`, status: 'done' });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Add error handling around writeMP3Metadata in the Quick Cleanse handler.

Right now, failures in these async steps can throw and leave the item in a partially updated state (e.g., status updated but no download URL). Please wrap the handler body in a try/catch, set an error on failure, and log via addLog so the UI remains consistent and failures are visible.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 69830c9bee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app.tsx
className="w-full bg-slate-950 border border-slate-700 rounded-lg px-3 py-2 text-sm focus:border-cyan-500 outline-none resize-none" />
</div>
<button onClick={async ()=>{
const res = await fetch(`${BACKEND_URL}/api/generate-seo`, { method:'POST', headers:{'Content-Type':'application/json', Authorization:`Bearer ${authToken}`}, body: JSON.stringify({ title: activeItem.seo.title, artist: activeItem.analysis?.artist || '', genre: activeItem.analysis?.genre || '', platform })});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Send promptText when calling SEO generation API

The new SEO button posts { title, artist, genre, platform }, but POST /api/generate-seo validates only promptText and returns 400 when it is missing (see server.js handler). In this flow, every click on “Generate AI SEO Payload” fails server-side, and because only res.ok is handled, users get no feedback and the feature is effectively non-functional.

Useful? React with 👍 / 👎.

Comment thread app.tsx

const addLog = (id: string, message: string) => {
const stamp = new Date().toLocaleTimeString();
updateItem(id, { logs: [...(queue.find(i => i.id === id)?.logs || []), `[${stamp}] ${message}`] });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Derive log appends from current queue state

addLog reads queue from the render closure and then writes logs via updateItem, so multiple log writes in one async flow (e.g., runBatch or quick cleanse start/complete) can overwrite earlier entries instead of appending to the latest list. This makes the new System Log unreliable because prior messages are dropped under normal use.

Useful? React with 👍 / 👎.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant