Skip to content

Commit b267734

Browse files
committed
fetch cover art image locally on Linux
1 parent 788179e commit b267734

22 files changed

+241
-145
lines changed

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,10 @@ localApi.registerListener(new SpotifyListener() {
5858
public void onTrackChanged(Track track) {
5959
System.out.printf("Track changed: %s (%s)\n", track, formatDuration(track.getLength()));
6060

61-
// You could use the OpenSpotifyAPI to request the track cover image
62-
// try {
63-
// BufferedImage imageTrackCover = openApi.requestImage(track);
64-
// System.out.println("Loaded track cover: " + imageTrackCover.getWidth() + "x" + imageTrackCover.getHeight());
65-
// } catch (Exception e) {
66-
// System.out.println("Could not load track cover: " + e.getMessage());
67-
// }
61+
if (track.getCoverArt() != null) {
62+
BufferedImage coverArt = track.getCoverArt();
63+
System.out.println("Track cover: " + coverArt.getWidth() + "x" + coverArt.getHeight());
64+
}
6865
}
6966

7067
@Override
@@ -106,20 +103,23 @@ localApi.registerListener(new SpotifyListener() {
106103
localApi.initialize();
107104
```
108105

109-
Fetch an image of the current playing track:
106+
Request information of any track id using open.spotify.com:
110107
```java
111108
// Create a secret provider
112109
SecretProvider secretProvider = new DefaultSecretProvider(
113110
// Note: You have to update the secret with the latest TOTP secret from open.spotify.com
114111
// or find a way to retrieve it automatically from their website
115-
Secret.fromString("meZcB\\tlUFV1D6W2Hy4@9+$QaH5)N8", 9)
112+
Secret.fromString("=n:b#OuEfH\fE])e*K", 10)
116113
);
117114

118115
// Create an instance of the Open Spotify API
119116
OpenSpotifyAPI openSpotifyAPI = new OpenSpotifyAPI(secretProvider);
120117

121-
// Download the cover art of the current song
122-
BufferedImage imageTrackCover = openSpotifyAPI.requestImage(track);
118+
// Fetch cover art image by track id
119+
BufferedImage coverArt = openSpotifyAPI.requestImage(trackId);
120+
121+
// Fetch track information by track id
122+
OpenTrack openTrack = openSpotifyAPI.requestOpenTrack(trackId);
123123
```
124124

125125
You can also skip the current song using the Media Key API:

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
}
55

66
group 'de.labystudio'
7-
version '1.4.3'
7+
version '1.4.4'
88

99
compileJava {
1010
sourceCompatibility = '1.8'

src/main/java/de/labystudio/spotifyapi/model/Track.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package de.labystudio.spotifyapi.model;
22

3+
import java.awt.image.BufferedImage;
4+
35
/**
46
* A Spotify track containing the track id, name, artist and length of a song.
57
*
@@ -13,11 +15,20 @@ public class Track {
1315

1416
private final int length;
1517

16-
public Track(String id, String name, String artist, int length) {
18+
private final BufferedImage coverArt;
19+
20+
public Track(
21+
String id,
22+
String name,
23+
String artist,
24+
int length,
25+
BufferedImage coverArt
26+
) {
1727
this.id = id;
1828
this.name = name;
1929
this.artist = artist;
2030
this.length = length;
31+
this.coverArt = coverArt;
2132
}
2233

2334
public String getId() {
@@ -36,6 +47,10 @@ public int getLength() {
3647
return this.length;
3748
}
3849

50+
public BufferedImage getCoverArt() {
51+
return this.coverArt;
52+
}
53+
3954
@Override
4055
public boolean equals(Object obj) {
4156
return obj instanceof Track && this.id.equals(((Track) obj).id);

src/main/java/de/labystudio/spotifyapi/open/model/track/OpenTrack.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package de.labystudio.spotifyapi.open.model.track;
22

33
import com.google.gson.annotations.SerializedName;
4-
import de.labystudio.spotifyapi.model.Track;
54

65
import java.util.List;
76

@@ -83,13 +82,4 @@ public String getArtists(String delimiter) {
8382

8483
return builder.substring(delimiter.length());
8584
}
86-
87-
/**
88-
* Create a new {@link Track} based on the current object.
89-
*
90-
* @return The new {@link Track} object
91-
*/
92-
public Track toTrack() {
93-
return new Track(this.id, this.name, this.getArtists(), this.durationMs);
94-
}
9585
}

src/main/java/de/labystudio/spotifyapi/platform/linux/LinuxSpotifyApi.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
import de.labystudio.spotifyapi.model.Track;
66
import de.labystudio.spotifyapi.platform.AbstractTickSpotifyAPI;
77
import de.labystudio.spotifyapi.platform.linux.api.MPRISCommunicator;
8+
import de.labystudio.spotifyapi.platform.linux.api.model.Metadata;
89

10+
import javax.imageio.ImageIO;
11+
import java.awt.image.BufferedImage;
12+
import java.net.URL;
913
import java.util.Objects;
1014

1115
/**
@@ -29,23 +33,26 @@ public class LinuxSpotifyApi extends AbstractTickSpotifyAPI {
2933

3034
@Override
3135
protected void onTick() throws Exception {
32-
String trackId = this.mediaPlayer.getTrackId();
36+
Metadata metadata = this.mediaPlayer.readMetadata();
37+
String trackId = metadata.getTrackId();
3338

3439
// Handle on connect
35-
if (!this.connected && !trackId.isEmpty()) {
40+
if (!this.connected) {
3641
this.connected = true;
3742
this.listeners.forEach(SpotifyListener::onConnect);
3843
}
3944

4045
// Handle track changes
41-
if (!Objects.equals(trackId, this.currentTrack == null ? null : this.currentTrack.getId())) {
42-
String trackName = this.mediaPlayer.getTrackName();
43-
String trackArtist = this.mediaPlayer.getArtist();
44-
int trackLength = this.mediaPlayer.getTrackLength();
46+
String currentTrackId = this.currentTrack == null ? null : this.currentTrack.getId();
47+
if (!Objects.equals(trackId, currentTrackId)) {
48+
String trackName = metadata.getTrackName();
49+
String trackArtist = metadata.getArtistsJoined();
50+
int trackLength = metadata.getTrackLength();
51+
BufferedImage coverArt = this.toBufferedImage(metadata.getArtUrl());
4552

4653
boolean isFirstTrack = !this.hasTrack();
4754

48-
Track track = new Track(trackId, trackName, trackArtist, trackLength);
55+
Track track = new Track(trackId, trackName, trackArtist, trackLength, coverArt);
4956
this.currentTrack = track;
5057

5158
// Fire on track changed
@@ -58,7 +65,7 @@ protected void onTick() throws Exception {
5865
}
5966

6067
// Handle is playing changes
61-
boolean isPlaying = this.mediaPlayer.isPlaying();
68+
boolean isPlaying = this.mediaPlayer.readIsPlaying();
6269
if (isPlaying != this.isPlaying) {
6370
this.isPlaying = isPlaying;
6471

@@ -67,7 +74,7 @@ protected void onTick() throws Exception {
6774
}
6875

6976
// Handle position changes
70-
int position = this.mediaPlayer.getPosition();
77+
int position = this.mediaPlayer.readPosition();
7178
if (!this.hasPosition() || Math.abs(position - this.getPosition()) >= 1000) {
7279
this.updatePosition(position);
7380
}
@@ -150,4 +157,16 @@ public boolean hasPosition() {
150157
return this.currentPosition != -1;
151158
}
152159

160+
private BufferedImage toBufferedImage(String artUrl) {
161+
if (artUrl == null || artUrl.isEmpty()) {
162+
return null; // No cover art available
163+
}
164+
try {
165+
return ImageIO.read(new URL(artUrl));
166+
} catch (Throwable e) {
167+
e.printStackTrace();
168+
return null; // Failed to load cover art
169+
}
170+
}
171+
153172
}

src/main/java/de/labystudio/spotifyapi/platform/linux/api/DBusSend.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package de.labystudio.spotifyapi.platform.linux.api;
22

3+
import de.labystudio.spotifyapi.platform.linux.api.model.InterfaceMember;
4+
import de.labystudio.spotifyapi.platform.linux.api.model.Parameter;
5+
import de.labystudio.spotifyapi.platform.linux.api.model.Variant;
6+
37
import java.io.BufferedReader;
48
import java.io.InputStreamReader;
59

src/main/java/de/labystudio/spotifyapi/platform/linux/api/MPRISCommunicator.java

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package de.labystudio.spotifyapi.platform.linux.api;
22

3+
import de.labystudio.spotifyapi.platform.linux.api.model.InterfaceMember;
4+
import de.labystudio.spotifyapi.platform.linux.api.model.Metadata;
5+
import de.labystudio.spotifyapi.platform.linux.api.model.Parameter;
6+
import de.labystudio.spotifyapi.platform.linux.api.model.Variant;
7+
38
import java.util.HashMap;
49
import java.util.Map;
510

@@ -26,42 +31,20 @@ public class MPRISCommunicator {
2631
"/org/mpris/MediaPlayer2"
2732
);
2833

29-
private final Map<String, Object> metadata = new HashMap<>();
30-
31-
private void updateMetadata() throws Exception {
32-
this.metadata.clear();
33-
34+
public Metadata readMetadata() throws Exception {
35+
Map<String, Object> metadata = new HashMap<>();
3436
Variant array = this.dbus.get("org.mpris.MediaPlayer2.Player", "Metadata");
3537
for (Variant entry : array.<Variant[]>getValue()) {
36-
this.metadata.put(entry.getSig(), entry.getValue());
38+
metadata.put(entry.getSig(), entry.getValue());
3739
}
40+
return new Metadata(metadata);
3841
}
3942

40-
public String getTrackId() throws Exception {
41-
this.updateMetadata();
42-
return ((String) this.metadata.get("mpris:trackid")).split("/")[4];
43-
}
44-
45-
public String getTrackName() throws Exception {
46-
this.updateMetadata();
47-
return this.metadata.get("xesam:title").toString();
48-
}
49-
50-
public String getArtist() throws Exception {
51-
this.updateMetadata();
52-
return String.join(", ", (String[]) this.metadata.get("xesam:artist"));
53-
}
54-
55-
public Integer getTrackLength() throws Exception {
56-
this.updateMetadata();
57-
return (int) ((Long) this.metadata.get("mpris:length") / 1000L) + 1;
58-
}
59-
60-
public boolean isPlaying() throws Exception {
43+
public boolean readIsPlaying() throws Exception {
6144
return this.dbus.get("org.mpris.MediaPlayer2.Player", "PlaybackStatus").getValue().equals("Playing");
6245
}
6346

64-
public Integer getPosition() throws Exception {
47+
public Integer readPosition() throws Exception {
6548
return (int) ((Long) this.dbus.get("org.mpris.MediaPlayer2.Player", "Position").getValue() / 1000L);
6649
}
6750

src/main/java/de/labystudio/spotifyapi/platform/linux/api/InterfaceMember.java renamed to src/main/java/de/labystudio/spotifyapi/platform/linux/api/model/InterfaceMember.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package de.labystudio.spotifyapi.platform.linux.api;
1+
package de.labystudio.spotifyapi.platform.linux.api.model;
22

33
/**
44
* Interface member wrapper for the DBusSend class.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package de.labystudio.spotifyapi.platform.linux.api.model;
2+
3+
import java.util.Map;
4+
5+
public class Metadata {
6+
7+
private final String trackId;
8+
private final String trackName;
9+
private final String[] artists;
10+
private final int trackLength;
11+
private final String artUrl;
12+
13+
public Metadata(Map<String, Object> metadata) {
14+
this.trackId = ((String) metadata.get("mpris:trackid")).split("/")[4];
15+
this.trackName = metadata.get("xesam:title").toString();
16+
this.artists = (String[]) metadata.get("xesam:artist");
17+
this.trackLength = (int) ((Long) metadata.get("mpris:length") / 1000L) + 1;
18+
this.artUrl = (String) metadata.get("mpris:artUrl");
19+
}
20+
21+
public String getTrackId() {
22+
return this.trackId;
23+
}
24+
25+
public String getTrackName() {
26+
return this.trackName;
27+
}
28+
29+
public String[] getArtists() {
30+
return this.artists;
31+
}
32+
33+
public String getArtistsJoined() {
34+
return String.join(", ", this.artists);
35+
}
36+
37+
public int getTrackLength() {
38+
return this.trackLength;
39+
}
40+
41+
public String getArtUrl() {
42+
return this.artUrl;
43+
}
44+
}

src/main/java/de/labystudio/spotifyapi/platform/linux/api/Parameter.java renamed to src/main/java/de/labystudio/spotifyapi/platform/linux/api/model/Parameter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package de.labystudio.spotifyapi.platform.linux.api;
1+
package de.labystudio.spotifyapi.platform.linux.api.model;
22

33
/**
44
* Parameter wrapper for the DBusSend class.

0 commit comments

Comments
 (0)