Skip to content

fix: update loopyLoop to handle Spotify DOM restructuring#3724

Merged
rxri merged 4 commits intospicetify:mainfrom
yuvibirdi:main
Mar 7, 2026
Merged

fix: update loopyLoop to handle Spotify DOM restructuring#3724
rxri merged 4 commits intospicetify:mainfrom
yuvibirdi:main

Conversation

@yuvibirdi
Copy link
Contributor

@yuvibirdi yuvibirdi commented Mar 6, 2026

  • Progress bar selector .playback-bar .progress-bar no longer matches, Spotify restructured the playback bar DOM with new hashed classes not present in the CSS map
  • Replaced selector with structural DOM traversal via .playback-progressbar-container and input[type="range"]
  • Replaced ReactDOM.render(MenuItem) with plain HTML menu items since,MenuItem now requires React Router context (StableUseNavigateProvider) which isn't available when rendering into a detached div
  • Removed unnecessary async/webpackLoaded dependency since React components are no longer used

Summary by CodeRabbit

  • Refactor

    • Faster, leaner initialization for improved responsiveness.
    • Menu rendering simplified to plain DOM elements; items are accessible buttons with direct event wiring.
    • Context menu now triggers from the progress area and uses element bounds for more reliable placement.
  • Bug Fixes

    • Pointer position clamped to valid bounds to prevent out-of-range interactions and improve positioning stability.

Copilot AI review requested due to automatic review settings March 6, 2026 20:45
@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

📝 Walkthrough

Walkthrough

Rewrote Extensions/loopyLoop.js to initialize synchronously (removed webpackLoaded await), replace React-rendered context menu with plain DOM li/button elements, move context-menu trigger to the progress container, and compute/position bar percent using the bar's bounding rect with clamping.

Changes

Cohort / File(s) Summary
loopyLoop Refactor
Extensions/loopyLoop.js
Replaced async IIFE with synchronous IIFE and removed webpackLoaded await; replaced React menu rendering with plain DOM li/button items and onclick handlers; switched context-menu trigger from bar to progress container; compute mouseOnBarPercent via bar.getBoundingClientRect() and clamp to [0,1]; updated context-menu positioning to use bar bounding rect and menu height; preserved start/end/reset and drawing logic with simplified DOM paths.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I nibbled at async, made DOM my tune,
Synchronous hops beneath the moon,
Buttons for menus, no JSX to chew,
Clamped the percent, positioned true,
A tidy loop — a rabbit's small boon.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 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 summarizes the main change: updating loopyLoop to handle Spotify DOM restructuring, which matches the core objective of the PR.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@yuvibirdi yuvibirdi changed the title Fixd LoopyLoop.js Fixed LoopyLoop.js Mar 6, 2026
@yuvibirdi yuvibirdi changed the title Fixed LoopyLoop.js Fixed loopyLoop.js Mar 6, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the Loopy loop Spicetify extension to keep working with Spotify’s updated playback bar DOM and recent React component context requirements by switching to structural DOM traversal and a non-React context menu.

Changes:

  • Replace the progress bar element lookup with traversal via .playback-progressbar-container and input[type="range"].
  • Replace ReactComponent.MenuItem rendering with plain HTML menu items.
  • Remove the async IIFE / Spicetify.Events.webpackLoaded wait previously used for React rendering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@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.

🧹 Nitpick comments (2)
Extensions/loopyLoop.js (2)

80-89: Consider adding accessibility attributes for keyboard navigation.

The plain DOM menu items work but may lack accessibility features that the React MenuItem component provides (e.g., role, tabindex, keyboard event handling). For consistency with Spotify's UX:

♿ Suggested accessibility improvements
 function createMenuItem(title, callback) {
   const item = document.createElement("li");
   item.classList.add("main-contextMenu-menuItemButton");
+  item.setAttribute("role", "menuitem");
+  item.setAttribute("tabindex", "-1");
   item.textContent = title;
   item.onclick = () => {
     contextMenu.hidden = true;
     callback?.();
   };
+  item.onkeydown = (e) => {
+    if (e.key === "Enter" || e.key === " ") {
+      contextMenu.hidden = true;
+      callback?.();
+    }
+  };
   return item;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Extensions/loopyLoop.js` around lines 80 - 89, The createMenuItem function
creates plain <li> elements that lack accessibility attributes and keyboard
handling; update createMenuItem to set ARIA/role and focusability (e.g., set
role="menuitem" and tabindex="0" on the created item), add keyboard event
handling for Enter/Space to invoke the callback (mirror the existing
item.onclick behavior), and ensure hiding the contextMenu and calling callback
via the same handler; reference createMenuItem, contextMenu, and the
"main-contextMenu-menuItemButton" class when making these changes.

12-12: Fragile DOM traversal assumption.

The selector rangeInput?.closest("label")?.nextElementSibling assumes a specific DOM structure where the progress bar is the next sibling of a label containing the range input. This structural dependency could break if Spotify reorganizes the DOM again (which is the very reason this PR exists).

Consider adding a fallback query or a more robust selector strategy, and/or adding a comment documenting the expected structure for future maintainers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Extensions/loopyLoop.js` at line 12, The DOM traversal using
rangeInput?.closest("label")?.nextElementSibling (variable bar) is brittle;
change it to try more robust fallbacks: first attempt the existing
closest("label") path, then if that yields no valid progress element, search
upward for a common parent (e.g., closest container element) and run a
querySelector for known progress/progress-bar selectors or elements (e.g.,
[role="progressbar"], .progress, .progress-bar, svg.progress) and validate the
found element before using it; add a short code comment next to the
rangeInput/bar logic documenting the expected DOM relationship and why the
fallback queries exist so future maintainers understand the intent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Extensions/loopyLoop.js`:
- Around line 80-89: The createMenuItem function creates plain <li> elements
that lack accessibility attributes and keyboard handling; update createMenuItem
to set ARIA/role and focusability (e.g., set role="menuitem" and tabindex="0" on
the created item), add keyboard event handling for Enter/Space to invoke the
callback (mirror the existing item.onclick behavior), and ensure hiding the
contextMenu and calling callback via the same handler; reference createMenuItem,
contextMenu, and the "main-contextMenu-menuItemButton" class when making these
changes.
- Line 12: The DOM traversal using
rangeInput?.closest("label")?.nextElementSibling (variable bar) is brittle;
change it to try more robust fallbacks: first attempt the existing
closest("label") path, then if that yields no valid progress element, search
upward for a common parent (e.g., closest container element) and run a
querySelector for known progress/progress-bar selectors or elements (e.g.,
[role="progressbar"], .progress, .progress-bar, svg.progress) and validate the
found element before using it; add a short code comment next to the
rangeInput/bar logic documenting the expected DOM relationship and why the
fallback queries exist so future maintainers understand the intent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 66dcab70-0807-455c-a85d-60a2dfe2bb0e

📥 Commits

Reviewing files that changed from the base of the PR and between c430e68 and 7218a53.

📒 Files selected for processing (1)
  • Extensions/loopyLoop.js

@yuvibirdi yuvibirdi changed the title Fixed loopyLoop.js Update loopyLoop.js to handle Spotify DOM restructuring Mar 6, 2026
Copy link

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Extensions/loopyLoop.js`:
- Around line 8-16: The init loop in LoopyLoop currently only waits for DOM
elements and can still attach Spicetify.Player listeners too early; update
LoopyLoop so it also waits for Spicetify to be ready by checking for
Spicetify?.Events?.webpackLoaded (or listening for that event) before finishing
init and before any call to Spicetify.Player.addEventListener; e.g., if
Spicetify.Events.webpackLoaded hasn’t fired, register a one-time handler to
continue initialization (or poll Spicetify?.Player existence) and only attach
player event listeners after that readiness check to avoid race conditions with
the wrapper that makes the API safe.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: aa2a58b0-a1da-4db5-bde6-6718bf6d8a72

📥 Commits

Reviewing files that changed from the base of the PR and between 7218a53 and 97972fb.

📒 Files selected for processing (1)
  • Extensions/loopyLoop.js

Copy link

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Extensions/loopyLoop.js`:
- Around line 80-92: In createMenuItem, the class
main-contextMenu-menuItemButton is applied to the li but the interactive element
is the inner button, so move the class to the button element: remove
classList.add on the li and instead add
classList.add("main-contextMenu-menuItemButton") to the button, keep the li
role="menuitem" and append the button as before, and ensure existing button
event handlers (onclick) remain attached so hover/focus CSS selectors in
Themes/SpicetifyDefault/user.css (e.g., .main-contextMenu-menuItemButton:hover
and :focus) will match.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a2688863-0ac3-4066-b827-e821798b2426

📥 Commits

Reviewing files that changed from the base of the PR and between 97972fb and da4be53.

📒 Files selected for processing (1)
  • Extensions/loopyLoop.js

@yuvibirdi yuvibirdi changed the title Update loopyLoop.js to handle Spotify DOM restructuring fix: Update loopyLoop.js to handle Spotify DOM restructuring Mar 6, 2026
@yuvibirdi yuvibirdi changed the title fix: Update loopyLoop.js to handle Spotify DOM restructuring fix: update loopyLoop.js to handle Spotify DOM restructuring Mar 6, 2026
@rxri rxri changed the title fix: update loopyLoop.js to handle Spotify DOM restructuring fix: update loopyLoop to handle Spotify DOM restructuring Mar 7, 2026
@rxri rxri merged commit a5a81e3 into spicetify:main Mar 7, 2026
7 of 10 checks passed
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.

3 participants