From db2ecca5e64a393a4dbbd27fb2014e2b8124b22a Mon Sep 17 00:00:00 2001 From: sfrei Date: Wed, 12 Jul 2023 19:18:53 +0200 Subject: [PATCH 01/21] Set develop version to 0.8.2-SNAPSHOT --- CHANGELOG.md | 5 +++++ pom.xml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96f0ec8..316d1ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ Changelog ========= +0.8.2 - unreleased +------------------ + +Nothing to see here yet... + 0.8.1 ----- diff --git a/pom.xml b/pom.xml index afaef10..aaeef89 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.sfrei tracksearch - 0.8.1 + 0.8.2-SNAPSHOT jar From a5df6aa8b1038bce841686e0477964a95d09564a Mon Sep 17 00:00:00 2001 From: sfrei Date: Wed, 12 Jul 2023 19:20:32 +0200 Subject: [PATCH 02/21] Update latest version in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 61e05a5..2e2d483 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Maven dependency available on [Maven Central](https://search.maven.org/artifact/ io.sfrei tracksearch - 0.8.0 + 0.8.1 ``` From 65b6839aa0213e3fc9040a7587d6942ec0be8571 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 04:15:35 +0000 Subject: [PATCH 03/21] Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.5.0 to 3.6.0 Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.5.0 to 3.6.0. - [Release notes](https://github.com/apache/maven-javadoc-plugin/releases) - [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.5.0...maven-javadoc-plugin-3.6.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-javadoc-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aaeef89..006b196 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 1.18.20.0 3.11.0 3.2.1 - 3.5.0 + 3.6.0 3.0.0 2.0.1 2.0.1 From 52f7a89becbec0551c0fc1614f4c6000eecde06e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 04:34:31 +0000 Subject: [PATCH 04/21] Bump org.projectlombok:lombok from 1.18.26 to 1.18.30 Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.26 to 1.18.30. - [Release notes](https://github.com/projectlombok/lombok/releases) - [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/projectlombok/lombok/compare/v1.18.26...v1.18.30) --- updated-dependencies: - dependency-name: org.projectlombok:lombok dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aaeef89..d013ca5 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ 11 - 1.18.26 + 1.18.30 2.9.0 4.11.0 2.15.2 From e0ec4e7ee0e068b655adc296d2379268f127a900 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:19:21 +0000 Subject: [PATCH 05/21] Bump junit.version from 5.9.3 to 5.10.1 Bumps `junit.version` from 5.9.3 to 5.10.1. Updates `org.junit.jupiter:junit-jupiter-engine` from 5.9.3 to 5.10.1 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.3...r5.10.1) Updates `org.junit.jupiter:junit-jupiter-api` from 5.9.3 to 5.10.1 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.3...r5.10.1) Updates `org.junit.jupiter:junit-jupiter-params` from 5.9.3 to 5.10.1 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.3...r5.10.1) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: org.junit.jupiter:junit-jupiter-params dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aaeef89..746b264 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ 2.15.2 1.16.1 2.0.7 - 5.9.3 + 5.10.1 3.24.2 1.4.8 From 0453b1534dfe519537b2e177a9ae1cd14bb2c848 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:19:34 +0000 Subject: [PATCH 06/21] Bump org.apache.maven.plugins:maven-surefire-plugin from 3.1.2 to 3.2.1 Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.1.2 to 3.2.1. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.2...surefire-3.2.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aaeef89..89e6a93 100644 --- a/pom.xml +++ b/pom.xml @@ -53,7 +53,7 @@ 1.4.8 - 3.1.2 + 3.2.1 1.2.1 From 90bde9348a1831da02e0b06e3a3baa76032d743a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:19:40 +0000 Subject: [PATCH 07/21] Bump com.fasterxml.jackson.core:jackson-databind from 2.15.2 to 2.15.3 Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.15.2 to 2.15.3. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aaeef89..bce7f05 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,7 @@ 1.18.26 2.9.0 4.11.0 - 2.15.2 + 2.15.3 1.16.1 2.0.7 5.9.3 From 7290d2e4b7c28c2b5c37ea0f80c4e88b148a24c1 Mon Sep 17 00:00:00 2001 From: sfrei Date: Mon, 6 Nov 2023 20:33:41 +0100 Subject: [PATCH 08/21] Add auto-merge action for dependabot --- .github/workflows/dependabot-auto-merge.yml | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/dependabot-auto-merge.yml diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..336fbad --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,29 @@ +# https://github.com/dependabot/fetch-metadata#enabling-auto-merge + +name: "Dependabot auto-merge" + +on: pull_request_target + +permissions: + pull-requests: write + contents: write + +jobs: + + dependabot: + runs-on: ubuntu-latest + + if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }} + + steps: + + - name: "Dependabot metadata" + id: dependabot-metadata + uses: dependabot/fetch-metadata@v1 + + - name: "Enable auto-merge for Dependabot PRs" + if: ${{contains(steps.dependabot-metadata.outputs.dependency-names, 'rails') && steps.dependabot-metadata.outputs.update-type == 'version-update:semver-patch'}} + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GH_TOKEN: ${{secrets.GITHUB_TOKEN}} From 608fdadbfe93e8f20c2115d32b3d5ce03fefcb03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:36:00 +0000 Subject: [PATCH 09/21] Bump okhttp.version from 4.11.0 to 4.12.0 Bumps `okhttp.version` from 4.11.0 to 4.12.0. Updates `com.squareup.okhttp3:okhttp` from 4.11.0 to 4.12.0 - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.11.0...parent-4.12.0) Updates `com.squareup.okhttp3:okhttp-urlconnection` from 4.11.0 to 4.12.0 - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.11.0...parent-4.12.0) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.squareup.okhttp3:okhttp-urlconnection dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 061584b..f84ccc3 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ 1.18.30 2.9.0 - 4.11.0 + 4.12.0 2.15.3 1.16.1 2.0.7 From 32b434d10eb6a430014797a76253a515cadfd3a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:36:30 +0000 Subject: [PATCH 10/21] Bump org.slf4j:slf4j-api from 2.0.7 to 2.0.9 Bumps org.slf4j:slf4j-api from 2.0.7 to 2.0.9. --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 061584b..64d0ff8 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 4.11.0 2.15.3 1.16.1 - 2.0.7 + 2.0.9 5.10.1 3.24.2 1.4.8 From 4bb69edd972984ff2ea8f123d7afceab8b866f3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:36:40 +0000 Subject: [PATCH 11/21] Bump ch.qos.logback:logback-classic from 1.4.8 to 1.4.11 Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.8 to 1.4.11. - [Commits](https://github.com/qos-ch/logback/compare/v_1.4.8...v_1.4.11) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 061584b..fea057c 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ 2.0.7 5.10.1 3.24.2 - 1.4.8 + 1.4.11 3.2.1 From 7fc9d9aac75f4d7524f731018c128f4f7a67f250 Mon Sep 17 00:00:00 2001 From: sfrei Date: Mon, 6 Nov 2023 20:37:05 +0100 Subject: [PATCH 12/21] Increase open PRs limit for dependabot --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a9d7e2d..5471df3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,6 +11,6 @@ updates: timezone: "Europe/Berlin" time: "06:00" target-branch: "develop" - open-pull-requests-limit: 10 + open-pull-requests-limit: 25 reviewers: - "s-frei" From c68a9699575cb08a8363c25ed6ca4cf26a02652a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:37:13 +0000 Subject: [PATCH 13/21] Bump maven-release-plugin from 3.0.0 to 3.0.1 Bumps [maven-release-plugin](https://github.com/apache/maven-release) from 3.0.0 to 3.0.1. - [Release notes](https://github.com/apache/maven-release/releases) - [Commits](https://github.com/apache/maven-release/compare/maven-release-3.0.0...maven-release-3.0.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-release-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 061584b..ff29a81 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 3.11.0 3.2.1 3.5.0 - 3.0.0 + 3.0.1 2.0.1 2.0.1 1.6.13 From 2a27a87a295a70160bad411debf7214b00cf9f26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:37:25 +0000 Subject: [PATCH 14/21] Bump maven-source-plugin from 3.2.1 to 3.3.0 Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.2.1 to 3.3.0. - [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.2.1...maven-source-plugin-3.3.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-source-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 061584b..7ab521a 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 1.18.20.0 3.11.0 - 3.2.1 + 3.3.0 3.5.0 3.0.0 2.0.1 From 19262ff9ec25230526f22b8c6c2b58a1c287f552 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:37:57 +0000 Subject: [PATCH 15/21] Bump org.jsoup:jsoup from 1.16.1 to 1.16.2 Bumps [org.jsoup:jsoup](https://github.com/jhy/jsoup) from 1.16.1 to 1.16.2. - [Release notes](https://github.com/jhy/jsoup/releases) - [Changelog](https://github.com/jhy/jsoup/blob/master/CHANGES) - [Commits](https://github.com/jhy/jsoup/compare/jsoup-1.16.1...jsoup-1.16.2) --- updated-dependencies: - dependency-name: org.jsoup:jsoup dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 061584b..3f5f2da 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ 2.9.0 4.11.0 2.15.3 - 1.16.1 + 1.16.2 2.0.7 5.10.1 3.24.2 From 0de8672337237fe7d5f0a1e84dbe048dfb2d7eb0 Mon Sep 17 00:00:00 2001 From: sfrei Date: Mon, 6 Nov 2023 20:39:55 +0100 Subject: [PATCH 16/21] Fix dependabot auto-merge action --- .github/workflows/dependabot-auto-merge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 336fbad..7a34f76 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -22,7 +22,7 @@ jobs: uses: dependabot/fetch-metadata@v1 - name: "Enable auto-merge for Dependabot PRs" - if: ${{contains(steps.dependabot-metadata.outputs.dependency-names, 'rails') && steps.dependabot-metadata.outputs.update-type == 'version-update:semver-patch'}} + if: ${{steps.dependabot-metadata.outputs.update-type == 'version-update:semver-patch'}} run: gh pr merge --auto --merge "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} From c080e3193679ed075e6666c9003c7ee7f90811c3 Mon Sep 17 00:00:00 2001 From: sfrei Date: Mon, 6 Nov 2023 21:34:33 +0100 Subject: [PATCH 17/21] Fix YouTube content parsing --- .../clients/soundcloud/SoundCloudUtility.java | 4 +- .../clients/youtube/YouTubeUtility.java | 59 ++++++++++--------- .../SoundCloudTrackDeserializer.java | 22 +++---- .../YouTubeTrackDeserializer.java | 16 ++--- .../tracksearch/utils/json/JsonElement.java | 41 +++++++------ .../utils/json/JsonNodeResolver.java | 15 ++--- 6 files changed, 76 insertions(+), 81 deletions(-) diff --git a/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java b/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java index 48142f7..85496e1 100644 --- a/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java +++ b/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java @@ -83,12 +83,12 @@ protected GenericTrackList getSoundCloudTracks(final String jso final StreamURLFunction streamUrlFunction) throws SoundCloudException { - final JsonElement responseElement = JsonElement.readHandled(MAPPER, json) + final JsonElement responseElement = JsonElement.readTreeCatching(MAPPER, json) .orElseThrow(() -> new SoundCloudException("Cannot parse SoundCloudTracks JSON")) .path("collection"); final List scTracks = responseElement.elements() - .map(element -> element.mapToObjectHandled(MAPPER, SoundCloudTrack.SoundCloudTrackBuilder.class)) + .map(element -> element.mapCatching(MAPPER, SoundCloudTrack.SoundCloudTrackBuilder.class)) .filter(Objects::nonNull) .peek(soundCloudTrackBuilder -> soundCloudTrackBuilder.streamUrlFunction(streamUrlFunction)) .map(SoundCloudTrack.SoundCloudTrackBuilder::build) diff --git a/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java b/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java index db05218..1bd6c14 100644 --- a/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java +++ b/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java @@ -69,7 +69,7 @@ class YouTubeUtility { ); private static final Pattern EMBEDDED_PLAYER_SCRIPT_PATTERN = Pattern.compile("src=\"(/[a-zA-Z0-9/-_.]+base.js)\""); - private final CacheMap sigResolverCache = new CacheMap<>(); + private final CacheMap sigResolverCache = new CacheMap<>(); private static final ObjectMapper MAPPER = DeserializerUtility.mapperFor(YouTubeTrack.YouTubeTrackBuilder.class, new YouTubeTrackDeserializer()); @@ -78,37 +78,38 @@ private static String wrap(String functionContent) { } protected GenericTrackList getYouTubeTracks(final String json, final QueryType queryType, final String query, - final NextTrackListFunction nextTrackListFunction, - final StreamURLFunction streamUrlFunction) + final NextTrackListFunction nextTrackListFunction, + final StreamURLFunction streamUrlFunction) throws YouTubeException { - final JsonElement rootElement = JsonElement.readHandled(MAPPER, json) + final JsonElement rootElement = JsonElement.readTreeCatching(MAPPER, json) .orElseThrow(() -> new YouTubeException("Cannot parse YouTubeTracks JSON")); - final JsonElement responseElement = rootElement.path("response").orElse(rootElement).getAtIndex(1).path("response"); + final JsonElement responseElement = rootElement.path("response").orElse(rootElement).elementAtIndex(1).path("response"); final JsonElement defaultElement = responseElement.asUnresolved() .path("contents", "twoColumnSearchResultsRenderer", "primaryContents", "sectionListRenderer", "contents"); final JsonElement contentHolder = defaultElement - .firstElementWhereNotFound("itemSectionRenderer", "promotedSparklesWebRenderer") + .firstElement() + .path("itemSectionRenderer") .orElse(responseElement) .path("onResponseReceivedCommands") - .getFirstField() + .firstElement() .path("appendContinuationItemsAction", "continuationItems") - .getFirstField() + .firstElement() .path("itemSectionRenderer") .orElse(responseElement) .path("onResponseReceivedCommands") - .getFirstField() + .firstElement() .path("appendContinuationItemsAction", "continuationItems") - .getFirstField() + .firstElement() .path("itemSectionRenderer") .orElse(responseElement) .path("continuationContents", "itemSectionContinuation", "itemSectionContinuation") .orElse(responseElement) .path("continuationContents", "sectionListContinuation", "contents") - .getFirstField() + .firstElement() .path("itemSectionRenderer"); final String cToken = extractCToken(responseElement, defaultElement, contentHolder); @@ -117,9 +118,9 @@ protected GenericTrackList getYouTubeTracks(final String json, fin final List ytTracks = contents.elements() .filter(content -> content.path("videoRenderer", "upcomingEventData").isNull()) // Avoid premieres .filter(content -> content.path("promotedSparklesWebRenderer").isNull()) // Avoid ads - .map(content -> content.path("videoRenderer").orElse(content).path("searchPyvRenderer", "ads").getFirstField().path("promotedVideoRenderer")) + .map(content -> content.path("videoRenderer").orElse(content).path("searchPyvRenderer", "ads").firstElement().path("promotedVideoRenderer")) .filter(renderer -> renderer.asUnresolved().path("lengthText").isPresent()) // Avoid live streams - .map(renderer -> renderer.mapToObjectHandled(MAPPER, YouTubeTrack.YouTubeTrackBuilder.class)) + .map(renderer -> renderer.mapCatching(MAPPER, YouTubeTrack.YouTubeTrackBuilder.class)) .filter(Objects::nonNull) .peek(youTubeTrackBuilder -> youTubeTrackBuilder.streamUrlFunction(streamUrlFunction)) .map(YouTubeTrack.YouTubeTrackBuilder::build) @@ -136,32 +137,32 @@ protected GenericTrackList getYouTubeTracks(final String json, fin } private static String extractCToken(JsonElement responseElement, JsonElement defaultElement, JsonElement contentHolder) { - if (contentHolder.fieldPresent("continuations")) { + if (contentHolder.nodePresent("continuations")) { return contentHolder.asUnresolved() .path("continuations") - .getFirstField() + .firstElement() .path("nextContinuationData") - .fieldAsString("continuation"); + .asString("continuation"); } return responseElement.asUnresolved() .path("onResponseReceivedCommands") - .getFirstField() + .firstElement() .path("appendContinuationItemsAction", "continuationItems") - .getAtIndex(1) + .elementAtIndex(1) .path("continuationItemRenderer", "continuationEndpoint", "continuationCommand") .orElse(defaultElement) .firstElementFor("continuationItemRenderer") .path("continuationEndpoint", "continuationCommand") - .fieldAsString("token"); + .asString("token"); } protected YouTubeTrackInfo getTrackInfo(final String json, final String trackUrl, Function requester) { try { - final JsonElement jsonElement = JsonElement.read(MAPPER, json); + final JsonElement jsonElement = JsonElement.readTree(MAPPER, json); final JsonElement playerElement; if (jsonElement.isArray()) { - playerElement = jsonElement.getAtIndex(2).path("player"); + playerElement = jsonElement.elementAtIndex(2).path("player"); } else { playerElement = jsonElement.firstElementFor("player"); } @@ -174,13 +175,13 @@ protected YouTubeTrackInfo getTrackInfo(final String json, final String trackUrl final JsonElement args = playerElement.path("args"); if (playerElement.isPresent() && args.isPresent()) { - scriptUrl.set(playerElement.path("assets").fieldAsString("js")); + scriptUrl.set(playerElement.path("assets").asString("js")); streamingData = args.path("player_response") - .reRead(MAPPER) + .reReadTree(MAPPER) .path("streamingData"); } else { - streamingData = jsonElement.getAtIndex(2) + streamingData = jsonElement.elementAtIndex(2) .path("playerResponse", "streamingData"); } @@ -220,17 +221,17 @@ protected YouTubeTrackInfo getTrackInfo(final String json, final String trackUrl private Stream getFormatsFromStream(final Stream formats) { return formats.map(format -> { - final String mimeType = format.fieldAsString("mimeType"); + final String mimeType = format.asString("mimeType"); final FormatType formatType = FormatType.getFormatType(mimeType); - final String audioQuality = format.fieldAsString("audioQuality"); - final String audioSampleRate = format.fieldAsString("audioSampleRate"); + final String audioQuality = format.asString("audioQuality"); + final String audioSampleRate = format.asString("audioSampleRate"); final JsonElement cipherElement = format.path("cipher") .orElse(format) .path("signatureCipher"); if (cipherElement.isNull()) { - final String url = format.fieldAsString("url"); + final String url = format.asString("url"); return YouTubeTrackFormat.builder() .mimeType(mimeType) .formatType(formatType) @@ -240,7 +241,7 @@ private Stream getFormatsFromStream(final Stream params = URLUtility.splitParamsAndDecode(cipher); return YouTubeTrackFormat.builder() .mimeType(mimeType) diff --git a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/SoundCloudTrackDeserializer.java b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/SoundCloudTrackDeserializer.java index 1f7b3b6..c9b4211 100644 --- a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/SoundCloudTrackDeserializer.java +++ b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/SoundCloudTrackDeserializer.java @@ -40,9 +40,9 @@ public SoundCloudTrackBuilder deserialize(final JsonParser p, final Deserializat // Track final JsonElement rootElement = JsonElement.of(ctxt.readTree(p)); - final String title = rootElement.fieldAsString("title"); - final Duration duration = TimeUtility.getDurationForMilliseconds(rootElement.fieldAsLong("duration")); - final String url = rootElement.fieldAsString("permalink_url"); + final String title = rootElement.asString("title"); + final Duration duration = TimeUtility.getDurationForMilliseconds(rootElement.asLong("duration")); + final String url = rootElement.asString("permalink_url"); if (title == null || duration == null || url == null) return null; @@ -56,17 +56,17 @@ public SoundCloudTrackBuilder deserialize(final JsonParser p, final Deserializat final JsonElement owner = rootElement.path("user"); - final String channelName = owner.fieldAsString("username"); + final String channelName = owner.asString("username"); - final String channelUrl = owner.fieldAsString("permalink_url"); + final String channelUrl = owner.asString("permalink_url"); - final Long playbackCount = rootElement.fieldAsLong("playback_count"); + final Long playbackCount = rootElement.asLong("playback_count"); final Long streamAmount = playbackCount == null ? 0L : playbackCount; // Apparently can be 'null' in the JSON final String thumbNailUrl = rootElement.path("artwork_url") .orElse(rootElement) .path("user", "avatar_url") // Fallback to channel thumbnail - .fieldAsString(); + .asString(); soundCloudTrackBuilder.trackMetadata(SoundCloudTrackMetadata.of(channelName, channelUrl, streamAmount, thumbNailUrl)); @@ -84,12 +84,12 @@ public SoundCloudTrackBuilder deserialize(final JsonParser p, final Deserializat private static SoundCloudTrackFormat transcodingToTrackFormat(JsonElement transcoding) { - final String formatUrl = transcoding.fieldAsString("url"); - final String audioQuality = transcoding.fieldAsString("quality"); + final String formatUrl = transcoding.asString("url"); + final String audioQuality = transcoding.asString("quality"); final JsonElement formatElement = transcoding.path("format"); - final String mimeType = formatElement.fieldAsString("mime_type"); - final String protocol = formatElement.fieldAsString("protocol"); + final String mimeType = formatElement.asString("mime_type"); + final String protocol = formatElement.asString("protocol"); return SoundCloudTrackFormat.builder() .mimeType(mimeType) diff --git a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeTrackDeserializer.java b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeTrackDeserializer.java index e17fcb6..fcd979b 100644 --- a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeTrackDeserializer.java +++ b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeTrackDeserializer.java @@ -42,9 +42,9 @@ public YouTubeTrackBuilder deserialize(final JsonParser p, final Deserialization // Track - final String ref = rootElement.fieldAsString("videoId"); - final String title = rootElement.path("title", "runs").getFirstField().fieldAsString("text"); - final String timeString = rootElement.path("lengthText").fieldAsString("simpleText"); + final String ref = rootElement.asString("videoId"); + final String title = rootElement.path("title", "runs").firstElement().asString("text"); + final String timeString = rootElement.path("lengthText").asString("simpleText"); final Duration duration = TimeUtility.getDurationForTimeString(timeString); if (title == null || duration == null || ref == null) @@ -59,15 +59,15 @@ public YouTubeTrackBuilder deserialize(final JsonParser p, final Deserialization // Metadata - final JsonElement owner = rootElement.path("ownerText", "runs").getFirstField(); + final JsonElement owner = rootElement.path("ownerText", "runs").firstElement(); - final String channelName = owner.fieldAsString("text"); + final String channelName = owner.asString("text"); final String channelUrlSuffix = owner.path("navigationEndpoint", "commandMetadata", "webCommandMetadata") - .fieldAsString("url"); + .asString("url"); final String channelUrl = YouTubeClient.HOSTNAME.concat(channelUrlSuffix); - final String streamAmountText = rootElement.path("viewCountText").fieldAsString("simpleText"); + final String streamAmountText = rootElement.path("viewCountText").asString("simpleText"); final String streamAmountDigits = streamAmountText == null || streamAmountText.isEmpty() ? null : ReplaceUtility.replaceNonDigits(streamAmountText); final Long streamAmount = streamAmountDigits == null || streamAmountDigits.isEmpty() ? @@ -75,7 +75,7 @@ public YouTubeTrackBuilder deserialize(final JsonParser p, final Deserialization final Stream thumbNailStream = rootElement.path("thumbnail", "thumbnails").elements(); final Optional lastThumbnail = thumbNailStream.findFirst(); - final String thumbNailUrl = lastThumbnail.map(thumbNail -> thumbNail.fieldAsString("url")).orElse(null); + final String thumbNailUrl = lastThumbnail.map(thumbNail -> thumbNail.asString("url")).orElse(null); youTubeTrackBuilder.trackMetadata(YouTubeTrackMetadata.of(channelName, channelUrl, streamAmount, thumbNailUrl)); diff --git a/src/main/java/io/sfrei/tracksearch/utils/json/JsonElement.java b/src/main/java/io/sfrei/tracksearch/utils/json/JsonElement.java index f1d397a..3385a5d 100644 --- a/src/main/java/io/sfrei/tracksearch/utils/json/JsonElement.java +++ b/src/main/java/io/sfrei/tracksearch/utils/json/JsonElement.java @@ -38,13 +38,13 @@ public JsonElement(JsonNode node, boolean resolved) { super(node, resolved); } - public static JsonElement read(final ObjectMapper mapper, final String json) throws JsonProcessingException { + public static JsonElement readTree(final ObjectMapper mapper, final String json) throws JsonProcessingException { return new JsonElement(mapper.readTree(json), false); } - public static Optional readHandled(final ObjectMapper mapper, final String json) { + public static Optional readTreeCatching(final ObjectMapper mapper, final String json) { try { - return Optional.of(read(mapper, json)); + return Optional.of(readTree(mapper, json)); } catch (JsonProcessingException e) { log.error("Error occurred reading JSON: '{}'", json, e); return Optional.empty(); @@ -85,18 +85,14 @@ public JsonElement firstElementWhereNotFound(final String path, final String not } public Stream arrayElements() { - return isArray() ? StreamSupport.stream(arrayNode().spliterator(), false).map(JsonElement::of) : Stream.empty(); + return isArray() ? StreamSupport.stream(toArrayNode().spliterator(), false).map(JsonElement::of) : Stream.empty(); } - public String fieldAsString(final String... paths) { - return getAsString(path(paths).node()); + public String asString(final String... paths) { + return super.asString(path(paths).node()); } - public String fieldAsString() { - return getAsString(); - } - - public Long fieldAsLong(final String... paths) { + public Long asLong(final String... paths) { return getAsLong(path(paths).node()); } @@ -105,6 +101,9 @@ public JsonElement path(final String... paths) { } private JsonNode nodeForPath(String... paths) { + if (paths.length == 0) + return node(); + final AtomicReference tempNode = new AtomicReference<>(node()); for (final String path : paths) { @@ -116,25 +115,25 @@ private JsonNode nodeForPath(String... paths) { return tempNode.get(); } - public JsonElement getFirstField() { + public JsonElement firstElement() { return nextElement(node -> atIndex(0)); } - public JsonElement getAtIndex(final int index) { + public JsonElement elementAtIndex(final int index) { return nextElement(node -> atIndex(index)); } - public JsonElement reRead(final ObjectMapper mapper) throws JsonProcessingException { - return read(mapper, getAsString(node())); + public JsonElement reReadTree(final ObjectMapper mapper) throws JsonProcessingException { + return readTree(mapper, asString(node())); } - public T mapToObject(final ObjectMapper mapper, final Class clazz) throws JsonProcessingException { + public T map(final ObjectMapper mapper, final Class clazz) throws JsonProcessingException { return mapper.treeToValue(node(), clazz); } - public T mapToObjectHandled(final ObjectMapper mapper, final Class clazz) { + public T mapCatching(final ObjectMapper mapper, final Class clazz) { try { - return mapToObject(mapper, clazz); + return map(mapper, clazz); } catch (JsonProcessingException e) { log.error("Error parsing JSON as {}: '{}'", clazz.getSimpleName(), node(), e); } @@ -160,11 +159,11 @@ public boolean isNull() { } public boolean isPresent() { - return !isNull(); + return !nodeIsNull(); } - public boolean fieldPresent(String field) { - return JsonElement.of(nodeForPath(field)).isPresent(); + public boolean nodePresent(String path) { + return JsonElement.of(nodeForPath(path)).isPresent(); } } diff --git a/src/main/java/io/sfrei/tracksearch/utils/json/JsonNodeResolver.java b/src/main/java/io/sfrei/tracksearch/utils/json/JsonNodeResolver.java index 8e37744..3ed88db 100644 --- a/src/main/java/io/sfrei/tracksearch/utils/json/JsonNodeResolver.java +++ b/src/main/java/io/sfrei/tracksearch/utils/json/JsonNodeResolver.java @@ -19,22 +19,21 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import lombok.AllArgsConstructor; +import lombok.Getter; @AllArgsConstructor public abstract class JsonNodeResolver { private final JsonNode node; + + @Getter private final boolean resolved; public JsonNode node() { return node; } - public boolean isResolved() { - return resolved; - } - protected boolean nodeIsNull(JsonNode node) { return node == null || node.isNull(); } @@ -47,18 +46,14 @@ public boolean isArray() { return node.isArray(); } - protected ArrayNode arrayNode() { + protected ArrayNode toArrayNode() { return (ArrayNode) node; } - protected String getAsString(final JsonNode node) { + public String asString(final JsonNode node) { return nodeIsNull(node) ? null : node.asText(); } - protected String getAsString() { - return getAsString(node); - } - protected Long getAsLong(final JsonNode node) { return nodeIsNull(node) ? null : node.asLong(); } From 352abd66c7d56332887178f8fc35a8ff866656c5 Mon Sep 17 00:00:00 2001 From: sfrei Date: Tue, 7 Nov 2023 00:06:51 +0100 Subject: [PATCH 18/21] First shot of YouTube direct track URL search --- .../clients/soundcloud/SoundCloudUtility.java | 5 +- .../clients/youtube/YouTubeClient.java | 23 ++++-- .../clients/youtube/YouTubeUtility.java | 30 +++++-- .../io/sfrei/tracksearch/tracks/Track.java | 2 +- .../tracksearch/tracks/YouTubeTrack.java | 17 ++++ ...java => YouTubeListTrackDeserializer.java} | 9 ++- .../YouTubeURLTrackDeserializer.java | 81 +++++++++++++++++++ ...rUtility.java => ObjectMapperBuilder.java} | 17 ++-- .../tracksearch/utils/ReplaceUtility.java | 4 +- .../sfrei/tracksearch/utils/TimeUtility.java | 7 ++ .../tracksearch/utils/json/JsonElement.java | 15 +--- 11 files changed, 169 insertions(+), 41 deletions(-) rename src/main/java/io/sfrei/tracksearch/tracks/deserializer/{YouTubeTrackDeserializer.java => YouTubeListTrackDeserializer.java} (86%) create mode 100644 src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeURLTrackDeserializer.java rename src/main/java/io/sfrei/tracksearch/utils/{DeserializerUtility.java => ObjectMapperBuilder.java} (70%) diff --git a/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java b/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java index 85496e1..1ca9743 100644 --- a/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java +++ b/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java @@ -24,7 +24,7 @@ import io.sfrei.tracksearch.tracks.GenericTrackList; import io.sfrei.tracksearch.tracks.SoundCloudTrack; import io.sfrei.tracksearch.tracks.deserializer.SoundCloudTrackDeserializer; -import io.sfrei.tracksearch.utils.DeserializerUtility; +import io.sfrei.tracksearch.utils.ObjectMapperBuilder; import io.sfrei.tracksearch.utils.json.JsonElement; import lombok.extern.slf4j.Slf4j; import org.jsoup.Jsoup; @@ -54,7 +54,8 @@ class SoundCloudUtility { private static final Pattern ALTERNATIVE_PROGRESSIVE_SOUNDCLOUD_STREAM_URL_PATTERN = Pattern.compile(ALTERNATIVE_PROGRESSIVE_SOUNDCLOUD_STREAM_REGEX); private static final Pattern ALTERNATIVE_SOUNDCLOUD_STREAM_URL_PATTERN = Pattern.compile(ALTERNATIVE_SOUNDCLOUD_STREAM_REGEX); - private static final ObjectMapper MAPPER = DeserializerUtility.mapperFor(SoundCloudTrack.SoundCloudTrackBuilder.class, new SoundCloudTrackDeserializer()); + private static final ObjectMapper MAPPER = ObjectMapperBuilder.create() + .addDeserializer(SoundCloudTrack.SoundCloudTrackBuilder.class, new SoundCloudTrackDeserializer()).get(); protected List getCrossOriginScripts(final String html) { final Document doc = Jsoup.parse(html); diff --git a/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeClient.java b/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeClient.java index 00acd17..d52b27a 100644 --- a/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeClient.java +++ b/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeClient.java @@ -55,7 +55,7 @@ public class YouTubeClient extends SingleSearchClient private static final String ADDITIONAL_PAGING_KEY = "continuation"; private static final Map VIDEO_SEARCH_PARAMS = Map.of("sp", "EgIQAQ%3D%3D"); - private static final Map TRACK_PARAMS = Map.of("pbj", "1", "hl", "en", "alt", "json"); + public static final Map TRACK_PARAMS = Map.of("pbj", "1", "hl", "en", "alt", "json"); private static final Map DEFAULT_SEARCH_PARAMS; @@ -92,6 +92,14 @@ public static Map makeQueryInformation(final String query, final return new HashMap<>(Map.of(TrackList.QUERY_KEY, query, PAGING_INFORMATION, pagingToken)); } + public YouTubeTrack getTrack(@NonNull final String trackUrl) throws TrackSearchException { + final String trackUrlJSON = trackUrlJSON(api.getForUrlWithParams(trackUrl, TRACK_PARAMS)); + final YouTubeTrack youTubeTrack = youTubeUtility.getYouTubeTrack(trackUrlJSON, this::provideStreamUrl); + final YouTubeTrackInfo trackInfo = youTubeUtility.getTrackInfo(trackUrlJSON, trackUrl, this::requestURL); + youTubeTrack.setTrackInfo(trackInfo); + return youTubeTrack; + } + private GenericTrackList getTracksForSearch(@NonNull final String search, @NonNull final Map params, QueryType queryType) throws TrackSearchException { @@ -124,13 +132,18 @@ public TrackList getNext(@NonNull final TrackList throw unsupportedQueryTypeException(YouTubeException::new, trackListQueryType); } + private String trackUrlJSON(Call trackCall) throws TrackSearchException { + final ResponseWrapper trackResponse = Client.request(trackCall); + return trackResponse.getContentOrThrow(); + } + public YouTubeTrackInfo loadTrackInfo(final YouTubeTrack youtubeTrack) throws TrackSearchException { + if (youtubeTrack.getTrackInfo() != null) return youtubeTrack.getTrackInfo(); + final String trackUrl = youtubeTrack.getUrl(); - final Call trackRequest = api.getForUrlWithParams(trackUrl, TRACK_PARAMS); - final ResponseWrapper trackResponse = Client.request(trackRequest); + final String trackURLContent = trackUrlJSON(api.getForUrlWithParams(trackUrl, TRACK_PARAMS)); - final String trackContent = trackResponse.getContentOrThrow(); - final YouTubeTrackInfo trackInfo = youTubeUtility.getTrackInfo(trackContent, trackUrl, this::requestURL); + final YouTubeTrackInfo trackInfo = youTubeUtility.getTrackInfo(trackURLContent, trackUrl, this::requestURL); return youtubeTrack.setAndGetTrackInfo(trackInfo); } diff --git a/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java b/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java index 1bd6c14..1e5dd6d 100644 --- a/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java +++ b/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java @@ -25,12 +25,13 @@ import io.sfrei.tracksearch.exceptions.YouTubeException; import io.sfrei.tracksearch.tracks.GenericTrackList; import io.sfrei.tracksearch.tracks.YouTubeTrack; -import io.sfrei.tracksearch.tracks.deserializer.YouTubeTrackDeserializer; +import io.sfrei.tracksearch.tracks.deserializer.YouTubeListTrackDeserializer; +import io.sfrei.tracksearch.tracks.deserializer.YouTubeURLTrackDeserializer; import io.sfrei.tracksearch.tracks.metadata.FormatType; import io.sfrei.tracksearch.tracks.metadata.YouTubeTrackFormat; import io.sfrei.tracksearch.tracks.metadata.YouTubeTrackInfo; import io.sfrei.tracksearch.utils.CacheMap; -import io.sfrei.tracksearch.utils.DeserializerUtility; +import io.sfrei.tracksearch.utils.ObjectMapperBuilder; import io.sfrei.tracksearch.utils.URLUtility; import io.sfrei.tracksearch.utils.json.JsonElement; import lombok.Value; @@ -71,12 +72,28 @@ class YouTubeUtility { private final CacheMap sigResolverCache = new CacheMap<>(); - private static final ObjectMapper MAPPER = DeserializerUtility.mapperFor(YouTubeTrack.YouTubeTrackBuilder.class, new YouTubeTrackDeserializer()); + private static final ObjectMapper MAPPER = ObjectMapperBuilder.create() + .addDeserializer(YouTubeTrack.ListYouTubeTrackBuilder.class, new YouTubeListTrackDeserializer()) + .addDeserializer(YouTubeTrack.URLYouTubeTrackBuilder.class, new YouTubeURLTrackDeserializer()) + .get(); private static String wrap(String functionContent) { return "(" + VAR_NAME + ":function" + functionContent + FUNCTION_END + ")"; } + protected YouTubeTrack getYouTubeTrack(final String json, final StreamURLFunction streamUrlFunction) + throws YouTubeException { + + final JsonElement jsonElement = JsonElement.readTreeCatching(MAPPER, json) + .orElseThrow(() -> new YouTubeException("Cannot parse YouTubeTrack JSON")); + + final JsonElement playerResponse = jsonElement.elementAtIndex(2).path("playerResponse"); + + return playerResponse.mapCatching(MAPPER, YouTubeTrack.URLYouTubeTrackBuilder.class).getBuilder() + .streamUrlFunction(streamUrlFunction) + .build(); + } + protected GenericTrackList getYouTubeTracks(final String json, final QueryType queryType, final String query, final NextTrackListFunction nextTrackListFunction, final StreamURLFunction streamUrlFunction) @@ -120,8 +137,9 @@ protected GenericTrackList getYouTubeTracks(final String json, fin .filter(content -> content.path("promotedSparklesWebRenderer").isNull()) // Avoid ads .map(content -> content.path("videoRenderer").orElse(content).path("searchPyvRenderer", "ads").firstElement().path("promotedVideoRenderer")) .filter(renderer -> renderer.asUnresolved().path("lengthText").isPresent()) // Avoid live streams - .map(renderer -> renderer.mapCatching(MAPPER, YouTubeTrack.YouTubeTrackBuilder.class)) + .map(renderer -> renderer.mapCatching(MAPPER, YouTubeTrack.ListYouTubeTrackBuilder.class)) .filter(Objects::nonNull) + .map(YouTubeTrack.ListYouTubeTrackBuilder::getBuilder) .peek(youTubeTrackBuilder -> youTubeTrackBuilder.streamUrlFunction(streamUrlFunction)) .map(YouTubeTrack.YouTubeTrackBuilder::build) .collect(Collectors.toList()); @@ -151,7 +169,7 @@ private static String extractCToken(JsonElement responseElement, JsonElement def .elementAtIndex(1) .path("continuationItemRenderer", "continuationEndpoint", "continuationCommand") .orElse(defaultElement) - .firstElementFor("continuationItemRenderer") + .findElement("continuationItemRenderer") .path("continuationEndpoint", "continuationCommand") .asString("token"); } @@ -164,7 +182,7 @@ protected YouTubeTrackInfo getTrackInfo(final String json, final String trackUrl if (jsonElement.isArray()) { playerElement = jsonElement.elementAtIndex(2).path("player"); } else { - playerElement = jsonElement.firstElementFor("player"); + playerElement = jsonElement.findElement("player"); } AtomicReference scriptUrl = new AtomicReference<>(null); diff --git a/src/main/java/io/sfrei/tracksearch/tracks/Track.java b/src/main/java/io/sfrei/tracksearch/tracks/Track.java index 6114159..e79628d 100644 --- a/src/main/java/io/sfrei/tracksearch/tracks/Track.java +++ b/src/main/java/io/sfrei/tracksearch/tracks/Track.java @@ -45,7 +45,7 @@ public interface Track { * @return the clean track title. */ default String getCleanTitle() { - return ReplaceUtility.cleanOutTitle(getTitle()); + return ReplaceUtility.cleanTitle(getTitle()); } /** diff --git a/src/main/java/io/sfrei/tracksearch/tracks/YouTubeTrack.java b/src/main/java/io/sfrei/tracksearch/tracks/YouTubeTrack.java index 9792658..810bc43 100644 --- a/src/main/java/io/sfrei/tracksearch/tracks/YouTubeTrack.java +++ b/src/main/java/io/sfrei/tracksearch/tracks/YouTubeTrack.java @@ -22,6 +22,7 @@ import io.sfrei.tracksearch.tracks.metadata.YouTubeTrackMetadata; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import java.time.Duration; @@ -56,4 +57,20 @@ public String getStreamUrl() { return streamUrlFunction.apply(this); } + @Getter + @NoArgsConstructor + public static class ListYouTubeTrackBuilder { + + final YouTubeTrackBuilder builder = YouTubeTrack.builder(); + + } + + @Getter + @NoArgsConstructor + public static class URLYouTubeTrackBuilder { + + final YouTubeTrackBuilder builder = YouTubeTrack.builder(); + + } + } diff --git a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeTrackDeserializer.java b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeListTrackDeserializer.java similarity index 86% rename from src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeTrackDeserializer.java rename to src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeListTrackDeserializer.java index fcd979b..bab2c0a 100644 --- a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeTrackDeserializer.java +++ b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeListTrackDeserializer.java @@ -34,9 +34,9 @@ import java.util.stream.Stream; @Slf4j -public class YouTubeTrackDeserializer extends JsonDeserializer { +public class YouTubeListTrackDeserializer extends JsonDeserializer { - public YouTubeTrackBuilder deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException { + public YouTubeTrack.ListYouTubeTrackBuilder deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException { final JsonElement rootElement = JsonElement.of(ctxt.readTree(p)); @@ -52,7 +52,8 @@ public YouTubeTrackBuilder deserialize(final JsonParser p, final Deserialization final String url = YouTubeClient.HOSTNAME.concat("/watch?v=").concat(ref); - final YouTubeTrackBuilder youTubeTrackBuilder = YouTubeTrack.builder() + final YouTubeTrack.ListYouTubeTrackBuilder listYouTubeTrackBuilder = new YouTubeTrack.ListYouTubeTrackBuilder(); + final YouTubeTrackBuilder youTubeTrackBuilder = listYouTubeTrackBuilder.getBuilder() .title(title) .duration(duration) .url(url); @@ -79,7 +80,7 @@ public YouTubeTrackBuilder deserialize(final JsonParser p, final Deserialization youTubeTrackBuilder.trackMetadata(YouTubeTrackMetadata.of(channelName, channelUrl, streamAmount, thumbNailUrl)); - return youTubeTrackBuilder; + return listYouTubeTrackBuilder; } } diff --git a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeURLTrackDeserializer.java b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeURLTrackDeserializer.java new file mode 100644 index 0000000..29d1730 --- /dev/null +++ b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeURLTrackDeserializer.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023 s-frei (sfrei.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.sfrei.tracksearch.tracks.deserializer; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import io.sfrei.tracksearch.clients.youtube.YouTubeClient; +import io.sfrei.tracksearch.tracks.YouTubeTrack; +import io.sfrei.tracksearch.tracks.YouTubeTrack.YouTubeTrackBuilder; +import io.sfrei.tracksearch.tracks.metadata.YouTubeTrackMetadata; +import io.sfrei.tracksearch.utils.TimeUtility; +import io.sfrei.tracksearch.utils.json.JsonElement; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.time.Duration; +import java.util.Optional; +import java.util.stream.Stream; + +@Slf4j +public class YouTubeURLTrackDeserializer extends JsonDeserializer { + + public YouTubeTrack.URLYouTubeTrackBuilder deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException { + + final JsonElement rootElement = JsonElement.of(ctxt.readTree(p)); + + // Track + + final JsonElement videoDetails = rootElement.path("videoDetails"); + + final String ref = videoDetails.asString("videoId"); + final String title = videoDetails.asString("title"); + final Long lengthSeconds = Long.parseLong(videoDetails.asString("lengthSeconds")); + final Duration duration = TimeUtility.getDurationForSeconds(lengthSeconds); + + if (title == null || duration == null || ref == null) + return null; + + final String url = YouTubeClient.HOSTNAME.concat("/watch?v=").concat(ref); + + final YouTubeTrack.URLYouTubeTrackBuilder listYouTubeTrackBuilder = new YouTubeTrack.URLYouTubeTrackBuilder(); + final YouTubeTrackBuilder youTubeTrackBuilder = listYouTubeTrackBuilder.getBuilder() + .title(title) + .duration(duration) + .url(url); + + // Metadata + + final JsonElement owner = rootElement.path("microformat", "playerMicroformatRenderer"); + + final String channelName = owner.asString("ownerChannelName"); + + final String channelUrl = owner.asString("ownerProfileUrl").replaceFirst("^http", "https"); + + final long streamAmount = Long.parseLong(owner.asString("viewCount")); + + final Stream thumbNailStream = owner.path("thumbnail", "thumbnails").elements(); + final Optional firstThumbnail = thumbNailStream.findFirst(); + final String thumbNailUrl = firstThumbnail.map(thumbNail -> thumbNail.asString("url")).orElse(null); + + youTubeTrackBuilder.trackMetadata(YouTubeTrackMetadata.of(channelName, channelUrl, streamAmount, thumbNailUrl)); + + return listYouTubeTrackBuilder; + } + +} diff --git a/src/main/java/io/sfrei/tracksearch/utils/DeserializerUtility.java b/src/main/java/io/sfrei/tracksearch/utils/ObjectMapperBuilder.java similarity index 70% rename from src/main/java/io/sfrei/tracksearch/utils/DeserializerUtility.java rename to src/main/java/io/sfrei/tracksearch/utils/ObjectMapperBuilder.java index 5fac484..92aa3a5 100644 --- a/src/main/java/io/sfrei/tracksearch/utils/DeserializerUtility.java +++ b/src/main/java/io/sfrei/tracksearch/utils/ObjectMapperBuilder.java @@ -19,18 +19,21 @@ import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; -import lombok.experimental.UtilityClass; +import lombok.NoArgsConstructor; -@UtilityClass -public class DeserializerUtility { +@NoArgsConstructor(staticName = "create") +public class ObjectMapperBuilder { - public ObjectMapper mapperFor(Class type, JsonDeserializer deserializer) { - final ObjectMapper objectMapper = new ObjectMapper(); - final SimpleModule simpleModule = new SimpleModule(); + final ObjectMapper objectMapper = new ObjectMapper(); + private final SimpleModule simpleModule = new SimpleModule(); + public ObjectMapperBuilder addDeserializer(Class type, JsonDeserializer deserializer) { simpleModule.addDeserializer(type, deserializer); - objectMapper.registerModule(simpleModule); + return this; + } + public ObjectMapper get() { + objectMapper.registerModule(simpleModule); return objectMapper; } diff --git a/src/main/java/io/sfrei/tracksearch/utils/ReplaceUtility.java b/src/main/java/io/sfrei/tracksearch/utils/ReplaceUtility.java index a2fed84..9852a6e 100644 --- a/src/main/java/io/sfrei/tracksearch/utils/ReplaceUtility.java +++ b/src/main/java/io/sfrei/tracksearch/utils/ReplaceUtility.java @@ -21,8 +21,8 @@ @UtilityClass public class ReplaceUtility { - public String cleanOutTitle(final String chars) { - return chars + public String cleanTitle(final String title) { + return title .replaceAll("@", " at ") .replaceAll("_", " ") .replaceAll("\\s(\\[]\\(\\))", "") diff --git a/src/main/java/io/sfrei/tracksearch/utils/TimeUtility.java b/src/main/java/io/sfrei/tracksearch/utils/TimeUtility.java index 9f27bac..08dfa57 100644 --- a/src/main/java/io/sfrei/tracksearch/utils/TimeUtility.java +++ b/src/main/java/io/sfrei/tracksearch/utils/TimeUtility.java @@ -48,6 +48,13 @@ public Duration getDurationForMilliseconds(final Long milliseconds) { return Duration.ofMillis(milliseconds); } + public Duration getDurationForSeconds(final Long seconds) { + if (seconds == null) + return null; + + return Duration.ofSeconds(seconds); + } + public String formatSeconds(Duration duration) { final String mmss = String.format("%02d:%02d", duration.toMinutesPart(), duration.toSecondsPart()); diff --git a/src/main/java/io/sfrei/tracksearch/utils/json/JsonElement.java b/src/main/java/io/sfrei/tracksearch/utils/json/JsonElement.java index 3385a5d..c6111ad 100644 --- a/src/main/java/io/sfrei/tracksearch/utils/json/JsonElement.java +++ b/src/main/java/io/sfrei/tracksearch/utils/json/JsonElement.java @@ -21,7 +21,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; -import java.util.Objects; import java.util.Optional; import java.util.Spliterator; import java.util.Spliterators; @@ -68,22 +67,10 @@ public Stream elements() { .map(JsonElement::of); } - public JsonElement firstElementFor(final String path) { + public JsonElement findElement(final String path) { return nextElement(node -> node.findValues(path).stream().findFirst().orElse(null)); } - public JsonElement firstElementWhereNotFound(final String path, final String notPath) { - if (nodeIsNull(node())) - return this; - - return nextElement(node -> - node.findValues(path).stream() - .filter(pathNode -> Objects.isNull(pathNode.findValue(notPath))) - .findFirst() - .orElse(null) - ); - } - public Stream arrayElements() { return isArray() ? StreamSupport.stream(toArrayNode().spliterator(), false).map(JsonElement::of) : Stream.empty(); } From a66360be55ac567a18bf059bb59ebaf54fed3113 Mon Sep 17 00:00:00 2001 From: sfrei Date: Tue, 7 Nov 2023 00:18:19 +0100 Subject: [PATCH 19/21] Introduce package structure for deserializers --- .../clients/soundcloud/SoundCloudUtility.java | 2 +- .../clients/youtube/YouTubeUtility.java | 19 ++++++++----------- .../SoundCloudTrackDeserializer.java | 2 +- .../YouTubeListTrackDeserializer.java | 2 +- .../YouTubeURLTrackDeserializer.java | 2 +- .../sfrei/tracksearch/clients/ClientTest.java | 2 +- 6 files changed, 13 insertions(+), 16 deletions(-) rename src/main/java/io/sfrei/tracksearch/tracks/deserializer/{ => soundcloud}/SoundCloudTrackDeserializer.java (98%) rename src/main/java/io/sfrei/tracksearch/tracks/deserializer/{ => youtube}/YouTubeListTrackDeserializer.java (98%) rename src/main/java/io/sfrei/tracksearch/tracks/deserializer/{ => youtube}/YouTubeURLTrackDeserializer.java (98%) diff --git a/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java b/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java index 1ca9743..8995f2e 100644 --- a/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java +++ b/src/main/java/io/sfrei/tracksearch/clients/soundcloud/SoundCloudUtility.java @@ -23,7 +23,7 @@ import io.sfrei.tracksearch.exceptions.SoundCloudException; import io.sfrei.tracksearch.tracks.GenericTrackList; import io.sfrei.tracksearch.tracks.SoundCloudTrack; -import io.sfrei.tracksearch.tracks.deserializer.SoundCloudTrackDeserializer; +import io.sfrei.tracksearch.tracks.deserializer.soundcloud.SoundCloudTrackDeserializer; import io.sfrei.tracksearch.utils.ObjectMapperBuilder; import io.sfrei.tracksearch.utils.json.JsonElement; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java b/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java index 1e5dd6d..c6368b2 100644 --- a/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java +++ b/src/main/java/io/sfrei/tracksearch/clients/youtube/YouTubeUtility.java @@ -25,8 +25,8 @@ import io.sfrei.tracksearch.exceptions.YouTubeException; import io.sfrei.tracksearch.tracks.GenericTrackList; import io.sfrei.tracksearch.tracks.YouTubeTrack; -import io.sfrei.tracksearch.tracks.deserializer.YouTubeListTrackDeserializer; -import io.sfrei.tracksearch.tracks.deserializer.YouTubeURLTrackDeserializer; +import io.sfrei.tracksearch.tracks.deserializer.youtube.YouTubeListTrackDeserializer; +import io.sfrei.tracksearch.tracks.deserializer.youtube.YouTubeURLTrackDeserializer; import io.sfrei.tracksearch.tracks.metadata.FormatType; import io.sfrei.tracksearch.tracks.metadata.YouTubeTrackFormat; import io.sfrei.tracksearch.tracks.metadata.YouTubeTrackInfo; @@ -189,22 +189,19 @@ protected YouTubeTrackInfo getTrackInfo(final String json, final String trackUrl final JsonElement streamingData; - if (playerElement != null) { + final JsonElement playerArgs = playerElement.path("args"); + if (playerElement.isPresent() && playerArgs.isPresent()) { - final JsonElement args = playerElement.path("args"); - if (playerElement.isPresent() && args.isPresent()) { scriptUrl.set(playerElement.path("assets").asString("js")); - streamingData = args.path("player_response") + streamingData = playerArgs.path("player_response") .reReadTree(MAPPER) .path("streamingData"); - } else { - streamingData = jsonElement.elementAtIndex(2) - .path("playerResponse", "streamingData"); - } } else { - streamingData = jsonElement.path("playerResponse", "streamingData"); + streamingData = jsonElement.elementAtIndex(2) + .path("playerResponse", "streamingData"); +// streamingData = jsonElement.path("playerResponse", "streamingData"); } final JsonElement formatsElement = streamingData.path("formats"); diff --git a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/SoundCloudTrackDeserializer.java b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/soundcloud/SoundCloudTrackDeserializer.java similarity index 98% rename from src/main/java/io/sfrei/tracksearch/tracks/deserializer/SoundCloudTrackDeserializer.java rename to src/main/java/io/sfrei/tracksearch/tracks/deserializer/soundcloud/SoundCloudTrackDeserializer.java index c9b4211..b900431 100644 --- a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/SoundCloudTrackDeserializer.java +++ b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/soundcloud/SoundCloudTrackDeserializer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.sfrei.tracksearch.tracks.deserializer; +package io.sfrei.tracksearch.tracks.deserializer.soundcloud; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; diff --git a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeListTrackDeserializer.java b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/youtube/YouTubeListTrackDeserializer.java similarity index 98% rename from src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeListTrackDeserializer.java rename to src/main/java/io/sfrei/tracksearch/tracks/deserializer/youtube/YouTubeListTrackDeserializer.java index bab2c0a..ab4b1c0 100644 --- a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeListTrackDeserializer.java +++ b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/youtube/YouTubeListTrackDeserializer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.sfrei.tracksearch.tracks.deserializer; +package io.sfrei.tracksearch.tracks.deserializer.youtube; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; diff --git a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeURLTrackDeserializer.java b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/youtube/YouTubeURLTrackDeserializer.java similarity index 98% rename from src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeURLTrackDeserializer.java rename to src/main/java/io/sfrei/tracksearch/tracks/deserializer/youtube/YouTubeURLTrackDeserializer.java index 29d1730..b7310b4 100644 --- a/src/main/java/io/sfrei/tracksearch/tracks/deserializer/YouTubeURLTrackDeserializer.java +++ b/src/main/java/io/sfrei/tracksearch/tracks/deserializer/youtube/YouTubeURLTrackDeserializer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.sfrei.tracksearch.tracks.deserializer; +package io.sfrei.tracksearch.tracks.deserializer.youtube; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; diff --git a/src/test/java/io/sfrei/tracksearch/clients/ClientTest.java b/src/test/java/io/sfrei/tracksearch/clients/ClientTest.java index 7d263dd..7198207 100644 --- a/src/test/java/io/sfrei/tracksearch/clients/ClientTest.java +++ b/src/test/java/io/sfrei/tracksearch/clients/ClientTest.java @@ -74,7 +74,7 @@ private Stream> getAllTracksFromTrackLists() { public ClientTest(C searchClient, boolean single) { super(CookiePolicy.ACCEPT_ALL, null); this.searchClient = searchClient; - this.searchKeys = single ? List.of("Marek Hemann") : SEARCH_KEYS; + this.searchKeys = single ? List.of(SINGLE_SEARCH_KEY) : SEARCH_KEYS; tracksForSearch = new ArrayList<>(); } From 234939157cdafeda794c00babe0c52633049000c Mon Sep 17 00:00:00 2001 From: sfrei Date: Tue, 7 Nov 2023 00:39:21 +0100 Subject: [PATCH 20/21] Code fixes and default to 5 resolving tries --- .../io/sfrei/tracksearch/clients/interfaces/ClientHelper.java | 2 +- .../io/sfrei/tracksearch/clients/youtube/YouTubeClient.java | 4 +--- .../java/io/sfrei/tracksearch/config/TrackSearchConfig.java | 2 +- src/test/java/io/sfrei/tracksearch/clients/ClientTest.java | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/sfrei/tracksearch/clients/interfaces/ClientHelper.java b/src/main/java/io/sfrei/tracksearch/clients/interfaces/ClientHelper.java index a0c647f..058be0f 100644 --- a/src/main/java/io/sfrei/tracksearch/clients/interfaces/ClientHelper.java +++ b/src/main/java/io/sfrei/tracksearch/clients/interfaces/ClientHelper.java @@ -56,7 +56,7 @@ private Optional tryToGetStreamUrl(TrackSearchClient trackCall) throws TrackSearchE return trackResponse.getContentOrThrow(); } - public YouTubeTrackInfo loadTrackInfo(final YouTubeTrack youtubeTrack) throws TrackSearchException { - if (youtubeTrack.getTrackInfo() != null) return youtubeTrack.getTrackInfo(); - + private YouTubeTrackInfo loadTrackInfo(final YouTubeTrack youtubeTrack) throws TrackSearchException { final String trackUrl = youtubeTrack.getUrl(); final String trackURLContent = trackUrlJSON(api.getForUrlWithParams(trackUrl, TRACK_PARAMS)); diff --git a/src/main/java/io/sfrei/tracksearch/config/TrackSearchConfig.java b/src/main/java/io/sfrei/tracksearch/config/TrackSearchConfig.java index 8008998..dbbbc11 100644 --- a/src/main/java/io/sfrei/tracksearch/config/TrackSearchConfig.java +++ b/src/main/java/io/sfrei/tracksearch/config/TrackSearchConfig.java @@ -25,6 +25,6 @@ public final class TrackSearchConfig { public static final String HEADER_YOUTUBE_CLIENT_VERSION = "x-youtube-client-version: 2.20211004.00.00"; public static Integer playListOffset = 20; - public static Integer resolvingRetries = 2; + public static Integer resolvingRetries = 4; } diff --git a/src/test/java/io/sfrei/tracksearch/clients/ClientTest.java b/src/test/java/io/sfrei/tracksearch/clients/ClientTest.java index 7198207..9c48a90 100644 --- a/src/test/java/io/sfrei/tracksearch/clients/ClientTest.java +++ b/src/test/java/io/sfrei/tracksearch/clients/ClientTest.java @@ -195,7 +195,7 @@ public void getStreamUrl(Track track) { String streamUrl = track.getStreamUrl(); assertThat(streamUrl) - .as("Track '%s' should have stream for Track '%s'", track.getUrl()) + .as("Track should have stream URL for Track '%s'", track.getUrl()) .isNotEmpty(); final int code = requestAndGetCode(streamUrl); From 36bbd0c11513764f2c1f0975cb17f098fc8be897 Mon Sep 17 00:00:00 2001 From: sfrei Date: Tue, 7 Nov 2023 00:45:18 +0100 Subject: [PATCH 21/21] Set version to 0.8.2 and add changelog --- CHANGELOG.md | 13 ++++++++++--- README.md | 2 +- pom.xml | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 316d1ad..e9527e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,17 @@ Changelog ========= -0.8.2 - unreleased ------------------- +0.8.2 +----- + +**Features:** + +- Updated dependencies +- First shot of getting YouTubeTrack by URL + +**Bugfix:** -Nothing to see here yet... +- Fix YouTube tracks parsing 0.8.1 ----- diff --git a/README.md b/README.md index 2e2d483..8b3aaf0 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Maven dependency available on [Maven Central](https://search.maven.org/artifact/ io.sfrei tracksearch - 0.8.1 + 0.8.2 ``` diff --git a/pom.xml b/pom.xml index 8fe283f..a9ee48e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.sfrei tracksearch - 0.8.2-SNAPSHOT + 0.8.2 jar