diff --git a/spotify-web-api-core/src/main/resources/spotify-web-api.yml b/spotify-web-api-core/src/main/resources/spotify-web-api.yml index fc86ae45..5167fbb5 100644 --- a/spotify-web-api-core/src/main/resources/spotify-web-api.yml +++ b/spotify-web-api-core/src/main/resources/spotify-web-api.yml @@ -3752,6 +3752,14 @@ categories: \ their account in the [account settings](https://www.spotify.com/se/account/overview/)." type: String required: false + - location: BODY + name: ids + description: "A JSON array of the [Spotify IDs](https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids).\ + \ \nA maximum of 50 items can be specified in one request. *Note: if\ + \ the `ids` parameter is present in the query string, any IDs listed here\ + \ in the body will be ignored.*" + type: "Array[String]" + required: false responseDescription: "On success, the HTTP status code in the response header\ \ is `200` OK.\nOn error, the header status code is an [error code](https://developer.spotify.com/documentation/web-api/#response-status-codes)\ \ and the response body contains an [error object](https://developer.spotify.com/documentation/web-api/#error-details).\ @@ -3931,6 +3939,14 @@ categories: \ Maximum: 50 IDs." type: String required: true + - location: BODY + name: ids + description: "A JSON array of the [Spotify IDs](https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids).\ + \ \nA maximum of 50 items can be specified in one request. *Note: if\ + \ the `ids` parameter is present in the query string, any IDs listed here\ + \ in the body will be ignored.*" + type: "Array[String]" + required: false responseDescription: "On success, the HTTP status code in the response header\ \ is `200` OK. On error, the header status code is an [error code](https://developer.spotify.com/documentation/web-api/#response-status-codes)\ \ and the response body contains an [error object](https://developer.spotify.com/documentation/web-api/#error-details).\ diff --git a/spotify-web-api-generator-open-api/spotify-web-api-openapi.yml b/spotify-web-api-generator-open-api/spotify-web-api-openapi.yml index 6b315dbb..65045ff8 100644 --- a/spotify-web-api-generator-open-api/spotify-web-api-openapi.yml +++ b/spotify-web-api-generator-open-api/spotify-web-api-openapi.yml @@ -2695,6 +2695,21 @@ paths: required: true schema: type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + ids: + type: array + description: "A JSON array of the [Spotify IDs](https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids).\ + \ \nA maximum of 50 items can be specified in one request. *Note:\ + \ if the `ids` parameter is present in the query string, any IDs\ + \ listed here in the body will be ignored.*" + items: + type: string + required: false responses: default: $ref: '#/components/responses/ErrorResponse' @@ -2747,6 +2762,21 @@ paths: required: false schema: type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + ids: + type: array + description: "A JSON array of the [Spotify IDs](https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids).\ + \ \nA maximum of 50 items can be specified in one request. *Note:\ + \ if the `ids` parameter is present in the query string, any IDs\ + \ listed here in the body will be ignored.*" + items: + type: string + required: false responses: default: $ref: '#/components/responses/ErrorResponse' diff --git a/spotify-web-api-parser/response-types.yml b/spotify-web-api-parser/response-types.yml index 5f16cbc1..c6fce252 100644 --- a/spotify-web-api-parser/response-types.yml +++ b/spotify-web-api-parser/response-types.yml @@ -65,7 +65,7 @@ category-library: - type: "Array[Boolean]" status: 200 endpoint-get-users-saved-episodes: - md5Hash: 8c34757f341b78f13871c0642765aa84 + md5Hash: 80f3e189edc6742d8348ebee029f2a6d responseTypes: - type: "PagingObject[SavedEpisodeObject]" status: 200 diff --git a/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ApiEndpointFixes.java b/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ApiEndpointFixes.java index 58bf7ba8..49571f5e 100644 --- a/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ApiEndpointFixes.java +++ b/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ApiEndpointFixes.java @@ -1,6 +1,7 @@ package de.sonallux.spotify.parser; import de.sonallux.spotify.core.model.SpotifyWebApiCategory; +import de.sonallux.spotify.core.model.SpotifyWebApiEndpoint; import lombok.extern.slf4j.Slf4j; import java.util.List; @@ -18,6 +19,8 @@ static void fixApiEndpoints(SortedMap categories) fixGetUsersSavedShowsScope(categories); fixCheckUsersSavedShowsScope(categories); fixReplaceAndReorderPlaylistTrackUrisParameter(categories); + fixSaveShowsForCurrentUserBodyParameter(categories); + fixRemoveUsersSavedShowsBodyParameter(categories); } private static void fixChangePlaylistsDetails(SortedMap categories) { @@ -29,9 +32,9 @@ private static void fixChangePlaylistsDetails(SortedMap categories) { @@ -43,9 +46,9 @@ private static void fixGetInfoAboutUsersCurrentPlayback(SortedMap categories) { @@ -100,9 +103,9 @@ private static void fixGetUsersSavedShowsScope(SortedMap categories) { @@ -110,9 +113,9 @@ private static void fixCheckUsersSavedShowsScope(SortedMap categories) { @@ -125,8 +128,10 @@ private static void fixReplaceAndReorderPlaylistTrackUrisParameter(SortedMap categories) { + var endpoint = categories.get("category-library") + .getEndpoints().get("endpoint-save-shows-user"); + + if (endpoint.getParameters().stream().anyMatch(parameter -> parameter.getLocation() == BODY && "ids".equals(parameter.getName()))) { + log.warn("Missing body parameter for endpoint-save-shows-user has been fixed"); + return; + } + + endpoint.getParameters().add(new SpotifyWebApiEndpoint.Parameter( + BODY, + "ids", + "A JSON array of the [Spotify IDs](https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids). \n" + + "A maximum of 50 items can be specified in one request. *Note: if the `ids` parameter is present in the query string, " + + "any IDs listed here in the body will be ignored.*", + "Array[String]", + false)); + } + + private static void fixRemoveUsersSavedShowsBodyParameter(SortedMap categories) { + var endpoint = categories.get("category-library") + .getEndpoints().get("endpoint-remove-shows-user"); + + if (endpoint.getParameters().stream().anyMatch(parameter -> parameter.getLocation() == BODY && "ids".equals(parameter.getName()))) { + log.warn("Missing body parameter for endpoint-remove-shows-user has been fixed"); + return; + } + + endpoint.getParameters().add(new SpotifyWebApiEndpoint.Parameter( + BODY, + "ids", + "A JSON array of the [Spotify IDs](https://developer.spotify.com/documentation/web-api/#spotify-uris-and-ids). \n" + + "A maximum of 50 items can be specified in one request. *Note: if the `ids` parameter is present in the query string, " + + "any IDs listed here in the body will be ignored.*", + "Array[String]", + false)); + } } diff --git a/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ApiEndpointParser.java b/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ApiEndpointParser.java index 9bb27e22..5cd5fba9 100644 --- a/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ApiEndpointParser.java +++ b/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ApiEndpointParser.java @@ -59,20 +59,21 @@ private void addResponseTypes(SortedMap categorie try { if (isInteractive) { responseTypeMapper.update(new ArrayList<>(categories.values())); - responseTypeMapper.save(); } for (var category : categories.values()) { for (var endpoint : category.getEndpointList()) { - var endpointResponse = responseTypeMapper.getEndpointResponse(category.getId(), endpoint.getId()); - if (endpointResponse == null || endpointResponse.getResponseTypes().isEmpty()) { + var responseTypes = responseTypeMapper.getEndpointResponseTypes(category.getId(), endpoint); + if (responseTypes == null || responseTypes.isEmpty()) { log.warn("Missing response type in {} for {} {} with response: \n{}\n", category.getId(), endpoint.getHttpMethod(), endpoint.getId(), endpoint.getResponseDescription()); continue; } - endpoint.setResponseTypes(endpointResponse.getResponseTypes()); + endpoint.setResponseTypes(responseTypes); } } + + responseTypeMapper.save(); } catch (IOException e) { log.error("Failed to load missing response types", e); } diff --git a/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/Html2Markdown.java b/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/Html2Markdown.java index 6a71559a..48fd2c0a 100644 --- a/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/Html2Markdown.java +++ b/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/Html2Markdown.java @@ -15,7 +15,7 @@ import java.util.Set; import java.util.stream.Collectors; -public class Html2Markdown { +class Html2Markdown { private static final FlexmarkHtmlConverter CONVERTER; @@ -27,11 +27,11 @@ public class Html2Markdown { .build(); } - public static String convert(Node node) { + static String convert(Node node) { return CONVERTER.convert(node).trim(); } - public static String convert(List nodes) { + static String convert(List nodes) { return nodes.stream() .map(CONVERTER::convert) .collect(Collectors.joining("\n")) diff --git a/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ResponseTypeMapper.java b/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ResponseTypeMapper.java index 6ae336f3..bc7c8301 100644 --- a/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ResponseTypeMapper.java +++ b/spotify-web-api-parser/src/main/java/de/sonallux/spotify/parser/ResponseTypeMapper.java @@ -9,6 +9,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.math.BigInteger; @@ -19,14 +20,15 @@ import java.security.NoSuchAlgorithmException; import java.util.*; -public class ResponseTypeMapper { +@Slf4j +class ResponseTypeMapper { private final Path responseTypesFile; private final Map> responseTypes; private final MessageDigest md5Digest; private final ObjectMapper objectMapper; - public ResponseTypeMapper(Path responseTypesFile) throws IOException, NoSuchAlgorithmException { + ResponseTypeMapper(Path responseTypesFile) throws IOException, NoSuchAlgorithmException { this.responseTypesFile = responseTypesFile; this.objectMapper = Yaml.create(); this.md5Digest = MessageDigest.getInstance("MD5"); @@ -39,13 +41,26 @@ private Map> load() throws IOException { } } - public void save() throws IOException { + List getEndpointResponseTypes(String categoryId, SpotifyWebApiEndpoint endpoint) { + var endpointResponse = getEndpointResponse(categoryId, endpoint.getId()); + if (endpointResponse == null) { + return null; + } + var currentHash = calculateMD5Hash(endpoint); + if (!currentHash.equals(endpointResponse.getMd5Hash())) { + log.warn("Response description for endpoint {} has changed", endpoint.getId()); + endpointResponse.setMd5Hash(currentHash); + } + return endpointResponse.getResponseTypes(); + } + + void save() throws IOException { try (var outputStream = Files.newOutputStream(this.responseTypesFile)) { objectMapper.writeValue(outputStream, responseTypes); } } - public void update(List categories) { + void update(List categories) { var scanner = new Scanner(System.in); for (var category : categories) { for (var endpoint : category.getEndpointList()) { @@ -104,7 +119,7 @@ private static int readInt(Scanner scanner, int defaultValue) { } } - public EndpointResponse getEndpointResponse(String categoryId, String endpointId) { + private EndpointResponse getEndpointResponse(String categoryId, String endpointId) { var endpointTypes = responseTypes.get(categoryId); if (endpointTypes == null) { return null; @@ -135,7 +150,7 @@ private String calculateMD5Hash(SpotifyWebApiEndpoint endpoint) { @Setter @AllArgsConstructor @NoArgsConstructor - public static class EndpointResponse { + static class EndpointResponse { private String md5Hash; private List responseTypes = new ArrayList<>(); }