Skip to content

Commit eb07d70

Browse files
authored
Merge pull request #964 from AudricV/yt-support-handles-and-all-channel-usernames
[YouTube] Support handles and all channel usernames
2 parents ffffb04 + 20cd8e8 commit eb07d70

8 files changed

Lines changed: 157 additions & 138 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/linkHandler/YoutubeChannelLinkHandlerFactory.java

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,46 @@
1-
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
2-
3-
import java.util.regex.Pattern;
4-
import org.schabi.newpipe.extractor.exceptions.ParsingException;
5-
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
6-
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
7-
import org.schabi.newpipe.extractor.utils.Utils;
8-
9-
import java.net.URL;
10-
import java.util.List;
11-
121
/*
132
* Created by Christian Schabesberger on 25.07.16.
143
*
154
* Copyright (C) Christian Schabesberger 2018 <chrźis.schabesberger@mailbox.org>
16-
* YoutubeChannelLinkHandlerFactory.java is part of NewPipe.
5+
* YoutubeChannelLinkHandlerFactory.java is part of NewPipe Extractor.
176
*
18-
* NewPipe is free software: you can redistribute it and/or modify
7+
* NewPipe Extractor is free software: you can redistribute it and/or modify
198
* it under the terms of the GNU General Public License as published by
209
* the Free Software Foundation, either version 3 of the License, or
2110
* (at your option) any later version.
2211
*
23-
* NewPipe is distributed in the hope that it will be useful,
12+
* NewPipe Extractor is distributed in the hope that it will be useful,
2413
* but WITHOUT ANY WARRANTY; without even the implied warranty of
25-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2615
* GNU General Public License for more details.
2716
*
2817
* You should have received a copy of the GNU General Public License
29-
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
18+
* along with NewPipe Extractor. If not, see <https://www.gnu.org/licenses/>.
3019
*/
3120

21+
package org.schabi.newpipe.extractor.services.youtube.linkHandler;
22+
23+
import java.util.regex.Pattern;
24+
import org.schabi.newpipe.extractor.exceptions.ParsingException;
25+
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
26+
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
27+
import org.schabi.newpipe.extractor.utils.Utils;
28+
29+
import javax.annotation.Nonnull;
30+
import java.net.URL;
31+
import java.util.List;
32+
33+
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
34+
3235
public final class YoutubeChannelLinkHandlerFactory extends ListLinkHandlerFactory {
3336

3437
private static final YoutubeChannelLinkHandlerFactory INSTANCE
3538
= new YoutubeChannelLinkHandlerFactory();
3639

37-
private static final Pattern EXCLUDED_SEGMENTS =
38-
Pattern.compile("playlist|watch|attribution_link|watch_popup|embed|feed|select_site");
40+
private static final Pattern EXCLUDED_SEGMENTS = Pattern.compile(
41+
// CHECKSTYLE:OFF
42+
"playlist|watch|attribution_link|watch_popup|embed|feed|select_site|account|reporthistory|redirect");
43+
// CHECKSTYLE:ON
3944

4045
private YoutubeChannelLinkHandlerFactory() {
4146
}
@@ -45,10 +50,10 @@ public static YoutubeChannelLinkHandlerFactory getInstance() {
4550
}
4651

4752
/**
48-
* Returns URL to channel from an ID
53+
* Returns the URL to a channel from an ID.
4954
*
50-
* @param id Channel ID including e.g. 'channel/'
51-
* @return URL to channel
55+
* @param id the channel ID including e.g. 'channel/'
56+
* @return the URL to the channel
5257
*/
5358
@Override
5459
public String getUrl(final String id,
@@ -58,16 +63,26 @@ public String getUrl(final String id,
5863
}
5964

6065
/**
61-
* Returns true if path conform to
62-
* custom short channel URLs like youtube.com/yourcustomname
66+
* Checks whether the given path conforms to custom short channel URLs like
67+
* {@code youtube.com/yourcustomname}.
6368
*
64-
* @param splitPath path segments array
65-
* @return true - if value conform to short channel URL, false - not
69+
* @param splitPath the path segments array
70+
* @return whether the value conform to short channel URLs
6671
*/
67-
private boolean isCustomShortChannelUrl(final String[] splitPath) {
72+
private boolean isCustomShortChannelUrl(@Nonnull final String[] splitPath) {
6873
return splitPath.length == 1 && !EXCLUDED_SEGMENTS.matcher(splitPath[0]).matches();
6974
}
7075

76+
/**
77+
* Checks whether the given path conforms to handle URLs like {@code youtube.com/@yourhandle}.
78+
*
79+
* @param splitPath the path segments array
80+
* @return whether the value conform to handle URLs
81+
*/
82+
private boolean isHandle(@Nonnull final String[] splitPath) {
83+
return splitPath.length > 0 && splitPath[0].startsWith("@");
84+
}
85+
7186
@Override
7287
public String getId(final String url) throws ParsingException {
7388
try {
@@ -77,35 +92,38 @@ public String getId(final String url) throws ParsingException {
7792
if (!Utils.isHTTP(urlObj) || !(YoutubeParsingHelper.isYoutubeURL(urlObj)
7893
|| YoutubeParsingHelper.isInvidioURL(urlObj)
7994
|| YoutubeParsingHelper.isHooktubeURL(urlObj))) {
80-
throw new ParsingException("the URL given is not a Youtube-URL");
95+
throw new ParsingException("The URL given is not a YouTube URL");
8196
}
8297

83-
// remove leading "/"
98+
// Remove leading "/"
8499
path = path.substring(1);
100+
85101
String[] splitPath = path.split("/");
86102

87-
// Handle custom short channel URLs like youtube.com/yourcustomname
88-
if (isCustomShortChannelUrl(splitPath)) {
103+
if (isHandle(splitPath)) {
104+
// Handle YouTube handle URLs like youtube.com/@yourhandle
105+
return splitPath[0];
106+
} else if (isCustomShortChannelUrl(splitPath)) {
107+
// Handle custom short channel URLs like youtube.com/yourcustomname
89108
path = "c/" + path;
90109
splitPath = path.split("/");
91110
}
92111

93-
if (!path.startsWith("user/")
94-
&& !path.startsWith("channel/")
112+
if (!path.startsWith("user/") && !path.startsWith("channel/")
95113
&& !path.startsWith("c/")) {
96-
throw new ParsingException("the URL given is neither a channel nor an user");
114+
throw new ParsingException(
115+
"The given URL is not a channel, a user or a handle URL");
97116
}
98117

99118
final String id = splitPath[1];
100119

101-
if (id == null || !id.matches("[A-Za-z0-9_-]+")) {
102-
throw new ParsingException("The given id is not a Youtube-Video-ID");
120+
if (isBlank(id)) {
121+
throw new ParsingException("The given ID is not a YouTube channel or user ID");
103122
}
104123

105124
return splitPath[0] + "/" + id;
106-
} catch (final Exception exception) {
107-
throw new ParsingException("Error could not parse url :" + exception.getMessage(),
108-
exception);
125+
} catch (final Exception e) {
126+
throw new ParsingException("Could not parse URL :" + e.getMessage(), e);
109127
}
110128
}
111129

extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelExtractorTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ public static void setUp() throws Exception {
155155
YoutubeTestsUtils.ensureStateless();
156156
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "gronkh"));
157157
extractor = (YoutubeChannelExtractor) YouTube
158-
.getChannelExtractor("http://www.youtube.com/user/Gronkh");
158+
.getChannelExtractor("http://www.youtube.com/@Gronkh");
159159
extractor.fetchPage();
160160
}
161161

@@ -185,7 +185,7 @@ public void testUrl() throws ParsingException {
185185

186186
@Test
187187
public void testOriginalUrl() throws ParsingException {
188-
assertEquals("http://www.youtube.com/user/Gronkh", extractor.getOriginalUrl());
188+
assertEquals("http://www.youtube.com/@Gronkh", extractor.getOriginalUrl());
189189
}
190190

191191
/*//////////////////////////////////////////////////////////////////////////

extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelLinkHandlerFactoryTest.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ public static void setUp() {
2525
}
2626

2727
@Test
28-
public void acceptUrlTest() throws ParsingException {
28+
void acceptUrlTest() throws ParsingException {
2929
assertTrue(linkHandler.acceptUrl("https://www.youtube.com/user/Gronkh"));
3030
assertTrue(linkHandler.acceptUrl("https://www.youtube.com/user/Netzkino/videos"));
3131

3232
assertTrue(linkHandler.acceptUrl("https://www.youtube.com/c/creatoracademy"));
33+
assertTrue(linkHandler.acceptUrl("https://www.youtube.com/c/%EB%85%B8%EB%A7%88%EB%93%9C%EC%BD%94%EB%8D%94NomadCoders"));
3334

3435
assertTrue(linkHandler.acceptUrl("https://youtube.com/DIMENSI0N"));
3536

@@ -49,6 +50,7 @@ public void acceptUrlTest() throws ParsingException {
4950
assertTrue(linkHandler.acceptUrl("https://invidio.us/channel/UClq42foiSgl7sSpLupnugGA/videos?disable_polymer=1"));
5051
assertTrue(linkHandler.acceptUrl("https://www.youtube.com/watchismo"));
5152

53+
assertTrue(linkHandler.acceptUrl("https://www.youtube.com/@YouTube"));
5254

5355
// do not accept URLs which are not channels
5456
assertFalse(linkHandler.acceptUrl("https://www.youtube.com/watch?v=jZViOEv90dI&t=100"));
@@ -62,14 +64,13 @@ public void acceptUrlTest() throws ParsingException {
6264
}
6365

6466
@Test
65-
public void getIdFromUrl() throws ParsingException {
67+
void getIdFromUrl() throws ParsingException {
6668
assertEquals("user/Gronkh", linkHandler.fromUrl("https://www.youtube.com/user/Gronkh").getId());
6769
assertEquals("user/Netzkino", linkHandler.fromUrl("https://www.youtube.com/user/Netzkino/videos").getId());
6870

6971
assertEquals("channel/UClq42foiSgl7sSpLupnugGA", linkHandler.fromUrl("https://www.youtube.com/channel/UClq42foiSgl7sSpLupnugGA").getId());
7072
assertEquals("channel/UClq42foiSgl7sSpLupnugGA", linkHandler.fromUrl("https://www.youtube.com/channel/UClq42foiSgl7sSpLupnugGA/videos?disable_polymer=1").getId());
7173

72-
7374
assertEquals("user/Gronkh", linkHandler.fromUrl("https://hooktube.com/user/Gronkh").getId());
7475
assertEquals("user/Netzkino", linkHandler.fromUrl("https://hooktube.com/user/Netzkino/videos").getId());
7576

@@ -84,5 +85,9 @@ public void getIdFromUrl() throws ParsingException {
8485

8586
assertEquals("c/creatoracademy", linkHandler.fromUrl("https://www.youtube.com/c/creatoracademy").getId());
8687
assertEquals("c/YouTubeCreators", linkHandler.fromUrl("https://www.youtube.com/c/YouTubeCreators").getId());
88+
assertEquals("c/%EB%85%B8%EB%A7%88%EB%93%9C%EC%BD%94%EB%8D%94NomadCoders", linkHandler.fromUrl("https://www.youtube.com/c/%EB%85%B8%EB%A7%88%EB%93%9C%EC%BD%94%EB%8D%94NomadCoders").getId());
89+
90+
assertEquals("@Gronkh", linkHandler.fromUrl("https://www.youtube.com/@Gronkh?ucbcb=1").getId());
91+
assertEquals("@YouTubeCreators", linkHandler.fromUrl("https://www.youtube.com/@YouTubeCreators/shorts").getId());
8792
}
8893
}

extractor/src/test/resources/org/schabi/newpipe/extractor/services/youtube/extractor/channel/gronkh/generated_mock_0.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@
4141
"same-origin; report-to\u003d\"youtube_main\""
4242
],
4343
"date": [
44-
"Wed, 02 Nov 2022 17:40:36 GMT"
44+
"Wed, 02 Nov 2022 23:12:52 GMT"
4545
],
4646
"expires": [
47-
"Wed, 02 Nov 2022 17:40:36 GMT"
47+
"Wed, 02 Nov 2022 23:12:52 GMT"
4848
],
4949
"p3p": [
5050
"CP\u003d\"This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl\u003den-GB for more info.\""
@@ -59,9 +59,9 @@
5959
"ESF"
6060
],
6161
"set-cookie": [
62-
"YSC\u003dIPHKPblTox0; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
63-
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dThu, 06-Feb-2020 17:40:36 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
64-
"CONSENT\u003dPENDING+350; expires\u003dFri, 01-Nov-2024 17:40:36 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
62+
"YSC\u003daFOfH_xu8k4; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
63+
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dThu, 06-Feb-2020 23:12:52 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
64+
"CONSENT\u003dPENDING+976; expires\u003dFri, 01-Nov-2024 23:12:52 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
6565
],
6666
"strict-transport-security": [
6767
"max-age\u003d31536000"

extractor/src/test/resources/org/schabi/newpipe/extractor/services/youtube/extractor/channel/gronkh/generated_mock_1.json

Lines changed: 5 additions & 5 deletions
Large diffs are not rendered by default.

extractor/src/test/resources/org/schabi/newpipe/extractor/services/youtube/extractor/channel/gronkh/generated_mock_2.json

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -305,11 +305,7 @@
305305
111,
306306
109,
307307
47,
308-
117,
309-
115,
310-
101,
311-
114,
312-
47,
308+
64,
313309
71,
314310
114,
315311
111,
@@ -338,10 +334,10 @@
338334
"application/json; charset\u003dUTF-8"
339335
],
340336
"date": [
341-
"Wed, 02 Nov 2022 17:40:38 GMT"
337+
"Wed, 02 Nov 2022 23:12:53 GMT"
342338
],
343339
"expires": [
344-
"Wed, 02 Nov 2022 17:40:38 GMT"
340+
"Wed, 02 Nov 2022 23:12:53 GMT"
345341
],
346342
"p3p": [
347343
"CP\u003d\"This is not a P3P policy! See g.co/p3phelp for more info.\""
@@ -350,7 +346,7 @@
350346
"scaffolding on HTTPServer2"
351347
],
352348
"set-cookie": [
353-
"CONSENT\u003dPENDING+067; expires\u003dFri, 01-Nov-2024 17:40:38 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
349+
"CONSENT\u003dPENDING+288; expires\u003dFri, 01-Nov-2024 23:12:53 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
354350
],
355351
"vary": [
356352
"Origin",
@@ -367,7 +363,7 @@
367363
"0"
368364
]
369365
},
370-
"responseBody": "{\"responseContext\":{\"visitorData\":\"CgtRX2dsZzVrWGRZQSiW14qbBg%3D%3D\",\"serviceTrackingParams\":[{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"WEB\"},{\"key\":\"cver\",\"value\":\"2.20221101.00.00\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"ResolveUrl_rid\",\"value\":\"0x1a56ddef412e73c5\"}]},{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"e\",\"value\":\"1714240,9453586,9453587,23804281,23882502,23918597,23934970,23946420,23966208,23983296,23986022,23998056,24001373,24002022,24002025,24004644,24007246,24034168,24036948,24077241,24080738,24120819,24135310,24140247,24152443,24161116,24162920,24164186,24166867,24169501,24175559,24181174,24184445,24185614,24187043,24187377,24191629,24199724,24211178,24216872,24219359,24219713,24224266,24229161,24241378,24248092,24248955,24249296,24254502,24255543,24255545,24260783,24262346,24263273,24263796,24265820,24267564,24267570,24268142,24274310,24276618,24278596,24279196,24279628,24280997,24283093,24283556,24286005,24286017,24287169,24287327,24287604,24287795,24288045,24288912,24290971,24291857,24292955,24292977,24299747,24390675,24391541,24391851,24392269,24392403,24392421,24393382,24394397,24396645,24396819,24398124,24398991,24399052,24399918,24400658,24401557,24406381,24406984,24407199,24410009,39322399,39322504,39322574\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"2.20221101\"},{\"key\":\"client.name\",\"value\":\"WEB\"},{\"key\":\"client.fexp\",\"value\":\"24283556,24249296,24185614,24263273,24274310,1714240,24262346,24263796,24260783,24267564,24187043,23986022,24406381,24299747,24399052,24248092,24211178,24291857,24152443,24135310,24407199,24191629,24229161,24396819,24241378,24391541,24292977,24164186,24169501,24276618,24400658,24280997,24401557,24120819,24288045,39322574,24224266,24034168,23934970,24002022,24181174,24287795,24175559,23882502,24283093,24001373,24292955,24290971,24161116,9453587,24393382,24410009,24391851,24288912,24394397,24392269,24002025,24268142,24399918,24390675,24278596,24216872,24286005,24219713,24080738,23918597,39322504,24279196,24392403,24396645,9453586,24279628,39322399,24265820,24254502,24036948,24162920,24398991,24255545,24166867,23998056,24007246,24392421,24255543,24398124,24286017,24140247,23804281,24287169,24287327,23983296,24406984,24199724,23966208,24184445,24219359,24267570,24248955,23946420,24187377,24077241,24004644,24287604\"}]}],\"mainAppWebResponseContext\":{\"loggedOut\":true},\"webResponseContextExtensionData\":{\"hasDecorated\":true}},\"endpoint\":{\"clickTrackingParams\":\"IhMI1s3RtYWQ-wIV99URCB21lwMbMghleHRlcm5hbA\u003d\u003d\",\"commandMetadata\":{\"webCommandMetadata\":{\"url\":\"/youtubei/v1/navigation/resolve_url\",\"webPageType\":\"WEB_PAGE_TYPE_CHANNEL\",\"rootVe\":3611,\"apiUrl\":\"/youtubei/v1/browse\"},\"resolveUrlCommandMetadata\":{\"isVanityUrl\":true}},\"browseEndpoint\":{\"browseId\":\"UCYJ61XIK64sp6ZFFS8sctxw\",\"params\":\"EgC4AQDyBgQKAjIA\"}}}",
366+
"responseBody": "{\"responseContext\":{\"visitorData\":\"CgtieTdiV1lXeWFmTSj18oubBg%3D%3D\",\"serviceTrackingParams\":[{\"service\":\"CSI\",\"params\":[{\"key\":\"c\",\"value\":\"WEB\"},{\"key\":\"cver\",\"value\":\"2.20221101.00.00\"},{\"key\":\"yt_li\",\"value\":\"0\"},{\"key\":\"ResolveUrl_rid\",\"value\":\"0x01203331c856c87e\"}]},{\"service\":\"GFEEDBACK\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"},{\"key\":\"e\",\"value\":\"1714254,23804281,23882502,23918597,23934970,23940247,23946420,23966208,23983296,23986015,23998056,24001373,24002022,24002025,24004644,24007246,24034168,24036948,24077241,24080738,24120819,24135310,24140247,24152443,24161116,24162919,24164186,24166867,24169501,24181174,24185614,24187043,24187377,24191629,24199724,24211178,24218780,24219713,24224266,24224808,24229161,24241378,24248091,24254502,24255543,24255545,24256985,24260783,24262346,24262775,24263796,24265820,24267564,24267570,24268142,24273932,24278596,24279196,24279628,24280221,24283093,24283556,24286003,24286017,24286291,24287169,24287327,24287795,24288045,24288912,24290842,24290971,24291857,24292955,24297748,24298082,24299548,24299747,24390376,24390675,24390916,24391541,24392399,24393382,24394397,24396645,24396818,24398124,24398981,24400943,24401137,24401291,24401557,24406381,24406605,24406984,24407200,24408325,39322399,39322504,39322574\"}]},{\"service\":\"GUIDED_HELP\",\"params\":[{\"key\":\"logged_in\",\"value\":\"0\"}]},{\"service\":\"ECATCHER\",\"params\":[{\"key\":\"client.version\",\"value\":\"2.20221101\"},{\"key\":\"client.name\",\"value\":\"WEB\"},{\"key\":\"client.fexp\",\"value\":\"24135310,24080738,24255543,24267570,23918597,24406605,24164186,24396818,24398124,23804281,24406984,24401137,24286291,23983296,24219713,23966208,24287327,24287169,24291857,24398981,24248091,24152443,24286003,24140247,24286017,24390675,24290842,24036948,24224808,24396645,1714254,24218780,39322399,24161116,24299747,23940247,24401291,24400943,24278596,24256985,24001373,23946420,24268142,24298082,24290971,24077241,24292955,24408325,24229161,24169501,24401557,24391541,24241378,24390916,24297748,24224266,24002022,24280221,23934970,24407200,24034168,24262775,39322574,24181174,23882502,24211178,24120819,24265820,24288045,39322504,24254502,24288912,24166867,24255545,24393382,24279628,24394397,24002025,24279196,24273932,24191629,24283093,24263796,24187043,24406381,24390376,24267564,24260783,24287795,24392399,24004644,24007246,23986015,24299548,24162919,24187377,24283556,24262346,23998056,24185614,24199724\"}]}],\"mainAppWebResponseContext\":{\"loggedOut\":true},\"webResponseContextExtensionData\":{\"hasDecorated\":true}},\"endpoint\":{\"clickTrackingParams\":\"IhMIz4TI18-Q-wIV5YE4Ch01jgrjMghleHRlcm5hbA\u003d\u003d\",\"commandMetadata\":{\"webCommandMetadata\":{\"url\":\"/youtubei/v1/navigation/resolve_url\",\"webPageType\":\"WEB_PAGE_TYPE_CHANNEL\",\"rootVe\":3611,\"apiUrl\":\"/youtubei/v1/browse\"},\"resolveUrlCommandMetadata\":{\"isVanityUrl\":true}},\"browseEndpoint\":{\"browseId\":\"UCYJ61XIK64sp6ZFFS8sctxw\",\"params\":\"EgC4AQDyBgQKAjIA\"}}}",
371367
"latestUrl": "https://www.youtube.com/youtubei/v1/navigation/resolve_url?key\u003dAIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8\u0026prettyPrint\u003dfalse"
372368
}
373369
}

extractor/src/test/resources/org/schabi/newpipe/extractor/services/youtube/extractor/channel/gronkh/generated_mock_3.json

Lines changed: 4 additions & 4 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)