feat: Cache MPRIS artwork from HTTPS URLs to local files and update t…#33
feat: Cache MPRIS artwork from HTTPS URLs to local files and update t…#33josueygp wants to merge 1 commit intowimpysworld:mainfrom
Conversation
…he metadata key to `mpris:artUrl`.
There was a problem hiding this comment.
3 issues found across 1 file
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/integrations/mpris/index.ts">
<violation number="1" location="src/integrations/mpris/index.ts:645">
P2: Artwork cache file extension is derived unsafely from full URL, allowing path separators/traversal-like tokens in generated cache paths.</violation>
<violation number="2" location="src/integrations/mpris/index.ts:652">
P2: Async artwork callbacks can race and overwrite MPRIS metadata/trackId with stale track data because no track-change guard is checked before calling setMetadata.</violation>
<violation number="3" location="src/integrations/mpris/index.ts:657">
P2: HTTPS artwork download path lacks timeout and stream/response error handling, risking hangs and unhandled stream failures.</violation>
</file>
Since this is your first cubic review, here's how it works:
- cubic automatically reviews your code and comments on bugs and improvements
- Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
- Add one-off context when rerunning by tagging
@cubic-dev-aiwith guidance or docs links (includingllms.txt) - Ask questions if you need clarification on any suggestion
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| require('fs').mkdirSync(cacheDir, { recursive: true }); | ||
| } | ||
| const hash = crypto.createHash('md5').update(p.artworkUrl).digest('hex'); | ||
| const ext = p.artworkUrl.split('.').pop()?.split('?')[0] || 'jpg'; |
There was a problem hiding this comment.
P2: Artwork cache file extension is derived unsafely from full URL, allowing path separators/traversal-like tokens in generated cache paths.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/integrations/mpris/index.ts, line 645:
<comment>Artwork cache file extension is derived unsafely from full URL, allowing path separators/traversal-like tokens in generated cache paths.</comment>
<file context>
@@ -609,14 +622,62 @@ function onNowPlayingItemDidChange(payload: unknown): void {
+ require('fs').mkdirSync(cacheDir, { recursive: true });
+ }
+ const hash = crypto.createHash('md5').update(p.artworkUrl).digest('hex');
+ const ext = p.artworkUrl.split('.').pop()?.split('?')[0] || 'jpg';
+ const filepath = path.join(cacheDir, `sidra-art-${hash}.${ext}`);
+ const fileUrl = `file://${filepath}`;
</file context>
| fsp.stat(filepath) | ||
| .then(() => { | ||
| metadata['mpris:artUrl'] = new Variant('s', fileUrl); | ||
| setMetadata(); |
There was a problem hiding this comment.
P2: Async artwork callbacks can race and overwrite MPRIS metadata/trackId with stale track data because no track-change guard is checked before calling setMetadata.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/integrations/mpris/index.ts, line 652:
<comment>Async artwork callbacks can race and overwrite MPRIS metadata/trackId with stale track data because no track-change guard is checked before calling setMetadata.</comment>
<file context>
@@ -609,14 +622,62 @@ function onNowPlayingItemDidChange(payload: unknown): void {
+ fsp.stat(filepath)
+ .then(() => {
+ metadata['mpris:artUrl'] = new Variant('s', fileUrl);
+ setMetadata();
+ })
+ .catch(() => {
</file context>
| .catch(() => { | ||
| https.get(p.artworkUrl as string, (res: any) => { | ||
| if (res.statusCode === 200) { | ||
| const stream = createWriteStream(filepath); |
There was a problem hiding this comment.
P2: HTTPS artwork download path lacks timeout and stream/response error handling, risking hangs and unhandled stream failures.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/integrations/mpris/index.ts, line 657:
<comment>HTTPS artwork download path lacks timeout and stream/response error handling, risking hangs and unhandled stream failures.</comment>
<file context>
@@ -609,14 +622,62 @@ function onNowPlayingItemDidChange(payload: unknown): void {
+ .catch(() => {
+ https.get(p.artworkUrl as string, (res: any) => {
+ if (res.statusCode === 200) {
+ const stream = createWriteStream(filepath);
+ res.pipe(stream);
+ stream.on('finish', () => {
</file context>
flexiondotorg
left a comment
There was a problem hiding this comment.
Thanks for this, the fixes look useful and are welcome.
I'd ask that you split this into separate, focused pull requests, one per concern:
- Fix MPRIS metadata property name (
xesam:artUrl→mpris:artUrl) - Add local artwork caching (download HTTPS URLs to
file://URIs) - Resolve GNOME Shell premature caching (orchestrate metadata emission after artwork is ready)
Each change is independently reviewable and revertable, which keeps the git history clean and makes bisecting easier. Please reference this PR in each new one for context, but I'll close this pull request.
Description
This Pull Request overhauls the MPRIS artwork integration to ensure compatibility with strict desktop environments like GNOME Shell, which previously failed to display any album art from Sidra. The fix targets three core architectural issues related to how the D-Bus Metadata payload is handled.
Key Changes & Justification
Fixed Metadata Property Name (
xesam:artUrl→mpris:artUrl)According to the official MPRIS v2 D-Bus Interface Specification, while most track information utilizes the
xesam:ontology (likexesam:title,xesam:artist), the album art URL is an exception and must be populated under thempris:artUrlkey. The previous code was incorrectly assigning it toxesam:artUrl, causing strict MPRIS clients to discard the property entirely.Implemented Local Image Caching (
file://URIs)Many Linux desktop environments (most notably GNOME's built-in media controls) deliberately reject remote
https://URLs for security and performance reasons.app.getPath('userData')/art(e.g.,~/.config/sidra/art).https://URL is still emitted immediately as a fallback for more tolerant environments like KDE Plasma.file:///...URI.userDatainstead ofcacheto prevent AppImage FUSE mounting bugs, ensuring the host OS can successfully traverse and read the cached image path.Resolved GNOME Shell's Premature Caching Bug
GNOME Shell contains an aggressive optimization behavior where it ignores subsequent D-Bus metadata updates if the
mpris:trackidremains unchanged. To bypass this, the onNowPlayingItemDidChange property emission is now smartly wrapped in a setMetadata() orchestrator. The initialPropertiesChangedpayload is emitted only after the local artwork is verified or downloaded, guaranteeing GNOME receives the complete payload (with the localfile://URI) on its very first read.Testing