Skip to content

Commit ed46c33

Browse files
committed
Updated proto parsers
1 parent dbc7e7b commit ed46c33

File tree

3 files changed

+194
-5
lines changed

3 files changed

+194
-5
lines changed

core/src/main/java/xyz/gianlu/librespot/mercury/MercuryRequests.java

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,14 @@
55
import com.google.gson.JsonObject;
66
import com.google.protobuf.AbstractMessage;
77
import com.google.protobuf.ByteString;
8+
import com.google.protobuf.ProtocolMessageEnum;
89
import com.google.protobuf.ProtocolStringList;
910
import org.jetbrains.annotations.Contract;
1011
import org.jetbrains.annotations.NotNull;
1112
import org.jetbrains.annotations.Nullable;
1213
import xyz.gianlu.librespot.common.Utils;
1314
import xyz.gianlu.librespot.common.proto.*;
14-
import xyz.gianlu.librespot.mercury.model.AlbumId;
15-
import xyz.gianlu.librespot.mercury.model.ArtistId;
16-
import xyz.gianlu.librespot.mercury.model.PlaylistId;
17-
import xyz.gianlu.librespot.mercury.model.TrackId;
15+
import xyz.gianlu.librespot.mercury.model.*;
1816
import xyz.gianlu.librespot.player.remote.Remote3Page;
1917

2018
import java.util.ArrayList;
@@ -42,7 +40,8 @@ public final class MercuryRequests {
4240
obj.addProperty("allowed", proto.getCountriesAllowed());
4341
obj.addProperty("forbidden", proto.getCountriesForbidden());
4442
obj.addProperty("type", proto.getType().name());
45-
putArray(obj, "catalogues", proto.getCatalogueStrList());
43+
putArray(obj, "catalogueStrings", proto.getCatalogueStrList());
44+
putArray(obj, "catalogues", proto.getCatalogueList());
4645
return obj;
4746
};
4847
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.Copyright> COPYRIGHT_JSON_CONVERTER = proto -> {
@@ -78,18 +77,32 @@ public final class MercuryRequests {
7877
obj.addProperty("format", proto.getFormat().name());
7978
return obj;
8079
};
80+
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.VideoFile> VIDEO_FILE_JSON_CONVERTER = proto -> {
81+
JsonObject obj = new JsonObject();
82+
obj.addProperty("fileId", Utils.toBase64(proto.getFileId()));
83+
return obj;
84+
};
8185
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.Artist> ARTIST_JSON_CONVERTER;
86+
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.Episode> EPISODE_JSON_CONVERTER;
87+
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.Show> SHOW_JSON_CONVERTER;
8288
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.Album> ALBUM_JSON_CONVERTER;
8389
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.AlbumGroup> ALBUM_GROUP_JSON_CONVERTER;
8490
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.Track> TRACK_JSON_CONVERTER;
8591
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.Disc> DISC_JSON_CONVERTER;
8692
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.TopTracks> TOP_TRACKS_JSON_CONVERTER;
8793
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.SalePeriod> SALE_PERIOD_JSON_CONVERTER;
94+
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.Availability> AVAILABILITY_JSON_CONVERTER;
8895
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.ImageGroup> IMAGE_GROUP_JSON_CONVERTER;
8996
private static final ProtoJsonMercuryRequest.JsonConverter<Metadata.Biography> BIOGRAPHY_JSON_CONVERTER;
9097
private static final String KEYMASTER_CLIENT_ID = "65b708073fc0480ea92a077233ca87bd";
9198

9299
static {
100+
AVAILABILITY_JSON_CONVERTER = proto -> {
101+
JsonObject obj = new JsonObject();
102+
obj.add("start", DATE_JSON_CONVERTER.convert(proto.getStart()));
103+
putArray(obj, "catalogueStrings", proto.getCatalogueStrList());
104+
return obj;
105+
};
93106
SALE_PERIOD_JSON_CONVERTER = proto -> {
94107
JsonObject obj = new JsonObject();
95108
obj.add("start", DATE_JSON_CONVERTER.convert(proto.getStart()));
@@ -130,6 +143,7 @@ public final class MercuryRequests {
130143
putArray(obj, "biographies", proto.getBiographyList(), BIOGRAPHY_JSON_CONVERTER);
131144
putArray(obj, "topTracks", proto.getTopTrackList(), TOP_TRACKS_JSON_CONVERTER);
132145
putArray(obj, "activityPeriods", proto.getActivityPeriodList(), ACTIVITY_PERIOD_JSON_CONVERTER);
146+
putArray(obj, "availabilities", proto.getAvailabilityList(), AVAILABILITY_JSON_CONVERTER);
133147
return obj;
134148
}
135149
};
@@ -154,6 +168,7 @@ public final class MercuryRequests {
154168
obj.add("coverGroup", IMAGE_GROUP_JSON_CONVERTER.convert(proto.getCoverGroup()));
155169
putArray(obj, "covers", proto.getCoverList(), IMAGE_JSON_CONVERTER);
156170
putArray(obj, "externalIds", proto.getExternalIdList(), EXTERNAL_ID_JSON_CONVERTER);
171+
putArray(obj, "availabilities", proto.getAvailabilityList(), AVAILABILITY_JSON_CONVERTER);
157172
return obj;
158173
}
159174
};
@@ -181,6 +196,55 @@ public final class MercuryRequests {
181196
putArray(obj, "salePeriods", proto.getSalePeriodList(), SALE_PERIOD_JSON_CONVERTER);
182197
putArray(obj, "previews", proto.getPreviewList(), AUDIO_FILE_JSON_CONVERTER);
183198
putArray(obj, "files", proto.getFileList(), AUDIO_FILE_JSON_CONVERTER);
199+
putArray(obj, "availabilities", proto.getAvailabilityList(), AVAILABILITY_JSON_CONVERTER);
200+
return obj;
201+
}
202+
};
203+
EPISODE_JSON_CONVERTER = new ProtoJsonMercuryRequest.JsonConverter<Metadata.Episode>() {
204+
@Override
205+
public @NotNull JsonElement convert(Metadata.@NotNull Episode proto) {
206+
JsonObject obj = new JsonObject();
207+
obj.addProperty("gid", Utils.bytesToHex(proto.getGid()));
208+
putArray(obj, "audio", proto.getAudioList(), AUDIO_FILE_JSON_CONVERTER);
209+
obj.addProperty("description", proto.getDescription());
210+
obj.add("publishTime", DATE_JSON_CONVERTER.convert(proto.getPublishTime()));
211+
obj.addProperty("language", proto.getLanguage());
212+
putArray(obj, "keywords", proto.getKeywordList());
213+
obj.addProperty("allowBackgroundPlayback", proto.getAllowBackgroundPlayback());
214+
obj.addProperty("externalUrl", proto.getExternalUrl());
215+
obj.addProperty("name", proto.getName());
216+
obj.addProperty("number", proto.getNumber());
217+
obj.addProperty("duration", proto.getDuration());
218+
obj.addProperty("explicit", proto.getExplicit());
219+
obj.add("freezeFrame", IMAGE_GROUP_JSON_CONVERTER.convert(proto.getFreezeFrame()));
220+
obj.add("coverImage", IMAGE_GROUP_JSON_CONVERTER.convert(proto.getCoverImage()));
221+
putArray(obj, "restrictions", proto.getRestrictionList(), RESTRICTION_JSON_CONVERTER);
222+
putArray(obj, "audioPreviews", proto.getAudioPreviewList(), AUDIO_FILE_JSON_CONVERTER);
223+
putArray(obj, "availabilities", proto.getAvailabilityList(), AVAILABILITY_JSON_CONVERTER);
224+
obj.add("show", SHOW_JSON_CONVERTER.convert(proto.getShow()));
225+
putArray(obj, "videos", proto.getVideoList(), VIDEO_FILE_JSON_CONVERTER);
226+
putArray(obj, "videoPreviews", proto.getVideoPreviewList(), VIDEO_FILE_JSON_CONVERTER);
227+
return obj;
228+
}
229+
};
230+
SHOW_JSON_CONVERTER = new ProtoJsonMercuryRequest.JsonConverter<Metadata.Show>() {
231+
@Override
232+
public @NotNull JsonElement convert(Metadata.@NotNull Show proto) {
233+
JsonObject obj = new JsonObject();
234+
obj.addProperty("gid", Utils.bytesToHex(proto.getGid()));
235+
obj.addProperty("description", proto.getDescription());
236+
obj.addProperty("language", proto.getLanguage());
237+
putArray(obj, "keywords", proto.getKeywordList());
238+
obj.addProperty("name", proto.getName());
239+
obj.addProperty("explicit", proto.getExplicit());
240+
obj.add("coverImage", IMAGE_GROUP_JSON_CONVERTER.convert(proto.getCoverImage()));
241+
obj.addProperty("publisher", proto.getPublisher());
242+
putArray(obj, "restrictions", proto.getRestrictionList(), RESTRICTION_JSON_CONVERTER);
243+
putArray(obj, "episodes", proto.getEpisodeList(), EPISODE_JSON_CONVERTER);
244+
putArray(obj, "copyrights", proto.getCopyrightList(), COPYRIGHT_JSON_CONVERTER);
245+
putArray(obj, "availabilities", proto.getAvailabilityList(), AVAILABILITY_JSON_CONVERTER);
246+
obj.addProperty("mediaType", proto.getMediaType().name());
247+
obj.addProperty("consumptionOrder", proto.getConsumptionOrder().name());
184248
return obj;
185249
}
186250
};
@@ -210,13 +274,24 @@ private static void putArray(@NotNull JsonObject dest, @NotNull String key, @Not
210274
if (!list.isEmpty()) dest.add(key, makeArray(list));
211275
}
212276

277+
private static void putArray(@NotNull JsonObject dest, @NotNull String key, @NotNull List<? extends Enum<? extends ProtocolMessageEnum>> list) {
278+
if (!list.isEmpty()) dest.add(key, makeArray(list));
279+
}
280+
213281
@NotNull
214282
private static JsonArray makeArray(@NotNull ProtocolStringList list) {
215283
JsonArray array = new JsonArray(list.size());
216284
for (String item : list) array.add(item);
217285
return array;
218286
}
219287

288+
@NotNull
289+
private static JsonArray makeArray(@NotNull List<? extends Enum<? extends ProtocolMessageEnum>> list) {
290+
JsonArray array = new JsonArray(list.size());
291+
for (Enum item : list) array.add(item.name());
292+
return array;
293+
}
294+
220295
@NotNull
221296
private static <P extends AbstractMessage> JsonArray makeArray(@NotNull List<P> list, @NotNull ProtoJsonMercuryRequest.JsonConverter<P> converter) {
222297
JsonArray array = new JsonArray(list.size());
@@ -251,6 +326,16 @@ public static ProtoJsonMercuryRequest<Metadata.Album> getAlbum(@NotNull AlbumId
251326
return new ProtoJsonMercuryRequest<>(RawMercuryRequest.get(id.toMercuryUri()), Metadata.Album.parser(), ALBUM_JSON_CONVERTER);
252327
}
253328

329+
@NotNull
330+
public static ProtoJsonMercuryRequest<Metadata.Episode> getEpisode(@NotNull EpisodeId id) {
331+
return new ProtoJsonMercuryRequest<>(RawMercuryRequest.get(id.toMercuryUri()), Metadata.Episode.parser(), EPISODE_JSON_CONVERTER);
332+
}
333+
334+
@NotNull
335+
public static ProtoJsonMercuryRequest<Metadata.Show> getShow(@NotNull ShowId id) {
336+
return new ProtoJsonMercuryRequest<>(RawMercuryRequest.get(id.toMercuryUri()), Metadata.Show.parser(), SHOW_JSON_CONVERTER);
337+
}
338+
254339
@NotNull
255340
public static ProtobufMercuryRequest<Mercury.MercuryMultiGetReply> multiGet(@NotNull String uri, Mercury.MercuryRequest... subs) {
256341
RawMercuryRequest.Builder request = RawMercuryRequest.newBuilder()
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package xyz.gianlu.librespot.mercury.model;
2+
3+
import io.seruco.encoding.base62.Base62;
4+
import org.jetbrains.annotations.NotNull;
5+
import xyz.gianlu.librespot.common.Utils;
6+
7+
import java.util.regex.Matcher;
8+
import java.util.regex.Pattern;
9+
10+
/**
11+
* @author Gianlu
12+
*/
13+
public final class EpisodeId implements SpotifyId {
14+
private static final Pattern PATTERN = Pattern.compile("spotify:episode:(.{22})");
15+
private static final Base62 BASE62 = Base62.createInstanceWithInvertedCharacterSet();
16+
private final String hexId;
17+
18+
private EpisodeId(@NotNull String hex) {
19+
this.hexId = hex;
20+
}
21+
22+
@NotNull
23+
public static EpisodeId fromUri(@NotNull String uri) {
24+
Matcher matcher = PATTERN.matcher(uri);
25+
if (matcher.find()) {
26+
String id = matcher.group(1);
27+
return new EpisodeId(Utils.bytesToHex(BASE62.decode(id.getBytes())));
28+
} else {
29+
throw new IllegalArgumentException("Not a Spotify episode ID: " + uri);
30+
}
31+
}
32+
33+
@NotNull
34+
public static EpisodeId fromBase62(@NotNull String base62) {
35+
return new EpisodeId(Utils.bytesToHex(BASE62.decode(base62.getBytes())));
36+
}
37+
38+
@NotNull
39+
public static EpisodeId fromHex(@NotNull String hex) {
40+
return new EpisodeId(hex);
41+
}
42+
43+
@Override
44+
public @NotNull String toMercuryUri() {
45+
return "hm://metadata/4/episode/" + hexId;
46+
}
47+
48+
@Override
49+
public @NotNull String toSpotifyUri() {
50+
return "spotify:episode:" + new String(BASE62.encode(Utils.hexToBytes(hexId)));
51+
}
52+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package xyz.gianlu.librespot.mercury.model;
2+
3+
import io.seruco.encoding.base62.Base62;
4+
import org.jetbrains.annotations.NotNull;
5+
import xyz.gianlu.librespot.common.Utils;
6+
7+
import java.util.regex.Matcher;
8+
import java.util.regex.Pattern;
9+
10+
/**
11+
* @author Gianlu
12+
*/
13+
public final class ShowId implements SpotifyId {
14+
private static final Pattern PATTERN = Pattern.compile("spotify:show:(.{22})");
15+
private static final Base62 BASE62 = Base62.createInstanceWithInvertedCharacterSet();
16+
private final String hexId;
17+
18+
private ShowId(@NotNull String hex) {
19+
this.hexId = hex;
20+
}
21+
22+
@NotNull
23+
public static ShowId fromUri(@NotNull String uri) {
24+
Matcher matcher = PATTERN.matcher(uri);
25+
if (matcher.find()) {
26+
String id = matcher.group(1);
27+
return new ShowId(Utils.bytesToHex(BASE62.decode(id.getBytes())));
28+
} else {
29+
throw new IllegalArgumentException("Not a Spotify show ID: " + uri);
30+
}
31+
}
32+
33+
@NotNull
34+
public static ShowId fromBase62(@NotNull String base62) {
35+
return new ShowId(Utils.bytesToHex(BASE62.decode(base62.getBytes())));
36+
}
37+
38+
@NotNull
39+
public static ShowId fromHex(@NotNull String hex) {
40+
return new ShowId(hex);
41+
}
42+
43+
@Override
44+
public @NotNull String toMercuryUri() {
45+
return "hm://metadata/4/show/" + hexId;
46+
}
47+
48+
@Override
49+
public @NotNull String toSpotifyUri() {
50+
return "spotify:show:" + new String(BASE62.encode(Utils.hexToBytes(hexId)));
51+
}
52+
}

0 commit comments

Comments
 (0)