Skip to content

feat: integrate AI Queue and Discord RPC features#31

Merged
Skeptic-systems merged 2 commits intomainfrom
feature/ai-queue
Jan 2, 2026
Merged

feat: integrate AI Queue and Discord RPC features#31
Skeptic-systems merged 2 commits intomainfrom
feature/ai-queue

Conversation

@Skeptic-systems
Copy link
Copy Markdown
Contributor

@Skeptic-systems Skeptic-systems commented Jan 2, 2026

  • Added support for AI Queue functionality to enable continuous music playback based on user mood or genre.
  • Implemented Discord Rich Presence integration to update user status with currently playing track information.
  • Updated settings to allow users to enable/disable Discord RPC and show/hide AI Queue border.
  • Enhanced Spotify client to support fetching user playlists and managing tracks within playlists.
  • Introduced new UI components for managing playlists and displaying AI Queue status.
  • Updated documentation to reflect new features and usage guidelines.

Description

Brief description of the changes in this PR.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement
  • Test coverage improvement

Related Issues

Fixes #(issue number)
Closes #(issue number)
Related to #(issue number)

Changes Made

  • Change 1
  • Change 2
  • Change 3

Testing

  • I have tested these changes locally
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Screenshots (if applicable)

Add screenshots to help explain your changes.

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Additional Notes

Add any additional notes about the PR here.

Summary by CodeRabbit

  • New Features

    • Playlist browsing and add-to-playlist flow (context menu + quick modal)
    • Discord Rich Presence showing current track on Discord
    • AI Queue: continuous, auto-generated playlists with UI controls
    • Volume panel with presets and slider; keyboard shortcuts for quick navigation
  • Bug Fixes

    • AI Queue auto-stops when you manually start another song
  • Performance Improvements

    • Lazy-loaded playlist tracks and album art; reduced redundant API calls and token caching

✏️ Tip: You can customize this high-level summary in your review settings.

- Added support for AI Queue functionality to enable continuous music playback based on user mood or genre.
- Implemented Discord Rich Presence integration to update user status with currently playing track information.
- Updated settings to allow users to enable/disable Discord RPC and show/hide AI Queue border.
- Enhanced Spotify client to support fetching user playlists and managing tracks within playlists.
- Introduced new UI components for managing playlists and displaying AI Queue status.
- Updated documentation to reflect new features and usage guidelines.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 2, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds Discord Rich Presence, AI Queue for continuous, AI-generated playlists (TOON-encoded), playlist browsing and add-to-playlist UI, a Volume view, token/request optimizations, and various UI wiring and settings to support these features.

Changes

Cohort / File(s) Summary
Changesets & Docs
.changeset/*.md
New changelog entries describing playlist UX, TOON format, Discord RPC, AI Queue, AI context, volume control, and optimizations.
Tauri / Rust backend
apps/desktop/src-tauri/src/discord_rpc.rs, .../lib.rs, .../settings.rs, .../spotify_auth.rs, .../resize.rs, apps/desktop/src-tauri/Cargo.toml
New Discord RPC module + state and invoke handlers; settings gains discord_rpc_enabled and show_ai_queue_border; OAuth scopes expanded for playlist modification; Layout::Volume added; Discord/ log deps added.
Package deps
apps/desktop/package.json
Added dependency @toon-format/toon.
Spotify client & API surface
apps/desktop/src/ui/spotifyClient.ts, apps/desktop/src/lib/spotifyTools.ts
Token caching, request dedupe, fire-and-forget player actions, debounced seek/volume; new playlist APIs (fetch user playlists, fetch playlist tracks, add track to playlist), AI queue control tools, and TOON-encoded tooling output.
AI Queue: store & service
apps/desktop/src/lib/aiQueueStore.ts, apps/desktop/src/lib/aiQueueService.ts
New Zustand AI queue store and service: fetchNextBatch, start/stop AI Queue, background monitor (3s), TOON formatting helpers, URI resolution and fallbacks, mood context and caching.
AI client & tools
apps/desktop/src/lib/aiClient.ts, apps/desktop/src/lib/spotifyTools.ts
System prompt updated with TOON spec, AI Queue actions added, playback decision rules updated. Spotify tools return TOON-encoded track/artist payloads.
Frontend wiring & views
apps/desktop/src/ui/index.tsx, apps/desktop/src/ui/layouts/LayoutB.tsx, apps/desktop/src/ui/views/PlaylistView.tsx, .../AddToPlaylistView.tsx, .../VolumeView.tsx
App view union extended (playlist, addToPlaylist, volume); LayoutB exposes onAddToPlaylist; new PlaylistView (browse + infinite scroll), AddToPlaylistView (add track to playlist), and VolumeView (debounced slider, presets).
AIDJ & Settings UI
apps/desktop/src/ui/views/AIDJView.tsx, apps/desktop/src/ui/views/Settings.tsx
AIDJ prepends user context (profile/current/recent/top, TOON-encoded) and integrates AI Queue controls/status. Settings adds toggles for Discord RPC and AI Queue border and persists settings.
Hooks & controls
apps/desktop/src/hooks/useCurrentlyPlaying.ts, apps/desktop/src/hooks/useWindowLayout.ts, apps/desktop/src/ui/components/...
Discord presence updates via change detection; Layout type gains "Volume"; Playback handlers simplified to fire-and-forget (removed awaits); track control handlers made synchronous.
Cleanup & removals
apps/desktop/src/ui/views/ContextMenu.tsx, apps/desktop/src/ui/views/SplashScreen.tsx, apps/desktop/src/ui/global.css
Removed custom ContextMenu component, SplashScreen component, and associated splash CSS animations; various minor cleanups and static import adjustments.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as Desktop UI
    participant AIS as aiQueueService
    participant Store as AIQueueStore
    participant SClient as SpotifyClient
    participant AI as AI Provider
    participant Spotify as Spotify API

    User->>UI: Toggle "Start AI Queue" (optional mood)
    UI->>AIS: startAIQueue(mood)
    AIS->>Store: setLoading(true)
    AIS->>SClient: getRecentlyPlayed(), getTopArtists()
    SClient->>Spotify: GET /v1/me/...
    Spotify-->>SClient: recent/top data (tracks/artists)
    SClient-->>AIS: TOON-encoded data
    AIS->>AI: generateText(system + TOON context + mood)
    AI-->>AIS: suggestions (JSON)
    AIS->>SClient: searchAndGetUri(track names) (resolve URIs)
    SClient->>Spotify: GET /v1/search (fallbacks)
    Spotify-->>SClient: track URIs
    SClient-->>AIS: resolved URIs
    AIS->>Store: setQueue(resolvedTracks)
    AIS->>SClient: playTracks(batch)
    SClient->>Spotify: PUT /v1/me/player/play
    Spotify-->>SClient: OK
    loop Background monitor (every 3s)
      AIS->>SClient: getPlayerState()
      SClient->>Spotify: GET /v1/me/player
      Spotify-->>SClient: player state
      SClient-->>AIS: current progress
      AIS->>Store: advance or fetchNextBatch if nearing end
      alt User manually plays other track
        AIS->>Store: stopAIQueue()
      end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hop through playlists, bytes, and tunes,

Discord glows beneath the moons,
AI queues hum, TOON tokens saved,
Volume sliders neatly paved,
A tiny rabbit cheers—MiniFy blooms! 🎶

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.27% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The PR description lists the main changes but lacks completion of required template sections including Related Issues, Changes Made checklist, Testing checklist, and Additional Notes. Complete the PR description template by filling in Related Issues, marking Changes Made items, confirming Testing completion, and providing Additional Notes to ensure reviewers have full context.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the two main features introduced in this PR: AI Queue functionality and Discord RPC integration.

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f4b2319 and bdfac29.

📒 Files selected for processing (8)
  • .changeset/clean-code-flow.md
  • .changeset/quick-keys-dance.md
  • apps/desktop/src/lib/aiQueueService.ts
  • apps/desktop/src/ui/global.css
  • apps/desktop/src/ui/index.tsx
  • apps/desktop/src/ui/views/ContextMenu.tsx
  • apps/desktop/src/ui/views/PlaylistView.tsx
  • apps/desktop/src/ui/views/SplashScreen.tsx

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

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

⚠️ Outside diff range comments (1)
apps/desktop/src/lib/settingLib.ts (1)

106-129: Missing initialization for discord_rpc_enabled field.

The discord_rpc_enabled field was added to the Settings type (line 59) but is not initialized in either the success path (line 114) or the fallback object (line 126). This will result in undefined values when the backend doesn't provide this field, causing potential runtime errors and type inconsistencies.

🔎 Proposed fix to initialize discord_rpc_enabled
   return {
     ...settings,
     ai_providers: settings.ai_providers ?? [],
     active_ai_provider: settings.active_ai_provider ?? null,
     active_music_provider: settings.active_music_provider ?? "spotify",
     show_ai_queue_border: settings.show_ai_queue_border ?? true,
+    discord_rpc_enabled: settings.discord_rpc_enabled ?? true,
   };
 } catch (err) {
   console.warn("Failed to read settings via Tauri, using defaults:", err);
   return {
     first_boot_done: false,
     spotify: { access_token: null, refresh_token: null },
     layout: "LayoutA",
     theme: "dark",
     ai_providers: [],
     active_ai_provider: null,
     active_music_provider: "spotify",
     show_ai_queue_border: true,
+    discord_rpc_enabled: true,
   };
 }
🧹 Nitpick comments (11)
apps/desktop/src/ui/views/AddToPlaylistView.tsx (2)

10-14: Consider requiring trackId to be non-null.

The trackId prop is typed as string | null, but the component's purpose requires a valid track ID. If trackId is null, the add button becomes effectively non-functional. Consider either:

  1. Making trackId required (non-null) at the type level
  2. Adding an early return or error state when trackId is null

This would make the component's contract clearer and prevent rendering a non-functional UI.


45-56: Missing user-facing error feedback.

When addTrackToPlaylist fails, the error is only logged to the console (line 53). Users won't know why the action failed. Consider adding a toast notification or inline error message.

🔎 Suggested enhancement
+const [error, setError] = useState<string | null>(null);
+
 const handleAddToPlaylist = async (playlist: SimplifiedPlaylist) => {
   if (!trackId || addingTo) return;

   setAddingTo(playlist.id);
+  setError(null);
   try {
     await addTrackToPlaylist(playlist.id, `spotify:track:${trackId}`);
     onBack();
   } catch (err) {
     console.error("Failed to add track to playlist:", err);
+    setError("Failed to add track. Please try again.");
     setAddingTo(null);
   }
 };
apps/desktop/src/ui/views/VolumeView.tsx (2)

20-31: Consider handling the case when no active device is available.

If getPlayerState() returns null or state.device is undefined, the component silently keeps the default volume of 50 and empty device name. This could be confusing if there's no active Spotify session.

🔎 Suggested enhancement
+const [noDevice, setNoDevice] = useState<boolean>(false);
+
 useEffect(() => {
   const loadVolume = async () => {
     setLoading(true);
     const state = await getPlayerState();
     if (state?.device) {
       setLocalVolume(state.device.volume_percent);
       setDeviceName(state.device.name);
+    } else {
+      setNoDevice(true);
     }
     setLoading(false);
   };
   loadVolume();
 }, []);

Then render a message when noDevice is true.


136-156: Inline <style> tag works but consider CSS modules or Tailwind plugin.

The inline style tag for slider thumb customization is functional but could be moved to a global stylesheet or handled via a Tailwind plugin for consistency. This is a minor stylistic concern given that other components in the codebase use similar patterns.

apps/desktop/src/ui/layouts/LayoutB.tsx (1)

43-61: Consider using CSS for hover state instead of React state.

The plusHovered state with onMouseEnter/onMouseLeave handlers works, but the hover color change could be achieved purely with CSS, reducing React re-renders on hover.

🔎 CSS-based alternative
-const [plusHovered, setPlusHovered] = useState<boolean>(false);
...
 <button
   type="button"
   onClick={() => {
     if (track && onAddToPlaylist) {
       onAddToPlaylist(track.id, track.name);
     }
   }}
   disabled={!track || !onAddToPlaylist}
   aria-label="Add to playlist"
-  className="w-8 h-8 flex items-center justify-center active:scale-[0.95] transition-all duration-150 disabled:opacity-30 disabled:cursor-not-allowed"
-  onMouseEnter={() => setPlusHovered(true)}
-  onMouseLeave={() => setPlusHovered(false)}
+  className="w-8 h-8 flex items-center justify-center active:scale-[0.95] transition-all duration-150 disabled:opacity-30 disabled:cursor-not-allowed group"
 >
   <PlusCircle
     size={24}
     weight="fill"
-    color={plusHovered ? "var(--player-controls-color-active)" : "var(--player-controls-color)"}
+    className="text-[--player-controls-color] group-hover:text-[--player-controls-color-active] transition-colors"
   />
 </button>
apps/desktop/src/ui/views/AIDJView.tsx (1)

108-114: Missing error handling for startAIQueue.

The handleToggleQueue function awaits startAIQueue() but doesn't handle potential errors. While the AI queue store sets an error state internally, the UI might benefit from local error handling or at least a try-catch for unexpected failures.

🔎 Suggested improvement
 const handleToggleQueue = async () => {
   if (aiQueueActive) {
     stopAIQueue();
   } else {
-    await startAIQueue();
+    try {
+      await startAIQueue();
+    } catch (err) {
+      console.error("Failed to start AI Queue:", err);
+    }
   }
 };
apps/desktop/src/ui/views/Settings.tsx (1)

821-833: Consider extracting toggle switch to a reusable component.

The toggle switch UI is duplicated between Discord RPC (lines 821-833) and AI Queue Border (lines 1101-1113). Extracting this to a shared ToggleSwitch component would improve maintainability.

🔎 Example component
type ToggleSwitchProps = {
  enabled: boolean;
  onToggle: () => void;
  activeColor?: string;
};

function ToggleSwitch({ enabled, onToggle, activeColor = "bg-[--settings-accent]" }: ToggleSwitchProps) {
  return (
    <button
      type="button"
      onClick={onToggle}
      className={`relative w-10 h-5 rounded-full transition-colors duration-200 flex-shrink-0 ${
        enabled ? activeColor : "bg-white/20"
      }`}
    >
      <span
        className={`absolute top-0.5 left-0.5 w-4 h-4 rounded-full bg-white transition-all duration-200 ${
          enabled ? "translate-x-5" : "translate-x-0"
        }`}
      />
    </button>
  );
}

Also applies to: 1101-1113

apps/desktop/src/ui/views/PlaylistView.tsx (1)

116-125: playingId cleared immediately may cause premature UI state reset.

The playingId is set before playTrack and cleared in finally, which runs immediately after the API call resolves. However, the track doesn't start playing instantly on Spotify. The spinner will disappear before the track actually begins playing, which may confuse users.

Consider either:

  1. Using a timeout before clearing
  2. Not clearing playingId and letting the next track change update the state naturally
  3. Polling player state briefly to confirm playback started
apps/desktop/src/lib/aiQueueStore.ts (1)

44-50: Potential mutation before state update in setQueue.

The current implementation mutates the existing playedUris Set before creating a new one. While a new Set is created at the end, mutating the original could cause issues if other code holds a reference to it.

🔎 Suggested fix
  setQueue: (queue) => {
-   const playedUris = get().playedUris;
-   for (const track of queue) {
-     playedUris.add(track.uri);
-   }
-   set({ queue, currentIndex: 0, playedUris: new Set(playedUris) });
+   const newPlayedUris = new Set(get().playedUris);
+   for (const track of queue) {
+     newPlayedUris.add(track.uri);
+   }
+   set({ queue, currentIndex: 0, playedUris: newPlayedUris });
  },
apps/desktop/src-tauri/src/discord_rpc.rs (1)

184-189: Reconnection doesn't retry setting the activity.

When set_activity fails and reconnection succeeds, the activity is not retried on the new client. The presence update is effectively lost for this call.

Consider retrying the activity set after successful reconnection, or document that the next update will use the new client.

apps/desktop/src/ui/index.tsx (1)

229-238: Consider extracting inline styles to Tailwind classes.

The hardcoded color values and box-shadow could be defined as CSS custom properties or Tailwind classes for better maintainability and theme consistency.

🔎 Example approach
      {showBorder && (
        <div
-          className="absolute inset-0 pointer-events-none z-50"
-          style={{
-            border: "1.5px solid #7f1d1d",
-            borderRadius: "12px",
-            boxShadow: "inset 0 0 30px rgba(127, 29, 29, 0.4), inset 0 0 60px rgba(127, 29, 29, 0.15)",
-          }}
+          className="absolute inset-0 pointer-events-none z-50 rounded-xl border-[1.5px] border-red-900 shadow-[inset_0_0_30px_rgba(127,29,29,0.4),inset_0_0_60px_rgba(127,29,29,0.15)]"
        />
      )}
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76356be and f4b2319.

⛔ Files ignored due to path filters (6)
  • apps/desktop/src-tauri/Cargo.lock is excluded by !**/*.lock
  • apps/desktop/src-tauri/gen/schemas/acl-manifests.json is excluded by !**/gen/**
  • apps/desktop/src-tauri/gen/schemas/capabilities.json is excluded by !**/gen/**
  • apps/desktop/src-tauri/gen/schemas/desktop-schema.json is excluded by !**/gen/**
  • apps/desktop/src-tauri/gen/schemas/windows-schema.json is excluded by !**/gen/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (30)
  • .changeset/brave-playlists-flow.md
  • .changeset/clever-llms-save.md
  • .changeset/discord-rich-presence.md
  • .changeset/smart-ai-context.md
  • .changeset/smart-dj-queue.md
  • .changeset/swift-api-optimizations.md
  • apps/desktop/package.json
  • apps/desktop/src-tauri/Cargo.toml
  • apps/desktop/src-tauri/src/discord_rpc.rs
  • apps/desktop/src-tauri/src/lib.rs
  • apps/desktop/src-tauri/src/resize.rs
  • apps/desktop/src-tauri/src/settings.rs
  • apps/desktop/src-tauri/src/spotify_auth.rs
  • apps/desktop/src/hooks/useCurrentlyPlaying.ts
  • apps/desktop/src/hooks/useWindowLayout.ts
  • apps/desktop/src/lib/aiClient.ts
  • apps/desktop/src/lib/aiQueueService.ts
  • apps/desktop/src/lib/aiQueueStore.ts
  • apps/desktop/src/lib/settingLib.ts
  • apps/desktop/src/lib/spotifyTools.ts
  • apps/desktop/src/ui/components/TrackControls/PlaybackBar.tsx
  • apps/desktop/src/ui/components/TrackControls/TrackControls.tsx
  • apps/desktop/src/ui/index.tsx
  • apps/desktop/src/ui/layouts/LayoutB.tsx
  • apps/desktop/src/ui/spotifyClient.ts
  • apps/desktop/src/ui/views/AIDJView.tsx
  • apps/desktop/src/ui/views/AddToPlaylistView.tsx
  • apps/desktop/src/ui/views/PlaylistView.tsx
  • apps/desktop/src/ui/views/Settings.tsx
  • apps/desktop/src/ui/views/VolumeView.tsx
🧰 Additional context used
📓 Path-based instructions (13)
.changeset/*.md

📄 CodeRabbit inference engine (.cursor/rules/020-changesets.mdc)

.changeset/*.md: Changeset markdown files must follow the format with frontmatter containing package name and version type, followed by description with maximum 99 characters per line
Use major version type for breaking changes in changesets
Use minor version type for new features in changesets
Use patch version type for bug fixes and improvements in changesets

Files:

  • .changeset/clever-llms-save.md
  • .changeset/smart-dj-queue.md
  • .changeset/swift-api-optimizations.md
  • .changeset/brave-playlists-flow.md
  • .changeset/discord-rich-presence.md
  • .changeset/smart-ai-context.md
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/020-coding-style.mdc)

**/*.{ts,tsx}: NEVER use any types - Always provide proper type definitions in TypeScript
Use unknown instead of any when the type is truly unknown in TypeScript
Use interfaces for object shapes that will be extended in TypeScript
Use type aliases for complex types and unions in TypeScript
Use the latest TypeScript features appropriately
Document public APIs and interfaces in code

Use TypeScript strict types and avoid any type

Files:

  • apps/desktop/src/hooks/useWindowLayout.ts
  • apps/desktop/src/ui/components/TrackControls/PlaybackBar.tsx
  • apps/desktop/src/ui/views/Settings.tsx
  • apps/desktop/src/ui/components/TrackControls/TrackControls.tsx
  • apps/desktop/src/lib/aiQueueService.ts
  • apps/desktop/src/hooks/useCurrentlyPlaying.ts
  • apps/desktop/src/lib/settingLib.ts
  • apps/desktop/src/ui/views/PlaylistView.tsx
  • apps/desktop/src/ui/views/AddToPlaylistView.tsx
  • apps/desktop/src/ui/views/AIDJView.tsx
  • apps/desktop/src/lib/aiClient.ts
  • apps/desktop/src/ui/views/VolumeView.tsx
  • apps/desktop/src/lib/spotifyTools.ts
  • apps/desktop/src/lib/aiQueueStore.ts
  • apps/desktop/src/ui/layouts/LayoutB.tsx
  • apps/desktop/src/ui/spotifyClient.ts
  • apps/desktop/src/ui/index.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/020-coding-style.mdc)

**/*.{ts,tsx,js,jsx}: Avoid dynamic imports - use static imports at the top of files for better performance and code clarity
Write self-documenting code with meaningful names instead of extra comments
Avoid obvious comments that just repeat what the code does
Add comments only for complex logic, business rules, or non-obvious decisions
Use meaningful variable and function names instead of explanatory comments
Always use static imports at the top of files instead of dynamic imports
Import all dependencies at the file beginning for better bundling and performance
Use tree-shaking friendly named imports when possible
Use streaming APIs instead of loading large files into memory
Avoid buffer accumulation for large data processing
Implement proper cleanup for temporary files and streams
Set appropriate file size limits based on available memory
Maintain consistency with existing code style when modifying files
Keep code DRY (Don't Repeat Yourself)
Prefer verbose variable names and maintainability over concise code
Optimize for memory efficiency in data processing applications

Place static imports at the top of files

Files:

  • apps/desktop/src/hooks/useWindowLayout.ts
  • apps/desktop/src/ui/components/TrackControls/PlaybackBar.tsx
  • apps/desktop/src/ui/views/Settings.tsx
  • apps/desktop/src/ui/components/TrackControls/TrackControls.tsx
  • apps/desktop/src/lib/aiQueueService.ts
  • apps/desktop/src/hooks/useCurrentlyPlaying.ts
  • apps/desktop/src/lib/settingLib.ts
  • apps/desktop/src/ui/views/PlaylistView.tsx
  • apps/desktop/src/ui/views/AddToPlaylistView.tsx
  • apps/desktop/src/ui/views/AIDJView.tsx
  • apps/desktop/src/lib/aiClient.ts
  • apps/desktop/src/ui/views/VolumeView.tsx
  • apps/desktop/src/lib/spotifyTools.ts
  • apps/desktop/src/lib/aiQueueStore.ts
  • apps/desktop/src/ui/layouts/LayoutB.tsx
  • apps/desktop/src/ui/spotifyClient.ts
  • apps/desktop/src/ui/index.tsx
apps/desktop/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/030-codebase-structure.mdc)

Keep React components focused with typed props

Files:

  • apps/desktop/src/hooks/useWindowLayout.ts
  • apps/desktop/src/ui/components/TrackControls/PlaybackBar.tsx
  • apps/desktop/src/ui/views/Settings.tsx
  • apps/desktop/src/ui/components/TrackControls/TrackControls.tsx
  • apps/desktop/src/lib/aiQueueService.ts
  • apps/desktop/src/hooks/useCurrentlyPlaying.ts
  • apps/desktop/src/lib/settingLib.ts
  • apps/desktop/src/ui/views/PlaylistView.tsx
  • apps/desktop/src/ui/views/AddToPlaylistView.tsx
  • apps/desktop/src/ui/views/AIDJView.tsx
  • apps/desktop/src/lib/aiClient.ts
  • apps/desktop/src/ui/views/VolumeView.tsx
  • apps/desktop/src/lib/spotifyTools.ts
  • apps/desktop/src/lib/aiQueueStore.ts
  • apps/desktop/src/ui/layouts/LayoutB.tsx
  • apps/desktop/src/ui/spotifyClient.ts
  • apps/desktop/src/ui/index.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/020-coding-style.mdc)

**/*.{tsx,jsx}: Use functional components with hooks in React
Use named exports for React components
Keep React components small and focused on a single responsibility
Use proper prop typing in React components
Use Tailwind CSS for styling in React applications
Follow component-based styling practices with Tailwind CSS
Use Tailwind CSS utility classes for one-off styling needs
Extract common styling patterns to shared components in React

Files:

  • apps/desktop/src/ui/components/TrackControls/PlaybackBar.tsx
  • apps/desktop/src/ui/views/Settings.tsx
  • apps/desktop/src/ui/components/TrackControls/TrackControls.tsx
  • apps/desktop/src/ui/views/PlaylistView.tsx
  • apps/desktop/src/ui/views/AddToPlaylistView.tsx
  • apps/desktop/src/ui/views/AIDJView.tsx
  • apps/desktop/src/ui/views/VolumeView.tsx
  • apps/desktop/src/ui/layouts/LayoutB.tsx
  • apps/desktop/src/ui/index.tsx
apps/desktop/src/ui/components/**

📄 CodeRabbit inference engine (.cursor/rules/030-codebase-structure.mdc)

Reusable UI components should be organized under apps/desktop/src/ui/components/*

Files:

  • apps/desktop/src/ui/components/TrackControls/PlaybackBar.tsx
  • apps/desktop/src/ui/components/TrackControls/TrackControls.tsx
apps/desktop/src-tauri/src/spotify_auth.rs

📄 CodeRabbit inference engine (.cursor/rules/030-codebase-structure.mdc)

Spotify authentication module should be located at apps/desktop/src-tauri/src/spotify_auth.rs

Files:

  • apps/desktop/src-tauri/src/spotify_auth.rs
apps/desktop/src-tauri/src/**/*.rs

📄 CodeRabbit inference engine (.cursor/rules/030-codebase-structure.mdc)

Store secrets and tokens in OS keychain via keyring

Files:

  • apps/desktop/src-tauri/src/spotify_auth.rs
  • apps/desktop/src-tauri/src/resize.rs
  • apps/desktop/src-tauri/src/discord_rpc.rs
  • apps/desktop/src-tauri/src/lib.rs
  • apps/desktop/src-tauri/src/settings.rs
apps/desktop/src/ui/views/**

📄 CodeRabbit inference engine (.cursor/rules/030-codebase-structure.mdc)

View components should be organized under apps/desktop/src/ui/views/*

Files:

  • apps/desktop/src/ui/views/Settings.tsx
  • apps/desktop/src/ui/views/PlaylistView.tsx
  • apps/desktop/src/ui/views/AddToPlaylistView.tsx
  • apps/desktop/src/ui/views/AIDJView.tsx
  • apps/desktop/src/ui/views/VolumeView.tsx
apps/desktop/src-tauri/src/lib.rs

📄 CodeRabbit inference engine (.cursor/rules/030-codebase-structure.mdc)

Tauri library crate should be defined in apps/desktop/src-tauri/src/lib.rs

Files:

  • apps/desktop/src-tauri/src/lib.rs
apps/desktop/src-tauri/src/settings.rs

📄 CodeRabbit inference engine (.cursor/rules/030-codebase-structure.mdc)

apps/desktop/src-tauri/src/settings.rs: Settings module implementation should be located at apps/desktop/src-tauri/src/settings.rs
Persist app settings under platform config directory as JSON

Files:

  • apps/desktop/src-tauri/src/settings.rs
apps/desktop/src/ui/layouts/**

📄 CodeRabbit inference engine (.cursor/rules/030-codebase-structure.mdc)

Layout components should be organized under apps/desktop/src/ui/layouts/*

Files:

  • apps/desktop/src/ui/layouts/LayoutB.tsx
apps/desktop/src/ui/index.tsx

📄 CodeRabbit inference engine (.cursor/rules/030-codebase-structure.mdc)

UI root component should be located at apps/desktop/src/ui/index.tsx

Files:

  • apps/desktop/src/ui/index.tsx
🧠 Learnings (11)
📚 Learning: 2025-12-29T21:56:02.721Z
Learnt from: CR
Repo: ModioStudio/MiniFy PR: 0
File: .cursor/rules/030-codebase-structure.mdc:0-0
Timestamp: 2025-12-29T21:56:02.721Z
Learning: Applies to apps/desktop/src-tauri/src/spotify_auth.rs : Spotify authentication module should be located at `apps/desktop/src-tauri/src/spotify_auth.rs`

Applied to files:

  • apps/desktop/src-tauri/src/spotify_auth.rs
  • apps/desktop/src-tauri/src/discord_rpc.rs
  • apps/desktop/src-tauri/src/lib.rs
📚 Learning: 2025-12-29T21:56:02.721Z
Learnt from: CR
Repo: ModioStudio/MiniFy PR: 0
File: .cursor/rules/030-codebase-structure.mdc:0-0
Timestamp: 2025-12-29T21:56:02.721Z
Learning: Applies to apps/desktop/src/ui/settingLib.ts : Settings helper utilities should be located at `apps/desktop/src/ui/settingLib.ts`

Applied to files:

  • apps/desktop/src/ui/views/Settings.tsx
  • apps/desktop/src/lib/settingLib.ts
📚 Learning: 2025-12-29T21:56:02.721Z
Learnt from: CR
Repo: ModioStudio/MiniFy PR: 0
File: .cursor/rules/030-codebase-structure.mdc:0-0
Timestamp: 2025-12-29T21:56:02.721Z
Learning: Applies to apps/desktop/src-tauri/src/settings.rs : Settings module implementation should be located at `apps/desktop/src-tauri/src/settings.rs`

Applied to files:

  • apps/desktop/src/lib/settingLib.ts
  • apps/desktop/src-tauri/src/lib.rs
  • apps/desktop/src-tauri/src/settings.rs
📚 Learning: 2025-12-29T21:56:02.721Z
Learnt from: CR
Repo: ModioStudio/MiniFy PR: 0
File: .cursor/rules/030-codebase-structure.mdc:0-0
Timestamp: 2025-12-29T21:56:02.721Z
Learning: Applies to apps/desktop/src/ui/index.tsx : UI root component should be located at `apps/desktop/src/ui/index.tsx`

Applied to files:

  • apps/desktop/src/ui/views/PlaylistView.tsx
  • apps/desktop/src/ui/views/AddToPlaylistView.tsx
  • apps/desktop/src/ui/views/VolumeView.tsx
  • apps/desktop/src/ui/index.tsx
📚 Learning: 2025-12-29T21:56:02.721Z
Learnt from: CR
Repo: ModioStudio/MiniFy PR: 0
File: .cursor/rules/030-codebase-structure.mdc:0-0
Timestamp: 2025-12-29T21:56:02.721Z
Learning: Applies to apps/desktop/src/main.tsx : Entry point for desktop frontend is at `apps/desktop/src/main.tsx`

Applied to files:

  • apps/desktop/src/ui/views/PlaylistView.tsx
  • apps/desktop/src/ui/index.tsx
📚 Learning: 2026-01-01T15:42:43.329Z
Learnt from: CR
Repo: ModioStudio/MiniFy PR: 0
File: .cursor/rules/020-changesets.mdc:0-0
Timestamp: 2026-01-01T15:42:43.329Z
Learning: Applies to .changeset/*.md : Use `minor` version type for new features in changesets

Applied to files:

  • .changeset/discord-rich-presence.md
  • .changeset/smart-ai-context.md
📚 Learning: 2025-12-29T21:56:02.721Z
Learnt from: CR
Repo: ModioStudio/MiniFy PR: 0
File: .cursor/rules/030-codebase-structure.mdc:0-0
Timestamp: 2025-12-29T21:56:02.721Z
Learning: Applies to apps/desktop/src-tauri/src/lib.rs : Tauri library crate should be defined in `apps/desktop/src-tauri/src/lib.rs`

Applied to files:

  • apps/desktop/src-tauri/src/lib.rs
  • apps/desktop/src-tauri/Cargo.toml
📚 Learning: 2025-12-29T21:56:02.721Z
Learnt from: CR
Repo: ModioStudio/MiniFy PR: 0
File: .cursor/rules/030-codebase-structure.mdc:0-0
Timestamp: 2025-12-29T21:56:02.721Z
Learning: Applies to apps/desktop/src-tauri/src/main.rs : Tauri backend entry point should be at `apps/desktop/src-tauri/src/main.rs`

Applied to files:

  • apps/desktop/src-tauri/src/lib.rs
📚 Learning: 2025-12-29T21:55:52.410Z
Learnt from: CR
Repo: ModioStudio/MiniFy PR: 0
File: .cursor/rules/020-coding-style.mdc:0-0
Timestamp: 2025-12-29T21:55:52.410Z
Learning: Use Tauri commands for system interactions in desktop applications

Applied to files:

  • apps/desktop/src-tauri/src/lib.rs
📚 Learning: 2025-12-29T21:56:02.721Z
Learnt from: CR
Repo: ModioStudio/MiniFy PR: 0
File: .cursor/rules/030-codebase-structure.mdc:0-0
Timestamp: 2025-12-29T21:56:02.721Z
Learning: Applies to apps/desktop/src-tauri/src/settings.rs : Persist app settings under platform config directory as JSON

Applied to files:

  • apps/desktop/src-tauri/src/settings.rs
📚 Learning: 2025-12-29T21:56:02.721Z
Learnt from: CR
Repo: ModioStudio/MiniFy PR: 0
File: .cursor/rules/030-codebase-structure.mdc:0-0
Timestamp: 2025-12-29T21:56:02.721Z
Learning: Applies to apps/desktop/src-tauri/src/bin/clear.rs : CLI utility for clearing settings should be located at `apps/desktop/src-tauri/src/bin/clear.rs`

Applied to files:

  • apps/desktop/src-tauri/src/settings.rs
🧬 Code graph analysis (12)
apps/desktop/src/ui/components/TrackControls/PlaybackBar.tsx (1)
apps/desktop/src/ui/spotifyClient.ts (1)
  • seek (194-206)
apps/desktop/src-tauri/src/resize.rs (1)
apps/desktop/src/hooks/useWindowLayout.ts (1)
  • Layout (4-4)
apps/desktop/src/ui/views/Settings.tsx (1)
apps/desktop/src/lib/settingLib.ts (1)
  • writeSettings (131-139)
apps/desktop/src/ui/components/TrackControls/TrackControls.tsx (1)
apps/desktop/src/ui/spotifyClient.ts (4)
  • previousTrack (142-144)
  • nextTrack (138-140)
  • play (130-132)
  • pause (134-136)
apps/desktop/src/hooks/useCurrentlyPlaying.ts (2)
apps/desktop/src/ui/spotifyClient.ts (1)
  • CurrentlyPlaying (26-30)
apps/desktop/src/lib/aiQueueStore.ts (1)
  • useAIQueueStore (32-86)
apps/desktop/src/ui/views/PlaylistView.tsx (2)
apps/desktop/src/hooks/useWindowLayout.ts (1)
  • useWindowLayout (6-12)
apps/desktop/src/ui/spotifyClient.ts (6)
  • SimplifiedPlaylist (417-429)
  • SimplifiedTrack (18-24)
  • fetchUserPlaylists (438-445)
  • fetchPlaylistTracks (457-466)
  • playTrack (234-239)
  • getLargestImageUrl (213-217)
apps/desktop/src-tauri/src/discord_rpc.rs (1)
apps/desktop/src-tauri/src/settings.rs (1)
  • default (47-59)
apps/desktop/src/ui/views/AddToPlaylistView.tsx (2)
apps/desktop/src/hooks/useWindowLayout.ts (1)
  • useWindowLayout (6-12)
apps/desktop/src/ui/spotifyClient.ts (3)
  • SimplifiedPlaylist (417-429)
  • fetchUserPlaylists (438-445)
  • addTrackToPlaylist (468-474)
apps/desktop/src/ui/views/AIDJView.tsx (3)
apps/desktop/src/ui/spotifyClient.ts (4)
  • fetchUserProfile (389-392)
  • fetchCurrentlyPlaying (123-128)
  • fetchRecentlyPlayed (248-263)
  • fetchTopArtists (294-298)
apps/desktop/src/lib/aiQueueStore.ts (1)
  • useAIQueueStore (32-86)
apps/desktop/src/lib/aiQueueService.ts (2)
  • stopAIQueue (248-259)
  • startAIQueue (218-246)
apps/desktop/src-tauri/src/lib.rs (3)
apps/desktop/src-tauri/src/discord_rpc.rs (7)
  • new (15-20)
  • default (24-26)
  • enable_discord_rpc (45-85)
  • disable_discord_rpc (88-108)
  • update_discord_presence (111-193)
  • is_discord_rpc_enabled (196-202)
  • init_discord_rpc (204-223)
apps/desktop/src-tauri/src/settings.rs (1)
  • default (47-59)
apps/desktop/src-tauri/src/custom_themes.rs (1)
  • validate_theme_json (183-187)
apps/desktop/src/ui/views/VolumeView.tsx (2)
apps/desktop/src/hooks/useWindowLayout.ts (1)
  • useWindowLayout (6-12)
apps/desktop/src/ui/spotifyClient.ts (2)
  • getPlayerState (169-176)
  • setVolume (178-192)
apps/desktop/src/ui/layouts/LayoutB.tsx (3)
apps/desktop/src/hooks/useWindowLayout.ts (1)
  • useWindowLayout (6-12)
apps/desktop/src/hooks/useCurrentlyPlaying.ts (1)
  • useCurrentlyPlaying (22-86)
apps/desktop/src/ui/components/LayoutTrackInfo/TrackInfoLayout.tsx (1)
  • TrackInfoLayout (17-48)
🔇 Additional comments (59)
.changeset/swift-api-optimizations.md (1)

1-19: Perfect! Changeset adheres to all guidelines.

The frontmatter is properly formatted with the correct package name and minor version type (appropriate for new features). All description lines comply with the 99-character limit, and the content is well-structured and clear.

.changeset/smart-ai-context.md (1)

1-13: Changeset is well-structured and follows conventions.

The minor version type is appropriate for these new features. The description clearly documents the AI DJ enhancements, privacy notice, and queue monitoring improvements. Based on learnings, minor version type is correct for new features in changesets.

.changeset/brave-playlists-flow.md (1)

1-12: Changeset correctly documents the playlist feature additions.

The minor version type is appropriate for these new playlist browsing and add-to-playlist capabilities.

apps/desktop/src/lib/aiClient.ts (2)

11-41: Well-documented AI Queue and TOON format integration in system prompt.

The system prompt additions provide clear guidance for when to use AI Queue vs. single track playback. The TOON format documentation with examples will help the AI model understand the compact data format.


58-65: Strategy guidelines clearly distinguish continuous vs. single-track playback.

Good prioritization of AI Queue for mood-based and continuous playback requests while preserving single-track functionality for specific song requests.

apps/desktop/src/lib/aiQueueService.ts (1)

261-320: Monitoring logic is well-implemented with appropriate safeguards.

Good handling of:

  • Auto-stop when user starts manual playback outside AI queue
  • Proactive batch fetching when remaining tracks ≤ 2
  • Proper cleanup of interval on stop
  • Error isolation that doesn't crash the monitoring loop
apps/desktop/src-tauri/src/spotify_auth.rs (1)

361-361: OAuth scopes correctly expanded for playlist modification.

The addition of playlist-modify-public and playlist-modify-private scopes enables the new add-to-playlist functionality. This aligns with the PR's playlist management features.

Note: Existing users will need to re-authenticate to grant the new playlist modification permissions. Consider documenting this in release notes or triggering a re-auth flow when users first attempt to add tracks to playlists.

apps/desktop/package.json (1)

22-22: TOON format dependency added for token-efficient data encoding.

The @toon-format/toon package enables the compact data format used in the AI Queue and DJ features to reduce token usage when communicating with LLMs. The package is imported and used in aiQueueService.ts, spotifyTools.ts, and AIDJView.tsx.

apps/desktop/src/ui/components/TrackControls/PlaybackBar.tsx (2)

62-100: LGTM! Correctly removed unnecessary async/await.

The removal of async from handlePointer and endDrag, along with the removal of await on seek() calls, is correct. The seek() function returns void and uses a debounced fire-and-forget pattern, so there was never a Promise to await.


124-136: LGTM! Keyboard seek handling correctly simplified.

The removal of await on seek() calls within the onKeyDown handler is correct and consistent with the other changes in this file.

apps/desktop/src/hooks/useWindowLayout.ts (1)

4-4: LGTM! Layout type correctly extended for Volume view.

The addition of "Volume" to the Layout union is consistent with the corresponding Rust-side Layout::Volume variant in apps/desktop/src-tauri/src/resize.rs.

.changeset/clever-llms-save.md (1)

1-13: LGTM! Changeset format is correct.

The changeset properly follows the required format with correct frontmatter ("MiniFy": minor), appropriate version type for a new feature, and all description lines under the 99-character limit.

apps/desktop/src-tauri/src/resize.rs (2)

12-12: LGTM! Volume variant correctly added to Layout enum.

The Volume variant addition is consistent with the TypeScript-side Layout type in apps/desktop/src/hooks/useWindowLayout.ts (line 4).


25-25: LGTM! Volume layout dimensions are appropriate.

The 300×280 logical size is reasonable for a volume control UI.

apps/desktop/src/ui/components/TrackControls/TrackControls.tsx (2)

12-18: LGTM! Correctly removed unnecessary async from navigation handlers.

The removal of async from handlePrev and handleNext is correct. Both previousTrack() and nextTrack() return void and use a fire-and-forget pattern (as shown in apps/desktop/src/ui/spotifyClient.ts), so there was never a Promise to await.


20-28: LGTM! Toggle handler correctly simplified.

The removal of async and the busy state from handleToggle is correct. The play() and pause() functions return void and use fire-and-forget, making the async handling unnecessary overhead. The optimistic UI update pattern (calling onTogglePlaying before the API call) is consistent with the fire-and-forget approach used throughout the codebase.

.changeset/discord-rich-presence.md (1)

1-13: LGTM!

The changeset is properly formatted with the correct minor version type for a new feature. All description lines are under the 99-character limit, and the content clearly documents the Discord Rich Presence integration.

.changeset/smart-dj-queue.md (1)

1-14: LGTM!

The changeset follows the correct format with minor version type for the new AI Queue feature. All lines comply with the 99-character limit, and the feature description is clear and comprehensive.

apps/desktop/src/lib/settingLib.ts (1)

58-59: LGTM!

The new Settings fields are properly typed as booleans, consistent with TypeScript strict typing guidelines.

apps/desktop/src/hooks/useCurrentlyPlaying.ts (4)

1-3: LGTM!

The new imports follow the coding guidelines by using static imports at the top of the file with proper named imports.


6-20: LGTM!

The updateDiscordPresence function correctly uses Tauri's invoke API and appropriately silences errors since Discord RPC is an optional feature that shouldn't break core functionality if it fails.


24-26: LGTM!

The refs are properly typed and initialized for change detection. Note that on component remount, these refs will reset to their initial values, potentially triggering one redundant Discord presence update. This is acceptable behavior for this use case.


36-53: LGTM!

The change detection logic correctly tracks changes to track ID, playing state, and AI Queue activity. The direct getState() access on line 38 is appropriate here since the function runs on a polling interval, ensuring AI Queue state changes are detected on the next poll cycle (default 3 seconds). This is consistent with how track changes are detected throughout this hook.

apps/desktop/src-tauri/src/lib.rs (4)

4-9: LGTM!

The new module declarations for custom_themes and discord_rpc are properly added to the public module list, maintaining consistency with the Tauri app structure guidelines.


12-17: LGTM!

The Discord state is correctly created before the app builder and properly registered with .manage() for dependency injection. This follows the proper initialization pattern for Tauri managed state.


46-51: LGTM!

All new command handlers are properly registered with correct module namespacing. The Discord RPC handlers (enable_discord_rpc, disable_discord_rpc, update_discord_presence, is_discord_rpc_enabled) and the validate_theme_json handler are correctly formatted in the invoke handler list.


54-57: LGTM!

The Discord RPC initialization is correctly placed in the setup hook after the app is built. The state is properly retrieved using app.state::<discord_rpc::DiscordState>() and passed to init_discord_rpc for startup initialization. The placement after the token refresh task is reasonable.

apps/desktop/src/ui/views/AddToPlaylistView.tsx (1)

30-43: Good implementation of data fetching with proper loading state management.

The effect correctly handles loading state, error catching, and uses a finally block to ensure loading is reset. The empty dependency array is appropriate for a one-time fetch on mount.

apps/desktop/src-tauri/src/settings.rs (2)

18-26: Well-structured addition of new settings fields.

The use of #[serde(default = "default_true")] ensures backward compatibility when deserializing settings files that predate these fields. The default_true() helper is appropriately scoped and reusable. The implementation aligns with the coding guideline to persist settings as JSON under the platform config directory.


56-57: Default implementation correctly mirrors serde defaults.

Both the Default trait implementation and serde defaults are aligned, ensuring consistent behavior whether settings are created fresh or deserialized from incomplete JSON.

apps/desktop/src/ui/views/VolumeView.tsx (1)

33-42: Good use of useCallback for event handlers.

The handlers are properly memoized with empty dependency arrays since they only use state setters (which are stable) and setVolume (imported function).

apps/desktop/src/ui/layouts/LayoutB.tsx (1)

9-13: Good use of typed props with optional callback.

The LayoutBProps type properly marks onAddToPlaylist as optional, allowing the component to be used without the add-to-playlist feature while maintaining type safety.

apps/desktop/src/ui/views/AIDJView.tsx (2)

43-89: Well-designed context building with graceful error handling.

The buildUserContext function uses Promise.all with individual .catch() handlers, ensuring partial context is still provided even if some API calls fail. The TOON encoding for track/artist data is a good optimization for token efficiency.

One minor observation: the outer try-catch at line 82 is redundant since all promises already have individual catch handlers, but it's harmless defensive code.


505-508: Safe optional chaining for next track display.

Good use of optional chaining (aiQueueTracks[aiQueueCurrentIndex + 1]?.name) to safely handle the case when no next track exists.

apps/desktop/src/ui/views/Settings.tsx (3)

365-385: Good error handling for Discord RPC toggle.

The handleToggleDiscordRpc function properly persists the setting first, then attempts to invoke the Tauri command. Errors are caught and logged without breaking the UI. Consider whether the setting should be reverted on failure, but the current behavior (optimistic update with warning log) is acceptable for a non-critical feature.


1158-1205: Excellent privacy disclosure for AI DJ data usage.

The privacy section clearly documents what user data is sent to LLM providers (display name, currently playing, recent tracks, top artists, time of day). This transparency is important for user trust and aligns with good privacy practices.


262-263: Good use of nullish coalescing for settings initialization.

The ?? true fallback ensures backward compatibility when reading settings that may not have these new fields yet, though the serde defaults in Rust should handle this. The defensive approach is appropriate.

apps/desktop/src/ui/views/PlaylistView.tsx (2)

255-259: Good implementation of infinite scroll with loading indicator.

The scroll handler with a 150px threshold, combined with the loading spinner at the bottom of the list, provides a good user experience. The loading="lazy" attribute on images is also a nice performance touch.

Also applies to: 336-343


21-26: Extract formatDuration to a shared utility file to avoid duplication.

This function is duplicated in SearchBar.tsx with identical implementation. Additionally, PlaybackBar.tsx has an equivalent msToTime function that does the same thing. Extract this utility to a shared location (e.g., apps/desktop/src/ui/utils.ts) and import it in all three components.

apps/desktop/src/lib/aiQueueStore.ts (2)

77-85: Verify: reset() preserves cachedUserProfile and lastFetchTime.

The reset() function doesn't clear cachedUserProfile or lastFetchTime. If this is intentional (to preserve the profile cache across queue resets), consider adding a comment. Otherwise, add these fields to the reset.


1-41: LGTM!

Well-structured Zustand store with clean TypeScript interfaces. The QueuedTrack interface is properly exported, and the state shape is well-defined with appropriate types including Set<string> for deduplication.

apps/desktop/src-tauri/src/discord_rpc.rs (5)

9-27: LGTM!

Clean struct design with appropriate thread-safe state management using Mutex. The Default trait implementation delegates to new() following Rust best practices.


29-42: LGTM!

Helper functions are well-implemented with appropriate error mapping.


44-85: LGTM!

The enable_discord_rpc command properly acquires locks in sequence and handles client creation with appropriate error propagation.


87-108: LGTM!

The disable_discord_rpc command properly clears activity, closes the client, and resets state.


204-223: LGTM!

The init_discord_rpc function appropriately silences errors during initialization, as Discord may not be running. This is the correct behavior for optional integrations.

apps/desktop/src/ui/index.tsx (4)

26-31: LGTM!

Good TypeScript type definitions for AppView and AddToPlaylistTrack. The union type for views is clear and the nullable track type is well-defined.


96-122: LGTM!

Context menu items are properly added for the new Playlist and Volume views, with consistent handling for both AI-enabled and non-AI menu variants.


204-221: LGTM!

View rendering logic is clean with proper prop passing. The AddToPlaylistView correctly receives nullable trackId and trackName props, and the onBack handler properly clears the track state.


169-179: Verify: onAddToPlaylist only passed to LayoutB.

Only LayoutB receives the onAddToPlaylist handler. If this is intentional (different layouts have different feature sets), this is fine. Otherwise, consider extending to other layouts.

apps/desktop/src/lib/spotifyTools.ts (4)

28-51: LGTM!

Well-implemented TOON format helpers with concise property names (n, a, u, g, p, id) for token efficiency. The functions are pure and properly typed.


139-160: LGTM!

Tool descriptions clearly document the TOON format output structure, helping AI models understand the response shape.


451-484: LGTM!

The startAIQueueWithMood tool properly uses useAIQueueStore.getState() to access the store outside React, includes appropriate pre-condition checking for active queues, and has good error handling.


486-522: LGTM!

Both tools properly access store state and return appropriate status information. The getAIQueueStatus provides useful queue metadata including remaining tracks and next track preview.

apps/desktop/src/ui/spotifyClient.ts (5)

32-47: LGTM!

Good token caching implementation with a 1-minute buffer before expiry to prevent edge cases. The cache invalidation on 401 (line 82) ensures stale tokens are refreshed.


56-114: LGTM!

Request deduplication is well-implemented with proper cleanup in finally(). The cache key construction and GET-only deduplication are appropriate design choices.


146-206: LGTM!

Debounced implementations for seek and volume are well-designed to reduce API flooding during slider interactions. Value clamping and timeout management are correct.


405-474: LGTM!

New playlist and queue APIs are well-implemented with proper typing. The fetchPlaylistTracks correctly filters out null tracks (which can occur for unavailable/deleted tracks in playlists).


116-121: LGTM!

The fireAndForget pattern is appropriate for player commands where we don't need to block on the response. Error logging to console.warn provides visibility without breaking the UI.

Comment on lines +40 to +41
discord-rich-presence = "0.2"
log = "0.4"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check latest versions of added crates
echo "Checking discord-rich-presence:"
curl -s https://crates.io/api/v1/crates/discord-rich-presence | jq '.crate.max_stable_version'

echo "Checking log:"
curl -s https://crates.io/api/v1/crates/log | jq '.crate.max_stable_version'

Repository: ModioStudio/MiniFy

Length of output: 124


🏁 Script executed:

# Search for usage of discord-rich-presence and log crates in the codebase
echo "=== Searching for discord-rich-presence usage ==="
rg "discord" --type rust -i

echo "=== Searching for log crate usage ==="
rg "use log" --type rust

Repository: ModioStudio/MiniFy

Length of output: 3108


🏁 Script executed:

# Check if discord_rpc.rs module exists and examine it
fd "discord" --type f

Repository: ModioStudio/MiniFy

Length of output: 103


Update discord-rich-presence to version 1.0.0; clarify purpose of log dependency.

The discord-rich-presence crate version 0.2 is severely outdated—the latest stable version is 1.0.0. Update this dependency to benefit from bug fixes, security patches, and API improvements. Additionally, the log crate has been added but appears unused in the codebase. Either integrate logging into the discord_rpc module or remove this unnecessary dependency.

🤖 Prompt for AI Agents
In apps/desktop/src-tauri/Cargo.toml around lines 40-41, update the
discord-rich-presence dependency from "0.2" to "1.0.0" to use the latest stable
release, and address the added log = "0.4" entry by either removing it from
Cargo.toml if unused or integrating it: add appropriate log calls (and a logger
initialization like env_logger or tracing) in the discord_rpc module so the
dependency is actually used; ensure Cargo.toml reflects the change and run cargo
update/build to verify compatibility with the new discord-rich-presence API.

Comment thread apps/desktop/src/lib/aiQueueService.ts
Comment thread apps/desktop/src/lib/aiQueueService.ts Outdated
Comment thread apps/desktop/src/lib/aiQueueService.ts
Comment thread apps/desktop/src/lib/aiQueueService.ts
Comment thread apps/desktop/src/ui/views/PlaylistView.tsx Outdated
- Removed unused splash screen and context menu components to streamline the UI.
- Enhanced AI queue service with better error handling for AI suggestions parsing.
- Updated playlist view to utilize a ref for tracking loaded tracks, improving performance and accuracy in loading more tracks.
- Simplified keyboard shortcuts in the app for better user experience.
- Cleaned up CSS by removing obsolete splash screen animations.
@Skeptic-systems Skeptic-systems merged commit b5e530b into main Jan 2, 2026
2 of 3 checks passed
@Skeptic-systems Skeptic-systems deleted the feature/ai-queue branch January 2, 2026 17:54
@coderabbitai coderabbitai Bot mentioned this pull request Jan 7, 2026
22 tasks
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.

1 participant