Skip to content

Commit 0a7b72a

Browse files
authored
Merge pull request #1354 from AudricV/yt_more_kiosks_and_trending_deprecation
2 parents 426a227 + 2cccf48 commit 0a7b72a

33 files changed

Lines changed: 4849 additions & 39 deletions
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.schabi.newpipe.extractor.exceptions;
2+
3+
/**
4+
* Exception for contents not supported in a country.
5+
*
6+
* <p>
7+
* Unsupported content means content is not intentionally geographically restricted such as for
8+
* distribution rights, for which {@link GeographicRestrictionException} should be used instead.
9+
* </p>
10+
*/
11+
public class UnsupportedContentInCountryException extends ContentNotAvailableException {
12+
13+
public UnsupportedContentInCountryException(final String message) {
14+
super(message);
15+
}
16+
17+
public UnsupportedContentInCountryException(final String message, final Throwable cause) {
18+
super(message, cause);
19+
}
20+
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/ClientsConstants.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ private ClientsConstants() {
4545
static final String WEB_EMBEDDED_CLIENT_NAME = "WEB_EMBEDDED_PLAYER";
4646
static final String WEB_EMBEDDED_CLIENT_VERSION = "1.20250121.00.00";
4747

48+
// WEB_MUSIC_ANALYTICS (YouTube charts)
49+
50+
static final String WEB_MUSIC_ANALYTICS_CLIENT_ID = "31";
51+
static final String WEB_MUSIC_ANALYTICS_CLIENT_NAME = "WEB_MUSIC_ANALYTICS";
52+
static final String WEB_MUSIC_ANALYTICS_CLIENT_VERSION = "2.0";
53+
4854
// IOS (iOS YouTube app) client fields
4955

5056
static final String IOS_CLIENT_ID = "5";

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/InnertubeClientRequestInfo.java

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package org.schabi.newpipe.extractor.services.youtube;
22

3+
import javax.annotation.Nonnull;
4+
import javax.annotation.Nullable;
5+
36
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.ANDROID_CLIENT_ID;
47
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.ANDROID_CLIENT_NAME;
58
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.ANDROID_CLIENT_VERSION;
@@ -16,11 +19,11 @@
1619
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_CLIENT_NAME;
1720
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_EMBEDDED_CLIENT_ID;
1821
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_EMBEDDED_CLIENT_NAME;
22+
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_EMBEDDED_CLIENT_VERSION;
1923
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_HARDCODED_CLIENT_VERSION;
20-
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_REMIX_HARDCODED_CLIENT_VERSION;
21-
22-
import javax.annotation.Nonnull;
23-
import javax.annotation.Nullable;
24+
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_MUSIC_ANALYTICS_CLIENT_ID;
25+
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_MUSIC_ANALYTICS_CLIENT_NAME;
26+
import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.WEB_MUSIC_ANALYTICS_CLIENT_VERSION;
2427

2528
// TODO: add docs
2629

@@ -38,28 +41,28 @@ public static final class ClientInfo {
3841
@Nonnull
3942
public String clientVersion;
4043
@Nonnull
41-
public String clientScreen;
42-
@Nullable
4344
public String clientId;
4445
@Nullable
46+
public String clientScreen;
47+
@Nullable
4548
public String visitorData;
4649

4750
private ClientInfo(@Nonnull final String clientName,
4851
@Nonnull final String clientVersion,
49-
@Nonnull final String clientScreen,
50-
@Nullable final String clientId,
52+
@Nonnull final String clientId,
53+
@Nullable final String clientScreen,
5154
@Nullable final String visitorData) {
5255
this.clientName = clientName;
5356
this.clientVersion = clientVersion;
54-
this.clientScreen = clientScreen;
5557
this.clientId = clientId;
58+
this.clientScreen = clientScreen;
5659
this.visitorData = visitorData;
5760
}
5861
}
5962

6063
public static final class DeviceInfo {
6164

62-
@Nonnull
65+
@Nullable
6366
public String platform;
6467
@Nullable
6568
public String deviceMake;
@@ -71,7 +74,7 @@ public static final class DeviceInfo {
7174
public String osVersion;
7275
public int androidSdkVersion;
7376

74-
private DeviceInfo(@Nonnull final String platform,
77+
private DeviceInfo(@Nullable final String platform,
7578
@Nullable final String deviceMake,
7679
@Nullable final String deviceModel,
7780
@Nullable final String osName,
@@ -96,8 +99,8 @@ private InnertubeClientRequestInfo(@Nonnull final ClientInfo clientInfo,
9699
public static InnertubeClientRequestInfo ofWebClient() {
97100
return new InnertubeClientRequestInfo(
98101
new InnertubeClientRequestInfo.ClientInfo(
99-
WEB_CLIENT_NAME, WEB_HARDCODED_CLIENT_VERSION, WATCH_CLIENT_SCREEN,
100-
WEB_CLIENT_ID, null),
102+
WEB_CLIENT_NAME, WEB_HARDCODED_CLIENT_VERSION, WEB_CLIENT_ID,
103+
WATCH_CLIENT_SCREEN, null),
101104
new InnertubeClientRequestInfo.DeviceInfo(DESKTOP_CLIENT_PLATFORM, null, null,
102105
null, null, -1));
103106
}
@@ -106,17 +109,27 @@ public static InnertubeClientRequestInfo ofWebClient() {
106109
public static InnertubeClientRequestInfo ofWebEmbeddedPlayerClient() {
107110
return new InnertubeClientRequestInfo(
108111
new InnertubeClientRequestInfo.ClientInfo(WEB_EMBEDDED_CLIENT_NAME,
109-
WEB_REMIX_HARDCODED_CLIENT_VERSION, EMBED_CLIENT_SCREEN,
110-
WEB_EMBEDDED_CLIENT_ID, null),
112+
WEB_EMBEDDED_CLIENT_VERSION, WEB_EMBEDDED_CLIENT_ID, EMBED_CLIENT_SCREEN,
113+
null),
111114
new InnertubeClientRequestInfo.DeviceInfo(DESKTOP_CLIENT_PLATFORM, null, null,
112115
null, null, -1));
113116
}
114117

118+
@Nonnull
119+
public static InnertubeClientRequestInfo ofWebMusicAnalyticsChartsClient() {
120+
return new InnertubeClientRequestInfo(
121+
new InnertubeClientRequestInfo.ClientInfo(WEB_MUSIC_ANALYTICS_CLIENT_NAME,
122+
WEB_MUSIC_ANALYTICS_CLIENT_VERSION, WEB_MUSIC_ANALYTICS_CLIENT_ID, null,
123+
null),
124+
new InnertubeClientRequestInfo.DeviceInfo(null, null, null,
125+
null, null, -1));
126+
}
127+
115128
@Nonnull
116129
public static InnertubeClientRequestInfo ofAndroidClient() {
117130
return new InnertubeClientRequestInfo(
118131
new InnertubeClientRequestInfo.ClientInfo(ANDROID_CLIENT_NAME,
119-
ANDROID_CLIENT_VERSION, WATCH_CLIENT_SCREEN, ANDROID_CLIENT_ID, null),
132+
ANDROID_CLIENT_VERSION, ANDROID_CLIENT_ID, WATCH_CLIENT_SCREEN, null),
120133
new InnertubeClientRequestInfo.DeviceInfo(MOBILE_CLIENT_PLATFORM, null, null,
121134
"Android", "15", 35));
122135
}
@@ -125,7 +138,7 @@ public static InnertubeClientRequestInfo ofAndroidClient() {
125138
public static InnertubeClientRequestInfo ofIosClient() {
126139
return new InnertubeClientRequestInfo(
127140
new InnertubeClientRequestInfo.ClientInfo(IOS_CLIENT_NAME, IOS_CLIENT_VERSION,
128-
WATCH_CLIENT_SCREEN, IOS_CLIENT_ID, null),
141+
IOS_CLIENT_ID, WATCH_CLIENT_SCREEN, null),
129142
new InnertubeClientRequestInfo.DeviceInfo(MOBILE_CLIENT_PLATFORM, "Apple",
130143
IOS_DEVICE_MODEL, "iOS", IOS_OS_VERSION, -1));
131144
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,8 +1181,8 @@ public static Map<String, List<String>> getOriginReferrerHeaders(@Nonnull final
11811181
* @param name The X-YouTube-Client-Name value.
11821182
* @param version X-YouTube-Client-Version value.
11831183
*/
1184-
static Map<String, List<String>> getClientHeaders(@Nonnull final String name,
1185-
@Nonnull final String version) {
1184+
public static Map<String, List<String>> getClientHeaders(@Nonnull final String name,
1185+
@Nonnull final String version) {
11861186
return Map.of("X-YouTube-Client-Name", List.of(name),
11871187
"X-YouTube-Client-Version", List.of(version));
11881188
}
@@ -1525,7 +1525,7 @@ public static String getVisitorDataFromInnertube(
15251525
}
15261526

15271527
@Nonnull
1528-
static JsonBuilder<JsonObject> prepareJsonBuilder(
1528+
public static JsonBuilder<JsonObject> prepareJsonBuilder(
15291529
@Nonnull final Localization localization,
15301530
@Nonnull final ContentCountry contentCountry,
15311531
@Nonnull final InnertubeClientRequestInfo innertubeClientRequestInfo,
@@ -1534,9 +1534,15 @@ static JsonBuilder<JsonObject> prepareJsonBuilder(
15341534
.object("context")
15351535
.object("client")
15361536
.value("clientName", innertubeClientRequestInfo.clientInfo.clientName)
1537-
.value("clientVersion", innertubeClientRequestInfo.clientInfo.clientVersion)
1538-
.value("clientScreen", innertubeClientRequestInfo.clientInfo.clientScreen)
1539-
.value("platform", innertubeClientRequestInfo.deviceInfo.platform);
1537+
.value("clientVersion", innertubeClientRequestInfo.clientInfo.clientVersion);
1538+
1539+
if (innertubeClientRequestInfo.clientInfo.clientScreen != null) {
1540+
builder.value("clientScreen", innertubeClientRequestInfo.clientInfo.clientScreen);
1541+
}
1542+
1543+
if (innertubeClientRequestInfo.deviceInfo.platform != null) {
1544+
builder.value("platform", innertubeClientRequestInfo.deviceInfo.platform);
1545+
}
15401546

15411547
if (innertubeClientRequestInfo.clientInfo.visitorData != null) {
15421548
builder.value("visitorData", innertubeClientRequestInfo.clientInfo.visitorData);

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeService.java

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,24 @@
3535
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor;
3636
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeSubscriptionExtractor;
3737
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeSuggestionExtractor;
38-
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeTrendingExtractor;
38+
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingExtractor;
39+
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeLiveExtractor;
40+
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingGamingVideosExtractor;
41+
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingMoviesAndShowsTrailersExtractor;
42+
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingMusicExtractor;
43+
import org.schabi.newpipe.extractor.services.youtube.extractors.kiosk.YoutubeTrendingPodcastsEpisodesExtractor;
3944
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
4045
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelTabLinkHandlerFactory;
4146
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeCommentsLinkHandlerFactory;
47+
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeLiveLinkHandlerFactory;
4248
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubePlaylistLinkHandlerFactory;
4349
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory;
4450
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
51+
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeTrendingGamingVideosLinkHandlerFactory;
4552
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeTrendingLinkHandlerFactory;
53+
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeTrendingMoviesAndShowsTrailersLinkHandlerFactory;
54+
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeTrendingMusicLinkHandlerFactory;
55+
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeTrendingPodcastsEpisodesLinkHandlerFactory;
4656
import org.schabi.newpipe.extractor.stream.StreamExtractor;
4757
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
4858
import org.schabi.newpipe.extractor.suggestion.SuggestionExtractor;
@@ -154,20 +164,71 @@ public SuggestionExtractor getSuggestionExtractor() {
154164
@Override
155165
public KioskList getKioskList() throws ExtractionException {
156166
final KioskList list = new KioskList(this);
157-
final ListLinkHandlerFactory h = YoutubeTrendingLinkHandlerFactory.getInstance();
167+
final ListLinkHandlerFactory trendingLHF = YoutubeTrendingLinkHandlerFactory.INSTANCE;
168+
final ListLinkHandlerFactory runningLivesLHF =
169+
YoutubeLiveLinkHandlerFactory.INSTANCE;
170+
final ListLinkHandlerFactory trendingPodcastsEpisodesLHF =
171+
YoutubeTrendingPodcastsEpisodesLinkHandlerFactory.INSTANCE;
172+
final ListLinkHandlerFactory trendingGamingVideosLHF =
173+
YoutubeTrendingGamingVideosLinkHandlerFactory.INSTANCE;
174+
final ListLinkHandlerFactory trendingMoviesAndShowsLHF =
175+
YoutubeTrendingMoviesAndShowsTrailersLinkHandlerFactory.INSTANCE;
176+
final ListLinkHandlerFactory trendingMusicLHF =
177+
YoutubeTrendingMusicLinkHandlerFactory.INSTANCE;
158178

159-
// add kiosks here e.g.:
160179
try {
180+
list.addKioskEntry(
181+
(streamingService, url, id) -> new YoutubeLiveExtractor(
182+
YoutubeService.this,
183+
runningLivesLHF.fromUrl(url),
184+
id),
185+
runningLivesLHF,
186+
YoutubeLiveLinkHandlerFactory.KIOSK_ID
187+
);
188+
list.addKioskEntry(
189+
(streamingService, url, id) -> new YoutubeTrendingPodcastsEpisodesExtractor(
190+
YoutubeService.this,
191+
trendingPodcastsEpisodesLHF.fromUrl(url),
192+
id),
193+
trendingPodcastsEpisodesLHF,
194+
YoutubeTrendingPodcastsEpisodesLinkHandlerFactory.KIOSK_ID
195+
);
196+
list.addKioskEntry(
197+
(streamingService, url, id) -> new YoutubeTrendingGamingVideosExtractor(
198+
YoutubeService.this,
199+
trendingGamingVideosLHF.fromUrl(url),
200+
id),
201+
trendingGamingVideosLHF,
202+
YoutubeTrendingGamingVideosLinkHandlerFactory.KIOSK_ID
203+
);
204+
list.addKioskEntry(
205+
(streamingService, url, id) ->
206+
new YoutubeTrendingMoviesAndShowsTrailersExtractor(
207+
YoutubeService.this,
208+
trendingMoviesAndShowsLHF.fromUrl(url),
209+
id),
210+
trendingMoviesAndShowsLHF,
211+
YoutubeTrendingMoviesAndShowsTrailersLinkHandlerFactory.KIOSK_ID
212+
);
213+
list.addKioskEntry(
214+
(streamingService, url, id) -> new YoutubeTrendingMusicExtractor(
215+
YoutubeService.this,
216+
trendingMusicLHF.fromUrl(url),
217+
id),
218+
trendingMusicLHF,
219+
YoutubeTrendingMusicLinkHandlerFactory.KIOSK_ID
220+
);
221+
// Deprecated (i.e. removed from the interface of YouTube) since July 21, 2025
161222
list.addKioskEntry(
162223
(streamingService, url, id) -> new YoutubeTrendingExtractor(
163224
YoutubeService.this,
164-
h.fromUrl(url),
225+
trendingLHF.fromUrl(url),
165226
id
166227
),
167-
h,
228+
trendingLHF,
168229
YoutubeTrendingExtractor.KIOSK_ID
169230
);
170-
list.setDefaultKiosk(YoutubeTrendingExtractor.KIOSK_ID);
231+
list.setDefaultKiosk(YoutubeLiveLinkHandlerFactory.KIOSK_ID);
171232
} catch (final Exception e) {
172233
throw new ExtractionException(e);
173234
}

0 commit comments

Comments
 (0)