Skip to content

fix(fullAppDisplay): use GraphQL to fetch album date#3733

Open
cvius wants to merge 3 commits intospicetify:mainfrom
cvius:fad
Open

fix(fullAppDisplay): use GraphQL to fetch album date#3733
cvius wants to merge 3 commits intospicetify:mainfrom
cvius:fad

Conversation

@cvius
Copy link

@cvius cvius commented Mar 11, 2026

Summary by CodeRabbit

  • Bug Fixes
    • Album release dates are now retrieved more reliably via an updated data retrieval method.
    • Improved handling of incomplete dates—shows year when month/day are missing.
    • Fully specified dates display consistently using localized numeric year, short month, and day.
    • Missing, invalid, or errored date data is gracefully ignored to avoid incorrect displays.

@coderabbitai
Copy link

coderabbitai bot commented Mar 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 35f3a61e-5f19-45ad-9c9a-39389e88020b

📥 Commits

Reviewing files that changed from the base of the PR and between 021039a and eb5a573.

📒 Files selected for processing (1)
  • Extensions/fullAppDisplay.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • Extensions/fullAppDisplay.js

📝 Walkthrough

Walkthrough

getAlbumDate() in Extensions/fullAppDisplay.js now uses a GraphQL request (getAlbum) with the album URI (and locale/offset/limit), reads albumUnion.date from the GraphQL response, returns null on errors, returns just the year when precision is YEAR, otherwise returns a localized date string (year numeric, month short, day numeric).

Changes

Cohort / File(s) Summary
Album Date GraphQL Fetch & Parsing
Extensions/fullAppDisplay.js
Rewrote getAlbumDate() to call the GraphQL getAlbum query using the album uri (with locale/offset/limit), handle errors by returning null, parse albumUnion.date, return year-only when precision === 'YEAR', otherwise build a localized date string from albumDate.isoString. Removed prior Cosmos/metadata fetch path and related parsing logic.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 I hop on GraphQL paths with gleeful cheer,
I fetch the album date and hold it near,
If only the year peeks through the hay,
I show just the year — otherwise the full day,
A rabbit’s tidy hop to keep dates clear.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: switching from a Cosmos API approach to a GraphQL-based approach for fetching album dates in fullAppDisplay.js.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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

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.

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: 2

🧹 Nitpick comments (1)
Extensions/fullAppDisplay.js (1)

471-471: Redundant await on already resolved value.

response is already the resolved value from await ...send() on line 469. The additional await here is unnecessary.

♻️ Suggested fix
-			const albumInfo = await response;
-			if (!albumInfo?.ok) return null;
+			if (!response?.ok) return null;
+
+			const albumDate = response.body?.date;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Extensions/fullAppDisplay.js` at line 471, Remove the redundant await when
assigning albumInfo: the variable response is already resolved (from the prior
await ...send()), so change the assignment in Extensions/fullAppDisplay.js that
uses albumInfo and response to a direct assignment (albumInfo = response) rather
than awaiting response; update references to the variable if needed and ensure
no other code depends on response being a Promise.
🤖 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/fullAppDisplay.js`:
- Around line 462-469: Wrap the Spicetify.Platform.RequestBuilder usage in a
try-catch and guard against the RequestBuilder being undefined: verify
Spicetify.Platform && Spicetify.Platform.RequestBuilder exist before calling
RequestBuilder.build(), then call
build().withHost(...).withPath(path).withEndpointIdentifier(path).send() inside
a try block and handle failures in catch by logging the error (or returning a
safe fallback) so the caller won’t crash; keep using Spicetify.URI.idToHex(id)
for path construction but ensure any exceptions from idToHex or the network call
are caught and handled consistently with other network helpers like
Spicetify.CosmosAsync.get().
- Around line 465-472: The network request using
Spicetify.Platform.RequestBuilder.build().withHost(...).withPath(...).withEndpointIdentifier(...).send()
can throw; wrap that call (and the subsequent await of response/albumInfo) in a
try-catch inside the fetchInfo function, catch any errors, log them via the
existing logging mechanism (or Spicetify.showNotification/processLogger) and
return null on failure so the UI update flow doesn't break; specifically modify
the block that defines response/albumInfo to perform the send() and await inside
try { ... } and move the existing if (!albumInfo?.ok) return null into that try,
with the catch handling errors and returning null.

---

Nitpick comments:
In `@Extensions/fullAppDisplay.js`:
- Line 471: Remove the redundant await when assigning albumInfo: the variable
response is already resolved (from the prior await ...send()), so change the
assignment in Extensions/fullAppDisplay.js that uses albumInfo and response to a
direct assignment (albumInfo = response) rather than awaiting response; update
references to the variable if needed and ensure no other code depends on
response being a Promise.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9d90974f-9572-450d-87a9-507c703972cd

📥 Commits

Reviewing files that changed from the base of the PR and between 40008f8 and 52b1313.

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

Comment on lines +462 to +469
const id = uri.split(":")[2];
const path = `/album/${Spicetify.URI.idToHex(id)}`;

const albumInfo = await Spicetify.CosmosAsync.get(`https://api.spotify.com/v1/albums/${id}`);
const response = await Spicetify.Platform.RequestBuilder.build()
.withHost("https://spclient.wg.spotify.com/metadata/4")
.withPath(path)
.withEndpointIdentifier(path)
.send();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for existing usage of these Spicetify APIs in the codebase

echo "=== Searching for RequestBuilder usage ==="
rg -n "RequestBuilder" --type js -C3

echo ""
echo "=== Searching for idToHex usage ==="
rg -n "idToHex" --type js -C3

echo ""
echo "=== Searching for similar metadata endpoint patterns ==="
rg -n "spclient.wg.spotify.com" --type js -C2

Repository: spicetify/cli

Length of output: 4137


🏁 Script executed:

#!/bin/bash
# Search for response handling patterns to verify response structure

echo "=== Searching for response.ok usage ==="
rg -n "\.ok" --type js -C2 | head -40

echo ""
echo "=== Searching for response.body usage ==="
rg -n "response\.body" --type js -C2 | head -40

echo ""
echo "=== Checking the context around the getAlbumDate function ==="
sed -n '460,475p' Extensions/fullAppDisplay.js

echo ""
echo "=== Searching for any Platform.RequestBuilder documentation or comments ==="
rg -n "Platform" --type js -C1 | grep -i "builder\|request" -B2 -A2

Repository: spicetify/cli

Length of output: 2968


🏁 Script executed:

#!/bin/bash
# Search for context and error handling around getAlbumDate and RequestBuilder

echo "=== Full context of getAlbumDate function ==="
sed -n '455,490p' Extensions/fullAppDisplay.js

echo ""
echo "=== Search for any error handling or try-catch around this function ==="
rg -n "getAlbumDate" --type js -B5 -A15

echo ""
echo "=== Search for any Spicetify.Platform references with more context ==="
rg -n "Spicetify\.Platform" --type js -C3

echo ""
echo "=== Check if there are any imports or initialization of Platform.RequestBuilder ==="
rg -n "Platform\." --type js -C2 | head -60

Repository: spicetify/cli

Length of output: 46929


Add error handling for RequestBuilder call.

Spicetify.URI.idToHex exists and is properly defined, but Spicetify.Platform.RequestBuilder is an undocumented internal API with no other usages in the codebase. Wrap the RequestBuilder.build().send() call in a try-catch block to handle potential failures. Additionally, verify this API is available and stable across target Spotify versions, as it deviates from the standard patterns used elsewhere (e.g., Spicetify.CosmosAsync.get() in jsHelper/spicetifyWrapper.js:1534-1539).

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

In `@Extensions/fullAppDisplay.js` around lines 462 - 469, Wrap the
Spicetify.Platform.RequestBuilder usage in a try-catch and guard against the
RequestBuilder being undefined: verify Spicetify.Platform &&
Spicetify.Platform.RequestBuilder exist before calling RequestBuilder.build(),
then call
build().withHost(...).withPath(path).withEndpointIdentifier(path).send() inside
a try block and handle failures in catch by logging the error (or returning a
safe fallback) so the caller won’t crash; keep using Spicetify.URI.idToHex(id)
for path construction but ensure any exceptions from idToHex or the network call
are caught and handled consistently with other network helpers like
Spicetify.CosmosAsync.get().

Comment on lines +465 to +472
const response = await Spicetify.Platform.RequestBuilder.build()
.withHost("https://spclient.wg.spotify.com/metadata/4")
.withPath(path)
.withEndpointIdentifier(path)
.send();

const albumDate = new Date(albumInfo.release_date);
return albumDate.toLocaleString("default", {
const albumInfo = await response;
if (!albumInfo?.ok) return null;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing error handling for network request.

The RequestBuilder.send() call can throw on network failures, timeouts, or other request errors. Without a try-catch, this will propagate as an uncaught exception and could break the UI update flow in fetchInfo().

🛡️ Suggested fix to add error handling
 		async getAlbumDate(uri) {
 			const id = uri.split(":")[2];
 			const path = `/album/${Spicetify.URI.idToHex(id)}`;

+			try {
 			const response = await Spicetify.Platform.RequestBuilder.build()
 				.withHost("https://spclient.wg.spotify.com/metadata/4")
 				.withPath(path)
 				.withEndpointIdentifier(path)
 				.send();

-			const albumInfo = await response;
-			if (!albumInfo?.ok) return null;
+			if (!response?.ok) return null;

-			const albumDate = albumInfo.body?.date;
+			const albumDate = response.body?.date;
 			if (!albumDate?.year) return null;

 			if (!albumDate.month || !albumDate.day) {
 				return albumDate.year.toString();
 			}

 			const date = new Date(
 				albumDate.year,
 				albumDate.month - 1,
 				albumDate.day
 			);

 			return date.toLocaleString("default", {
 				year: "numeric",
 				month: "short",
 				day: "numeric",
 			});
+			} catch {
+				return null;
+			}
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Extensions/fullAppDisplay.js` around lines 465 - 472, The network request
using
Spicetify.Platform.RequestBuilder.build().withHost(...).withPath(...).withEndpointIdentifier(...).send()
can throw; wrap that call (and the subsequent await of response/albumInfo) in a
try-catch inside the fetchInfo function, catch any errors, log them via the
existing logging mechanism (or Spicetify.showNotification/processLogger) and
return null on failure so the UI update flow doesn't break; specifically modify
the block that defines response/albumInfo to perform the send() and await inside
try { ... } and move the existing if (!albumInfo?.ok) return null into that try,
with the catch handling errors and returning null.

@rxri
Copy link
Member

rxri commented Mar 11, 2026

Why not GraphQL endpoint?

@cvius cvius changed the title fix(fullAppDisplay): use internal endpoint to fetch album date fix(fullAppDisplay): use GraphQL to fetch album date Mar 11, 2026
@cvius
Copy link
Author

cvius commented Mar 11, 2026

Why not GraphQL endpoint?

done

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.

2 participants